--- /dev/null
+[submodule "src/3rdparty/v8"]
+ path = src/3rdparty/v8
+ url = git://github.com/aaronkennedy/v8.git
--- /dev/null
+
+
+NOTE! The LGPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to (the kde libraries) are copyrighted
+by the authors who actually wrote it.
+
+---------------------------------------------------------------------------
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor
+ Boston, MA 02110-1301, USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+
+ * Copyright 2006-2008 the V8 project authors. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "DateMath.h"
+
+#include <algorithm>
+#include <limits.h>
+#include <limits>
+#include <stdint.h>
+#include <time.h>
+
+//#if HAVE(SYS_TIME_H)
+#if defined(EXISTS_SYS_TIME)
+#include <sys/time.h>
+#endif
+
+//#if HAVE(SYS_TIMEB_H)
+#if defined(EXISTS_SYS_TIMEB)
+#include <sys/timeb.h>
+#endif
+
+#define NaN std::numeric_limits<double>::quiet_NaN()
+
+using namespace QV8DateConverter::WTF;
+
+namespace QV8DateConverter {
+
+namespace WTF {
+
+/* Constants */
+
+static const double minutesPerDay = 24.0 * 60.0;
+static const double secondsPerDay = 24.0 * 60.0 * 60.0;
+static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0;
+
+static const double usecPerSec = 1000000.0;
+
+static const double maxUnixTime = 2145859200.0; // 12/31/2037
+// ECMAScript asks not to support for a date of which total
+// millisecond value is larger than the following value.
+// See 15.9.1.14 of ECMA-262 5th edition.
+static const double maxECMAScriptTime = 8.64E15;
+
+// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1.
+// First for non-leap years, then for leap years.
+static const int firstDayOfMonth[2][12] = {
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
+};
+
+static inline bool isLeapYear(int year)
+{
+ if (year % 4 != 0)
+ return false;
+ if (year % 400 == 0)
+ return true;
+ if (year % 100 == 0)
+ return false;
+ return true;
+}
+
+static inline int daysInYear(int year)
+{
+ return 365 + isLeapYear(year);
+}
+
+static inline double daysFrom1970ToYear(int year)
+{
+ // The Gregorian Calendar rules for leap years:
+ // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years.
+ // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years.
+ // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years.
+
+ static const int leapDaysBefore1971By4Rule = 1970 / 4;
+ static const int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
+ static const int leapDaysBefore1971By400Rule = 1970 / 400;
+
+ const double yearMinusOne = year - 1;
+ const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule;
+ const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule;
+ const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule;
+
+ return 365.0 * (year - 1970) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
+}
+
+static inline double msToDays(double ms)
+{
+ return floor(ms / msPerDay);
+}
+
+int msToYear(double ms)
+{
+ int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
+ double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
+ if (msFromApproxYearTo1970 > ms)
+ return approxYear - 1;
+ if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms)
+ return approxYear + 1;
+ return approxYear;
+}
+
+int dayInYear(double ms, int year)
+{
+ return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
+}
+
+static inline double msToMilliseconds(double ms)
+{
+ double result = fmod(ms, msPerDay);
+ if (result < 0)
+ result += msPerDay;
+ return result;
+}
+
+// 0: Sunday, 1: Monday, etc.
+static inline int msToWeekDay(double ms)
+{
+ int wd = (static_cast<int>(msToDays(ms)) + 4) % 7;
+ if (wd < 0)
+ wd += 7;
+ return wd;
+}
+
+static inline int msToSeconds(double ms)
+{
+ double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
+ if (result < 0)
+ result += secondsPerMinute;
+ return static_cast<int>(result);
+}
+
+static inline int msToMinutes(double ms)
+{
+ double result = fmod(floor(ms / msPerMinute), minutesPerHour);
+ if (result < 0)
+ result += minutesPerHour;
+ return static_cast<int>(result);
+}
+
+static inline int msToHours(double ms)
+{
+ double result = fmod(floor(ms/msPerHour), hoursPerDay);
+ if (result < 0)
+ result += hoursPerDay;
+ return static_cast<int>(result);
+}
+
+int monthFromDayInYear(int dayInYear, bool leapYear)
+{
+ const int d = dayInYear;
+ int step;
+
+ if (d < (step = 31))
+ return 0;
+ step += (leapYear ? 29 : 28);
+ if (d < step)
+ return 1;
+ if (d < (step += 31))
+ return 2;
+ if (d < (step += 30))
+ return 3;
+ if (d < (step += 31))
+ return 4;
+ if (d < (step += 30))
+ return 5;
+ if (d < (step += 31))
+ return 6;
+ if (d < (step += 31))
+ return 7;
+ if (d < (step += 30))
+ return 8;
+ if (d < (step += 31))
+ return 9;
+ if (d < (step += 30))
+ return 10;
+ return 11;
+}
+
+static inline bool checkMonth(int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth)
+{
+ startDayOfThisMonth = startDayOfNextMonth;
+ startDayOfNextMonth += daysInThisMonth;
+ return (dayInYear <= startDayOfNextMonth);
+}
+
+int dayInMonthFromDayInYear(int dayInYear, bool leapYear)
+{
+ const int d = dayInYear;
+ int step;
+ int next = 30;
+
+ if (d <= next)
+ return d + 1;
+ const int daysInFeb = (leapYear ? 29 : 28);
+ if (checkMonth(d, step, next, daysInFeb))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ step = next;
+ return d - step;
+}
+
+static inline int monthToDayInYear(int month, bool isLeapYear)
+{
+ return firstDayOfMonth[isLeapYear][month];
+}
+
+static inline double timeToMS(double hour, double min, double sec, double ms)
+{
+ return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
+}
+
+double dateToDaysFrom1970(int year, int month, int day)
+{
+ year += month / 12;
+
+ month %= 12;
+ if (month < 0) {
+ month += 12;
+ --year;
+ }
+
+ double yearday = floor(daysFrom1970ToYear(year));
+ int monthday = monthToDayInYear(month, isLeapYear(year));
+
+ return yearday + monthday + day - 1;
+}
+
+static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
+{
+ double days = (day - 32075)
+ + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
+ + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
+ - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
+ - 2440588;
+ return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
+}
+
+// We follow the recommendation of RFC 2822 to consider all
+// obsolete time zones not listed here equivalent to "-0000".
+static const struct KnownZone {
+ const
+ char tzName[4];
+ int tzOffset;
+} known_zones[] = {
+ { "UT", 0 },
+ { "GMT", 0 },
+ { "EST", -300 },
+ { "EDT", -240 },
+ { "CST", -360 },
+ { "CDT", -300 },
+ { "MST", -420 },
+ { "MDT", -360 },
+ { "PST", -480 },
+ { "PDT", -420 }
+};
+
+double timeClip(double t)
+{
+ if (!isfinite(t))
+ return NaN;
+ if (fabs(t) > maxECMAScriptTime)
+ return NaN;
+ return trunc(t);
+}
+} // namespace WTF
+
+namespace JSC {
+
+double gregorianDateTimeToMS(const GregorianDateTime& t, double milliSeconds)
+{
+ double day = dateToDaysFrom1970(t.year + 1900, t.month, t.monthDay);
+ double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds);
+ double result = (day * WTF::msPerDay) + ms;
+
+ return result;
+}
+
+// input is UTC
+void msToGregorianDateTime(double ms, GregorianDateTime& tm)
+{
+ const int year = msToYear(ms);
+ tm.second = msToSeconds(ms);
+ tm.minute = msToMinutes(ms);
+ tm.hour = msToHours(ms);
+ tm.weekDay = msToWeekDay(ms);
+ tm.yearDay = dayInYear(ms, year);
+ tm.monthDay = dayInMonthFromDayInYear(tm.yearDay, isLeapYear(year));
+ tm.month = monthFromDayInYear(tm.yearDay, isLeapYear(year));
+ tm.year = year - 1900;
+ tm.isDST = false;
+ tm.utcOffset = static_cast<long>(0); // no ExecState :. cannot calculate offset. Assume UTC output.
+ tm.timeZone = NULL;
+}
+
+} // namespace JSC
+
+} // namespace QV8DateConverter
+
--- /dev/null
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ */
+
+#ifndef DateMath_h
+#define DateMath_h
+
+#include <math.h>
+#include <string.h>
+#include <time.h>
+
+namespace QV8DateConverter {
+
+namespace WTF {
+
+double timeClip(double);
+
+const char * const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+const double hoursPerDay = 24.0;
+const double minutesPerHour = 60.0;
+const double secondsPerHour = 60.0 * 60.0;
+const double secondsPerMinute = 60.0;
+const double msPerSecond = 1000.0;
+const double msPerMinute = 60.0 * 1000.0;
+const double msPerHour = 60.0 * 60.0 * 1000.0;
+const double msPerDay = 24.0 * 60.0 * 60.0 * 1000.0;
+const double msPerMonth = 2592000000.0;
+
+// Returns the number of days from 1970-01-01 to the specified date.
+double dateToDaysFrom1970(int year, int month, int day);
+int msToYear(double ms);
+int dayInYear(double ms, int year);
+int monthFromDayInYear(int dayInYear, bool leapYear);
+int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
+
+} // namespace WTF
+
+using WTF::dateToDaysFrom1970;
+using WTF::dayInMonthFromDayInYear;
+using WTF::dayInYear;
+using WTF::minutesPerHour;
+using WTF::monthFromDayInYear;
+using WTF::msPerDay;
+using WTF::msPerSecond;
+using WTF::msToYear;
+using WTF::secondsPerMinute;
+
+namespace JSC {
+struct GregorianDateTime;
+
+void msToGregorianDateTime(double, GregorianDateTime&);
+double gregorianDateTimeToMS(const GregorianDateTime&, double);
+
+// Intentionally overridding the default tm of the system.
+// The members of tm differ on various operating systems.
+struct GregorianDateTime {
+ GregorianDateTime()
+ : second(0)
+ , minute(0)
+ , hour(0)
+ , weekDay(0)
+ , monthDay(0)
+ , yearDay(0)
+ , month(0)
+ , year(0)
+ , isDST(0)
+ , utcOffset(0)
+ , timeZone(0)
+ {
+ }
+
+ ~GregorianDateTime()
+ {
+ delete [] timeZone;
+ }
+
+ GregorianDateTime(const tm& inTm)
+ : second(inTm.tm_sec)
+ , minute(inTm.tm_min)
+ , hour(inTm.tm_hour)
+ , weekDay(inTm.tm_wday)
+ , monthDay(inTm.tm_mday)
+ , yearDay(inTm.tm_yday)
+ , month(inTm.tm_mon)
+ , year(inTm.tm_year)
+ , isDST(inTm.tm_isdst)
+ {
+ utcOffset = static_cast<int>(0);
+ timeZone = 0;
+ }
+
+ operator tm() const
+ {
+ tm ret;
+ memset(&ret, 0, sizeof(ret));
+
+ ret.tm_sec = second;
+ ret.tm_min = minute;
+ ret.tm_hour = hour;
+ ret.tm_wday = weekDay;
+ ret.tm_mday = monthDay;
+ ret.tm_yday = yearDay;
+ ret.tm_mon = month;
+ ret.tm_year = year;
+ ret.tm_isdst = isDST;
+ return ret;
+ }
+
+ void copyFrom(const GregorianDateTime& rhs)
+ {
+ second = rhs.second;
+ minute = rhs.minute;
+ hour = rhs.hour;
+ weekDay = rhs.weekDay;
+ monthDay = rhs.monthDay;
+ yearDay = rhs.yearDay;
+ month = rhs.month;
+ year = rhs.year;
+ isDST = rhs.isDST;
+ utcOffset = rhs.utcOffset;
+ if (rhs.timeZone) {
+ int inZoneSize = strlen(rhs.timeZone) + 1;
+ timeZone = new char[inZoneSize];
+ strncpy(timeZone, rhs.timeZone, inZoneSize);
+ } else
+ timeZone = 0;
+ }
+
+ int second;
+ int minute;
+ int hour;
+ int weekDay;
+ int monthDay;
+ int yearDay;
+ int month;
+ int year;
+ int isDST;
+ int utcOffset;
+ char* timeZone;
+};
+
+static inline int gmtoffset(const GregorianDateTime& t)
+{
+ return t.utcOffset;
+}
+
+} // namespace JSC
+
+} // namespace QV8DateConverter
+
+#endif // DateMath_h
--- /dev/null
+This is a snapshot of the files: DateMath.h and DateMath.cpp
+from a snapshot of JavaScriptCore from
+
+ git://gitorious.org/qtwebkit/qtwebkit.git
+
+The commit imported was from the
+
+ javascriptcore-snapshot-27012011 branch/tag
+
+and has the sha1 checksum
+
+ 3ab0f621048fbeb480b687a28ed31d92d8506150
+
+The two files were then modified slightly so that unneeded
+functionality was removed (mostly regarding timezone offset).
--- /dev/null
+Subproject commit 15eb9c6a9444307a867a854c742505c15bd8b867
DEFINES += QT_NO_OPENTYPE
INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src
+
+macx:CONFIG(debug, debug|release) {
+ LIBS += -L../v8/ -lv8_debug
+} else {
+ LIBS += -L../v8/ -lv8
+}
+
+# Prevent qmake adding v8 as a dependency
+CONFIG -= explicitlib
#include <QtGui/qgraphicstransform.h>
#include <qlistmodelinterface_p.h>
+#include <private/qv8engine_p.h>
+
#include <float.h>
QT_BEGIN_NAMESPACE
If \a item is a \c null value, this maps the point from the coordinate
system of the root QML view.
*/
-QScriptValue QDeclarativeItem::mapFromItem(const QScriptValue &item, qreal x, qreal y) const
+void QDeclarativeItem::mapFromItem(QDeclarativeV8Function *args) const
{
- QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
- QDeclarativeItem *itemObj = qobject_cast<QDeclarativeItem*>(item.toQObject());
- if (!itemObj && !item.isNull()) {
- qmlInfo(this) << "mapFromItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
- return 0;
- }
+ if (args->Length() != 0) {
+ v8::Local<v8::Value> item = (*args)[0];
+ QV8Engine *engine = args->engine();
- // If QGraphicsItem::mapFromItem() is called with 0, behaves the same as mapFromScene()
- QPointF p = qobject_cast<QGraphicsItem*>(this)->mapFromItem(itemObj, x, y);
- sv.setProperty(QLatin1String("x"), p.x());
- sv.setProperty(QLatin1String("y"), p.y());
- return sv;
+ QDeclarativeItem *itemObj = 0;
+ if (!item->IsNull())
+ itemObj = qobject_cast<QDeclarativeItem*>(engine->toQObject(item));
+
+ if (!itemObj && !item->IsNull()) {
+ qmlInfo(this) << "mapFromItem() given argument \"" << engine->toString(item->ToString())
+ << "\" which is neither null nor an Item";
+ return;
+ }
+
+ v8::Local<v8::Object> rv = v8::Object::New();
+ args->returnValue(rv);
+
+ qreal x = (args->Length() > 1)?(*args)[1]->NumberValue():0;
+ qreal y = (args->Length() > 2)?(*args)[2]->NumberValue():0;
+
+ QPointF p = QGraphicsItem::mapFromItem(itemObj, x, y);
+
+ rv->Set(v8::String::New("x"), v8::Number::New(p.x()));
+ rv->Set(v8::String::New("y"), v8::Number::New(p.y()));
+ }
}
/*!
If \a item is a \c null value, this maps \a x and \a y to the coordinate
system of the root QML view.
*/
-QScriptValue QDeclarativeItem::mapToItem(const QScriptValue &item, qreal x, qreal y) const
+void QDeclarativeItem::mapToItem(QDeclarativeV8Function *args) const
{
- QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
- QDeclarativeItem *itemObj = qobject_cast<QDeclarativeItem*>(item.toQObject());
- if (!itemObj && !item.isNull()) {
- qmlInfo(this) << "mapToItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
- return 0;
- }
+ if (args->Length() != 0) {
+ v8::Local<v8::Value> item = (*args)[0];
+ QV8Engine *engine = args->engine();
+
+ QDeclarativeItem *itemObj = 0;
+ if (!item->IsNull())
+ itemObj = qobject_cast<QDeclarativeItem*>(engine->toQObject(item));
+
+ if (!itemObj && !item->IsNull()) {
+ qmlInfo(this) << "mapToItem() given argument \"" << engine->toString(item->ToString())
+ << "\" which is neither null nor an Item";
+ return;
+ }
+
+ v8::Local<v8::Object> rv = v8::Object::New();
+ args->returnValue(rv);
+
+ qreal x = (args->Length() > 1)?(*args)[1]->NumberValue():0;
+ qreal y = (args->Length() > 2)?(*args)[2]->NumberValue():0;
- // If QGraphicsItem::mapToItem() is called with 0, behaves the same as mapToScene()
- QPointF p = qobject_cast<QGraphicsItem*>(this)->mapToItem(itemObj, x, y);
- sv.setProperty(QLatin1String("x"), p.x());
- sv.setProperty(QLatin1String("y"), p.y());
- return sv;
+ QPointF p = QGraphicsItem::mapToItem(itemObj, x, y);
+
+ rv->Set(v8::String::New("x"), v8::Number::New(p.x()));
+ rv->Set(v8::String::New("y"), v8::Number::New(p.y()));
+ }
}
/*!
class QDeclarativeKeyEvent;
class QDeclarativeAnchors;
class QDeclarativeItemPrivate;
+class QDeclarativeV8Function;
class Q_DECLARATIVE_EXPORT QDeclarativeItem : public QGraphicsObject, public QDeclarativeParserStatus
{
Q_OBJECT
bool keepMouseGrab() const;
void setKeepMouseGrab(bool);
- Q_INVOKABLE QScriptValue mapFromItem(const QScriptValue &item, qreal x, qreal y) const;
- Q_INVOKABLE QScriptValue mapToItem(const QScriptValue &item, qreal x, qreal y) const;
+ Q_INVOKABLE void mapFromItem(QDeclarativeV8Function*) const;
+ Q_INVOKABLE void mapToItem(QDeclarativeV8Function*) const;
Q_INVOKABLE void forceActiveFocus();
Q_INVOKABLE QDeclarativeItem *childAt(qreal x, qreal y) const;
}
}
-QScriptValue QSGItem::mapFromItem(const QScriptValue &item, qreal x, qreal y) const
+void QSGItem::mapFromItem(QDeclarativeV8Function *args) const
{
- QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
- QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject());
- if (!itemObj && !item.isNull()) {
- qmlInfo(this) << "mapFromItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
- return 0;
- }
+ if (args->Length() != 0) {
+ v8::Local<v8::Value> item = (*args)[0];
+ QV8Engine *engine = args->engine();
+
+ QSGItem *itemObj = 0;
+ if (!item->IsNull())
+ itemObj = qobject_cast<QSGItem*>(engine->toQObject(item));
+
+ if (!itemObj && !item->IsNull()) {
+ qmlInfo(this) << "mapFromItem() given argument \"" << engine->toString(item->ToString())
+ << "\" which is neither null nor an Item";
+ return;
+ }
+
+ v8::Local<v8::Object> rv = v8::Object::New();
+ args->returnValue(rv);
+
+ qreal x = (args->Length() > 1)?(*args)[1]->NumberValue():0;
+ qreal y = (args->Length() > 2)?(*args)[2]->NumberValue():0;
- // If QSGItem::mapFromItem() is called with 0, behaves the same as mapFromScene()
- QPointF p = mapFromItem(itemObj, QPointF(x, y));
- sv.setProperty(QLatin1String("x"), p.x());
- sv.setProperty(QLatin1String("y"), p.y());
- return sv;
+ QPointF p = mapFromItem(itemObj, QPointF(x, y));
+
+ rv->Set(v8::String::New("x"), v8::Number::New(p.x()));
+ rv->Set(v8::String::New("y"), v8::Number::New(p.y()));
+ }
}
QTransform QSGItem::itemTransform(QSGItem *other, bool *ok) const
return t;
}
-QScriptValue QSGItem::mapToItem(const QScriptValue &item, qreal x, qreal y) const
+void QSGItem::mapToItem(QDeclarativeV8Function *args) const
{
- QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject();
- QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject());
- if (!itemObj && !item.isNull()) {
- qmlInfo(this) << "mapToItem() given argument \"" << item.toString() << "\" which is neither null nor an Item";
- return 0;
- }
+ if (args->Length() != 0) {
+ v8::Local<v8::Value> item = (*args)[0];
+ QV8Engine *engine = args->engine();
+
+ QSGItem *itemObj = 0;
+ if (!item->IsNull())
+ itemObj = qobject_cast<QSGItem*>(engine->toQObject(item));
+
+ if (!itemObj && !item->IsNull()) {
+ qmlInfo(this) << "mapToItem() given argument \"" << engine->toString(item->ToString())
+ << "\" which is neither null nor an Item";
+ return;
+ }
+
+ v8::Local<v8::Object> rv = v8::Object::New();
+ args->returnValue(rv);
+
+ qreal x = (args->Length() > 1)?(*args)[1]->NumberValue():0;
+ qreal y = (args->Length() > 2)?(*args)[2]->NumberValue():0;
- // If QSGItem::mapToItem() is called with 0, behaves the same as mapToScene()
- QPointF p = mapToItem(itemObj, QPointF(x, y));
- sv.setProperty(QLatin1String("x"), p.x());
- sv.setProperty(QLatin1String("y"), p.y());
- return sv;
+ QPointF p = mapToItem(itemObj, QPointF(x, y));
+
+ rv->Set(v8::String::New("x"), v8::Number::New(p.x()));
+ rv->Set(v8::String::New("y"), v8::Number::New(p.y()));
+ }
}
void QSGItem::forceActiveFocus()
void polish();
- Q_INVOKABLE QScriptValue mapFromItem(const QScriptValue &item, qreal x, qreal y) const;
- Q_INVOKABLE QScriptValue mapToItem(const QScriptValue &item, qreal x, qreal y) const;
+ Q_INVOKABLE void mapFromItem(QDeclarativeV8Function*) const;
+ Q_INVOKABLE void mapToItem(QDeclarativeV8Function*) const;
Q_INVOKABLE void forceActiveFocus();
Q_INVOKABLE QSGItem *childAt(qreal x, qreal y) const;
setNotifyOnValueChanged(true);
}
-QDeclarativeBinding::QDeclarativeBinding(const QScriptValue &func, QObject *obj, QDeclarativeContextData *ctxt, QObject *parent)
-: QDeclarativeExpression(ctxt, obj, func, *new QDeclarativeBindingPrivate)
+/*!
+ \internal
+
+ To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
+ For example:
+ v8::Handle<v8::Function> function;
+ new QDeclarativeBInding(&function, scope, ctxt);
+ */
+QDeclarativeBinding::QDeclarativeBinding(void *functionPtr, QObject *obj, QDeclarativeContextData *ctxt,
+ QObject *parent)
+: QDeclarativeExpression(ctxt, obj, functionPtr, *new QDeclarativeBindingPrivate)
{
setParent(parent);
setNotifyOnValueChanged(true);
bool isUndefined = false;
QVariant value;
- QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
+ v8::HandleScope handle_scope;
+ v8::Local<v8::Value> result = d->v8value(0, &isUndefined);
if (wasDeleted) {
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return;
}
- if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
- value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
- } else if (scriptValue.isNull() &&
- d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
+ if (isUndefined) {
+ } else if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
+ value = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject *> >());
+ } else if (result->IsNull() && d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
value = QVariant::fromValue((QObject *)0);
} else {
- value = ep->scriptValueToVariant(scriptValue, d->property.propertyType());
+ value = ep->v8engine.toVariant(result, d->property.propertyType());
if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
// If the object is null, we extract the predicted type. While this isn't
// 100% reliable, in many cases it gives us better error messages if we
// assign this null-object to an incompatible property
- int type = ep->objectClass->objectType(scriptValue);
+ // XXX aakenned
+ // int type = ep->objectClass->objectType(scriptValue);
+ int type = QMetaType::QObjectStar;
QObject *o = 0;
value = QVariant(type, (void *)&o);
}
QLatin1String(QMetaType::typeName(d->property.propertyType())) +
QLatin1String(" ") + d->property.name());
- } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) {
+ } else if (result->IsFunction()) {
QUrl url = QUrl(d->url);
int line = d->line;
QDeclarativeBinding(const QString &, QObject *, QDeclarativeContextData *, QObject *parent=0);
QDeclarativeBinding(void *, QDeclarativeRefCount *, QObject *, QDeclarativeContextData *,
const QString &, int, QObject *parent);
- QDeclarativeBinding(const QScriptValue &, QObject *, QDeclarativeContextData *, QObject *parent=0);
+ QDeclarativeBinding(void *, QObject *, QDeclarativeContextData *, QObject *parent=0);
void setTarget(const QDeclarativeProperty &);
QDeclarativeProperty property() const;
} else {
QByteArray propType = type;
if (t >= QVariant::UserType || t == QVariant::Invalid) {
- //copy of QDeclarativeObjectScriptClass::enumType()
QByteArray scope;
QByteArray name;
int scopeIdx = propType.lastIndexOf("::");
#include "private/qdeclarativescriptparser_p.h"
#include "private/qdeclarativebinding_p.h"
#include "private/qdeclarativev4compiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QColor>
#include <QDebug>
}
} else {
// Otherwise we have to search the whole type
- // This matches the logic in QDeclarativeTypeNameScriptClass
+ // This matches the logic in QV8TypeWrapper
QByteArray enumName = enumValue.toUtf8();
const QMetaObject *metaObject = type->baseMetaObject();
for (int ii = metaObject->enumeratorCount() - 1; value == -1 && ii >= 0; --ii) {
if (propName.at(0).isUpper())
COMPILE_EXCEPTION(&prop, tr("Property names cannot begin with an upper case letter"));
- if (enginePrivate->globalClass->illegalNames().contains(propName))
+ if (enginePrivate->v8engine.illegalNames().contains(propName))
COMPILE_EXCEPTION(&prop, tr("Illegal property name"));
propNames.insert(prop.name);
QString nameStr = QString::fromUtf8(name);
if (nameStr.at(0).isUpper())
COMPILE_EXCEPTION(obj, tr("Signal names cannot begin with an upper case letter"));
- if (enginePrivate->globalClass->illegalNames().contains(nameStr))
+ if (enginePrivate->v8engine.illegalNames().contains(nameStr))
COMPILE_EXCEPTION(obj, tr("Illegal signal name"));
methodNames.insert(name);
}
QString nameStr = QString::fromUtf8(name);
if (nameStr.at(0).isUpper())
COMPILE_EXCEPTION(obj, tr("Method names cannot begin with an upper case letter"));
- if (enginePrivate->globalClass->illegalNames().contains(nameStr))
+ if (enginePrivate->v8engine.illegalNames().contains(nameStr))
COMPILE_EXCEPTION(obj, tr("Illegal method name"));
methodNames.insert(name);
}
}
- if (enginePrivate->globalClass->illegalNames().contains(val))
+ if (enginePrivate->v8engine.illegalNames().contains(val))
COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property"));
return true;
if (compileState.ids.count() == 0)
return -1;
- QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache(engine);
+ QDeclarativeIntegerCache *cache = new QDeclarativeIntegerCache();
for (QHash<QString, QDeclarativeParser::Object *>::ConstIterator iter = compileState.ids.begin();
iter != compileState.ids.end();
Sets graphics object parent because forgetting to do this is a frequent
and serious problem.
*/
-QScriptValue QDeclarativeComponent::createObject(QObject* parent)
+void QDeclarativeComponent::createObject(QDeclarativeV8Function *args)
{
- Q_D(QDeclarativeComponent);
- return d->createObject(parent, QScriptValue(QScriptValue::NullValue));
-}
+ Q_ASSERT(args);
+
+#define RETURN(result) { args->returnValue((result)); return; }
-/*!
- \internal
- Overloadable method allows properties to be set during creation
-*/
-QScriptValue QDeclarativeComponent::createObject(QObject* parent, const QScriptValue& valuemap)
-{
Q_D(QDeclarativeComponent);
- if (!valuemap.isObject() || valuemap.isArray()) {
- qmlInfo(this) << tr("createObject: value is not an object");
- return QScriptValue(QScriptValue::NullValue);
+ Q_ASSERT(d->engine);
+
+ QDeclarativeEngine *engine = d->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+ QV8Engine *v8engine = &ep->v8engine;
+
+ QDeclarativeContext *ctxt = creationContext();
+ if (!ctxt) ctxt = engine->rootContext();
+
+ v8::Local<v8::Object> valuemap;
+ if (args->Length() >= 2) {
+ v8::Local<v8::Value> v = (*args)[1];
+ if (!v->IsObject() || v->IsArray()) {
+ qmlInfo(this) << tr("createObject: value is not an object");
+ RETURN(v8::Null());
+ }
+ valuemap = v8::Local<v8::Object>::Cast(v);
}
- return d->createObject(parent, valuemap);
-}
-QScriptValue QDeclarativeComponentPrivate::createObject(QObject *publicParent, const QScriptValue valuemap)
-{
- Q_Q(QDeclarativeComponent);
- QDeclarativeContext* ctxt = q->creationContext();
- if(!ctxt && engine)
- ctxt = engine->rootContext();
- if (!ctxt)
- return QScriptValue(QScriptValue::NullValue);
- QObject* ret = q->beginCreate(ctxt);
+ QObject *parent = args->Length()?v8engine->toQObject((*args)[0]):0;
+
+ QObject *ret = beginCreate(ctxt);
if (!ret) {
- q->completeCreate();
- return QScriptValue(QScriptValue::NullValue);
+ completeCreate();
+ RETURN(v8::Null());
}
- if (publicParent) {
- ret->setParent(publicParent);
+ if (parent) {
+ ret->setParent(parent);
+
QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
bool needParent = false;
for (int ii = 0; ii < functions.count(); ++ii) {
- QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, publicParent);
+ QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, parent);
if (res == QDeclarativePrivate::Parented) {
needParent = false;
break;
qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene.");
}
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
- QDeclarativeData::get(ret, true)->setImplicitDestructible();
- QScriptValue newObject = priv->objectClass->newQObject(ret, QMetaType::QObjectStar);
-
- if (valuemap.isObject() && !valuemap.isArray()) {
- //Iterate through and assign properties
- QScriptValueIterator it(valuemap);
- while (it.hasNext()) {
- it.next();
- QScriptValue prop = newObject;
- QString propName = it.name();
- int index = propName.indexOf(QLatin1Char('.'));
- if (index > 0) {
- QString subProp = propName;
- int lastIndex = 0;
- while (index > 0) {
- subProp = propName.mid(lastIndex, index - lastIndex);
- prop = prop.property(subProp);
- lastIndex = index + 1;
- index = propName.indexOf(QLatin1Char('.'), index + 1);
- }
- prop.setProperty(propName.mid(propName.lastIndexOf(QLatin1Char('.')) + 1), it.value());
- } else {
- newObject.setProperty(propName, it.value());
- }
- }
+ v8::Handle<v8::Value> ov = v8engine->newQObject(ret);
+ Q_ASSERT(ov->IsObject());
+ v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+
+ if (!valuemap.IsEmpty()) {
+
+#define SET_ARGS_SOURCE \
+ "(function(object, values) {"\
+ "try {"\
+ "for(var property in values) {"\
+ "try {"\
+ "var properties = property.split(\".\");"\
+ "var o = object;"\
+ "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
+ "o = o[properties[ii]];"\
+ "}"\
+ "o[properties[properties.length - 1]] = values[property];"\
+ "} catch(e) {}"\
+ "}"\
+ "} catch(e) {}"\
+ "})"
+
+ v8::Local<v8::Script> script = v8engine->qmlModeCompile(SET_ARGS_SOURCE);
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(script->Run(args->qmlGlobal()));
+
+ // Try catch isn't needed as the function itself is loaded with try/catch
+ v8::Handle<v8::Value> args[] = { object, valuemap };
+ function->Call(v8engine->global(), 2, args);
}
- q->completeCreate();
+ completeCreate();
+
+ RETURN(object);
- return newObject;
+#undef RETURN
}
/*!
class QDeclarativeComponentPrivate;
class QDeclarativeEngine;
class QDeclarativeComponentAttached;
+class QDeclarativeV8Function;
class Q_DECLARATIVE_EXPORT QDeclarativeComponent : public QObject
{
Q_OBJECT
protected:
QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject* parent);
- Q_INVOKABLE QScriptValue createObject(QObject* parent);
- Q_INVOKABLE Q_REVISION(1) QScriptValue createObject(QObject* parent, const QScriptValue& valuemap); //XXX Versioning
+ Q_INVOKABLE void createObject(QDeclarativeV8Function *);
private:
QDeclarativeComponent(QDeclarativeEngine *, QDeclarativeCompiledData *, int, QObject *parent);
ConstructionState *state);
static void complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state);
- QScriptValue createObject(QObject *publicParent, const QScriptValue valuemap);
-
QDeclarativeEngine *engine;
QDeclarativeGuardedContextData creationContext;
#include "private/qdeclarativeengine_p.h"
#include "qdeclarativeengine.h"
#include "qdeclarativeinfo.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include "private/qdeclarativev4bindings_p.h"
#include <qscriptengine.h>
}
}
- if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
+ if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
int idx = data->propertyNames->value(name);
if (idx == -1) {
return;
}
- if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache(data->engine);
+ if (!data->propertyNames) data->propertyNames = new QDeclarativeIntegerCache();
int idx = data->propertyNames->value(name);
if (idx == -1) {
QDeclarativeContextData::QDeclarativeContextData()
-: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(0), propertyNames(0), contextObject(0),
- imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
- contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
- componentAttached(0)
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), publicContext(0),
+ propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0),
+ linkedContext(0), componentAttached(0)
{
}
QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt)
-: parent(0), engine(0), isInternal(false), ownedByParent(false), publicContext(ctxt), propertyNames(0), contextObject(0),
- imports(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0),
- contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0), linkedContext(0),
- componentAttached(0)
+: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), publicContext(ctxt),
+ propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), optimizedBindings(0),
+ linkedContext(0), componentAttached(0)
{
}
if (optimizedBindings)
optimizedBindings->release();
+ for (int ii = 0; ii < importedScripts.count(); ++ii)
+ importedScripts[ii].Dispose();
+
delete [] idValues;
if (isInternal)
friend class QDeclarativeEnginePrivate;
friend class QDeclarativeExpression;
friend class QDeclarativeExpressionPrivate;
- friend class QDeclarativeContextScriptClass;
- friend class QDeclarativeObjectScriptClass;
friend class QDeclarativeComponent;
friend class QDeclarativeComponentPrivate;
friend class QDeclarativeScriptPrivate;
#include <private/qobject_p.h>
#include "private/qdeclarativeguard_p.h"
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeContext;
QDeclarativeContextPrivate *asQDeclarativeContextPrivate();
quint32 isInternal:1;
quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
- quint32 dummy:30;
+ quint32 isJSContext:1;
+ quint32 dummy:29;
QDeclarativeContext *publicContext;
// Property name cache
QObject *contextObject;
// Any script blocks that exist on this context
- QList<QScriptValue> importedScripts;
+ // XXX aakenned
+ QList<v8::Persistent<v8::Object> > importedScripts;
+// QList<QScriptValue> importedScripts;
// Context base url
QUrl url;
inline QDeclarativeGuardedContextData(QDeclarativeContextData *);
inline ~QDeclarativeGuardedContextData();
+ inline QDeclarativeContextData *contextData();
inline void setContextData(QDeclarativeContextData *);
- inline QDeclarativeContextData *contextData();
+ inline bool isNull() const { return !m_contextData; }
inline operator QDeclarativeContextData*() const { return m_contextData; }
inline QDeclarativeContextData* operator->() const { return m_contextData; }
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativecontextscriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
-#include "private/qdeclarativeguard_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct ContextData : public QScriptDeclarativeClass::Object {
- ContextData() : overrideObject(0), isSharedContext(true) {}
- ContextData(QDeclarativeContextData *c, QObject *o)
- : context(c), scopeObject(o), overrideObject(0), isSharedContext(false), isUrlContext(false) {}
- QDeclarativeGuardedContextData context;
- QDeclarativeGuard<QObject> scopeObject;
- QObject *overrideObject;
- bool isSharedContext:1;
- bool isUrlContext:1;
-
- QDeclarativeContextData *getContext(QDeclarativeEngine *engine) {
- if (isSharedContext) {
- return QDeclarativeEnginePrivate::get(engine)->sharedContext;
- } else {
- return context.contextData();
- }
- }
-
- QObject *getScope(QDeclarativeEngine *engine) {
- if (isSharedContext) {
- return QDeclarativeEnginePrivate::get(engine)->sharedScope;
- } else {
- return scopeObject.data();
- }
- }
-};
-
-struct UrlContextData : public ContextData {
- UrlContextData(QDeclarativeContextData *c, QObject *o, const QString &u)
- : ContextData(c, o), url(u) {
- isUrlContext = true;
- }
- UrlContextData(const QString &u)
- : ContextData(0, 0), url(u) {
- isUrlContext = true;
- }
- QString url;
-};
-
-/*
- The QDeclarativeContextScriptClass handles property access for a QDeclarativeContext
- via QtScript.
- */
-QDeclarativeContextScriptClass::QDeclarativeContextScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine),
- lastScopeObject(0), lastContext(0), lastData(0), lastPropertyIndex(-1)
-{
-}
-
-QDeclarativeContextScriptClass::~QDeclarativeContextScriptClass()
-{
-}
-
-QScriptValue QDeclarativeContextScriptClass::newContext(QDeclarativeContextData *context, QObject *scopeObject)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new ContextData(context, scopeObject));
-}
-
-QScriptValue QDeclarativeContextScriptClass::newUrlContext(QDeclarativeContextData *context, QObject *scopeObject,
- const QString &url)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new UrlContextData(context, scopeObject, url));
-}
-
-QScriptValue QDeclarativeContextScriptClass::newUrlContext(const QString &url)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new UrlContextData(url));
-}
-
-QScriptValue QDeclarativeContextScriptClass::newSharedContext()
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new ContextData());
-}
-
-QDeclarativeContextData *QDeclarativeContextScriptClass::contextFromValue(const QScriptValue &v)
-{
- if (scriptClass(v) != this)
- return 0;
-
- ContextData *data = (ContextData *)object(v);
- return data->getContext(engine);
-}
-
-QUrl QDeclarativeContextScriptClass::urlFromValue(const QScriptValue &v)
-{
- if (scriptClass(v) != this)
- return QUrl();
-
- ContextData *data = (ContextData *)object(v);
- if (data->isUrlContext) {
- return QUrl(static_cast<UrlContextData *>(data)->url);
- } else {
- return QUrl();
- }
-}
-
-QObject *QDeclarativeContextScriptClass::setOverrideObject(QScriptValue &v, QObject *override)
-{
- if (scriptClass(v) != this)
- return 0;
-
- ContextData *data = (ContextData *)object(v);
- QObject *rv = data->overrideObject;
- data->overrideObject = override;
- return rv;
-}
-
-QScriptClass::QueryFlags
-QDeclarativeContextScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(flags);
-
- lastScopeObject = 0;
- lastContext = 0;
- lastData = 0;
- lastPropertyIndex = -1;
-
- QDeclarativeContextData *bindContext = ((ContextData *)object)->getContext(engine);
- QObject *scopeObject = ((ContextData *)object)->getScope(engine);
- if (!bindContext)
- return 0;
-
- QObject *overrideObject = ((ContextData *)object)->overrideObject;
- if (overrideObject) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptClass::QueryFlags rv =
- ep->objectClass->queryProperty(overrideObject, name, flags, bindContext,
- QDeclarativeObjectScriptClass::ImplicitObject |
- QDeclarativeObjectScriptClass::SkipAttachedProperties);
- if (rv) {
- lastScopeObject = overrideObject;
- lastContext = bindContext;
- return rv;
- }
- }
-
- bool includeTypes = true;
- while (bindContext) {
- QScriptClass::QueryFlags rv =
- queryProperty(bindContext, scopeObject, name, flags, includeTypes);
- scopeObject = 0; // Only applies to the first context
- includeTypes = false; // Only applies to the first context
- if (rv) return rv;
- bindContext = bindContext->parent;
- }
-
- return 0;
-}
-
-QScriptClass::QueryFlags
-QDeclarativeContextScriptClass::queryProperty(QDeclarativeContextData *bindContext, QObject *scopeObject,
- const Identifier &name,
- QScriptClass::QueryFlags flags,
- bool includeTypes)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- lastPropertyIndex = bindContext->propertyNames?bindContext->propertyNames->value(name):-1;
- if (lastPropertyIndex != -1) {
- lastContext = bindContext;
- return QScriptClass::HandlesReadAccess;
- }
-
- if (includeTypes && bindContext->imports) {
- QDeclarativeTypeNameCache::Data *data = bindContext->imports->data(name);
-
- if (data) {
- lastData = data;
- lastContext = bindContext;
- lastScopeObject = scopeObject;
- return QScriptClass::HandlesReadAccess;
- }
- }
-
- if (scopeObject) {
- QScriptClass::QueryFlags rv =
- ep->objectClass->queryProperty(scopeObject, name, flags, bindContext,
- QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties);
- if (rv) {
- lastScopeObject = scopeObject;
- lastContext = bindContext;
- return rv;
- }
- }
-
- if (bindContext->contextObject) {
- QScriptClass::QueryFlags rv =
- ep->objectClass->queryProperty(bindContext->contextObject, name, flags, bindContext,
- QDeclarativeObjectScriptClass::ImplicitObject | QDeclarativeObjectScriptClass::SkipAttachedProperties);
-
- if (rv) {
- lastScopeObject = bindContext->contextObject;
- lastContext = bindContext;
- return rv;
- }
- }
-
- return 0;
-}
-
-QDeclarativeContextScriptClass::Value
-QDeclarativeContextScriptClass::property(Object *object, const Identifier &name)
-{
- Q_UNUSED(object);
-
- QDeclarativeContextData *bindContext = lastContext;
- Q_ASSERT(bindContext);
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (lastData) {
-
- if (lastData->type) {
- return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->type));
- } else if (lastData->typeNamespace) {
- return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->typeNamespace));
- } else {
- int index = lastData->importedScriptIndex;
- if (index < bindContext->importedScripts.count()) {
- return Value(scriptEngine, bindContext->importedScripts.at(index));
- } else {
- return Value();
- }
- }
-
- } else if (lastScopeObject) {
-
- return ep->objectClass->property(lastScopeObject, name);
-
- } else if (lastPropertyIndex != -1) {
-
- QScriptValue rv;
- if (lastPropertyIndex < bindContext->idValueCount) {
- rv = ep->objectClass->newQObject(bindContext->idValues[lastPropertyIndex].data());
-
- if (ep->captureProperties)
- ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(&bindContext->idValues[lastPropertyIndex].bindings);
- } else {
- QDeclarativeContextPrivate *cp = bindContext->asQDeclarativeContextPrivate();
- const QVariant &value = cp->propertyValues.at(lastPropertyIndex);
- if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
- rv = ep->listClass->newList(QDeclarativeListProperty<QObject>(bindContext->asQDeclarativeContext(), (void*)lastPropertyIndex, 0, QDeclarativeContextPrivate::context_count, QDeclarativeContextPrivate::context_at), qMetaTypeId<QDeclarativeListProperty<QObject> >());
- } else {
- rv = ep->scriptValueFromVariant(value);
- }
-
- if (ep->captureProperties)
- ep->capturedProperties << QDeclarativeEnginePrivate::CapturedProperty(bindContext->asQDeclarativeContext(), -1, lastPropertyIndex + cp->notifyIndex);
- }
-
- return Value(scriptEngine, rv);
-
- } else {
-
- return Value(scriptEngine, lastFunction);
-
- }
-}
-
-void QDeclarativeContextScriptClass::setProperty(Object *object, const Identifier &name,
- const QScriptValue &value)
-{
- Q_UNUSED(object);
- Q_ASSERT(lastScopeObject);
-
- QDeclarativeContextData *bindContext = lastContext;
- Q_ASSERT(bindContext);
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- ep->objectClass->setProperty(lastScopeObject, name, value, context(), bindContext);
-}
-
-QT_END_NAMESPACE
#include <private/qobject_p.h>
#include "private/qdeclarativeguard_p.h"
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeCompiledData;
QDeclarativeData()
: ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
context(0), outerContext(0), bindings(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0),
- bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0),
- scriptValue(0), objectDataRefCount(0), propertyCache(0), guards(0), extendedData(0) {
+ bindingBits(0), lineNumber(0), columnNumber(0), deferredComponent(0), deferredIdx(0), propertyCache(0),
+ guards(0), extendedData(0) {
init();
}
QDeclarativeCompiledData *deferredComponent; // Can't this be found from the context?
unsigned int deferredIdx;
- // ### Can we make this QScriptValuePrivate so we incur no additional allocation
- // cost?
- QScriptValue *scriptValue;
- quint32 objectDataRefCount;
+ v8::Persistent<v8::Object> v8object;
QDeclarativePropertyCache *propertyCache;
QDeclarativeGuard<QObject> *guards;
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include "qdeclarative.h"
#include "qdeclarativecontext.h"
#include "qdeclarativeexpression.h"
#include "private/qdeclarativestringconverters_p.h"
#include "private/qdeclarativexmlhttprequest_p.h"
#include "private/qdeclarativesqldatabase_p.h"
-#include "private/qdeclarativescarceresourcescriptclass_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
#include "qdeclarativescriptstring.h"
#include "private/qdeclarativeglobal_p.h"
#include "private/qdeclarativeworkerscript_p.h"
#include "qdeclarativeextensioninterface.h"
#include "private/qdeclarativelist_p.h"
#include "private/qdeclarativetypenamecache_p.h"
-#include "private/qdeclarativeinclude_p.h"
#include "private/qdeclarativenotifier_p.h"
#include "private/qdeclarativedebugtrace_p.h"
#include "private/qdeclarativeapplication_p.h"
#include <QtCore/qmetaobject.h>
-#include <QScriptClass>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
If provided, \a callback is invoked when the operation completes. The callback is passed
the same object as is returned from the Qt.include() call.
*/
-// Qt.include() is implemented in qdeclarativeinclude.cpp
+// Qt.include() is implemented in qv8include.cpp
QDeclarativeEnginePrivate::QDeclarativeEnginePrivate(QDeclarativeEngine *e)
: captureProperties(false), rootContext(0), isDebugging(false),
- outputWarningsToStdErr(true), contextClass(0), sharedContext(0), sharedScope(0),
- objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0),
- inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttached(0),
- inBeginCreate(false), networkAccessManager(0), networkAccessManagerFactory(0),
- scarceResources(0), scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
+ cleanup(0), erroredBindings(0), inProgressCreations(0), scriptEngine(this),
+ workerScriptEngine(0), componentAttached(0), inBeginCreate(false),
+ networkAccessManager(0), networkAccessManagerFactory(0),
+ scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
sgContext(0)
{
if (!qt_QmlQtModule_registered) {
QSGItemsModule::defineModule();
QDeclarativeValueTypeFactory::registerValueTypes();
}
- globalClass = new QDeclarativeGlobalScriptClass(&scriptEngine);
-}
-
-/*!
- \qmlmethod url Qt::resolvedUrl(url url)
- Returns \a url resolved relative to the URL of the caller.
-*/
-QUrl QDeclarativeScriptEngine::resolvedUrl(QScriptContext *context, const QUrl& url)
-{
- if (p) {
- QDeclarativeContextData *ctxt = p->getContext(context);
- if (ctxt)
- return ctxt->resolvedUrl(url);
- else
- return p->getUrl(context).resolved(url);
- }
- return baseUrl.resolved(url);
}
QDeclarativeScriptEngine::QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv)
-: p(priv), sqlQueryClass(0), namedNodeMapClass(0), nodeListClass(0)
+: p(priv)
{
// Note that all documentation for stuff put on the global object goes in
// doc/src/declarative/globalobject.qdoc
- bool mainthread = priv != 0;
-
QScriptValue qtObject =
newQMetaObject(StaticQtMetaObject::get());
globalObject().setProperty(QLatin1String("Qt"), qtObject);
-#ifndef QT_NO_DESKTOPSERVICES
- offlineStoragePath = QDesktopServices::storageLocation(QDesktopServices::DataLocation).replace(QLatin1Char('/'), QDir::separator())
- + QDir::separator() + QLatin1String("QML")
- + QDir::separator() + QLatin1String("OfflineStorage");
-#endif
-
-#ifndef QT_NO_XMLSTREAMREADER
- qt_add_qmlxmlhttprequest(this);
-#endif
- qt_add_qmlsqldatabase(this);
- // XXX A Multimedia "Qt.Sound" class also needs to be made available,
- // XXX but we don't want a dependency in that cirection.
- // XXX When the above a done some better way, that way should also be
- // XXX used to add Qt.Sound class.
-
- //types
- if (mainthread)
- qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::include, 2));
- else
- qtObject.setProperty(QLatin1String("include"), newFunction(QDeclarativeInclude::worker_include, 2));
-
- qtObject.setProperty(QLatin1String("isQtObject"), newFunction(QDeclarativeEnginePrivate::isQtObject, 1));
- qtObject.setProperty(QLatin1String("rgba"), newFunction(QDeclarativeEnginePrivate::rgba, 4));
- qtObject.setProperty(QLatin1String("hsla"), newFunction(QDeclarativeEnginePrivate::hsla, 4));
- qtObject.setProperty(QLatin1String("rect"), newFunction(QDeclarativeEnginePrivate::rect, 4));
- qtObject.setProperty(QLatin1String("point"), newFunction(QDeclarativeEnginePrivate::point, 2));
- qtObject.setProperty(QLatin1String("size"), newFunction(QDeclarativeEnginePrivate::size, 2));
- qtObject.setProperty(QLatin1String("vector3d"), newFunction(QDeclarativeEnginePrivate::vector3d, 3));
-
- if (mainthread) {
- //color helpers
- qtObject.setProperty(QLatin1String("lighter"), newFunction(QDeclarativeEnginePrivate::lighter, 1));
- qtObject.setProperty(QLatin1String("darker"), newFunction(QDeclarativeEnginePrivate::darker, 1));
- qtObject.setProperty(QLatin1String("tint"), newFunction(QDeclarativeEnginePrivate::tint, 2));
- }
-
-#ifndef QT_NO_DATESTRING
- //date/time formatting
- qtObject.setProperty(QLatin1String("formatDate"),newFunction(QDeclarativeEnginePrivate::formatDate, 2));
- qtObject.setProperty(QLatin1String("formatTime"),newFunction(QDeclarativeEnginePrivate::formatTime, 2));
- qtObject.setProperty(QLatin1String("formatDateTime"),newFunction(QDeclarativeEnginePrivate::formatDateTime, 2));
-#endif
-
- //misc methods
- qtObject.setProperty(QLatin1String("openUrlExternally"),newFunction(QDeclarativeEnginePrivate::desktopOpenUrl, 1));
- qtObject.setProperty(QLatin1String("fontFamilies"),newFunction(QDeclarativeEnginePrivate::fontFamilies, 0));
- qtObject.setProperty(QLatin1String("md5"),newFunction(QDeclarativeEnginePrivate::md5, 1));
- qtObject.setProperty(QLatin1String("btoa"),newFunction(QDeclarativeEnginePrivate::btoa, 1));
- qtObject.setProperty(QLatin1String("atob"),newFunction(QDeclarativeEnginePrivate::atob, 1));
- qtObject.setProperty(QLatin1String("quit"), newFunction(QDeclarativeEnginePrivate::quit, 0));
- qtObject.setProperty(QLatin1String("resolvedUrl"),newFunction(QDeclarativeScriptEngine::resolvedUrl, 1));
-
- if (mainthread) {
- qtObject.setProperty(QLatin1String("createQmlObject"),
- newFunction(QDeclarativeEnginePrivate::createQmlObject, 1));
- qtObject.setProperty(QLatin1String("createComponent"),
- newFunction(QDeclarativeEnginePrivate::createComponent, 1));
- }
-
- //firebug/webkit compat
- QScriptValue consoleObject = newObject();
- consoleObject.setProperty(QLatin1String("log"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1));
- consoleObject.setProperty(QLatin1String("debug"),newFunction(QDeclarativeEnginePrivate::consoleLog, 1));
- globalObject().setProperty(QLatin1String("console"), consoleObject);
-
// translation functions need to be installed
// before the global script class is constructed (QTBUG-6437)
installTranslatorFunctions();
QDeclarativeScriptEngine::~QDeclarativeScriptEngine()
{
- delete sqlQueryClass;
- delete nodeListClass;
- delete namedNodeMapClass;
-}
-
-QScriptValue QDeclarativeScriptEngine::resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine)
-{
- QString arg = ctxt->argument(0).toString();
- QUrl r = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt,QUrl(arg));
- return QScriptValue(r.toString());
}
QNetworkAccessManager *QDeclarativeScriptEngine::networkAccessManager()
delete rootContext;
rootContext = 0;
- delete contextClass;
- contextClass = 0;
- delete objectClass;
- objectClass = 0;
- delete scarceResourceClass;
- scarceResourceClass = 0;
- delete valueTypeClass;
- valueTypeClass = 0;
- delete typeNameClass;
- typeNameClass = 0;
- delete listClass;
- listClass = 0;
- delete globalClass;
- globalClass = 0;
for(QHash<int, QDeclarativeCompiledData*>::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter)
(*iter)->release();
QDeclarativeData::init();
- contextClass = new QDeclarativeContextScriptClass(q);
- objectClass = new QDeclarativeObjectScriptClass(q);
- scarceResourceClass = new QDeclarativeScarceResourceScriptClass(q);
- valueTypeClass = new QDeclarativeValueTypeScriptClass(q);
- typeNameClass = new QDeclarativeTypeNameScriptClass(q);
- listClass = new QDeclarativeListScriptClass(q);
- rootContext = new QDeclarativeContext(q,true);
+ // Init V8 data
+ v8engine.init(q);
- QScriptValue applicationObject = objectClass->newQObject(new QDeclarativeApplication(q));
- scriptEngine.globalObject().property(QLatin1String("Qt")).setProperty(QLatin1String("application"), applicationObject);
+ rootContext = new QDeclarativeContext(q,true);
if (QCoreApplication::instance()->thread() == q->thread() &&
QDeclarativeEngineDebugServer::isDebuggingEnabled()) {
}
/*!
+ Attempt to free unused memory.
+*/
+void QDeclarativeEngine::collectGarbage()
+{
+ v8::V8::LowMemoryNotification();
+ while (!v8::V8::IdleNotification()) {}
+}
+
+/*!
Returns the QDeclarativeContext for the \a object, or 0 if no
context has been set.
guard->objectDestroyed(object);
}
- if (scriptValue)
- delete scriptValue;
-
if (extendedData)
delete extendedData;
+ v8object.Dispose();
+
if (ownMemory)
delete this;
}
void QDeclarativeData::parentChanged(QObject *, QObject *parent)
{
- if (!parent && scriptValue) { delete scriptValue; scriptValue = 0; }
+ // XXX aakenned
+// if (!parent && scriptValue) { delete scriptValue; scriptValue = 0; }
}
void QDeclarativeData::objectNameChanged(QObject *)
bindingBits[bit / 32] |= (1 << (bit % 32));
}
-/*!
- Creates a QScriptValue allowing you to use \a object in QML script.
- \a engine is the QDeclarativeEngine it is to be created in.
-
- The QScriptValue returned is a QtScript Object, not a QtScript QObject, due
- to the special needs of QML requiring more functionality than a standard
- QtScript QObject.
-*/
-QScriptValue QDeclarativeEnginePrivate::qmlScriptObject(QObject* object,
- QDeclarativeEngine* engine)
-{
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
- return enginePriv->objectClass->newQObject(object);
-}
-
-/*!
- Returns the QDeclarativeContext for the executing QScript \a ctxt.
-*/
-QDeclarativeContextData *QDeclarativeEnginePrivate::getContext(QScriptContext *ctxt)
-{
- QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3);
- Q_ASSERT(scopeNode.isValid());
- Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass);
- return contextClass->contextFromValue(scopeNode);
-}
-
-/*!
- Returns the QUrl associated with the script \a ctxt for the case that there is
- no QDeclarativeContext.
-*/
-QUrl QDeclarativeEnginePrivate::getUrl(QScriptContext *ctxt)
-{
- QScriptValue scopeNode = QScriptDeclarativeClass::scopeChainValue(ctxt, -3);
- Q_ASSERT(scopeNode.isValid());
- Q_ASSERT(QScriptDeclarativeClass::scriptClass(scopeNode) == contextClass);
- return contextClass->urlFromValue(scopeNode);
-}
-
QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QUrl& url)
{
if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) {
return url.toLocalFile();
}
-/*!
-\qmlmethod object Qt::createComponent(url)
-
-Returns a \l Component object created using the QML file at the specified \a url,
-or \c null if an empty string was given.
-
-The returned component's \l Component::status property indicates whether the
-component was successfully created. If the status is \c Component.Error,
-see \l Component::errorString() for an error description.
-
-Call \l {Component::createObject()}{Component.createObject()} on the returned
-component to create an object instance of the component.
-
-For example:
-
-\snippet doc/src/snippets/declarative/createComponent-simple.qml 0
-
-See \l {Dynamic Object Management in QML} for more information on using this function.
-
-To create a QML object from an arbitrary string of QML (instead of a file),
-use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::createComponent(QScriptContext *ctxt, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *activeEnginePriv =
- static_cast<QDeclarativeScriptEngine*>(engine)->p;
- QDeclarativeEngine* activeEngine = activeEnginePriv->q_func();
-
- if(ctxt->argumentCount() != 1) {
- return ctxt->throwError(QLatin1String("Qt.createComponent(): Invalid arguments"));
- } else {
-
- QString arg = ctxt->argument(0).toString();
- if (arg.isEmpty())
- return engine->nullValue();
- QUrl url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(ctxt, QUrl(arg));
- QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt);
- QDeclarativeComponent *c = new QDeclarativeComponent(activeEngine, url, activeEngine);
- QDeclarativeComponentPrivate::get(c)->creationContext = context;
- QDeclarativeData::get(c, true)->setImplicitDestructible();
- return activeEnginePriv->objectClass->newQObject(c, qMetaTypeId<QDeclarativeComponent*>());
- }
-}
-
-/*!
-\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
-
-Returns a new object created from the given \a string of QML which will have the specified \a parent,
-or \c null if there was an error in creating the object.
-
-If \a filepath is specified, it will be used for error reporting for the created object.
-
-Example (where \c parentItem is the id of an existing QML item):
-
-\snippet doc/src/snippets/declarative/createQmlObject.qml 0
-
-In the case of an error, a QtScript Error object is thrown. This object has an additional property,
-\c qmlErrors, which is an array of the errors encountered.
-Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
-For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
-{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
-
-Note that this function returns immediately, and therefore may not work if
-the \a qml string loads new components (that is, external QML files that have not yet been loaded).
-If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead.
-
-See \l {Dynamic Object Management in QML} for more information on using this function.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *activeEnginePriv =
- static_cast<QDeclarativeScriptEngine*>(engine)->p;
- QDeclarativeEngine* activeEngine = activeEnginePriv->q_func();
-
- if(ctxt->argumentCount() < 2 || ctxt->argumentCount() > 3)
- return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Invalid arguments"));
-
- QDeclarativeContextData* context = activeEnginePriv->getContext(ctxt);
- Q_ASSERT(context);
-
- QString qml = ctxt->argument(0).toString();
- if (qml.isEmpty())
- return engine->nullValue();
-
- QUrl url;
- if(ctxt->argumentCount() > 2)
- url = QUrl(ctxt->argument(2).toString());
- else
- url = QUrl(QLatin1String("inline"));
-
- if (url.isValid() && url.isRelative())
- url = context->resolvedUrl(url);
-
- QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1));
- if(!parentArg)
- return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Missing parent object"));
-
- QDeclarativeComponent component(activeEngine);
- component.setData(qml.toUtf8(), url);
-
- if(component.isError()) {
- QList<QDeclarativeError> errors = component.errors();
- QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: ");
- QScriptValue arr = ctxt->engine()->newArray(errors.length());
- int i = 0;
- foreach (const QDeclarativeError &error, errors){
- errstr += QLatin1String("\n ") + error.toString();
- QScriptValue qmlErrObject = ctxt->engine()->newObject();
- qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
- qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
- qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString()));
- qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description()));
- arr.setProperty(i++, qmlErrObject);
- }
- QScriptValue err = ctxt->throwError(errstr);
- err.setProperty(QLatin1String("qmlErrors"),arr);
- return err;
- }
-
- if (!component.isReady())
- return ctxt->throwError(QLatin1String("Qt.createQmlObject(): Component is not ready"));
-
- QObject *obj = component.beginCreate(context->asQDeclarativeContext());
- if(obj)
- QDeclarativeData::get(obj, true)->setImplicitDestructible();
- component.completeCreate();
-
- if(component.isError()) {
- QList<QDeclarativeError> errors = component.errors();
- QString errstr = QLatin1String("Qt.createQmlObject() failed to create object: ");
- QScriptValue arr = ctxt->engine()->newArray(errors.length());
- int i = 0;
- foreach (const QDeclarativeError &error, errors){
- errstr += QLatin1String("\n ") + error.toString();
- QScriptValue qmlErrObject = ctxt->engine()->newObject();
- qmlErrObject.setProperty(QLatin1String("lineNumber"), QScriptValue(error.line()));
- qmlErrObject.setProperty(QLatin1String("columnNumber"), QScriptValue(error.column()));
- qmlErrObject.setProperty(QLatin1String("fileName"), QScriptValue(error.url().toString()));
- qmlErrObject.setProperty(QLatin1String("message"), QScriptValue(error.description()));
- arr.setProperty(i++, qmlErrObject);
- }
- QScriptValue err = ctxt->throwError(errstr);
- err.setProperty(QLatin1String("qmlErrors"),arr);
- return err;
- }
-
- Q_ASSERT(obj);
-
- obj->setParent(parentArg);
-
- QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
- for (int ii = 0; ii < functions.count(); ++ii) {
- if (QDeclarativePrivate::Parented == functions.at(ii)(obj, parentArg))
- break;
- }
-
- QDeclarativeData::get(obj, true)->setImplicitDestructible();
- return activeEnginePriv->objectClass->newQObject(obj, QMetaType::QObjectStar);
-}
-
-/*!
-\qmlmethod bool Qt::isQtObject(object)
-Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
-*/
-QScriptValue QDeclarativeEnginePrivate::isQtObject(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if (ctxt->argumentCount() == 0)
- return QScriptValue(engine, false);
-
- return QScriptValue(engine, 0 != ctxt->argument(0).toQObject());
-}
-
-/*!
-\qmlmethod Qt::vector3d(real x, real y, real z)
-Returns a Vector3D with the specified \c x, \c y and \c z.
-*/
-QScriptValue QDeclarativeEnginePrivate::vector3d(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 3)
- return ctxt->throwError(QLatin1String("Qt.vector(): Invalid arguments"));
- qsreal x = ctxt->argument(0).toNumber();
- qsreal y = ctxt->argument(1).toNumber();
- qsreal z = ctxt->argument(2).toNumber();
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QVector3D(x, y, z)));
-}
-
-/*!
-\qmlmethod string Qt::formatDate(datetime date, variant format)
-
-Returns a string representation of \c date, optionally formatted according
-to \c format.
-
-The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
-property, a QDate, or QDateTime value. The \a format parameter may be any of
-the possible format values as described for
-\l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
-
-If \a format is not specified, \a date is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
-*/
-#ifndef QT_NO_DATESTRING
-QScriptValue QDeclarativeEnginePrivate::formatDate(QScriptContext*ctxt, QScriptEngine*engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount == 0 || argCount > 2)
- return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid arguments"));
-
- QDate date = ctxt->argument(0).toDateTime().date();
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- if (argCount == 2) {
- QScriptValue formatArg = ctxt->argument(1);
- if (formatArg.isString()) {
- QString format = formatArg.toString();
- return engine->newVariant(QVariant::fromValue(date.toString(format)));
- } else if (formatArg.isNumber()) {
- enumFormat = Qt::DateFormat(formatArg.toUInt32());
- } else {
- return ctxt->throwError(QLatin1String("Qt.formatDate(): Invalid date format"));
- }
- }
- return engine->newVariant(QVariant::fromValue(date.toString(enumFormat)));
-}
-
-/*!
-\qmlmethod string Qt::formatTime(datetime time, variant format)
-
-Returns a string representation of \c time, optionally formatted according to
-\c format.
-
-The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
-value. The \a format parameter may be any of the possible format values as
-described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
-
-If \a format is not specified, \a time is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
-*/
-QScriptValue QDeclarativeEnginePrivate::formatTime(QScriptContext*ctxt, QScriptEngine*engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount == 0 || argCount > 2)
- return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid arguments"));
-
- QTime time;
- QScriptValue sv = ctxt->argument(0);
- if (sv.isDate())
- time = sv.toDateTime().time();
- else if (sv.toVariant().type() == QVariant::Time)
- time = sv.toVariant().toTime();
-
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- if (argCount == 2) {
- QScriptValue formatArg = ctxt->argument(1);
- if (formatArg.isString()) {
- QString format = formatArg.toString();
- return engine->newVariant(QVariant::fromValue(time.toString(format)));
- } else if (formatArg.isNumber()) {
- enumFormat = Qt::DateFormat(formatArg.toUInt32());
- } else {
- return ctxt->throwError(QLatin1String("Qt.formatTime(): Invalid time format"));
- }
- }
- return engine->newVariant(QVariant::fromValue(time.toString(enumFormat)));
-}
-
-/*!
-\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
-
-Returns a string representation of \c datetime, optionally formatted according to
-\c format.
-
-The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
-property, a QDate, QTime, or QDateTime value.
-
-If \a format is not provided, \a dateTime is formatted using
-\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
-\a format should be either.
-
-\list
-\o One of the Qt::DateFormat enumeration values, such as
- \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
-\o A string that specifies the format of the returned string, as detailed below.
-\endlist
-
-If \a format specifies a format string, it should use the following expressions
-to specify the date:
-
- \table
- \header \i Expression \i Output
- \row \i d \i the day as number without a leading zero (1 to 31)
- \row \i dd \i the day as number with a leading zero (01 to 31)
- \row \i ddd
- \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
- Uses QDate::shortDayName().
- \row \i dddd
- \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
- Uses QDate::longDayName().
- \row \i M \i the month as number without a leading zero (1-12)
- \row \i MM \i the month as number with a leading zero (01-12)
- \row \i MMM
- \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
- Uses QDate::shortMonthName().
- \row \i MMMM
- \i the long localized month name (e.g. 'January' to 'December').
- Uses QDate::longMonthName().
- \row \i yy \i the year as two digit number (00-99)
- \row \i yyyy \i the year as four digit number
- \endtable
-
-In addition the following expressions can be used to specify the time:
-
- \table
- \header \i Expression \i Output
- \row \i h
- \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
- \row \i hh
- \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
- \row \i m \i the minute without a leading zero (0 to 59)
- \row \i mm \i the minute with a leading zero (00 to 59)
- \row \i s \i the second without a leading zero (0 to 59)
- \row \i ss \i the second with a leading zero (00 to 59)
- \row \i z \i the milliseconds without leading zeroes (0 to 999)
- \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
- \row \i AP
- \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
- \row \i ap
- \i use am/pm display. \e ap will be replaced by either "am" or "pm".
- \endtable
-
- All other input characters will be ignored. Any sequence of characters that
- are enclosed in single quotes will be treated as text and not be used as an
- expression. Two consecutive single quotes ("''") are replaced by a single quote
- in the output.
-
-For example, if the following date/time value was specified:
-
- \code
- // 21 May 2001 14:13:09
- var dateTime = new Date(2001, 5, 21, 14, 13, 09)
- \endcode
-
-This \a dateTime value could be passed to \c Qt.formatDateTime(),
-\l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()}
-with the \a format values below to produce the following results:
-
- \table
- \header \i Format \i Result
- \row \i "dd.MM.yyyy" \i 21.05.2001
- \row \i "ddd MMMM d yy" \i Tue May 21 01
- \row \i "hh:mm:ss.zzz" \i 14:13:09.042
- \row \i "h:m:s ap" \i 2:13:9 pm
- \endtable
-*/
-QScriptValue QDeclarativeEnginePrivate::formatDateTime(QScriptContext*ctxt, QScriptEngine*engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount == 0 || argCount > 2)
- return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid arguments"));
-
- QDateTime date = ctxt->argument(0).toDateTime();
- Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- if (argCount == 2) {
- QScriptValue formatArg = ctxt->argument(1);
- if (formatArg.isString()) {
- QString format = formatArg.toString();
- return engine->newVariant(QVariant::fromValue(date.toString(format)));
- } else if (formatArg.isNumber()) {
- enumFormat = Qt::DateFormat(formatArg.toUInt32());
- } else {
- return ctxt->throwError(QLatin1String("Qt.formatDateTime(): Invalid datetime format"));
- }
- }
- return engine->newVariant(QVariant::fromValue(date.toString(enumFormat)));
-}
-#endif // QT_NO_DATESTRING
-
-/*!
-\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
-
-Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
-All components should be in the range 0-1 inclusive.
-*/
-QScriptValue QDeclarativeEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount < 3 || argCount > 4)
- return ctxt->throwError(QLatin1String("Qt.rgba(): Invalid arguments"));
- qsreal r = ctxt->argument(0).toNumber();
- qsreal g = ctxt->argument(1).toNumber();
- qsreal b = ctxt->argument(2).toNumber();
- qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
-
- if (r < 0.0) r=0.0;
- if (r > 1.0) r=1.0;
- if (g < 0.0) g=0.0;
- if (g > 1.0) g=1.0;
- if (b < 0.0) b=0.0;
- if (b > 1.0) b=1.0;
- if (a < 0.0) a=0.0;
- if (a > 1.0) a=1.0;
-
- return engine->toScriptValue(QVariant::fromValue(QColor::fromRgbF(r, g, b, a)));
-}
-
-/*!
-\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
-
-Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
-All components should be in the range 0-1 inclusive.
-*/
-QScriptValue QDeclarativeEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine)
-{
- int argCount = ctxt->argumentCount();
- if(argCount < 3 || argCount > 4)
- return ctxt->throwError(QLatin1String("Qt.hsla(): Invalid arguments"));
- qsreal h = ctxt->argument(0).toNumber();
- qsreal s = ctxt->argument(1).toNumber();
- qsreal l = ctxt->argument(2).toNumber();
- qsreal a = (argCount == 4) ? ctxt->argument(3).toNumber() : 1;
-
- if (h < 0.0) h=0.0;
- if (h > 1.0) h=1.0;
- if (s < 0.0) s=0.0;
- if (s > 1.0) s=1.0;
- if (l < 0.0) l=0.0;
- if (l > 1.0) l=1.0;
- if (a < 0.0) a=0.0;
- if (a > 1.0) a=1.0;
-
- return engine->toScriptValue(QVariant::fromValue(QColor::fromHslF(h, s, l, a)));
-}
-
-/*!
-\qmlmethod rect Qt::rect(int x, int y, int width, int height)
-
-Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
-
-The returned object has \c x, \c y, \c width and \c height attributes with the given values.
-*/
-QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 4)
- return ctxt->throwError(QLatin1String("Qt.rect(): Invalid arguments"));
-
- qsreal x = ctxt->argument(0).toNumber();
- qsreal y = ctxt->argument(1).toNumber();
- qsreal w = ctxt->argument(2).toNumber();
- qsreal h = ctxt->argument(3).toNumber();
-
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
-}
-
-/*!
-\qmlmethod point Qt::point(int x, int y)
-Returns a Point with the specified \c x and \c y coordinates.
-*/
-QScriptValue QDeclarativeEnginePrivate::point(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.point(): Invalid arguments"));
- qsreal x = ctxt->argument(0).toNumber();
- qsreal y = ctxt->argument(1).toNumber();
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QPointF(x, y)));
-}
-
-/*!
-\qmlmethod Qt::size(int width, int height)
-Returns a Size with the specified \c width and \c height.
-*/
-QScriptValue QDeclarativeEnginePrivate::size(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.size(): Invalid arguments"));
- qsreal w = ctxt->argument(0).toNumber();
- qsreal h = ctxt->argument(1).toNumber();
- return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QSizeF(w, h)));
-}
-
-/*!
-\qmlmethod color Qt::lighter(color baseColor, real factor)
-Returns a color lighter than \c baseColor by the \c factor provided.
-
-If the factor is greater than 1.0, this functions returns a lighter color.
-Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
-the return color is darker, but we recommend using the Qt.darker() function for this purpose.
-If the factor is 0 or negative, the return value is unspecified.
-
-The function converts the current RGB color to HSV, multiplies the value (V) component
-by factor and converts the color back to RGB.
-
-If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
-*/
-QScriptValue QDeclarativeEnginePrivate::lighter(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.lighter(): Invalid arguments"));
- QVariant v = ctxt->argument(0).toVariant();
- QColor color;
- if (v.userType() == QVariant::Color)
- color = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
- qsreal factor = 1.5;
- if (ctxt->argumentCount() == 2)
- factor = ctxt->argument(1).toNumber();
- color = color.lighter(int(qRound(factor*100.)));
- return engine->toScriptValue(QVariant::fromValue(color));
-}
-
-/*!
-\qmlmethod color Qt::darker(color baseColor, real factor)
-Returns a color darker than \c baseColor by the \c factor provided.
-
-If the factor is greater than 1.0, this function returns a darker color.
-Setting factor to 3.0 returns a color that has one-third the brightness.
-If the factor is less than 1.0, the return color is lighter, but we recommend using
-the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
-value is unspecified.
-
-The function converts the current RGB color to HSV, divides the value (V) component
-by factor and converts the color back to RGB.
-
-If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
-*/
-QScriptValue QDeclarativeEnginePrivate::darker(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 1 && ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.darker(): Invalid arguments"));
- QVariant v = ctxt->argument(0).toVariant();
- QColor color;
- if (v.userType() == QVariant::Color)
- color = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
- qsreal factor = 2.0;
- if (ctxt->argumentCount() == 2)
- factor = ctxt->argument(1).toNumber();
- color = color.darker(int(qRound(factor*100.)));
- return engine->toScriptValue(QVariant::fromValue(color));
-}
-
-/*!
-\qmlmethod bool Qt::openUrlExternally(url target)
-Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
-*/
-QScriptValue QDeclarativeEnginePrivate::desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e)
-{
- if(ctxt->argumentCount() < 1)
- return QScriptValue(e, false);
- bool ret = false;
-#ifndef QT_NO_DESKTOPSERVICES
- ret = QDesktopServices::openUrl(QDeclarativeScriptEngine::get(e)->resolvedUrl(ctxt, QUrl(ctxt->argument(0).toString())));
-#endif
- return QScriptValue(e, ret);
-}
-
-/*!
-\qmlmethod list<string> Qt::fontFamilies()
-Returns a list of the font families available to the application.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::fontFamilies(QScriptContext *ctxt, QScriptEngine *e)
-{
- if(ctxt->argumentCount() != 0)
- return ctxt->throwError(QLatin1String("Qt.fontFamilies(): Invalid arguments"));
-
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(e);
- QFontDatabase database;
- return p->scriptValueFromVariant(database.families());
-}
-
-/*!
-\qmlmethod string Qt::md5(data)
-Returns a hex string of the md5 hash of \c data.
-*/
-QScriptValue QDeclarativeEnginePrivate::md5(QScriptContext *ctxt, QScriptEngine *)
-{
- if (ctxt->argumentCount() != 1)
- return ctxt->throwError(QLatin1String("Qt.md5(): Invalid arguments"));
-
- QByteArray data = ctxt->argument(0).toString().toUtf8();
- QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
-
- return QScriptValue(QLatin1String(result.toHex()));
-}
-
-/*!
-\qmlmethod string Qt::btoa(data)
-Binary to ASCII - this function returns a base64 encoding of \c data.
-*/
-QScriptValue QDeclarativeEnginePrivate::btoa(QScriptContext *ctxt, QScriptEngine *)
-{
- if (ctxt->argumentCount() != 1)
- return ctxt->throwError(QLatin1String("Qt.btoa(): Invalid arguments"));
-
- QByteArray data = ctxt->argument(0).toString().toUtf8();
-
- return QScriptValue(QLatin1String(data.toBase64()));
-}
-
-/*!
-\qmlmethod string Qt::atob(data)
-ASCII to binary - this function returns a base64 decoding of \c data.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::atob(QScriptContext *ctxt, QScriptEngine *)
-{
- if (ctxt->argumentCount() != 1)
- return ctxt->throwError(QLatin1String("Qt.atob(): Invalid arguments"));
-
- QByteArray data = ctxt->argument(0).toString().toUtf8();
-
- return QScriptValue(QLatin1String(QByteArray::fromBase64(data)));
-}
-
-QScriptValue QDeclarativeEnginePrivate::consoleLog(QScriptContext *ctxt, QScriptEngine *e)
-{
- if(ctxt->argumentCount() < 1)
- return e->newVariant(QVariant(false));
-
- QByteArray msg;
-
- for (int i=0; i<ctxt->argumentCount(); ++i) {
- if (!msg.isEmpty()) msg += ' ';
- msg += ctxt->argument(i).toString().toLocal8Bit();
- // does not support firebug "%[a-z]" formatting, since firebug really
- // does just ignore the format letter, which makes it pointless.
- }
-
- qDebug("%s",msg.constData());
-
- return e->newVariant(QVariant(true));
-}
-
void QDeclarativeEnginePrivate::sendQuit()
{
Q_Q(QDeclarativeEngine);
dumpwarning(error);
}
-/*!
-\qmlmethod Qt::quit()
-This function causes the QDeclarativeEngine::quit() signal to be emitted.
-Within the \l {QML Viewer}, this causes the launcher application to exit;
-to quit a C++ application when this method is called, connect the
-QDeclarativeEngine::quit() signal to the QCoreApplication::quit() slot.
-*/
-
-QScriptValue QDeclarativeEnginePrivate::quit(QScriptContext * /*ctxt*/, QScriptEngine *e)
-{
- QDeclarativeEnginePrivate *qe = get (e);
- qe->sendQuit();
- return QScriptValue();
-}
-
-/*!
- \qmlmethod color Qt::tint(color baseColor, color tintColor)
- This function allows tinting one color with another.
-
- The tint color should usually be mostly transparent, or you will not be
- able to see the underlying color. The below example provides a slight red
- tint by having the tint color be pure red which is only 1/16th opaque.
-
- \qml
- Item {
- Rectangle {
- x: 0; width: 80; height: 80
- color: "lightsteelblue"
- }
- Rectangle {
- x: 100; width: 80; height: 80
- color: Qt.tint("lightsteelblue", "#10FF0000")
- }
- }
- \endqml
- \image declarative-rect_tint.png
-
- Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
-*/
-QScriptValue QDeclarativeEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if(ctxt->argumentCount() != 2)
- return ctxt->throwError(QLatin1String("Qt.tint(): Invalid arguments"));
- //get color
- QVariant v = ctxt->argument(0).toVariant();
- QColor color;
- if (v.userType() == QVariant::Color)
- color = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
-
- //get tint color
- v = ctxt->argument(1).toVariant();
- QColor tintColor;
- if (v.userType() == QVariant::Color)
- tintColor = v.value<QColor>();
- else if (v.userType() == QVariant::String) {
- bool ok;
- tintColor = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
- if (!ok)
- return engine->nullValue();
- } else
- return engine->nullValue();
-
- //tint
- QColor finalColor;
- int a = tintColor.alpha();
- if (a == 0xFF)
- finalColor = tintColor;
- else if (a == 0x00)
- finalColor = color;
- else {
- qreal a = tintColor.alphaF();
- qreal inv_a = 1.0 - a;
-
- finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a,
- tintColor.greenF() * a + color.greenF() * inv_a,
- tintColor.blueF() * a + color.blueF() * inv_a,
- a + inv_a * color.alphaF());
- }
-
- return engine->toScriptValue(QVariant::fromValue(finalColor));
-}
-
-QScriptValue QDeclarativeEnginePrivate::scriptValueFromVariant(const QVariant &val)
-{
- if (variantIsScarceResource(val)) {
- return scarceResourceClass->newScarceResource(val);
- } else if (val.userType() == qMetaTypeId<QDeclarativeListReference>()) {
- QDeclarativeListReferencePrivate *p =
- QDeclarativeListReferencePrivate::get((QDeclarativeListReference*)val.constData());
- if (p->object) {
- return listClass->newList(p->property, p->propertyType);
- } else {
- return scriptEngine.nullValue();
- }
- } else if (val.userType() == qMetaTypeId<QList<QObject *> >()) {
- const QList<QObject *> &list = *(QList<QObject *>*)val.constData();
- QScriptValue rv = scriptEngine.newArray(list.count());
- for (int ii = 0; ii < list.count(); ++ii) {
- QObject *object = list.at(ii);
- rv.setProperty(ii, objectClass->newQObject(object));
- }
- return rv;
- } else if (QDeclarativeValueType *vt = valueTypes[val.userType()]) {
- return valueTypeClass->newObject(val, vt);
- }
-
- bool objOk;
- QObject *obj = QDeclarativeMetaType::toQObject(val, &objOk);
- if (objOk) {
- return objectClass->newQObject(obj);
- } else {
- return scriptEngine.toScriptValue(val);
- }
-}
-
-/*
- If the variant is a scarce resource (consumes a large amount of memory, or
- only a limited number of them can be held in memory at any given time without
- exhausting supply for future use) we need to release the scarce resource
- after evaluation of the javascript binding is complete.
- */
-bool QDeclarativeEnginePrivate::variantIsScarceResource(const QVariant& val)
-{
- if (val.type() == QVariant::Pixmap) {
- return true;
- } else if (val.type() == QVariant::Image) {
- return true;
- }
-
- return false;
-}
-
/*
This function should be called prior to evaluation of any js expression,
so that scarce resources are not freed prematurely (eg, if there is a
// note that the actual SRD is owned by the JS engine,
// so we cannot delete the SRD; but we can free the
// memory used by the variant in the SRD.
- ScarceResourceData *srd = 0;
- while (scarceResources) {
- srd = scarceResources; // srd points to the "old" (current) head of the list
- scarceResources = srd->next; // srd->next is the "new" head of the list
- if (srd->next) srd->next->prev = &scarceResources; // newHead->prev = listptr.
- srd->next = 0;
- srd->prev = 0;
- srd->releaseResource(); // release the old head node.
+ while (ScarceResourceData *sr = scarceResources.first()) {
+ sr->data = QVariant();
+ scarceResources.remove(sr);
}
}
}
-QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val, int hint)
-{
- QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val);
- if (dc == objectClass)
- return QVariant::fromValue(objectClass->toQObject(val));
- else if (dc == scarceResourceClass)
- return scarceResourceClass->toVariant(val);
- else if (dc == valueTypeClass)
- return valueTypeClass->toVariant(val);
- else if (dc == contextClass)
- return QVariant();
-
- // Convert to a QList<QObject*> only if val is an array and we were explicitly hinted
- if (hint == qMetaTypeId<QList<QObject *> >() && val.isArray()) {
- QList<QObject *> list;
- int length = val.property(QLatin1String("length")).toInt32();
- for (int ii = 0; ii < length; ++ii) {
- QScriptValue arrayItem = val.property(ii);
- QObject *d = arrayItem.toQObject();
- list << d;
- }
- return QVariant::fromValue(list);
- }
-
- return val.toVariant();
-}
-
/*!
Adds \a path as a directory where the engine searches for
installed modules in a URL-based directory structure.
d->importDatabase.setPluginPathList(paths);
}
-
/*!
Imports the plugin named \a filePath with the \a uri provided.
Returns true if the plugin was successfully imported; otherwise returns false.
void QDeclarativeEngine::setOfflineStoragePath(const QString& dir)
{
Q_D(QDeclarativeEngine);
- d->scriptEngine.offlineStoragePath = dir;
+ qt_qmlsqldatabase_setOfflineStoragePath(&d->v8engine, dir);
}
QString QDeclarativeEngine::offlineStoragePath() const
{
Q_D(const QDeclarativeEngine);
- return d->scriptEngine.offlineStoragePath;
+ return qt_qmlsqldatabase_getOfflineStoragePath(&d->v8engine);
}
static void voidptr_destructor(void *v)
bool outputWarningsToStandardError() const;
void setOutputWarningsToStandardError(bool);
+ void collectGarbage();
+
static QDeclarativeContext *contextForObject(const QObject *);
static void setContextForObject(QObject *, QDeclarativeContext *);
#include "qdeclarativeimageprovider.h"
#include "private/qdeclarativeproperty_p.h"
#include "private/qdeclarativepropertycache_p.h"
-#include "private/qdeclarativeobjectscriptclass_p.h"
-#include "private/qdeclarativescarceresourcescriptclass_p.h"
-#include "private/qdeclarativecontextscriptclass_p.h"
-#include "private/qdeclarativevaluetypescriptclass_p.h"
#include "private/qdeclarativemetatype_p.h"
#include "private/qdeclarativedirparser_p.h"
+#include "private/qintrusivelist_p.h"
-#include <QtScript/QScriptClass>
#include <QtScript/QScriptValue>
#include <QtScript/QScriptString>
#include <QtCore/qstring.h>
#include <private/qobject_p.h>
+#include <private/qv8engine_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeContext;
class QDeclarativeEngine;
class QDeclarativeContextPrivate;
class QDeclarativeExpression;
-class QDeclarativeContextScriptClass;
class QDeclarativeImportDatabase;
-class QDeclarativeObjectScriptClass;
-class QDeclarativeScarceResourceScriptClass;
class ScarceResourceData;
-class QDeclarativeTypeNameScriptClass;
-class QDeclarativeValueTypeScriptClass;
class QScriptEngineDebugger;
class QNetworkReply;
class QNetworkAccessManager;
class QDeclarativeNetworkAccessManagerFactory;
class QDeclarativeAbstractBinding;
class QScriptDeclarativeClass;
-class QDeclarativeTypeNameScriptClass;
class QDeclarativeTypeNameCache;
class QDeclarativeComponentAttached;
-class QDeclarativeListScriptClass;
class QDeclarativeCleanup;
class QDeclarativeDelayedError;
class QDeclarativeWorkerScriptEngine;
-class QDeclarativeGlobalScriptClass;
class QDir;
class QSGTexture;
class QSGContext;
QDeclarativeScriptEngine(QDeclarativeEnginePrivate *priv);
virtual ~QDeclarativeScriptEngine();
- QUrl resolvedUrl(QScriptContext *context, const QUrl& url); // resolved against p's context, or baseUrl if no p
- static QScriptValue resolvedUrl(QScriptContext *ctxt, QScriptEngine *engine);
-
static QDeclarativeScriptEngine *get(QScriptEngine* e) { return static_cast<QDeclarativeScriptEngine*>(e); }
QDeclarativeEnginePrivate *p;
- // User by SQL API
- QScriptClass *sqlQueryClass;
- QString offlineStoragePath;
-
- // Used by DOM Core 3 API
- QScriptClass *namedNodeMapClass;
- QScriptClass *nodeListClass;
-
QUrl baseUrl;
virtual QNetworkAccessManager *networkAccessManager();
bool outputWarningsToStdErr;
- QDeclarativeContextScriptClass *contextClass;
QDeclarativeContextData *sharedContext;
QObject *sharedScope;
- QDeclarativeObjectScriptClass *objectClass;
- QDeclarativeScarceResourceScriptClass *scarceResourceClass;
- QDeclarativeValueTypeScriptClass *valueTypeClass;
- QDeclarativeTypeNameScriptClass *typeNameClass;
- QDeclarativeListScriptClass *listClass;
- // Global script class
- QDeclarativeGlobalScriptClass *globalClass;
// Registered cleanup handlers
QDeclarativeCleanup *cleanup;
QDeclarativeDelayedError *erroredBindings;
int inProgressCreations;
+ // V8 Engine
+ QV8Engine v8engine;
+
QDeclarativeScriptEngine scriptEngine;
QDeclarativeWorkerScriptEngine *getWorkerScriptEngine();
QImage getImageFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
QPixmap getPixmapFromProvider(const QUrl &url, QSize *size, const QSize& req_size);
- /*
- A scarce resource (like a large pixmap or texture) will be cached in a
- JavaScript wrapper object when accessed in a binding or other js expression.
- We need some way to automatically release that scarce resource prior to normal
- garbage collection (unless the user explicitly preserves the resource).
- */
- ScarceResourceData* scarceResources;
+ // Scarce resources are "exceptionally high cost" QVariant types where allowing the
+ // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
+ // out-of-resource situations. When such a resource is passed into JavaScript we
+ // add it to the scarceResources list and it is destroyed when we return from the
+ // JavaScript execution that created it. The user can prevent this behavior by
+ // calling preserve() on the object which removes it from this scarceResource list.
+ class ScarceResourceData {
+ public:
+ ScarceResourceData(const QVariant &data) : data(data) {}
+ QVariant data;
+ QIntrusiveListNode node;
+ };
+ QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
int scarceResourcesRefCount;
- static bool variantIsScarceResource(const QVariant& val);
void referenceScarceResources();
void dereferenceScarceResources();
QHash<int, int> m_qmlLists;
QHash<int, QDeclarativeCompiledData *> m_compositeTypes;
- QScriptValue scriptValueFromVariant(const QVariant &);
- QVariant scriptValueToVariant(const QScriptValue &, int hint = QVariant::Invalid);
-
void sendQuit();
void warning(const QDeclarativeError &);
void warning(const QList<QDeclarativeError> &);
static void warning(QDeclarativeEnginePrivate *, const QDeclarativeError &);
static void warning(QDeclarativeEnginePrivate *, const QList<QDeclarativeError> &);
- static QScriptValue qmlScriptObject(QObject*, QDeclarativeEngine*);
-
- static QScriptValue createComponent(QScriptContext*, QScriptEngine*);
- static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*);
- static QScriptValue isQtObject(QScriptContext*, QScriptEngine*);
- static QScriptValue vector3d(QScriptContext*, QScriptEngine*);
- static QScriptValue rgba(QScriptContext*, QScriptEngine*);
- static QScriptValue hsla(QScriptContext*, QScriptEngine*);
- static QScriptValue point(QScriptContext*, QScriptEngine*);
- static QScriptValue size(QScriptContext*, QScriptEngine*);
- static QScriptValue rect(QScriptContext*, QScriptEngine*);
-
- static QScriptValue lighter(QScriptContext*, QScriptEngine*);
- static QScriptValue darker(QScriptContext*, QScriptEngine*);
- static QScriptValue tint(QScriptContext*, QScriptEngine*);
-
- static QScriptValue desktopOpenUrl(QScriptContext*, QScriptEngine*);
- static QScriptValue fontFamilies(QScriptContext*, QScriptEngine*);
- static QScriptValue md5(QScriptContext*, QScriptEngine*);
- static QScriptValue btoa(QScriptContext*, QScriptEngine*);
- static QScriptValue atob(QScriptContext*, QScriptEngine*);
- static QScriptValue consoleLog(QScriptContext*, QScriptEngine*);
- static QScriptValue quit(QScriptContext*, QScriptEngine*);
-
-#ifndef QT_NO_DATESTRING
- static QScriptValue formatDate(QScriptContext*, QScriptEngine*);
- static QScriptValue formatTime(QScriptContext*, QScriptEngine*);
- static QScriptValue formatDateTime(QScriptContext*, QScriptEngine*);
-#endif
static QScriptEngine *getScriptEngine(QDeclarativeEngine *e) { return &e->d_func()->scriptEngine; }
static QDeclarativeEngine *getEngine(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p->q_func(); }
static QDeclarativeEnginePrivate *get(QDeclarativeEngine *e) { return e->d_func(); }
static QDeclarativeEnginePrivate *get(QDeclarativeContextData *c) { return (c && c->engine) ? QDeclarativeEnginePrivate::get(c->engine) : 0; }
static QDeclarativeEnginePrivate *get(QScriptEngine *e) { return static_cast<QDeclarativeScriptEngine*>(e)->p; }
static QDeclarativeEngine *get(QDeclarativeEnginePrivate *p) { return p->q_func(); }
- QDeclarativeContextData *getContext(QScriptContext *);
- QUrl getUrl(QScriptContext *);
static QString urlToLocalFileOrQrc(const QUrl& url);
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativerewrite_p.h"
#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QtCore/qdebug.h>
#include <QtScript/qscriptprogram.h>
QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
{
+ v8function.Dispose();
+ v8qmlscope.Dispose();
+ v8function = v8::Persistent<v8::Function>();
+ v8qmlscope = v8::Persistent<v8::Function>();
+
if (guardList) { delete [] guardList; guardList = 0; }
if (dataRef) dataRef->release();
if (deleted) *deleted = true;
expressionFunctionValid = false;
}
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func,
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
QObject *me)
{
- expression = func.toString();
+ // XXX aakenned
+ // expression = func.toString();
QDeclarativeAbstractExpression::setContext(ctxt);
scopeObject = me;
- expressionFunction = func;
+ v8function = v8::Persistent<v8::Function>::New(func);
expressionFunctionMode = ExplicitContext;
expressionFunctionValid = true;
}
url = srcUrl;
line = lineNumber;
- if (dataRef) dataRef->release();
+ Q_ASSERT(!dataRef);
+
dataRef = rc;
if (dataRef) dataRef->addref();
bool isSharedProgram = progIdx & 0x80000000;
progIdx &= 0x7FFFFFFF;
- QDeclarativeEngine *engine = ctxt->engine;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (isSharedProgram) {
-
- if (!dd->cachedClosures.at(progIdx)) {
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- scriptContext->pushScope(ep->contextClass->newSharedContext());
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line));
- scriptEngine->popContext();
- }
-
- expressionFunction = *dd->cachedClosures.at(progIdx);
- expressionFunctionMode = SharedContext;
- expressionFunctionValid = true;
+ v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope);
- } else {
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
- if (!dd->cachedPrograms.at(progIdx)) {
- dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
- }
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ scopeObject = me;
+}
- expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx),
- &expressionContext);
+// Callee owns the persistent handle
+v8::Persistent<v8::Function>
+QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope)
+{
+ QDeclarativeEngine *engine = ctxt->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- expressionFunctionMode = ExplicitContext;
- expressionFunctionValid = true;
- }
+ // XXX aakenned optimize
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine.context());
+
+ // XXX try/catch?
- QDeclarativeAbstractExpression::setContext(ctxt);
- scopeObject = me;
+ v8::Local<v8::Object> scopeobject = ep->v8engine.qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine.qmlModeCompile(code, filename, line);
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (qmlscope) *qmlscope = v8::Persistent<v8::Object>::New(scopeobject);
+ return v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(result));
}
QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
const QString &program, const QString &fileName,
int lineNumber, QScriptValue *contextObject)
{
+#if 0
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
if (contextObject) {
QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
ep->scriptEngine.popContext();
return rv;
+#else
+ qFatal("Not impl");
+#endif
}
QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
const QScriptProgram &program,
QScriptValue *contextObject)
{
+#if 0
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
if (contextObject) {
QScriptValue rv = ep->scriptEngine.evaluate(program);
ep->scriptEngine.popContext();
return rv;
+#else
+ qFatal("Not impl");
+#endif
}
/*!
d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
-/*! \internal */
-QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func,
+/*!
+ \internal
+
+ To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
+ For example:
+ v8::Handle<v8::Function> function;
+ new QDeclarativeExpression(ctxt, scope, &function, ...);
+ */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr,
QDeclarativeExpressionPrivate &dd)
: QObject(dd, 0)
{
+ v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
+
Q_D(QDeclarativeExpression);
- d->init(ctxt, func, scope);
+ d->init(ctxt, function, scope);
if (QDeclarativeExpression_notifyIdx == -1)
QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+
d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
d->resetNotifyOnChange();
d->expression = expression;
d->expressionFunctionValid = false;
- d->expressionFunction = QScriptValue();
+ d->v8function.Dispose();
+ d->v8qmlscope.Dispose();
+ d->v8function = v8::Persistent<v8::Function>();
+ d->v8qmlscope = v8::Persistent<v8::Function>();
}
-void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine,
- QDeclarativeError &error)
+void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message,
+ QDeclarativeError &error)
{
- if (scriptEngine->hasUncaughtException() &&
- scriptEngine->uncaughtException().isError()) {
+ Q_ASSERT(!message.IsEmpty());
- QString fileName;
- int lineNumber = scriptEngine->uncaughtExceptionLineNumber();
+ v8::Handle<v8::Value> name = message->GetScriptResourceName();
+ v8::Handle<v8::String> description = message->Get();
+ int lineNumber = message->GetLineNumber();
- QScriptValue exception = scriptEngine->uncaughtException();
- QLatin1String fileNameProp("fileName");
+ Q_ASSERT(name->IsString());
- if (!exception.property(fileNameProp).toString().isEmpty()){
- fileName = exception.property(fileNameProp).toString();
- } else {
- fileName = QLatin1String("<Unknown File>");
- }
+ v8::Local<v8::String> file = name->ToString();
+ if (file->Length() == 0)
+ error.setUrl(QUrl(QLatin1String("<Unknown File>")));
+ else
+ error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
- error.setUrl(QUrl(fileName));
- error.setLine(lineNumber);
- error.setColumn(-1);
- error.setDescription(exception.toString());
- } else {
- error = QDeclarativeError();
- }
+ error.setLine(lineNumber);
+ error.setColumn(-1);
+
+ QString qDescription = QV8Engine::toStringStatic(description);
+ if (qDescription.startsWith(QLatin1String("Uncaught ")))
+ qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
+
+ error.setDescription(qDescription);
+}
+
+void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine,
+ QDeclarativeError &error)
+{
+ qFatal("Not implemented - we use v8 now");
}
bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
return evalFlags;
}
-QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeQtScriptExpression::v8value(QObject *secondaryScope, bool *isUndefined)
{
Q_ASSERT(context() && context()->engine);
Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
- if (!expressionFunction.isValid()) {
+ if (v8function.IsEmpty() || v8function->IsUndefined()) {
if (isUndefined) *isUndefined = true;
- return QScriptValue();
+ return v8::Local<v8::Value>();
}
DeleteWatcher watcher(this);
ep->captureProperties = trackChange;
ep->capturedProperties.copyAndClear(lastCapturedProperties);
- QScriptValue value = eval(secondaryScope, isUndefined);
+ v8::Local<v8::Value> value = eval(secondaryScope, isUndefined);
if (!watcher.wasDeleted() && trackChange) {
if (ep->capturedProperties.count() == 0) {
return value;
}
-QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
{
Q_ASSERT(context() && context()->engine);
-
DeleteWatcher watcher(this);
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ QObject *restoreSecondaryScope = 0;
+ if (secondaryScope)
+ restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
- QDeclarativeContextData *oldSharedContext = 0;
- QObject *oldSharedScope = 0;
- QObject *oldOverride = 0;
- bool isShared = (expressionFunctionMode == SharedContext);
+ v8::TryCatch try_catch;
+ v8::Context::Scope scope(ep->v8engine.context()); // XXX is this needed?
- if (isShared) {
- oldSharedContext = ep->sharedContext;
- oldSharedScope = ep->sharedScope;
- ep->sharedContext = context();
- ep->sharedScope = scopeObject;
- } else {
- oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
+ v8::Handle<v8::Object> This;
+
+ if (evaluateFlags() & RequiresThisObject) {
+ v8::Handle<v8::Value> value = ep->v8engine.newQObject(scopeObject);
+ if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+ }
+ if (This.IsEmpty()) {
+ This = ep->v8engine.global();
}
- QScriptValue thisObject;
- if (evalFlags & RequiresThisObject)
- thisObject = ep->objectClass->newQObject(scopeObject);
- QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted
+ v8::Local<v8::Value> result = v8function->Call(This, 0, 0);
- if (isShared) {
- ep->sharedContext = oldSharedContext;
- ep->sharedScope = oldSharedScope;
- } else if (!watcher.wasDeleted()) {
- ep->contextClass->setOverrideObject(expressionContext, oldOverride);
- }
+ if (secondaryScope)
+ ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
if (isUndefined)
- *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
+ *isUndefined = try_catch.HasCaught() || result->IsUndefined();
- // Handle exception
- if (scriptEngine->hasUncaughtException()) {
- if (!watcher.wasDeleted())
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
-
- scriptEngine->clearExceptions();
- return QScriptValue();
- } else {
- if (!watcher.wasDeleted())
+ if (watcher.wasDeleted()) {
+ } else if (try_catch.HasCaught()) {
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ } else {
error = QDeclarativeError();
-
- return svalue;
+ }
+ } else {
+ error = QDeclarativeError();
}
+
+ return result;
}
void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
}
}
-QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+// Must be called with a valid handle scope
+v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
{
if (!expressionFunctionValid) {
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- expressionContext = ep->contextClass->newContext(context(), scopeObject);
- scriptContext->pushScope(expressionContext);
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
QDeclarativeRewrite::RewriteBinding rewriteBinding;
rewriteBinding.setName(name);
bool ok = true;
const QString code = rewriteBinding(expression, &ok);
- if (ok)
- expressionFunction = scriptEngine->evaluate(code, url, line);
-
- scriptEngine->popContext();
+ if (ok) v8function = evalFunction(context(), scopeObject, code, url, line, &v8qmlscope);
expressionFunctionMode = ExplicitContext;
expressionFunctionValid = true;
}
- return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
+ return QDeclarativeQtScriptExpression::v8value(secondaryScope, isUndefined);
}
QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
}
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
+ QVariant rv;
+
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
+
+ {
+ v8::HandleScope handle_scope;
+ v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
+ rv = ep->v8engine.toVariant(result, qMetaTypeId<QList<QObject*> >());
+ }
+
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
- return retn;
+
+ return rv;
}
/*!
class QDeclarativeContext;
class QDeclarativeExpressionPrivate;
class QDeclarativeContextData;
-class QScriptValue;
class Q_DECLARATIVE_EXPORT QDeclarativeExpression : public QObject
{
Q_OBJECT
protected:
QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QString &,
QDeclarativeExpressionPrivate &dd);
- QDeclarativeExpression(QDeclarativeContextData *, QObject *, const QScriptValue &,
+ QDeclarativeExpression(QDeclarativeContextData *, QObject *, void *,
QDeclarativeExpressionPrivate &dd);
QDeclarativeExpression(QDeclarativeContextData *, void *, QDeclarativeRefCount *rc,
QObject *me, const QString &, int, QDeclarativeExpressionPrivate &dd);
#include <QtScript/qscriptvalue.h>
+#include <private/qv8engine_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeAbstractExpression
QString expression;
Mode expressionFunctionMode;
- QScriptValue expressionFunction;
+ v8::Persistent<v8::Function> v8function;
+ v8::Persistent<v8::Object> v8qmlscope;
QScriptValue expressionContext; // Only used in ExplicitContext
QObject *scopeObject; // Only used in SharedContext
void setEvaluateFlags(EvaluateFlags flags);
EvaluateFlags evaluateFlags() const;
- QScriptValue scriptValue(QObject *secondaryScope, bool *isUndefined);
+ v8::Local<v8::Value> v8value(QObject *secondaryScope, bool *isUndefined);
class DeleteWatcher {
public:
private:
void clearGuards();
- QScriptValue eval(QObject *secondaryScope, bool *isUndefined);
+ v8::Local<v8::Value> eval(QObject *secondaryScope, bool *isUndefined);
void updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties);
bool trackChange;
~QDeclarativeExpressionPrivate();
void init(QDeclarativeContextData *, const QString &, QObject *);
- void init(QDeclarativeContextData *, const QScriptValue &, QObject *);
+ void init(QDeclarativeContextData *, v8::Handle<v8::Function>, QObject *);
void init(QDeclarativeContextData *, void *, QDeclarativeRefCount *, QObject *, const QString &, int);
QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
- QScriptValue scriptValue(QObject *secondaryScope = 0, bool *isUndefined = 0);
+
+ v8::Local<v8::Value> v8value(QObject *secondaryScope = 0, bool *isUndefined = 0);
static QDeclarativeExpressionPrivate *get(QDeclarativeExpression *expr) {
return static_cast<QDeclarativeExpressionPrivate *>(QObjectPrivate::get(expr));
virtual void emitValueChanged();
static void exceptionToError(QScriptEngine *, QDeclarativeError &);
+ static void exceptionToError(v8::Handle<v8::Message>, QDeclarativeError &);
static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QString &, const QString &,
int, QScriptValue *);
static QScriptValue evalInObjectScope(QDeclarativeContextData *, QObject *, const QScriptProgram &,
QScriptValue *);
+ static v8::Persistent<v8::Function> evalFunction(QDeclarativeContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, int line,
+ v8::Persistent<v8::Object> *qmlscope = 0);
+
bool expressionFunctionValid:1;
QString url; // This is a QString for a reason. QUrls are slooooooow...
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativeglobalscriptclass_p.h"
-
-#include <QtCore/qstringlist.h>
-#include <QtCore/qvector.h>
-#include <QtScript/qscriptstring.h>
-#include <QtScript/qscriptengine.h>
-#include <QtScript/qscriptvalueiterator.h>
-
-#include <private/qscriptdeclarativeclass_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*
- Used to prevent any writes to the global object.
-*/
-QDeclarativeGlobalScriptClass::QDeclarativeGlobalScriptClass(QScriptEngine *engine)
-: QScriptClass(engine)
-{
- QString eval = QLatin1String("eval");
- QString version = QLatin1String("version");
-
- QScriptValue originalGlobalObject = engine->globalObject();
-
- QScriptValue newGlobalObject = engine->newObject();
-
- {
- QScriptValueIterator iter(originalGlobalObject);
- QVector<QString> names;
- QVector<QScriptValue> values;
- QVector<QScriptValue::PropertyFlags> flags;
- while (iter.hasNext()) {
- iter.next();
-
- QString name = iter.name();
-
- if (name == version)
- continue;
-
- if (name != eval) {
- names.append(name);
- values.append(iter.value());
- flags.append(iter.flags() | QScriptValue::Undeletable);
- }
- newGlobalObject.setProperty(iter.scriptName(), iter.value());
-
- m_illegalNames.insert(name);
- }
- m_staticGlobalObject = QScriptDeclarativeClass::newStaticScopeObject(
- engine, names.size(), names.constData(), values.constData(), flags.constData());
- }
-
- newGlobalObject.setScriptClass(this);
- engine->setGlobalObject(newGlobalObject);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeGlobalScriptClass::queryProperty(const QScriptValue &object,
- const QScriptString &name,
- QueryFlags flags, uint *id)
-{
- Q_UNUSED(object);
- Q_UNUSED(name);
- Q_UNUSED(flags);
- Q_UNUSED(id);
- return HandlesWriteAccess;
-}
-
-void QDeclarativeGlobalScriptClass::setProperty(QScriptValue &object,
- const QScriptString &name,
- uint id, const QScriptValue &value)
-{
- Q_UNUSED(object);
- Q_UNUSED(id);
- Q_UNUSED(value);
- QString error = QLatin1String("Invalid write to global property \"") +
- name.toString() + QLatin1Char('\"');
- engine()->currentContext()->throwError(error);
-}
-
-/* This method is for the use of tst_qdeclarativeecmascript::callQtInvokables() only */
-void QDeclarativeGlobalScriptClass::explicitSetProperty(const QStringList &names, const QList<QScriptValue> &values)
-{
- Q_ASSERT(names.count() == values.count());
- QScriptValue globalObject = engine()->globalObject();
-
- QScriptValue v = engine()->newObject();
-
- QScriptValueIterator iter(v);
- while (iter.hasNext()) {
- iter.next();
- v.setProperty(iter.scriptName(), iter.value());
- }
-
- for (int ii = 0; ii < names.count(); ++ii) {
- const QString &name = names.at(ii);
- const QScriptValue &value = values.at(ii);
- v.setProperty(name, value);
- }
-
- v.setScriptClass(this);
-
- engine()->setGlobalObject(v);
-}
-
-QT_END_NAMESPACE
-
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdeclarativeinclude_p.h"
-
-#include <QtScript/qscriptengine.h>
-#include <QtNetwork/qnetworkrequest.h>
-#include <QtNetwork/qnetworkreply.h>
-#include <QtCore/qfile.h>
-
-#include <private/qdeclarativeengine_p.h>
-#include <private/qdeclarativeglobalscriptclass_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeInclude::QDeclarativeInclude(const QUrl &url,
- QDeclarativeEngine *engine,
- QScriptContext *ctxt)
-: QObject(engine), m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- m_context = ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
-
- m_scope[0] = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
- m_scope[1] = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
-
- m_scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- m_network = QDeclarativeScriptEngine::get(m_scriptEngine)->networkAccessManager();
-
- m_result = resultValue(m_scriptEngine);
-
- QNetworkRequest request;
- request.setUrl(url);
-
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
-}
-
-QDeclarativeInclude::~QDeclarativeInclude()
-{
- delete m_reply;
-}
-
-QScriptValue QDeclarativeInclude::resultValue(QScriptEngine *engine, Status status)
-{
- QScriptValue result = engine->newObject();
- result.setProperty(QLatin1String("OK"), QScriptValue(engine, Ok));
- result.setProperty(QLatin1String("LOADING"), QScriptValue(engine, Loading));
- result.setProperty(QLatin1String("NETWORK_ERROR"), QScriptValue(engine, NetworkError));
- result.setProperty(QLatin1String("EXCEPTION"), QScriptValue(engine, Exception));
-
- result.setProperty(QLatin1String("status"), QScriptValue(engine, status));
- return result;
-}
-
-QScriptValue QDeclarativeInclude::result() const
-{
- return m_result;
-}
-
-void QDeclarativeInclude::setCallback(const QScriptValue &c)
-{
- m_callback = c;
-}
-
-QScriptValue QDeclarativeInclude::callback() const
-{
- return m_callback;
-}
-
-#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
-void QDeclarativeInclude::finished()
-{
- m_redirectCount++;
-
- if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
- QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- m_url = m_url.resolved(redirect.toUrl());
- delete m_reply;
-
- QNetworkRequest request;
- request.setUrl(m_url);
-
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
- return;
- }
- }
-
- if (m_reply->error() == QNetworkReply::NoError) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine);
-
- QByteArray data = m_reply->readAll();
-
- QString code = QString::fromUtf8(data);
-
- QString urlString = m_url.toString();
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(m_scriptEngine);
- scriptContext->pushScope(ep->contextClass->newUrlContext(m_context, 0, urlString));
- scriptContext->pushScope(m_scope[0]);
-
- scriptContext->pushScope(m_scope[1]);
- scriptContext->setActivationObject(m_scope[1]);
- QDeclarativeScriptParser::extractPragmas(code);
-
- m_scriptEngine->evaluate(code, urlString, 1);
-
- m_scriptEngine->popContext();
-
- if (m_scriptEngine->hasUncaughtException()) {
- m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Exception));
- m_result.setProperty(QLatin1String("exception"), m_scriptEngine->uncaughtException());
- m_scriptEngine->clearExceptions();
- } else {
- m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, Ok));
- }
- } else {
- m_result.setProperty(QLatin1String("status"), QScriptValue(m_scriptEngine, NetworkError));
- }
-
- callback(m_scriptEngine, m_callback, m_result);
-
- disconnect();
- deleteLater();
-}
-
-void QDeclarativeInclude::callback(QScriptEngine *engine, QScriptValue &callback, QScriptValue &status)
-{
- if (callback.isValid()) {
- QScriptValue args = engine->newArray(1);
- args.setProperty(0, status);
- callback.call(QScriptValue(), args);
- }
-}
-
-/*
- Documented in qdeclarativeengine.cpp
-*/
-QScriptValue QDeclarativeInclude::include(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if (ctxt->argumentCount() == 0)
- return engine->undefinedValue();
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- QUrl contextUrl = ep->contextClass->urlFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
- if (contextUrl.isEmpty())
- return ctxt->throwError(QLatin1String("Qt.include(): Can only be called from JavaScript files"));
-
- QString urlString = ctxt->argument(0).toString();
- QUrl url(urlString);
- if (url.isRelative()) {
- url = QUrl(contextUrl).resolved(url);
- urlString = url.toString();
- }
-
- QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
-
- QScriptValue func = ctxt->argument(1);
- if (!func.isFunction())
- func = QScriptValue();
-
- QScriptValue result;
- if (localFile.isEmpty()) {
- QDeclarativeInclude *i =
- new QDeclarativeInclude(url, QDeclarativeEnginePrivate::getEngine(engine), ctxt);
-
- if (func.isValid())
- i->setCallback(func);
-
- result = i->result();
- } else {
-
- QFile f(localFile);
- if (f.open(QIODevice::ReadOnly)) {
- QByteArray data = f.readAll();
- QString code = QString::fromUtf8(data);
-
- QDeclarativeContextData *context =
- ep->contextClass->contextFromValue(QScriptDeclarativeClass::scopeChainValue(ctxt, -3));
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
- scriptContext->pushScope(ep->contextClass->newUrlContext(context, 0, urlString));
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
- QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -5);
- scriptContext->pushScope(scope);
- scriptContext->setActivationObject(scope);
- QDeclarativeScriptParser::extractPragmas(code);
-
- engine->evaluate(code, urlString, 1);
-
- engine->popContext();
-
- if (engine->hasUncaughtException()) {
- result = resultValue(engine, Exception);
- result.setProperty(QLatin1String("exception"), engine->uncaughtException());
- engine->clearExceptions();
- } else {
- result = resultValue(engine, Ok);
- }
- callback(engine, func, result);
- } else {
- result = resultValue(engine, NetworkError);
- callback(engine, func, result);
- }
- }
-
- return result;
-}
-
-QScriptValue QDeclarativeInclude::worker_include(QScriptContext *ctxt, QScriptEngine *engine)
-{
- if (ctxt->argumentCount() == 0)
- return engine->undefinedValue();
-
- QString urlString = ctxt->argument(0).toString();
- QUrl url(ctxt->argument(0).toString());
- if (url.isRelative()) {
- QString contextUrl = QScriptDeclarativeClass::scopeChainValue(ctxt, -3).data().toString();
- Q_ASSERT(!contextUrl.isEmpty());
-
- url = QUrl(contextUrl).resolved(url);
- urlString = url.toString();
- }
-
- QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
-
- QScriptValue func = ctxt->argument(1);
- if (!func.isFunction())
- func = QScriptValue();
-
- QScriptValue result;
- if (!localFile.isEmpty()) {
-
- QFile f(localFile);
- if (f.open(QIODevice::ReadOnly)) {
- QByteArray data = f.readAll();
- QString code = QString::fromUtf8(data);
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(engine);
- QScriptValue urlContext = engine->newObject();
- urlContext.setData(QScriptValue(engine, urlString));
- scriptContext->pushScope(urlContext);
-
- QScriptValue scope = QScriptDeclarativeClass::scopeChainValue(ctxt, -4);
- scriptContext->pushScope(scope);
- scriptContext->setActivationObject(scope);
- QDeclarativeScriptParser::extractPragmas(code);
-
- engine->evaluate(code, urlString, 1);
-
- engine->popContext();
-
- if (engine->hasUncaughtException()) {
- result = resultValue(engine, Exception);
- result.setProperty(QLatin1String("exception"), engine->uncaughtException());
- engine->clearExceptions();
- } else {
- result = resultValue(engine, Ok);
- }
- callback(engine, func, result);
- } else {
- result = resultValue(engine, NetworkError);
- callback(engine, func, result);
- }
- }
-
- return result;
-}
-
-QT_END_NAMESPACE
#include "private/qdeclarativeintegercache_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativemetatype_p.h"
-
QT_BEGIN_NAMESPACE
-QDeclarativeIntegerCache::QDeclarativeIntegerCache(QDeclarativeEngine *e)
-: QDeclarativeCleanup(e), engine(e)
+QDeclarativeIntegerCache::QDeclarativeIntegerCache()
{
}
QDeclarativeIntegerCache::~QDeclarativeIntegerCache()
{
- clear();
-}
-
-void QDeclarativeIntegerCache::clear()
-{
- qDeleteAll(stringCache);
- stringCache.clear();
- identifierCache.clear();
- engine = 0;
}
QString QDeclarativeIntegerCache::findId(int value) const
{
for (StringCache::ConstIterator iter = stringCache.begin();
iter != stringCache.end(); ++iter) {
- if (iter.value() && iter.value()->value == value)
+ if (iter.value() == value)
return iter.key();
}
return QString();
{
Q_ASSERT(!stringCache.contains(id));
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- // ### use contextClass
- Data *d = new Data(enginePriv->objectClass->createPersistentIdentifier(id), value);
-
- stringCache.insert(id, d);
- identifierCache.insert(d->identifier, d);
+ stringCache.insert(id, value);
}
int QDeclarativeIntegerCache::value(const QString &id)
{
- Data *d = stringCache.value(id);
- return d?d->value:-1;
+ int *rv = stringCache.value(id);
+ return rv?*rv:-1;
}
QT_END_NAMESPACE
//
#include "private/qdeclarativerefcount_p.h"
-#include "private/qdeclarativecleanup_p.h"
-
-#include <QtCore/qhash.h>
-
-#include <private/qscriptdeclarativeclass_p.h>
+#include "private/qhashedstring_p.h"
QT_BEGIN_NAMESPACE
class QDeclarativeType;
class QDeclarativeEngine;
-class QDeclarativeIntegerCache : public QDeclarativeRefCount, public QDeclarativeCleanup
+class QDeclarativeIntegerCache : public QDeclarativeRefCount
{
public:
- QDeclarativeIntegerCache(QDeclarativeEngine *);
+ QDeclarativeIntegerCache();
virtual ~QDeclarativeIntegerCache();
inline int count() const;
void add(const QString &, int);
+
int value(const QString &);
- QString findId(int value) const;
- inline int value(const QScriptDeclarativeClass::Identifier &id) const;
+ inline int value(v8::Handle<v8::String>);
-protected:
- virtual void clear();
+ QString findId(int value) const;
private:
- struct Data : public QScriptDeclarativeClass::PersistentIdentifier {
- Data(const QScriptDeclarativeClass::PersistentIdentifier &i, int v)
- : QScriptDeclarativeClass::PersistentIdentifier(i), value(v) {}
-
- int value;
- };
-
- typedef QHash<QString, Data *> StringCache;
- typedef QHash<QScriptDeclarativeClass::Identifier, Data *> IdentifierCache;
-
+ typedef QStringHash<int> StringCache;
StringCache stringCache;
- IdentifierCache identifierCache;
- QDeclarativeEngine *engine;
};
-int QDeclarativeIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const
+int QDeclarativeIntegerCache::value(v8::Handle<v8::String> name)
{
- Data *d = identifierCache.value(id);
- return d?d->value:-1;
+ int *result = stringCache.value(name);
+ return result?*result:-1;
}
int QDeclarativeIntegerCache::count() const
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativelistscriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativeguard_p.h"
-#include "private/qdeclarativelist_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct ListData : public QScriptDeclarativeClass::Object {
- QDeclarativeGuard<QObject> object;
- QDeclarativeListProperty<QObject> property;
- int propertyType;
-};
-
-QDeclarativeListScriptClass::QDeclarativeListScriptClass(QDeclarativeEngine *e)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(e)), engine(e)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- Q_UNUSED(scriptEngine);
-
- m_lengthId = createPersistentIdentifier(QLatin1String("length"));
-}
-
-QDeclarativeListScriptClass::~QDeclarativeListScriptClass()
-{
-}
-
-QScriptValue QDeclarativeListScriptClass::newList(QObject *object, int propId, int propType)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (!object || propId == -1)
- return scriptEngine->nullValue();
-
- ListData *data = new ListData;
- data->object = object;
- data->propertyType = propType;
- void *args[] = { &data->property, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
-
- return newObject(scriptEngine, this, data);
-}
-
-QScriptValue QDeclarativeListScriptClass::newList(const QDeclarativeListProperty<QObject> &prop, int propType)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- ListData *data = new ListData;
- data->object = prop.object;
- data->property = prop;
- data->propertyType = propType;
-
- return newObject(scriptEngine, this, data);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeListScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(object);
- Q_UNUSED(flags);
- if (name == m_lengthId.identifier)
- return QScriptClass::HandlesReadAccess;
-
- bool ok = false;
- quint32 idx = toArrayIndex(name, &ok);
-
- if (ok) {
- lastIndex = idx;
- return QScriptClass::HandlesReadAccess;
- } else {
- return 0;
- }
-}
-
-QDeclarativeListScriptClass::Value QDeclarativeListScriptClass::property(Object *obj, const Identifier &name)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- ListData *data = (ListData *)obj;
- if (!data->object)
- return Value();
-
- quint32 count = data->property.count?data->property.count(&data->property):0;
-
- if (name == m_lengthId.identifier)
- return Value(scriptEngine, count);
- else if (lastIndex < count && data->property.at)
- return Value(scriptEngine, enginePriv->objectClass->newQObject(data->property.at(&data->property, lastIndex)));
- else
- return Value();
-}
-
-QVariant QDeclarativeListScriptClass::toVariant(Object *obj, bool *ok)
-{
- ListData *data = (ListData *)obj;
-
- if (!data->object) {
- if (ok) *ok = false;
- return QVariant();
- }
-
- return QVariant::fromValue(QDeclarativeListReferencePrivate::init(data->property, data->propertyType, engine));
-}
-
-QT_END_NAMESPACE
-
#include <QtGui/qvector3d.h>
#include <QtGui/qvector4d.h>
#include <QtGui/qquaternion.h>
+#include <private/qv8engine_p.h>
Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QDeclarativeV8Handle);
QT_BEGIN_NAMESPACE
default:
if (type == qMetaTypeId<QVariant>() ||
type == qMetaTypeId<QScriptValue>() ||
+ type == qMetaTypeId<QDeclarativeV8Handle>() ||
typeCategory(type) != Unknown) {
return true;
}
} else if (type == qMetaTypeId<QScriptValue>()) {
*static_cast<NS(QScriptValue) *>(data) = *static_cast<const NS(QScriptValue)*>(copy);
return true;
+ } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) {
+ *static_cast<NS(QDeclarativeV8Handle) *>(data) = *static_cast<const NS(QDeclarativeV8Handle)*>(copy);
+ return true;
} else if (typeCategory(type) != Unknown) {
*static_cast<void **>(data) = *static_cast<void* const *>(copy);
return true;
} else if (type == qMetaTypeId<QScriptValue>()) {
*static_cast<NS(QScriptValue) *>(data) = NS(QScriptValue)();
return true;
+ } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) {
+ *static_cast<NS(QDeclarativeV8Handle) *>(data) = NS(QDeclarativeV8Handle)();
+ return true;
} else if (typeCategory(type) != Unknown) {
*static_cast<void **>(data) = 0;
return true;
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativeobjectscriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativedata_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
-#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativeguard_p.h"
-#include "private/qdeclarativevmemetaobject_p.h"
-
-#include <QtCore/qtimer.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtScript/qscriptcontextinfo.h>
-
-Q_DECLARE_METATYPE(QScriptValue)
-
-#if defined(__GNUC__)
-# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
-// The code in this file does not violate strict aliasing, but GCC thinks it does
-// so turn off the warnings for us to have a clean build
-# pragma GCC diagnostic ignored "-Wstrict-aliasing"
-# endif
-#endif
-
-QT_BEGIN_NAMESPACE
-
-struct ObjectData : public QScriptDeclarativeClass::Object {
- ObjectData(QObject *o, int t) : object(o), type(t) {
- if (o) {
- QDeclarativeData *ddata = QDeclarativeData::get(object, true);
- if (ddata) ddata->objectDataRefCount++;
- }
- }
-
- virtual ~ObjectData() {
- if (object && !object->parent()) {
- QDeclarativeData *ddata = QDeclarativeData::get(object, false);
- if (ddata && !ddata->indestructible && 0 == --ddata->objectDataRefCount)
- object->deleteLater();
- }
- }
-
- QDeclarativeGuard<QObject> object;
- int type;
-};
-
-/*
- The QDeclarativeObjectScriptClass handles property access for QObjects
- via QtScript. It is also used to provide a more useful API in
- QtScript for QML.
- */
-QDeclarativeObjectScriptClass::QDeclarativeObjectScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- methods(bindEngine), lastData(0), engine(bindEngine)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- m_destroy = scriptEngine->newFunction(destroy);
- m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
- m_toString = scriptEngine->newFunction(tostring);
- m_toStringId = createPersistentIdentifier(QLatin1String("toString"));
-}
-
-QDeclarativeObjectScriptClass::~QDeclarativeObjectScriptClass()
-{
-}
-
-QScriptValue QDeclarativeObjectScriptClass::newQObject(QObject *object, int type)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (!object)
- return scriptEngine->nullValue();
-// return newObject(scriptEngine, this, new ObjectData(object, type));
-
- if (QObjectPrivate::get(object)->wasDeleted)
- return scriptEngine->undefinedValue();
-
- QDeclarativeData *ddata = QDeclarativeData::get(object, true);
-
- if (!ddata) {
- return scriptEngine->undefinedValue();
- } else if (!ddata->indestructible && !object->parent()) {
- return newObject(scriptEngine, this, new ObjectData(object, type));
- } else if (!ddata->scriptValue) {
- ddata->scriptValue = new QScriptValue(newObject(scriptEngine, this, new ObjectData(object, type)));
- return *ddata->scriptValue;
- } else if (ddata->scriptValue->engine() == QDeclarativeEnginePrivate::getScriptEngine(engine)) {
- return *ddata->scriptValue;
- } else {
- return newObject(scriptEngine, this, new ObjectData(object, type));
- }
-}
-
-QObject *QDeclarativeObjectScriptClass::toQObject(const QScriptValue &value) const
-{
- return value.toQObject();
-}
-
-int QDeclarativeObjectScriptClass::objectType(const QScriptValue &value) const
-{
- if (scriptClass(value) != this)
- return QVariant::Invalid;
-
- Object *o = object(value);
- return ((ObjectData*)(o))->type;
-}
-
-QScriptClass::QueryFlags
-QDeclarativeObjectScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- return queryProperty(toQObject(object), name, flags, 0);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &name,
- QScriptClass::QueryFlags flags, QDeclarativeContextData *evalContext,
- QueryHints hints)
-{
- Q_UNUSED(flags);
- lastData = 0;
- lastTNData = 0;
-
- if (name == m_destroyId.identifier ||
- name == m_toStringId.identifier)
- return QScriptClass::HandlesReadAccess;
-
- if (!obj)
- return 0;
-
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
- lastData = QDeclarativePropertyCache::property(engine, obj, name, local);
- if ((hints & ImplicitObject) && lastData && lastData->revision != 0) {
-
- QDeclarativeData *ddata = QDeclarativeData::get(obj);
- if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(lastData))
- return 0;
- }
-
- if (lastData)
- return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess;
-
- if (!(hints & SkipAttachedProperties)) {
- if (!evalContext && context()) {
- // Global object, QScriptContext activation object, QDeclarativeContext object
- QScriptValue scopeNode = scopeChainValue(context(), -3);
- if (scopeNode.isValid()) {
- Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass);
-
- evalContext = enginePrivate->contextClass->contextFromValue(scopeNode);
- }
- }
-
- if (evalContext && evalContext->imports) {
- QDeclarativeTypeNameCache::Data *data = evalContext->imports->data(name);
- if (data) {
- lastTNData = data;
- return QScriptClass::HandlesReadAccess;
- }
- }
- }
-
- if (!(hints & ImplicitObject)) {
- local.coreIndex = -1;
- lastData = &local;
- return QScriptClass::HandlesWriteAccess;
- }
-
- return 0;
-}
-
-QDeclarativeObjectScriptClass::Value
-QDeclarativeObjectScriptClass::property(Object *object, const Identifier &name)
-{
- return property(toQObject(object), name);
-}
-
-QDeclarativeObjectScriptClass::Value
-QDeclarativeObjectScriptClass::property(QObject *obj, const Identifier &name)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (name == m_destroyId.identifier)
- return Value(scriptEngine, m_destroy);
- else if (name == m_toStringId.identifier)
- return Value(scriptEngine, m_toString);
-
- if (lastData && !lastData->isValid())
- return Value();
-
- Q_ASSERT(obj);
-
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- if (lastTNData) {
-
- if (lastTNData->type)
- return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->type));
- else
- return Value(scriptEngine, enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace));
-
- } else if (lastData->flags & QDeclarativePropertyCache::Data::IsFunction) {
- if (lastData->flags & QDeclarativePropertyCache::Data::IsVMEFunction) {
- return Value(scriptEngine, ((QDeclarativeVMEMetaObject *)(obj->metaObject()))->vmeMethod(lastData->coreIndex));
- } else {
- // Uncomment to use QtScript method call logic
- // QScriptValue sobj = scriptEngine->newQObject(obj);
- // return Value(scriptEngine, sobj.property(toString(name)));
- return Value(scriptEngine, methods.newMethod(obj, lastData));
- }
- } else {
- if (enginePriv->captureProperties && !(lastData->flags & QDeclarativePropertyCache::Data::IsConstant)) {
- if (lastData->coreIndex == 0) {
- enginePriv->capturedProperties <<
- QDeclarativeEnginePrivate::CapturedProperty(QDeclarativeData::get(obj, true)->objectNameNotifier());
- } else {
- enginePriv->capturedProperties <<
- QDeclarativeEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex);
- }
- }
-
- if (QDeclarativeValueTypeFactory::isValueType((uint)lastData->propType)) {
- QDeclarativeValueType *valueType = enginePriv->valueTypes[lastData->propType];
- if (valueType)
- return Value(scriptEngine, enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType));
- }
-
- if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) {
- return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, lastData->propType));
- } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
- QObject *rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, newQObject(rv, lastData->propType));
- } else if (lastData->flags & QDeclarativePropertyCache::Data::IsQScriptValue) {
- QScriptValue rv = scriptEngine->nullValue();
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::QReal) {
- qreal rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Int || lastData->flags & QDeclarativePropertyCache::Data::IsEnumType) {
- int rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Bool) {
- bool rv = false;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::QString) {
- QString rv;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::UInt) {
- uint rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Float) {
- float rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else if (lastData->propType == QMetaType::Double) {
- double rv = 0;
- void *args[] = { &rv, 0 };
- QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args);
- return Value(scriptEngine, rv);
- } else {
- QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj);
- return Value(scriptEngine, enginePriv->scriptValueFromVariant(var));
- }
- }
-}
-
-void QDeclarativeObjectScriptClass::setProperty(Object *object,
- const Identifier &name,
- const QScriptValue &value)
-{
- return setProperty(toQObject(object), name, value, context());
-}
-
-void QDeclarativeObjectScriptClass::setProperty(QObject *obj,
- const Identifier &name,
- const QScriptValue &value,
- QScriptContext *context,
- QDeclarativeContextData *evalContext)
-{
- Q_UNUSED(name);
-
- Q_ASSERT(obj);
- Q_ASSERT(lastData);
- Q_ASSERT(context);
-
- if (!lastData->isValid()) {
- QString error = QLatin1String("Cannot assign to non-existent property \"") +
- toString(name) + QLatin1Char('\"');
- context->throwError(error);
- return;
- }
-
- if (!(lastData->flags & QDeclarativePropertyCache::Data::IsWritable) &&
- !(lastData->flags & QDeclarativePropertyCache::Data::IsQList)) {
- QString error = QLatin1String("Cannot assign to read-only property \"") +
- toString(name) + QLatin1Char('\"');
- context->throwError(error);
- return;
- }
-
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
-
- if (!evalContext) {
- // Global object, QScriptContext activation object, QDeclarativeContext object
- QScriptValue scopeNode = scopeChainValue(context, -3);
- if (scopeNode.isValid()) {
- Q_ASSERT(scriptClass(scopeNode) == enginePriv->contextClass);
-
- evalContext = enginePriv->contextClass->contextFromValue(scopeNode);
- }
- }
-
- QDeclarativeBinding *newBinding = 0;
- if (value.isFunction() && !value.isRegExp()) {
- QScriptContextInfo ctxtInfo(context);
- QDeclarativePropertyCache::ValueTypeData valueTypeData;
-
- newBinding = new QDeclarativeBinding(value, obj, evalContext);
- newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber());
- newBinding->setTarget(QDeclarativePropertyPrivate::restore(*lastData, valueTypeData, obj, evalContext));
- if (newBinding->expression().contains(QLatin1String("this")))
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
- }
-
- QDeclarativeAbstractBinding *delBinding =
- QDeclarativePropertyPrivate::setBinding(obj, lastData->coreIndex, -1, newBinding);
- if (delBinding)
- delBinding->destroy();
-
- if (value.isNull() && lastData->flags & QDeclarativePropertyCache::Data::IsQObjectDerived) {
- QObject *o = 0;
- int status = -1;
- int flags = 0;
- void *argv[] = { &o, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, argv);
- } else if (value.isUndefined() && lastData->flags & QDeclarativePropertyCache::Data::IsResettable) {
- void *a[] = { 0 };
- QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a);
- } else if (value.isUndefined() && lastData->propType == qMetaTypeId<QVariant>()) {
- QDeclarativePropertyPrivate::write(obj, *lastData, QVariant(), evalContext);
- } else if (value.isUndefined()) {
- QString error = QLatin1String("Cannot assign [undefined] to ") +
- QLatin1String(QMetaType::typeName(lastData->propType));
- context->throwError(error);
- } else if (value.isFunction() && !value.isRegExp()) {
- // this is handled by the binding creation above
- } else {
- //### expand optimization for other known types
- if (lastData->propType == QMetaType::Int && value.isNumber()) {
- int rawValue = qRound(value.toNumber());
- int status = -1;
- int flags = 0;
- void *a[] = { (void *)&rawValue, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty,
- lastData->coreIndex, a);
- return;
- } else if (lastData->propType == QMetaType::QReal && value.isNumber()) {
- qreal rawValue = qreal(value.toNumber());
- int status = -1;
- int flags = 0;
- void *a[] = { (void *)&rawValue, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty,
- lastData->coreIndex, a);
- return;
- } else if (lastData->propType == QMetaType::QString && value.isString()) {
- const QString &rawValue = value.toString();
- int status = -1;
- int flags = 0;
- void *a[] = { (void *)&rawValue, 0, &status, &flags };
- QMetaObject::metacall(obj, QMetaObject::WriteProperty,
- lastData->coreIndex, a);
- return;
- }
-
- QVariant v;
- if (lastData->flags & QDeclarativePropertyCache::Data::IsQList)
- v = enginePriv->scriptValueToVariant(value, qMetaTypeId<QList<QObject *> >());
- else
- v = enginePriv->scriptValueToVariant(value, lastData->propType);
-
- if (!QDeclarativePropertyPrivate::write(obj, *lastData, v, evalContext)) {
- const char *valueType = 0;
- if (v.userType() == QVariant::Invalid) valueType = "null";
- else valueType = QMetaType::typeName(v.userType());
-
- QString error = QLatin1String("Cannot assign ") +
- QLatin1String(valueType) +
- QLatin1String(" to ") +
- QLatin1String(QMetaType::typeName(lastData->propType));
- context->throwError(error);
- }
- }
-}
-
-bool QDeclarativeObjectScriptClass::isQObject() const
-{
- return true;
-}
-
-QObject *QDeclarativeObjectScriptClass::toQObject(Object *object, bool *ok)
-{
- if (ok) *ok = true;
-
- ObjectData *data = (ObjectData*)object;
- return data->object.data();
-}
-
-QScriptValue QDeclarativeObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *)
-{
- QObject* obj = context->thisObject().toQObject();
-
- QString ret;
- if(obj){
- QString objectName = obj->objectName();
-
- ret += QString::fromUtf8(obj->metaObject()->className());
- ret += QLatin1String("(0x");
- ret += QString::number((quintptr)obj,16);
-
- if (!objectName.isEmpty()) {
- ret += QLatin1String(", \"");
- ret += objectName;
- ret += QLatin1Char('\"');
- }
-
- ret += QLatin1Char(')');
- }else{
- ret += QLatin1String("null");
- }
- return QScriptValue(ret);
-}
-
-QScriptValue QDeclarativeObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
- QScriptValue that = context->thisObject();
-
- if (scriptClass(that) != p->objectClass)
- return engine->undefinedValue();
-
- ObjectData *data = (ObjectData *)p->objectClass->object(that);
- if (!data->object)
- return engine->undefinedValue();
-
- QDeclarativeData *ddata = QDeclarativeData::get(data->object, false);
- if (!ddata || ddata->indestructible)
- return engine->currentContext()->throwError(QLatin1String("Invalid attempt to destroy() an indestructible object"));
-
- QObject *obj = data->object;
- int delay = 0;
- if (context->argumentCount() > 0)
- delay = context->argument(0).toInt32();
- if (delay > 0)
- QTimer::singleShot(delay, obj, SLOT(deleteLater()));
- else
- obj->deleteLater();
-
- return engine->undefinedValue();
-}
-
-QStringList QDeclarativeObjectScriptClass::propertyNames(Object *object)
-{
- QObject *obj = toQObject(object);
- if (!obj)
- return QStringList();
-
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
-
- QDeclarativePropertyCache *cache = 0;
- QDeclarativeData *ddata = QDeclarativeData::get(obj);
- if (ddata)
- cache = ddata->propertyCache;
- if (!cache) {
- cache = enginePrivate->cache(obj);
- if (cache) {
- if (ddata) { cache->addref(); ddata->propertyCache = cache; }
- } else {
- // Not cachable - fall back to QMetaObject (eg. dynamic meta object)
- // XXX QDeclarativeOpenMetaObject has a cache, so this is suboptimal.
- // XXX This is a workaround for QTBUG-9420.
- const QMetaObject *mo = obj->metaObject();
- QStringList r;
- int pc = mo->propertyCount();
- int po = mo->propertyOffset();
- for (int i=po; i<pc; ++i)
- r += QString::fromUtf8(mo->property(i).name());
- return r;
- }
- }
- return cache->propertyNames();
-}
-
-bool QDeclarativeObjectScriptClass::compare(Object *o1, Object *o2)
-{
- ObjectData *d1 = (ObjectData *)o1;
- ObjectData *d2 = (ObjectData *)o2;
-
- return d1 == d2 || d1->object == d2->object;
-}
-
-struct MethodData : public QScriptDeclarativeClass::Object {
- MethodData(QObject *o, const QDeclarativePropertyCache::Data &d) : object(o), data(d) {}
-
- QDeclarativeGuard<QObject> object;
- QDeclarativePropertyCache::Data data;
-};
-
-QDeclarativeObjectMethodScriptClass::QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- engine(bindEngine)
-{
- qRegisterMetaType<QList<QObject *> >("QList<QObject *>");
-
- setSupportsCall(true);
-
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- m_connect = scriptEngine->newFunction(connect);
- m_connectId = createPersistentIdentifier(QLatin1String("connect"));
- m_disconnect = scriptEngine->newFunction(disconnect);
- m_disconnectId = createPersistentIdentifier(QLatin1String("disconnect"));
-}
-
-QDeclarativeObjectMethodScriptClass::~QDeclarativeObjectMethodScriptClass()
-{
-}
-
-QScriptValue QDeclarativeObjectMethodScriptClass::newMethod(QObject *object, const QDeclarativePropertyCache::Data *method)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return newObject(scriptEngine, this, new MethodData(object, *method));
-}
-
-QScriptValue QDeclarativeObjectMethodScriptClass::connect(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
-
- QScriptValue that = context->thisObject();
- if (&p->objectClass->methods != scriptClass(that))
- return engine->undefinedValue();
-
- MethodData *data = (MethodData *)object(that);
-
- if (!data->object || context->argumentCount() == 0)
- return engine->undefinedValue();
-
- QByteArray signal("2");
- signal.append(data->object->metaObject()->method(data->data.coreIndex).signature());
-
- if (context->argumentCount() == 1) {
- qScriptConnect(data->object, signal.constData(), QScriptValue(), context->argument(0));
- } else {
- qScriptConnect(data->object, signal.constData(), context->argument(0), context->argument(1));
- }
-
- return engine->undefinedValue();
-}
-
-QScriptValue QDeclarativeObjectMethodScriptClass::disconnect(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
-
- QScriptValue that = context->thisObject();
- if (&p->objectClass->methods != scriptClass(that))
- return engine->undefinedValue();
-
- MethodData *data = (MethodData *)object(that);
-
- if (!data->object || context->argumentCount() == 0)
- return engine->undefinedValue();
-
- QByteArray signal("2");
- signal.append(data->object->metaObject()->method(data->data.coreIndex).signature());
-
- if (context->argumentCount() == 1) {
- qScriptDisconnect(data->object, signal.constData(), QScriptValue(), context->argument(0));
- } else {
- qScriptDisconnect(data->object, signal.constData(), context->argument(0), context->argument(1));
- }
-
- return engine->undefinedValue();
-}
-
-QScriptClass::QueryFlags
-QDeclarativeObjectMethodScriptClass::queryProperty(Object *, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(flags);
- if (name == m_connectId.identifier || name == m_disconnectId.identifier)
- return QScriptClass::HandlesReadAccess;
- else
- return 0;
-
-}
-
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::property(Object *, const Identifier &name)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- if (name == m_connectId.identifier)
- return Value(scriptEngine, m_connect);
- else if (name == m_disconnectId.identifier)
- return Value(scriptEngine, m_disconnect);
- else
- return Value();
-}
-
-namespace {
-struct MetaCallArgument {
- inline MetaCallArgument();
- inline ~MetaCallArgument();
- inline void *dataPtr();
-
- inline void initAsType(int type, QDeclarativeEngine *);
- void fromScriptValue(int type, QDeclarativeEngine *, const QScriptValue &);
- inline QScriptDeclarativeClass::Value toValue(QDeclarativeEngine *);
-
-private:
- MetaCallArgument(const MetaCallArgument &);
-
- inline void cleanup();
-
- char data[4 * sizeof(void *)];
- int type;
- bool isObjectType;
-};
-}
-
-MetaCallArgument::MetaCallArgument()
-: type(QVariant::Invalid), isObjectType(false)
-{
-}
-
-MetaCallArgument::~MetaCallArgument()
-{
- cleanup();
-}
-
-void MetaCallArgument::cleanup()
-{
- if (type == QMetaType::QString) {
- ((QString *)&data)->~QString();
- } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
- ((QVariant *)&data)->~QVariant();
- } else if (type == qMetaTypeId<QScriptValue>()) {
- ((QScriptValue *)&data)->~QScriptValue();
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- ((QList<QObject *> *)&data)->~QList<QObject *>();
- }
-}
-
-void *MetaCallArgument::dataPtr()
-{
- if (type == -1)
- return ((QVariant *)data)->data();
- else
- return (void *)&data;
-}
-
-void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e)
-{
- if (type != 0) { cleanup(); type = 0; }
- if (callType == 0) return;
-
- QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e);
-
- if (callType == qMetaTypeId<QScriptValue>()) {
- new (&data) QScriptValue(engine->undefinedValue());
- type = callType;
- } else if (callType == QMetaType::Int ||
- callType == QMetaType::UInt ||
- callType == QMetaType::Bool ||
- callType == QMetaType::Double ||
- callType == QMetaType::Float) {
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
- *((QObject **)&data) = 0;
- type = callType;
- } else if (callType == QMetaType::QString) {
- new (&data) QString();
- type = callType;
- } else if (callType == qMetaTypeId<QVariant>()) {
- type = callType;
- new (&data) QVariant();
- } else if (callType == qMetaTypeId<QList<QObject *> >()) {
- type = callType;
- new (&data) QList<QObject *>();
- } else {
- type = -1;
- new (&data) QVariant(callType, (void *)0);
- }
-}
-
-void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, const QScriptValue &value)
-{
- if (type != 0) { cleanup(); type = 0; }
-
- if (callType == qMetaTypeId<QScriptValue>()) {
- new (&data) QScriptValue(value);
- type = qMetaTypeId<QScriptValue>();
- } else if (callType == QMetaType::Int) {
- *((int *)&data) = int(value.toInt32());
- type = callType;
- } else if (callType == QMetaType::UInt) {
- *((uint *)&data) = uint(value.toUInt32());
- type = callType;
- } else if (callType == QMetaType::Bool) {
- *((bool *)&data) = value.toBool();
- type = callType;
- } else if (callType == QMetaType::Double) {
- *((double *)&data) = double(value.toNumber());
- type = callType;
- } else if (callType == QMetaType::Float) {
- *((float *)&data) = float(value.toNumber());
- type = callType;
- } else if (callType == QMetaType::QString) {
- if (value.isNull() || value.isUndefined())
- new (&data) QString();
- else
- new (&data) QString(value.toString());
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
- *((QObject **)&data) = value.toQObject();
- type = callType;
- } else if (callType == qMetaTypeId<QVariant>()) {
- new (&data) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value));
- type = callType;
- } else if (callType == qMetaTypeId<QList<QObject*> >()) {
- QList<QObject *> *list = new (&data) QList<QObject *>();
- if (value.isArray()) {
- int length = value.property(QLatin1String("length")).toInt32();
- for (int ii = 0; ii < length; ++ii) {
- QScriptValue arrayItem = value.property(ii);
- QObject *d = arrayItem.toQObject();
- list->append(d);
- }
- } else if (QObject *d = value.toQObject()) {
- list->append(d);
- }
- type = callType;
- } else {
- new (&data) QVariant();
- type = -1;
-
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
- QVariant v = priv->scriptValueToVariant(value);
- if (v.userType() == callType) {
- *((QVariant *)&data) = v;
- } else if (v.canConvert((QVariant::Type)callType)) {
- *((QVariant *)&data) = v;
- ((QVariant *)&data)->convert((QVariant::Type)callType);
- } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) {
- QObject *obj = priv->toQObject(v);
-
- if (obj) {
- const QMetaObject *objMo = obj->metaObject();
- while (objMo && objMo != mo) objMo = objMo->superClass();
- if (!objMo) obj = 0;
- }
-
- *((QVariant *)&data) = QVariant(callType, &obj);
- } else {
- *((QVariant *)&data) = QVariant(callType, (void *)0);
- }
- }
-}
-
-QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e)
-{
- QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e);
-
- if (type == qMetaTypeId<QScriptValue>()) {
- return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data));
- } else if (type == QMetaType::Int) {
- return QScriptDeclarativeClass::Value(engine, *((int *)&data));
- } else if (type == QMetaType::UInt) {
- return QScriptDeclarativeClass::Value(engine, *((uint *)&data));
- } else if (type == QMetaType::Bool) {
- return QScriptDeclarativeClass::Value(engine, *((bool *)&data));
- } else if (type == QMetaType::Double) {
- return QScriptDeclarativeClass::Value(engine, *((double *)&data));
- } else if (type == QMetaType::Float) {
- return QScriptDeclarativeClass::Value(engine, *((float *)&data));
- } else if (type == QMetaType::QString) {
- return QScriptDeclarativeClass::Value(engine, *((QString *)&data));
- } else if (type == QMetaType::QObjectStar) {
- QObject *object = *((QObject **)&data);
- if (object)
- QDeclarativeData::get(object, true)->setImplicitDestructible();
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e);
- return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object));
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- QList<QObject *> &list = *(QList<QObject *>*)&data;
- QScriptValue rv = engine->newArray(list.count());
- QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e);
- for (int ii = 0; ii < list.count(); ++ii) {
- QObject *object = list.at(ii);
- QDeclarativeData::get(object, true)->setImplicitDestructible();
- rv.setProperty(ii, priv->objectClass->newQObject(object));
- }
- return QScriptDeclarativeClass::Value(engine, rv);
- } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(e);
- QScriptValue rv = ep->scriptValueFromVariant(*((QVariant *)&data));
- if (rv.isQObject()) {
- QObject *object = rv.toQObject();
- if (object)
- QDeclarativeData::get(object, true)->setImplicitDestructible();
- }
- return QScriptDeclarativeClass::Value(engine, rv);
- } else {
- return QScriptDeclarativeClass::Value();
- }
-}
-
-int QDeclarativeObjectMethodScriptClass::enumType(const QMetaObject *meta, const QString &strname)
-{
- QByteArray str = strname.toUtf8();
- QByteArray scope;
- QByteArray name;
- int scopeIdx = str.lastIndexOf("::");
- if (scopeIdx != -1) {
- scope = str.left(scopeIdx);
- name = str.mid(scopeIdx + 2);
- } else {
- name = str;
- }
- for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
- QMetaEnum m = meta->enumerator(i);
- if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
- return QVariant::Int;
- }
- return QVariant::Invalid;
-}
-
-QDeclarativeObjectMethodScriptClass::Value QDeclarativeObjectMethodScriptClass::call(Object *o, QScriptContext *ctxt)
-{
- MethodData *method = static_cast<MethodData *>(o);
-
- if (method->data.relatedIndex == -1)
- return callPrecise(method->object, method->data, ctxt);
- else
- return callOverloaded(method, ctxt);
-}
-
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::callPrecise(QObject *object, const QDeclarativePropertyCache::Data &data,
- QScriptContext *ctxt)
-{
- if (data.flags & QDeclarativePropertyCache::Data::HasArguments) {
-
- QMetaMethod m = object->metaObject()->method(data.coreIndex);
- QList<QByteArray> argTypeNames = m.parameterTypes();
- QVarLengthArray<int, 9> argTypes(argTypeNames.count());
-
- // ### Cache
- for (int ii = 0; ii < argTypeNames.count(); ++ii) {
- argTypes[ii] = QMetaType::type(argTypeNames.at(ii));
- if (argTypes[ii] == QVariant::Invalid)
- argTypes[ii] = enumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii)));
- if (argTypes[ii] == QVariant::Invalid)
- return Value(ctxt, ctxt->throwError(QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii)))));
- }
-
- if (argTypes.count() > ctxt->argumentCount())
- return Value(ctxt, ctxt->throwError(QLatin1String("Insufficient arguments")));
-
- return callMethod(object, data.coreIndex, data.propType, argTypes.count(), argTypes.data(), ctxt);
-
- } else {
-
- return callMethod(object, data.coreIndex, data.propType, 0, 0, ctxt);
-
- }
-}
-
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index,
- int returnType, int argCount, int *argTypes,
- QScriptContext *ctxt)
-{
- if (argCount > 0) {
-
- QVarLengthArray<MetaCallArgument, 9> args(argCount + 1);
- args[0].initAsType(returnType, engine);
-
- for (int ii = 0; ii < argCount; ++ii)
- args[ii + 1].fromScriptValue(argTypes[ii], engine, ctxt->argument(ii));
-
- QVarLengthArray<void *, 9> argData(args.count());
- for (int ii = 0; ii < args.count(); ++ii)
- argData[ii] = args[ii].dataPtr();
-
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
-
- return args[0].toValue(engine);
-
- } else if (returnType != 0) {
-
- MetaCallArgument arg;
- arg.initAsType(returnType, engine);
-
- void *args[] = { arg.dataPtr() };
-
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
-
- return arg.toValue(engine);
-
- } else {
-
- void *args[] = { 0 };
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
- return Value();
-
- }
-}
-
-/*!
-Resolve the overloaded method to call. The algorithm works conceptually like this:
- 1. Resolve the set of overloads it is *possible* to call.
- Impossible overloads include those that have too many parameters or have parameters
- of unknown type.
- 2. Filter the set of overloads to only contain those with the closest number of
- parameters.
- For example, if we are called with 3 parameters and there are 2 overloads that
- take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
- 3. Find the best remaining overload based on its match score.
- If two or more overloads have the same match score, call the last one. The match
- score is constructed by adding the matchScore() result for each of the parameters.
-*/
-QDeclarativeObjectMethodScriptClass::Value
-QDeclarativeObjectMethodScriptClass::callOverloaded(MethodData *method, QScriptContext *ctxt)
-{
- int argumentCount = ctxt->argumentCount();
-
- QDeclarativePropertyCache::Data *best = 0;
- int bestParameterScore = INT_MAX;
- int bestMatchScore = INT_MAX;
-
- QDeclarativePropertyCache::Data dummy;
- QDeclarativePropertyCache::Data *attempt = &method->data;
-
- do {
- QList<QByteArray> methodArgTypeNames;
-
- if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments)
- methodArgTypeNames = method->object->metaObject()->method(attempt->coreIndex).parameterTypes();
-
- int methodArgumentCount = methodArgTypeNames.count();
-
- if (methodArgumentCount > argumentCount)
- continue; // We don't have sufficient arguments to call this method
-
- int methodParameterScore = argumentCount - methodArgumentCount;
- if (methodParameterScore > bestParameterScore)
- continue; // We already have a better option
-
- int methodMatchScore = 0;
- QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount);
-
- bool unknownArgument = false;
- for (int ii = 0; ii < methodArgumentCount; ++ii) {
- methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii));
- if (methodArgTypes[ii] == QVariant::Invalid)
- methodArgTypes[ii] = enumType(method->object->metaObject(),
- QString::fromLatin1(methodArgTypeNames.at(ii)));
- if (methodArgTypes[ii] == QVariant::Invalid) {
- unknownArgument = true;
- break;
- }
- methodMatchScore += matchScore(ctxt->argument(ii), methodArgTypes[ii], methodArgTypeNames.at(ii));
- }
- if (unknownArgument)
- continue; // We don't understand all the parameters
-
- if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
- best = attempt;
- bestParameterScore = methodParameterScore;
- bestMatchScore = methodMatchScore;
- }
-
- if (bestParameterScore == 0 && bestMatchScore == 0)
- break; // We can't get better than that
-
- } while((attempt = relatedMethod(method->object, attempt, dummy)) != 0);
-
- if (best) {
- return callPrecise(method->object, *best, ctxt);
- } else {
- QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
- QDeclarativePropertyCache::Data *candidate = &method->data;
- while (candidate) {
- error += QLatin1String("\n ") + QString::fromUtf8(method->object->metaObject()->method(candidate->coreIndex).signature());
- candidate = relatedMethod(method->object, candidate, dummy);
- }
- return Value(ctxt, ctxt->throwError(error));
- }
-}
-
-/*!
- Returns the match score for converting \a actual to be of type \a conversionType. A
- zero score means "perfect match" whereas a higher score is worse.
-
- The conversion table is copied out of the QtScript callQtMethod() function.
-*/
-int QDeclarativeObjectMethodScriptClass::matchScore(const QScriptValue &actual, int conversionType,
- const QByteArray &conversionTypeName)
-{
- if (actual.isNumber()) {
- switch (conversionType) {
- case QMetaType::Double:
- return 0;
- case QMetaType::Float:
- return 1;
- case QMetaType::LongLong:
- case QMetaType::ULongLong:
- return 2;
- case QMetaType::Long:
- case QMetaType::ULong:
- return 3;
- case QMetaType::Int:
- case QMetaType::UInt:
- return 4;
- case QMetaType::Short:
- case QMetaType::UShort:
- return 5;
- break;
- case QMetaType::Char:
- case QMetaType::UChar:
- return 6;
- default:
- return 10;
- }
- } else if (actual.isString()) {
- switch (conversionType) {
- case QMetaType::QString:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isBoolean()) {
- switch (conversionType) {
- case QMetaType::Bool:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isDate()) {
- switch (conversionType) {
- case QMetaType::QDateTime:
- return 0;
- case QMetaType::QDate:
- return 1;
- case QMetaType::QTime:
- return 2;
- default:
- return 10;
- }
- } else if (actual.isRegExp()) {
- switch (conversionType) {
- case QMetaType::QRegExp:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isVariant()) {
- if (conversionType == qMetaTypeId<QVariant>())
- return 0;
- else if (actual.toVariant().userType() == conversionType)
- return 0;
- else
- return 10;
- } else if (actual.isArray()) {
- switch (conversionType) {
- case QMetaType::QStringList:
- case QMetaType::QVariantList:
- return 5;
- default:
- return 10;
- }
- } else if (actual.isQObject()) {
- switch (conversionType) {
- case QMetaType::QObjectStar:
- return 0;
- default:
- return 10;
- }
- } else if (actual.isNull()) {
- switch (conversionType) {
- case QMetaType::VoidStar:
- case QMetaType::QObjectStar:
- return 0;
- default:
- if (!conversionTypeName.endsWith('*'))
- return 10;
- else
- return 0;
- }
- } else {
- return 10;
- }
-}
-
-static inline int QMetaObject_methods(const QMetaObject *metaObject)
-{
- struct Private
- {
- int revision;
- int className;
- int classInfoCount, classInfoData;
- int methodCount, methodData;
- };
-
- return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
-}
-
-static QByteArray QMetaMethod_name(const QMetaMethod &m)
-{
- QByteArray sig = m.signature();
- int paren = sig.indexOf('(');
- if (paren == -1)
- return sig;
- else
- return sig.left(paren);
-}
-
-/*!
-Returns the next related method, if one, or 0.
-*/
-QDeclarativePropertyCache::Data *
-QDeclarativeObjectMethodScriptClass::relatedMethod(QObject *object, QDeclarativePropertyCache::Data *current,
- QDeclarativePropertyCache::Data &dummy)
-{
- QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache;
- if (current->relatedIndex == -1)
- return 0;
-
- if (cache) {
- return cache->method(current->relatedIndex);
- } else {
- const QMetaObject *mo = object->metaObject();
- int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
-
- while (methodOffset > current->relatedIndex) {
- mo = mo->superClass();
- methodOffset -= QMetaObject_methods(mo);
- }
-
- QMetaMethod method = mo->method(current->relatedIndex);
- dummy.load(method);
-
- // Look for overloaded methods
- QByteArray methodName = QMetaMethod_name(method);
- for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) {
- if (methodName == QMetaMethod_name(mo->method(ii))) {
- dummy.relatedIndex = ii;
- return &dummy;
- }
- }
-
- return &dummy;
- }
-}
-
-QT_END_NAMESPACE
-
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVEOBJECTSCRIPTCLASS_P_H
-#define QDECLARATIVEOBJECTSCRIPTCLASS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "private/qdeclarativepropertycache_p.h"
-#include "private/qdeclarativetypenamecache_p.h"
-
-#include <private/qscriptdeclarativeclass_p.h>
-#include <QtScript/qscriptengine.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDeclarativeEngine;
-class QScriptContext;
-class QScriptEngine;
-class QDeclarativeContextData;
-class MethodData;
-
-class Q_AUTOTEST_EXPORT QDeclarativeObjectMethodScriptClass : public QScriptDeclarativeClass
-{
-public:
- QDeclarativeObjectMethodScriptClass(QDeclarativeEngine *);
- ~QDeclarativeObjectMethodScriptClass();
-
- QScriptValue newMethod(QObject *, const QDeclarativePropertyCache::Data *);
-
-protected:
- virtual Value call(Object *, QScriptContext *);
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
-
-private:
- int enumType(const QMetaObject *, const QString &);
-
- Value callPrecise(QObject *, const QDeclarativePropertyCache::Data &, QScriptContext *);
- Value callOverloaded(MethodData *, QScriptContext *);
- Value callMethod(QObject *, int index, int returnType, int argCount, int *argTypes, QScriptContext *ctxt);
-
- int matchScore(const QScriptValue &, int, const QByteArray &);
- QDeclarativePropertyCache::Data *relatedMethod(QObject *, QDeclarativePropertyCache::Data *current,
- QDeclarativePropertyCache::Data &dummy);
-
- PersistentIdentifier m_connectId;
- PersistentIdentifier m_disconnectId;
- QScriptValue m_connect;
- QScriptValue m_disconnect;
-
- static QScriptValue connect(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue disconnect(QScriptContext *context, QScriptEngine *engine);
-
- QDeclarativeEngine *engine;
-};
-
-class Q_AUTOTEST_EXPORT QDeclarativeObjectScriptClass : public QScriptDeclarativeClass
-{
-public:
- QDeclarativeObjectScriptClass(QDeclarativeEngine *);
- ~QDeclarativeObjectScriptClass();
-
- QScriptValue newQObject(QObject *, int type = QMetaType::QObjectStar);
-
- QObject *toQObject(const QScriptValue &) const;
- int objectType(const QScriptValue &) const;
-
- enum QueryHint {
- ImplicitObject = 0x01,
- SkipAttachedProperties = 0x02
- };
- Q_DECLARE_FLAGS(QueryHints, QueryHint)
-
- QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &,
- QScriptClass::QueryFlags flags,
- QDeclarativeContextData *evalContext,
- QueryHints hints = 0);
-
- Value property(QObject *, const Identifier &);
-
- void setProperty(QObject *, const Identifier &name, const QScriptValue &,
- QScriptContext *context, QDeclarativeContextData *evalContext = 0);
- virtual QStringList propertyNames(Object *);
- virtual bool compare(Object *, Object *);
-
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
-
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
- virtual bool isQObject() const;
- virtual QObject *toQObject(Object *, bool *ok = 0);
-
-private:
- friend class QDeclarativeObjectMethodScriptClass;
- QDeclarativeObjectMethodScriptClass methods;
-
- QDeclarativeTypeNameCache::Data *lastTNData;
- QDeclarativePropertyCache::Data *lastData;
- QDeclarativePropertyCache::Data local;
-
- PersistentIdentifier m_destroyId;
- PersistentIdentifier m_toStringId;
- QScriptValue m_destroy;
- QScriptValue m_toString;
-
- static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
-
- QDeclarativeEngine *engine;
-};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeObjectScriptClass::QueryHints);
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVEOBJECTSCRIPTCLASS_P_H
-
prop.d = new QDeclarativePropertyPrivate;
prop.d->object = object;
prop.d->context = ctxt;
- prop.d->engine = ctxt->engine;
+ prop.d->engine = ctxt?ctxt->engine:0;
prop.d->core = data;
prop.d->valueType = valueType;
#include "private/qdeclarativeengine_p.h"
#include "private/qdeclarativebinding_p.h"
+#include "private/qv8engine_p.h"
#include <QtCore/qdebug.h>
Q_DECLARE_METATYPE(QScriptValue)
+Q_DECLARE_METATYPE(QDeclarativeV8Handle);
QT_BEGIN_NAMESPACE
flags |= Data::IsQmlBinding;
} else if (propType == qMetaTypeId<QScriptValue>()) {
flags |= Data::IsQScriptValue;
+ } else if (propType == qMetaTypeId<QDeclarativeV8Handle>()) {
+ flags |= Data::IsV8Handle;
} else if (p.isEnumType()) {
flags |= Data::IsEnumType;
} else {
propType = QMetaType::type(returnType);
QList<QByteArray> params = m.parameterTypes();
- if (!params.isEmpty())
+ if (!params.isEmpty()) {
flags |= Data::HasArguments;
+ if (params.at(0).length() == 23 &&
+ 0 == qstrcmp(params.at(0).constData(), "QDeclarativeV8Function*")) {
+ flags |= Data::IsV8Function;
+ }
+ }
revision = m.revision();
}
data->release();
}
- for (IdentifierCache::ConstIterator iter = identifierCache.begin();
- iter != identifierCache.end(); ++iter) {
- RData *data = (*iter);
- data->release();
- }
-
indexCache.clear();
methodIndexCache.clear();
stringCache.clear();
- identifierCache.clear();
+ constructor.Dispose();
+ constructor = v8::Persistent<v8::Function>();
}
QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject,
cache->indexCache = indexCache;
cache->methodIndexCache = methodIndexCache;
cache->stringCache = stringCache;
- cache->identifierCache = identifierCache;
cache->allowedRevisionCache = allowedRevisionCache;
for (int ii = 0; ii < indexCache.count(); ++ii) {
}
for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
(*iter)->addref();
- for (IdentifierCache::ConstIterator iter = identifierCache.begin(); iter != identifierCache.end(); ++iter)
- (*iter)->addref();
+
+ // We specifically do *NOT* copy the constructor
return cache;
}
{
Q_UNUSED(revision);
+ constructor.Dispose(); // Now invalid
+ constructor = v8::Persistent<v8::Function>();
+
allowedRevisionCache.append(0);
QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
methodName = methodName.left(parenIdx);
RData *data = new RData;
- data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName);
methodIndexCache[ii] = data;
data->load(m);
data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction);
data->overrideIndex = old->coreIndex;
stringCache[methodName]->release();
- identifierCache[data->identifier.identifier]->release();
}
stringCache.insert(methodName, data);
- identifierCache.insert(data->identifier.identifier, data);
- data->addref();
data->addref();
}
QString propName = QString::fromUtf8(p.name());
RData *data = new RData;
- data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName);
indexCache[ii] = data;
data->load(p, engine);
data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction);
data->overrideIndex = old->coreIndex;
stringCache[propName]->release();
- identifierCache[data->identifier.identifier]->release();
}
stringCache.insert(propName, data);
- identifierCache.insert(data->identifier.identifier, data);
- data->addref();
data->addref();
}
}
QDeclarativePropertyCache::Data *
QDeclarativePropertyCache::property(const QString &str) const
{
- return stringCache.value(str);
+ QDeclarativePropertyCache::RData **rv = stringCache.value(str);
+ return rv?*rv:0;
}
QString QDeclarativePropertyCache::Data::name(QObject *object)
QStringList QDeclarativePropertyCache::propertyNames() const
{
- return stringCache.keys();
+ QStringList keys;
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
+ keys.append(iter.key());
+ return keys;
}
-QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
- const QScriptDeclarativeClass::Identifier &name, Data &local)
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
+ v8::Handle<v8::String> name, Data &local)
{
- QDeclarativePropertyCache::Data *rv = 0;
-
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
+ Q_ASSERT(engine);
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
QDeclarativePropertyCache *cache = 0;
QDeclarativeData *ddata = QDeclarativeData::get(obj);
- if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine)
+ if (ddata && ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine) // XXX aakenend
cache = ddata->propertyCache;
if (!cache) {
- cache = enginePrivate->cache(obj);
+ cache = ep->cache(obj);
if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; }
}
+ QDeclarativePropertyCache::Data *rv = 0;
+
if (cache) {
rv = cache->property(name);
} else {
- local = QDeclarativePropertyCache::create(obj->metaObject(), enginePrivate->objectClass->toString(name));
+ QString strname = ep->v8engine.toString(name);
+ local = QDeclarativePropertyCache::create(obj->metaObject(), strname);
if (local.isValid())
rv = &local;
}
return rv;
}
-QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
- const QString &name, Data &local)
+QDeclarativePropertyCache::Data *
+QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj,
+ const QString &name, Data &local)
{
QDeclarativePropertyCache::Data *rv = 0;
#include "private/qdeclarativecleanup_p.h"
#include "private/qdeclarativenotifier_p.h"
+#include "private/qhashedstring_p.h"
#include <QtCore/qvector.h>
#include <QtScript/private/qscriptdeclarativeclass_p.h>
class QDeclarativeEngine;
class QMetaProperty;
+class QV8Engine;
+class QV8QObjectWrapper;
class Q_AUTOTEST_EXPORT QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup
{
IsQList = 0x00000100,
IsQmlBinding = 0x00000200,
IsQScriptValue = 0x00000400,
+ IsV8Handle = 0x00000800,
// Apply only to IsFunctions
- IsVMEFunction = 0x00000800,
- HasArguments = 0x00001000,
- IsSignal = 0x00002000,
- IsVMESignal = 0x00004000
+ IsVMEFunction = 0x00001000,
+ HasArguments = 0x00002000,
+ IsSignal = 0x00004000,
+ IsVMESignal = 0x00008000,
+ IsV8Function = 0x00010000
};
Q_DECLARE_FLAGS(Flags, Flag)
bool isValid() const { return coreIndex != -1; }
+ bool isConstant() const { return flags & IsConstant; }
+ bool isWritable() const { return flags & IsWritable; }
+ bool isResettable() const { return flags & IsResettable; }
+ bool isAlias() const { return flags & IsAlias; }
+ bool isFinal() const { return flags & IsFinal; }
+ bool isFunction() const { return flags & IsFunction; }
+ bool isQObject() const { return flags & IsQObjectDerived; }
+ bool isEnum() const { return flags & IsEnumType; }
+ bool isQList() const { return flags & IsQList; }
+ bool isQmlBinding() const { return flags & IsQmlBinding; }
+ bool isQScriptValue() const { return flags & IsQScriptValue; }
+ bool isV8Handle() const { return flags & IsV8Handle; }
Flags flags;
int propType;
static Data create(const QMetaObject *, const QString &);
- inline Data *property(const QScriptDeclarativeClass::Identifier &id) const;
+ inline Data *property(v8::Handle<v8::String>) const;
Data *property(const QString &) const;
Data *property(int) const;
Data *method(int) const;
inline bool isAllowedInRevision(Data *) const;
inline QDeclarativeEngine *qmlEngine() const;
- static Data *property(QDeclarativeEngine *, QObject *, const QScriptDeclarativeClass::Identifier &, Data &);
static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &);
+ static Data *property(QDeclarativeEngine *, QObject *, v8::Handle<v8::String>, Data &);
protected:
virtual void clear();
private:
friend class QDeclarativeEnginePrivate;
+ friend class QV8QObjectWrapper;
+ // Implemented in v8/qv8qobjectwrapper.cpp
+ v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
+
+ // XXX is this worth it anymore?
struct RData : public Data, public QDeclarativeRefCount {
- QScriptDeclarativeClass::PersistentIdentifier identifier;
};
typedef QVector<RData *> IndexCache;
- typedef QHash<QString, RData *> StringCache;
- typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache;
+ typedef QStringHash<RData *> StringCache;
typedef QVector<int> AllowedRevisionCache;
void updateRecur(QDeclarativeEngine *, const QMetaObject *);
IndexCache indexCache;
IndexCache methodIndexCache;
StringCache stringCache;
- IdentifierCache identifierCache;
AllowedRevisionCache allowedRevisionCache;
+ v8::Persistent<v8::Function> constructor;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyCache::Data::Flags);
return methodIndexCache.at(data->overrideIndex);
}
-QDeclarativePropertyCache::Data *
-QDeclarativePropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const
-{
- return identifierCache.value(id);
-}
-
QDeclarativePropertyCache::ValueTypeData::ValueTypeData()
: flags(QDeclarativePropertyCache::Data::NoFlags), valueTypeCoreIdx(-1), valueTypePropType(0)
{
return engine;
}
+QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(v8::Handle<v8::String> str) const
+{
+ QDeclarativePropertyCache::RData **rv = stringCache.value(str);
+ return rv?*rv:0;
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVEPROPERTYCACHE_P_H
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativescarceresourcescriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativedata_p.h"
-#include "private/qdeclarativetypenamescriptclass_p.h"
-#include "private/qdeclarativelistscriptclass_p.h"
-#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativeguard_p.h"
-#include "private/qdeclarativevmemetaobject_p.h"
-
-#include <QtCore/qtimer.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtScript/qscriptcontextinfo.h>
-
-Q_DECLARE_METATYPE(QScriptValue);
-
-QT_BEGIN_NAMESPACE
-
-QDeclarativeScarceResourceScriptClass::QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *bindEngine)
- : QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- // Properties of this type can be explicitly preserved by clients,
- // which prevents the scarce resource from being automatically
- // released after the binding has been evaluated.
- m_preserve = scriptEngine->newFunction(preserve);
- m_preserveId = createPersistentIdentifier(QLatin1String("preserve"));
-
- // Similarly, they can be explicitly destroyed by clients,
- // which releases the scarce resource.
- m_destroy = scriptEngine->newFunction(destroy);
- m_destroyId = createPersistentIdentifier(QLatin1String("destroy"));
-}
-
-QDeclarativeScarceResourceScriptClass::~QDeclarativeScarceResourceScriptClass()
-{
-}
-
-/*
- Returns a JavaScript object whose instance data is a new scarce resource data.
- The scarce resource is added to the doubly-linked-list of scarce resources in the engine
- so that the scarce resource can be released after evaluation completes.
- */
-QScriptValue QDeclarativeScarceResourceScriptClass::newScarceResource(const QVariant &v)
-{
- // create the scarce resource
- ScarceResourceData *srd = new ScarceResourceData(v);
-
- // insert into the linked list
- QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine);
- srd->insertInto(&enginePrivate->scarceResources);
- Q_ASSERT(enginePrivate->scarceResourcesRefCount > 0);
-
- // return the javascript object with the scarce resource instance data
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return QScriptDeclarativeClass::newObject(scriptEngine, this, srd); // JSC takes ownership of srd.
-}
-
-QVariant QDeclarativeScarceResourceScriptClass::toVariant(Object *object, bool *ok)
-{
- ScarceResourceData *obj = static_cast<ScarceResourceData*>(object);
- if (ok) *ok = true;
- return obj->resource;
-}
-
-QVariant QDeclarativeScarceResourceScriptClass::toVariant(const QScriptValue &value)
-{
- Q_ASSERT(scriptClass(value) == this);
-
- return toVariant(object(value), 0);
-}
-
-// The destroy() and preserve() function properties are readable.
-QScriptClass::QueryFlags
-QDeclarativeScarceResourceScriptClass::queryProperty(Object *object, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(object)
- Q_UNUSED(flags)
-
- if (name == m_destroyId.identifier || name == m_preserveId.identifier)
- return (QScriptClass::HandlesReadAccess);
- return 0;
-}
-
-// Return the (function) values which may be evaluated by clients.
-QDeclarativeScarceResourceScriptClass::Value
-QDeclarativeScarceResourceScriptClass::property(Object *object, const Identifier &name)
-{
- Q_UNUSED(object)
-
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- // functions
- if (name == m_preserveId.identifier)
- return Value(scriptEngine, m_preserve);
- else if (name == m_destroyId.identifier)
- return Value(scriptEngine, m_destroy);
-
- return Value();
-}
-
-/*
- This method is called when the user explicitly calls the "preserve" method of a scarce resource in JavaScript
- within the specified evaluation context \a context of the script engine \a engine.
- Calling this function signifies that the user explicitly wants to preserve the resource rather than let it
- be automatically released once evaluation of the expression is complete.
- This function removes the internal scarce resource from the declarative engine's linked list of scarce resources
- to release after evaluation of the expression completes. This means that the resource will only be truly
- released when the JavaScript engine's garbage collector is run.
-
- Example:
- \qml
- function getIcon(model) {
- var icon = model.avatar; // a pixmap property
- icon.preserve(); // explicitly preserves the resource
- return icon; // a valid variant will be returned
- }
- \endqml
- */
-QScriptValue QDeclarativeScarceResourceScriptClass::preserve(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
- QScriptValue that = context->thisObject();
-
- if (scriptClass(that) != p->scarceResourceClass)
- return engine->undefinedValue();
-
- // The client wishes to preserve the resource in this SRD.
- ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
- if (!data)
- return engine->undefinedValue();
-
- // remove node from list, without releasing the resource.
- data->removeNode();
-
- return engine->undefinedValue();
-}
-
-/*
- This method is called when the user explicitly calls the "destroy" method of a scarce resource in JavaScript
- within the specified evaluation context \a context of the script engine \a engine.
- Calling this function signifies that the user explicitly wants to release the resource.
- This function sets the internal scarce resource variant to the invalid variant, in order to release the original resource,
- and then removes the resource from the declarative engine's linked-list of scarce resources to
- to release after evaluation of the expression completes, as it has already been released.
-
- Example:
- \qml
- function getIcon(model) {
- var icon = model.avatar; // a pixmap property
- icon.destroy(); // explicitly releases the resource
- return icon; // an invalid variant will be returned
- }
- \endqml
- */
-QScriptValue QDeclarativeScarceResourceScriptClass::destroy(QScriptContext *context, QScriptEngine *engine)
-{
- QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
- QScriptValue that = context->thisObject();
-
- if (scriptClass(that) != p->scarceResourceClass)
- return engine->undefinedValue();
-
- // the client wishes to release the resource in this SRD.
- ScarceResourceData *data = static_cast<ScarceResourceData *>(p->scarceResourceClass->object(that));
- if (!data)
- return engine->undefinedValue();
-
- // release the resource and remove the node from the list.
- data->releaseResource();
-
- return engine->undefinedValue();
-}
-
-QT_END_NAMESPACE
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
-#define QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "private/qdeclarativepropertycache_p.h"
-#include "private/qdeclarativetypenamecache_p.h"
-
-#include <private/qscriptdeclarativeclass_p.h>
-#include <QtScript/qscriptengine.h>
-
-QT_BEGIN_NAMESPACE
-
-class QDeclarativeEngine;
-
-/*
- Scarce resources (like pixmaps and textures) are managed manually
- in that the variant will be set to the invalid variant once the
- JavaScript engine has finished using the JavaScript object whose
- instance data is the ScarceResourceData (but before the garbage
- collector frees the JavaScript object itself).
-
- The engine stores a doubly-linked-list of scarce resources which
- will to be cleaned up after a binding is successfully evaluated
- (unless the user explicitly preserves the scarce resource).
-
- A ScarceResourceData pointer should not be deleted manually, as
- all instances of a ScarceResourceData should be owned by the
- JavaScript engine.
- */
-struct ScarceResourceData : public QScriptDeclarativeClass::Object {
- ScarceResourceData(const QVariant &v) : resource(v), prev(0), next(0)
- {
- }
-
- virtual ~ScarceResourceData()
- {
- releaseResource();
- }
-
- // Insert this resource into the given list of resources.
- void insertInto(ScarceResourceData **list)
- {
- // This node becomes the head of the list.
- next = *list; // so our next = old list head
- *list = this; // list now points to us (we're the head)
- prev = list; // as we're the head, our prev ptr becomes the list ptr.
-
- // and the next node's prev pointer must contain a ptr to our next ptr,
- // since per definition, prev always contains a pointer to the previous node's "next" ptr,
- // and the "this" node is the "this->next" node's "prev" node.
- if (next) next->prev = &next;
- }
-
- // Remove this resource from the list of resources, without releasing the resource.
- void removeNode()
- {
- // whatever previously pointed to this node (ie, as that node's "next" node)
- // should now point to our next node (since we no longer exist in the list).
- // and the next node's prev ptr should point to our prev node.
- if (prev) *prev = next;
- if (next) next->prev = prev;
- prev = 0;
- next = 0;
- }
-
- // Release this resource, and remove from the list.
- void releaseResource()
- {
- resource = QVariant();
- removeNode();
- }
-
- QVariant resource;
-
- // prev always contains a pointer to the previous node's "next" ptr.
- // :. for the head node, [*prev] will be engine->scarceResources
- // :. for every other node, [*prev] will be the previous node's "next" ptr.
- ScarceResourceData **prev;
- ScarceResourceData *next;
-};
-
-class Q_AUTOTEST_EXPORT QDeclarativeScarceResourceScriptClass : public QScriptDeclarativeClass
-{
-public:
- QDeclarativeScarceResourceScriptClass(QDeclarativeEngine *);
- ~QDeclarativeScarceResourceScriptClass();
-
- // Creates a new JavaScript object whose instance data is the scarce resource v
- QScriptValue newScarceResource(const QVariant &v);
-
- // inherited from QScriptDeclarativeClass
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual QVariant toVariant(Object *, bool *ok = 0);
- QVariant toVariant(const QScriptValue &value);
-
-private:
- PersistentIdentifier m_preserveId;
- PersistentIdentifier m_destroyId;
- QScriptValue m_preserve;
- QScriptValue m_destroy;
-
- static QScriptValue preserve(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine);
-
- QDeclarativeEngine *engine;
-};
-
-QT_END_NAMESPACE
-
-#endif // QDECLARATIVESCARCERESOURCESCRIPTCLASS_P_H
#include "private/qdeclarativeengine_p.h"
#include <QtCore/qobject.h>
-#include <QtScript/qscriptvalue.h>
-#include <QtScript/qscriptvalueiterator.h>
-#include <QtScript/qscriptcontext.h>
-#include <QtScript/qscriptengine.h>
-#include <QtScript/qscriptclasspropertyiterator.h>
#include <QtSql/qsqldatabase.h>
#include <QtSql/qsqlquery.h>
#include <QtSql/qsqlerror.h>
#include <QtSql/qsqlrecord.h>
+#include <QtGui/qdesktopservices.h>
#include <QtCore/qstack.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qsettings.h>
#include <QtCore/qdir.h>
#include <QtCore/qdebug.h>
-Q_DECLARE_METATYPE(QSqlDatabase)
-Q_DECLARE_METATYPE(QSqlQuery)
+#include <private/qv8engine_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeSqlQueryScriptClass: public QScriptClass {
-public:
- QDeclarativeSqlQueryScriptClass(QScriptEngine *engine) : QScriptClass(engine)
- {
- str_length = engine->toStringHandle(QLatin1String("length"));
- str_forwardOnly = engine->toStringHandle(QLatin1String("forwardOnly")); // not in HTML5 (an optimization)
- }
-
- QueryFlags queryProperty(const QScriptValue &,
- const QScriptString &name,
- QueryFlags flags, uint *)
- {
- if (flags & HandlesReadAccess) {
- if (name == str_length) {
- return HandlesReadAccess;
- } else if (name == str_forwardOnly) {
- return flags;
- }
- }
- if (flags & HandlesWriteAccess)
- if (name == str_forwardOnly)
- return flags;
- return 0;
- }
-
- QScriptValue property(const QScriptValue &object,
- const QScriptString &name, uint)
- {
- QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
- if (name == str_length) {
- int s = query.size();
- if (s<0) {
- // Inefficient.
- if (query.last()) {
- return query.at()+1;
- } else {
- return 0;
- }
- } else {
- return s;
- }
- } else if (name == str_forwardOnly) {
- return query.isForwardOnly();
- }
- return engine()->undefinedValue();
- }
-
- void setProperty(QScriptValue &object,
- const QScriptString &name, uint, const QScriptValue & value)
- {
- if (name == str_forwardOnly) {
- QSqlQuery query = qscriptvalue_cast<QSqlQuery>(object.data());
- query.setForwardOnly(value.toBool());
- }
- }
-
- QScriptValue::PropertyFlags propertyFlags(const QScriptValue &/*object*/, const QScriptString &name, uint /*id*/)
- {
- if (name == str_length) {
- return QScriptValue::Undeletable
- | QScriptValue::SkipInEnumeration;
- }
- return QScriptValue::Undeletable;
- }
-
-private:
- QScriptString str_length;
- QScriptString str_forwardOnly;
-};
-
-// If the spec changes to allow iteration, check git history...
-// class QDeclarativeSqlQueryScriptClassPropertyIterator : public QScriptClassPropertyIterator
-
-
-
enum SqlException {
UNKNOWN_ERR,
DATABASE_ERR,
0
};
-#define THROW_SQL(error, desc) \
+#define THROW_SQL(error, desc)
+
+#define V8THROW_SQL(error, desc) \
{ \
- QScriptValue errorValue = context->throwError(desc); \
- errorValue.setProperty(QLatin1String("code"), error); \
- return errorValue; \
+ v8::Local<v8::Value> v = v8::Exception::Error(engine->toString(desc)); \
+ v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
+ v8::ThrowException(v); \
+ return v8::Handle<v8::Value>(); \
+}
+
+#define V8THROW_REFERENCE(string) { \
+ v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
+
+#define V8THROW_REFERENCE_VOID(string) { \
+ v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
+ return; \
}
-static QString qmlsqldatabase_databasesPath(QScriptEngine *engine)
+struct QDeclarativeSqlDatabaseData {
+ QDeclarativeSqlDatabaseData(QV8Engine *engine);
+ ~QDeclarativeSqlDatabaseData();
+
+ QString offlineStoragePath;
+ v8::Persistent<v8::Function> constructor;
+ v8::Persistent<v8::Function> queryConstructor;
+ v8::Persistent<v8::Function> rowsConstructor;
+
+ static inline QDeclarativeSqlDatabaseData *data(QV8Engine *e) {
+ return (QDeclarativeSqlDatabaseData *)e->sqlDatabaseData();
+ }
+ static inline QDeclarativeSqlDatabaseData *data(void *d) {
+ return (QDeclarativeSqlDatabaseData *)d;
+ }
+};
+
+class QV8SqlDatabaseResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(SQLDatabaseType)
+
+public:
+ enum Type { Database, Query, Rows };
+
+ QV8SqlDatabaseResource(QV8Engine *e)
+ : QV8ObjectResource(e), type(Database), inTransaction(false), readonly(false), forwardOnly(false) {}
+
+ Type type;
+ QSqlDatabase database;
+
+ QString version; // type == Database
+
+ bool inTransaction; // type == Query
+ bool readonly; // type == Query
+
+ QSqlQuery query; // type == Rows
+ bool forwardOnly; // type == Rows
+};
+
+static v8::Handle<v8::Value> qmlsqldatabase_version(v8::Local<v8::String> property, const v8::AccessorInfo& info)
{
- QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine);
- return qmlengine->offlineStoragePath
- + QDir::separator() + QLatin1String("Databases");
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Database)
+ V8THROW_REFERENCE("Not a SQLDatabase object");
+
+ return r->engine->toString(r->version);
}
-static void qmlsqldatabase_initDatabasesPath(QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_length(v8::Local<v8::String> property, const v8::AccessorInfo& info)
{
- QDir().mkpath(qmlsqldatabase_databasesPath(engine));
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ int s = r->query.size();
+ if (s < 0) {
+ // Inefficient
+ if (r->query.last()) {
+ s = r->query.at() + 1;
+ } else {
+ s = 0;
+ }
+ }
+ return v8::Integer::New(s);
}
-static QString qmlsqldatabase_databaseFile(const QString& connectionName, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_forwardOnly(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- return qmlsqldatabase_databasesPath(engine) + QDir::separator()
- + connectionName;
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ return v8::Boolean::New(r->query.isForwardOnly());
}
+static void qmlsqldatabase_rows_setForwardOnly(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info)
+{
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE_VOID("Not a SQLDatabase::Rows object");
+
+ r->query.setForwardOnly(value->BooleanValue());
+}
-static QScriptValue qmlsqldatabase_item(QScriptContext *context, QScriptEngine *engine)
+QDeclarativeSqlDatabaseData::~QDeclarativeSqlDatabaseData()
{
- QSqlQuery query = qscriptvalue_cast<QSqlQuery>(context->thisObject().data());
- int i = context->argument(0).toNumber();
- if (query.at() == i || query.seek(i)) { // Qt 4.6 doesn't optimize seek(at())
- QSqlRecord r = query.record();
- QScriptValue row = engine->newObject();
- for (int j=0; j<r.count(); ++j) {
- row.setProperty(r.fieldName(j), QScriptValue(engine,r.value(j).toString()));
+ constructor.Dispose(); constructor = v8::Persistent<v8::Function>();
+ queryConstructor.Dispose(); queryConstructor = v8::Persistent<v8::Function>();
+}
+
+static QString qmlsqldatabase_databasesPath(QV8Engine *engine)
+{
+ return QDeclarativeSqlDatabaseData::data(engine)->offlineStoragePath +
+ QDir::separator() + QLatin1String("Databases");
+}
+
+static void qmlsqldatabase_initDatabasesPath(QV8Engine *engine)
+{
+ QDir().mkpath(qmlsqldatabase_databasesPath(engine));
+}
+
+static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Engine *engine)
+{
+ return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
+}
+
+static v8::Handle<v8::Value> qmlsqldatabase_rows_index(QV8SqlDatabaseResource *r, uint32_t index)
+{
+ if (r->query.at() == index || r->query.seek(index)) {
+
+ QSqlRecord record = r->query.record();
+ // XXX optimize
+ v8::Local<v8::Object> row = v8::Object::New();
+ for (int ii = 0; ii < record.count(); ++ii) {
+ row->Set(r->engine->toString(record.fieldName(ii)),
+ r->engine->toString(record.value(ii).toString()));
}
return row;
+ } else {
+ return v8::Undefined();
}
- return engine->undefinedValue();
}
-static QScriptValue qmlsqldatabase_executeSql_outsidetransaction(QScriptContext *context, QScriptEngine * /*engine*/)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_index(uint32_t index, const v8::AccessorInfo& info)
{
- THROW_SQL(DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()"));
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ return qmlsqldatabase_rows_index(r, index);
}
-static QScriptValue qmlsqldatabase_executeSql(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_rows_item(const v8::Arguments& args)
{
- QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
- QString sql = context->argument(0).toString();
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Rows)
+ V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
+
+ return qmlsqldatabase_rows_index(r, args.Length()?args[0]->Uint32Value():0);
+}
+
+static v8::Handle<v8::Value> qmlsqldatabase_executeSql(const v8::Arguments& args)
+{
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Query)
+ V8THROW_REFERENCE("Not a SQLDatabase::Query object");
+
+ QV8Engine *engine = r->engine;
+
+ if (!r->inTransaction)
+ V8THROW_SQL(DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()"));
+
+ QSqlDatabase db = r->database;
+
+ QString sql = engine->toString(args[0]);
+
+ if (r->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
+ V8THROW_SQL(SYNTAX_ERR, QDeclarativeEngine::tr("Read-only Transaction"));
+ }
+
QSqlQuery query(db);
bool err = false;
- QScriptValue result;
+ v8::Handle<v8::Value> result = v8::Undefined();
if (query.prepare(sql)) {
- if (context->argumentCount() > 1) {
- QScriptValue values = context->argument(1);
- if (values.isObject()) {
- if (values.isArray()) {
- int size = values.property(QLatin1String("length")).toInt32();
- for (int i = 0; i < size; ++i)
- query.bindValue(i, values.property(i).toVariant());
- } else {
- for (QScriptValueIterator it(values); it.hasNext();) {
- it.next();
- query.bindValue(it.name(),it.value().toVariant());
- }
- }
+ if (args.Length() > 1) {
+ v8::Local<v8::Value> values = args[1];
+ if (values->IsArray()) {
+ v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(values);
+ uint32_t size = array->Length();
+ for (uint32_t ii = 0; ii < size; ++ii)
+ query.bindValue(ii, engine->toVariant(array->Get(ii), -1));
+ } else if (values->IsObject() && !values->ToObject()->GetExternalResource()) {
+ v8::Local<v8::Object> object = values->ToObject();
+ v8::Local<v8::Array> names = object->GetPropertyNames();
+ uint32_t size = names->Length();
+ for (uint32_t ii = 0; ii < size; ++ii)
+ query.bindValue(engine->toString(names->Get(ii)),
+ engine->toVariant(object->Get(names->Get(ii)), -1));
} else {
- query.bindValue(0,values.toVariant());
+ query.bindValue(0, engine->toVariant(values, -1));
}
}
if (query.exec()) {
- result = engine->newObject();
- QDeclarativeScriptEngine *qmlengine = static_cast<QDeclarativeScriptEngine*>(engine);
- if (!qmlengine->sqlQueryClass)
- qmlengine->sqlQueryClass = new QDeclarativeSqlQueryScriptClass(engine);
- QScriptValue rows = engine->newObject(qmlengine->sqlQueryClass);
- rows.setData(engine->newVariant(QVariant::fromValue(query)));
- rows.setProperty(QLatin1String("item"), engine->newFunction(qmlsqldatabase_item,1), QScriptValue::SkipInEnumeration);
- result.setProperty(QLatin1String("rows"),rows);
- result.setProperty(QLatin1String("rowsAffected"),query.numRowsAffected());
- result.setProperty(QLatin1String("insertId"),query.lastInsertId().toString());
+ v8::Handle<v8::Object> rows = QDeclarativeSqlDatabaseData::data(engine)->rowsConstructor->NewInstance();
+ QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
+ r->type = QV8SqlDatabaseResource::Rows;
+ r->database = db;
+ r->query = query;
+ rows->SetExternalResource(r);
+
+ v8::Local<v8::Object> resultObject = v8::Object::New();
+ result = resultObject;
+ // XXX optimize
+ resultObject->Set(v8::String::New("rowsAffected"), v8::Integer::New(query.numRowsAffected()));
+ resultObject->Set(v8::String::New("insertId"), engine->toString(query.lastInsertId().toString()));
+ resultObject->Set(v8::String::New("rows"), rows);
} else {
err = true;
}
err = true;
}
if (err)
- THROW_SQL(DATABASE_ERR,query.lastError().text());
+ V8THROW_SQL(DATABASE_ERR,query.lastError().text());
+
return result;
}
-static QScriptValue qmlsqldatabase_executeSql_readonly(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_changeVersion(const v8::Arguments& args)
{
- QString sql = context->argument(0).toString();
- if (sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
- return qmlsqldatabase_executeSql(context,engine);
- } else {
- THROW_SQL(SYNTAX_ERR,QDeclarativeEngine::tr("Read-only Transaction"))
- }
-}
+ if (args.Length() < 2)
+ return v8::Undefined();
-static QScriptValue qmlsqldatabase_change_version(QScriptContext *context, QScriptEngine *engine)
-{
- if (context->argumentCount() < 2)
- return engine->undefinedValue();
-
- QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
- QString from_version = context->argument(0).toString();
- QString to_version = context->argument(1).toString();
- QScriptValue callback = context->argument(2);
-
- QScriptValue instance = engine->newObject();
- instance.setProperty(QLatin1String("executeSql"), engine->newFunction(qmlsqldatabase_executeSql,1));
- QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db));
-
- QString foundvers = context->thisObject().property(QLatin1String("version")).toString();
- if (from_version!=foundvers) {
- THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(foundvers));
- return engine->undefinedValue();
- }
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Database)
+ V8THROW_REFERENCE("Not a SQLDatabase object");
+
+ QV8Engine *engine = r->engine;
+
+ QSqlDatabase db = r->database;
+ QString from_version = engine->toString(args[0]);
+ QString to_version = engine->toString(args[1]);
+ v8::Handle<v8::Value> callback = args[2];
+
+ if (from_version != r->version)
+ V8THROW_SQL(VERSION_ERR, QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version));
+
+ v8::Local<v8::Object> instance = QDeclarativeSqlDatabaseData::data(engine)->queryConstructor->NewInstance();
+ QV8SqlDatabaseResource *r2 = new QV8SqlDatabaseResource(engine);
+ r2->type = QV8SqlDatabaseResource::Query;
+ r2->database = db;
+ r2->version = r->version;
+ r2->inTransaction = true;
+ instance->SetExternalResource(r2);
bool ok = true;
- if (callback.isFunction()) {
+ if (callback->IsFunction()) {
ok = false;
db.transaction();
- callback.call(QScriptValue(), QScriptValueList() << tx);
- if (engine->hasUncaughtException()) {
+
+ v8::TryCatch tc;
+ v8::Handle<v8::Value> callbackArgs[] = { instance };
+ v8::Handle<v8::Function>::Cast(callback)->Call(engine->global(), 1, callbackArgs);
+
+ if (tc.HasCaught()) {
+ db.rollback();
+ tc.ReThrow();
+ return v8::Handle<v8::Value>();
+ } else if (!db.commit()) {
db.rollback();
+ V8THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed"));
} else {
- if (!db.commit()) {
- db.rollback();
- THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed"));
- } else {
- ok = true;
- }
+ ok = true;
}
}
+ r2->inTransaction = false;
+
if (ok) {
- context->thisObject().setProperty(QLatin1String("version"), to_version, QScriptValue::ReadOnly);
+ r2->version = to_version;
#ifndef QT_NO_SETTINGS
QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat);
ini.setValue(QLatin1String("Version"), to_version);
#endif
}
- return engine->undefinedValue();
+ return v8::Undefined();
}
-static QScriptValue qmlsqldatabase_transaction_shared(QScriptContext *context, QScriptEngine *engine, bool readOnly)
+static v8::Handle<v8::Value> qmlsqldatabase_transaction_shared(const v8::Arguments& args, bool readOnly)
{
- QSqlDatabase db = qscriptvalue_cast<QSqlDatabase>(context->thisObject());
- QScriptValue callback = context->argument(0);
- if (!callback.isFunction())
- THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback"));
-
- QScriptValue instance = engine->newObject();
- instance.setProperty(QLatin1String("executeSql"),
- engine->newFunction(readOnly ? qmlsqldatabase_executeSql_readonly : qmlsqldatabase_executeSql,1));
- QScriptValue tx = engine->newVariant(instance,QVariant::fromValue(db));
+ QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
+ if (!r || r->type != QV8SqlDatabaseResource::Database)
+ V8THROW_REFERENCE("Not a SQLDatabase object");
+
+ QV8Engine *engine = r->engine;
+
+ if (args.Length() == 0 || !args[0]->IsFunction())
+ V8THROW_SQL(UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback"));
+
+ QSqlDatabase db = r->database;
+ v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(args[0]);
+
+ v8::Local<v8::Object> instance = QDeclarativeSqlDatabaseData::data(engine)->queryConstructor->NewInstance();
+ QV8SqlDatabaseResource *q = new QV8SqlDatabaseResource(engine);
+ q->type = QV8SqlDatabaseResource::Query;
+ q->database = db;
+ q->readonly = readOnly;
+ q->inTransaction = true;
+ instance->SetExternalResource(q);
db.transaction();
- callback.call(QScriptValue(), QScriptValueList() << tx);
- instance.setProperty(QLatin1String("executeSql"),
- engine->newFunction(qmlsqldatabase_executeSql_outsidetransaction));
- if (engine->hasUncaughtException()) {
+ v8::TryCatch tc;
+ v8::Handle<v8::Value> callbackArgs[] = { instance };
+ callback->Call(engine->global(), 1, callbackArgs);
+
+ q->inTransaction = false;
+
+ if (tc.HasCaught()) {
+ db.rollback();
+ tc.ReThrow();
+ return v8::Handle<v8::Value>();
+ } else if (!db.commit()) {
db.rollback();
- } else {
- if (!db.commit())
- db.rollback();
}
- return engine->undefinedValue();
+
+ return v8::Undefined();
}
-static QScriptValue qmlsqldatabase_transaction(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_transaction(const v8::Arguments& args)
{
- return qmlsqldatabase_transaction_shared(context,engine,false);
+ return qmlsqldatabase_transaction_shared(args, false);
}
-static QScriptValue qmlsqldatabase_read_transaction(QScriptContext *context, QScriptEngine *engine)
+
+static v8::Handle<v8::Value> qmlsqldatabase_read_transaction(const v8::Arguments& args)
{
- return qmlsqldatabase_transaction_shared(context,engine,true);
+ return qmlsqldatabase_transaction_shared(args, true);
}
/*
Currently documented in doc/src/declarative/globalobject.qdoc
*/
-static QScriptValue qmlsqldatabase_open_sync(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlsqldatabase_open_sync(const v8::Arguments& args)
{
#ifndef QT_NO_SETTINGS
+ QV8Engine *engine = V8ENGINE();
qmlsqldatabase_initDatabasesPath(engine);
QSqlDatabase database;
- QString dbname = context->argument(0).toString();
- QString dbversion = context->argument(1).toString();
- QString dbdescription = context->argument(2).toString();
- int dbestimatedsize = context->argument(3).toNumber();
- QScriptValue dbcreationCallback = context->argument(4);
+ QString dbname = engine->toString(args[0]);
+ QString dbversion = engine->toString(args[1]);
+ QString dbdescription = engine->toString(args[2]);
+ int dbestimatedsize = args[3]->Int32Value();
+ v8::Handle<v8::Value> dbcreationCallback = args[4];
QCryptographicHash md5(QCryptographicHash::Md5);
md5.addData(dbname.toUtf8());
database = QSqlDatabase::database(dbid);
version = ini.value(QLatin1String("Version")).toString();
if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
- THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
+ V8THROW_SQL(VERSION_ERR, QDeclarativeEngine::tr("SQL: database version mismatch"));
} else {
created = !QFile::exists(basename+QLatin1String(".sqlite"));
database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
if (created) {
ini.setValue(QLatin1String("Name"), dbname);
- if (dbcreationCallback.isFunction())
+ if (dbcreationCallback->IsFunction())
version = QString();
ini.setValue(QLatin1String("Version"), version);
ini.setValue(QLatin1String("Description"), dbdescription);
} else {
if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
// Incompatible
- THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
+ V8THROW_SQL(VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch"));
}
version = ini.value(QLatin1String("Version")).toString();
}
database.open();
}
- QScriptValue instance = engine->newObject();
- instance.setProperty(QLatin1String("transaction"), engine->newFunction(qmlsqldatabase_transaction,1));
- instance.setProperty(QLatin1String("readTransaction"), engine->newFunction(qmlsqldatabase_read_transaction,1));
- instance.setProperty(QLatin1String("version"), version, QScriptValue::ReadOnly);
- instance.setProperty(QLatin1String("changeVersion"), engine->newFunction(qmlsqldatabase_change_version,3));
-
- QScriptValue result = engine->newVariant(instance,QVariant::fromValue(database));
-
- if (created && dbcreationCallback.isFunction()) {
- dbcreationCallback.call(QScriptValue(), QScriptValueList() << result);
+ v8::Local<v8::Object> instance = QDeclarativeSqlDatabaseData::data(engine)->constructor->NewInstance();
+ QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
+ r->database = database;
+ r->version = version;
+ instance->SetExternalResource(r);
+
+ if (created && dbcreationCallback->IsFunction()) {
+ v8::TryCatch tc;
+ v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(dbcreationCallback);
+ v8::Handle<v8::Value> args[] = { instance };
+ callback->Call(engine->global(), 1, args);
+ if (tc.HasCaught()) {
+ tc.ReThrow();
+ return v8::Handle<v8::Value>();
+ }
}
- return result;
+ return instance;
#else
- return engine->undefinedValue();
+ return v8::Undefined();
#endif // QT_NO_SETTINGS
}
-void qt_add_qmlsqldatabase(QScriptEngine *engine)
+QDeclarativeSqlDatabaseData::QDeclarativeSqlDatabaseData(QV8Engine *engine)
{
- QScriptValue openDatabase = engine->newFunction(qmlsqldatabase_open_sync, 4);
- engine->globalObject().setProperty(QLatin1String("openDatabaseSync"), openDatabase);
+ QString dataLocation = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
+ offlineStoragePath = dataLocation.replace(QLatin1Char('/'), QDir::separator()) +
+ QDir::separator() + QLatin1String("QML") +
+ QDir::separator() + QLatin1String("OfflineStorage");
- QScriptValue sqlExceptionPrototype = engine->newObject();
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->Set(v8::String::New("transaction"),
+ V8FUNCTION(qmlsqldatabase_transaction, engine));
+ ft->PrototypeTemplate()->Set(v8::String::New("readTransaction"),
+ V8FUNCTION(qmlsqldatabase_read_transaction, engine));
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("version"), qmlsqldatabase_version);
+ ft->PrototypeTemplate()->Set(v8::String::New("changeVersion"),
+ V8FUNCTION(qmlsqldatabase_changeVersion, engine));
+ constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->Set(v8::String::New("executeSql"),
+ V8FUNCTION(qmlsqldatabase_executeSql, engine));
+ queryConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->PrototypeTemplate()->Set(v8::String::New("item"), V8FUNCTION(qmlsqldatabase_rows_item, engine));
+ ft->PrototypeTemplate()->SetAccessor(v8::String::New("length"), qmlsqldatabase_rows_length);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("forwardOnly"), qmlsqldatabase_rows_forwardOnly,
+ qmlsqldatabase_rows_setForwardOnly);
+ ft->InstanceTemplate()->SetIndexedPropertyHandler(qmlsqldatabase_rows_index);
+ rowsConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+}
+
+void *qt_add_qmlsqldatabase(QV8Engine *engine)
+{
+ v8::Local<v8::Function> openDatabase = V8FUNCTION(qmlsqldatabase_open_sync, engine);
+ engine->global()->Set(v8::String::New("openDatabaseSync"), openDatabase);
+
+ v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+ v8::Local<v8::Object> sqlExceptionPrototype = v8::Object::New();
for (int i=0; sqlerror[i]; ++i)
- sqlExceptionPrototype.setProperty(QLatin1String(sqlerror[i]),
- i,QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ sqlExceptionPrototype->Set(v8::String::New(sqlerror[i]), v8::Integer::New(i), attributes);
+ engine->global()->Set(v8::String::New("SQLException"), sqlExceptionPrototype);
+
+ return (void *)new QDeclarativeSqlDatabaseData(engine);
+}
+
+void qt_rem_qmlsqldatabase(QV8Engine *engine, void *d)
+{
+ QDeclarativeSqlDatabaseData *data = (QDeclarativeSqlDatabaseData *)d;
+ delete data;
+}
- engine->globalObject().setProperty(QLatin1String("SQLException"), sqlExceptionPrototype);
+void qt_qmlsqldatabase_setOfflineStoragePath(QV8Engine *engine, const QString &path)
+{
+ QDeclarativeSqlDatabaseData::data(engine)->offlineStoragePath = path;
+}
+
+QString qt_qmlsqldatabase_getOfflineStoragePath(const QV8Engine *engine)
+{
+ return QDeclarativeSqlDatabaseData::data(const_cast<QV8Engine *>(engine))->offlineStoragePath;
}
/*
QT_BEGIN_NAMESPACE
-class QScriptEngine;
-void qt_add_qmlsqldatabase(QScriptEngine *engine);
+class QV8Engine;
+
+void *qt_add_qmlsqldatabase(QV8Engine *engine);
+void qt_rem_qmlsqldatabase(QV8Engine *engine, void *);
+void qt_qmlsqldatabase_setOfflineStoragePath(QV8Engine *engine, const QString &);
+QString qt_qmlsqldatabase_getOfflineStoragePath(const QV8Engine *);
QT_END_NAMESPACE
for (int ii = 0; ii < scripts.count(); ++ii)
scripts.at(ii)->release();
scripts.clear();
+
+ m_program.Dispose();
+ m_value.Dispose();
}
QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
m_imports.populateCache(m_scriptData->importCache, engine);
m_scriptData->pragmas = m_pragmas;
- m_scriptData->m_program = QScriptProgram(m_source, finalUrl().toString());
+
+ // XXX aakenned - what about error handling?
+ QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine;
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+ v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_source, finalUrl().toString(), 1);
+ m_scriptData->m_program = v8::Persistent<v8::Script>::New(program);
}
QDeclarativeQmldirData::QDeclarativeQmldirData(const QUrl &url)
#include <private/qdeclarativedirparser_p.h>
#include <private/qdeclarativeimport_p.h>
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeScriptData;
friend class QDeclarativeScriptBlob;
bool m_loaded;
- QScriptProgram m_program;
- QScriptValue m_value;
+ v8::Persistent<v8::Script> m_program;
+ v8::Persistent<v8::Object> m_value;
+// QScriptProgram m_program;
+// QScriptValue m_value;
};
class Q_AUTOTEST_EXPORT QDeclarativeScriptBlob : public QDeclarativeDataBlob
void QDeclarativeTypeNameCache::clear()
{
- qDeleteAll(stringCache);
stringCache.clear();
- identifierCache.clear();
m_moduleApi = 0;
engine = 0;
}
if (stringCache.contains(name))
return;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- RData *data = new RData;
- // ### Use typename class
- data->identifier = ep->objectClass->createPersistentIdentifier(name);
- data->importedScriptIndex = importedScriptIndex;
+ Data data;
+ data.importedScriptIndex = importedScriptIndex;
stringCache.insert(name, data);
- identifierCache.insert(data->identifier.identifier, data);
}
void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeType *type)
if (stringCache.contains(name))
return;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- RData *data = new RData;
- // ### Use typename class
- data->identifier = ep->objectClass->createPersistentIdentifier(name);
- data->type = type;
+ Data data;
+ data.type = type;
stringCache.insert(name, data);
- identifierCache.insert(data->identifier.identifier, data);
}
void QDeclarativeTypeNameCache::add(const QString &name, QDeclarativeTypeNameCache *typeNamespace)
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- RData *data = new RData;
- // ### Use typename class
- data->identifier = ep->objectClass->createPersistentIdentifier(name);
- data->typeNamespace = typeNamespace;
- stringCache.insert(name, data);
- identifierCache.insert(data->identifier.identifier, data);
+ Data data;
typeNamespace->addref();
+ data.typeNamespace = typeNamespace;
+ stringCache.insert(name, data);
}
QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QString &id) const
#include <private/qscriptdeclarativeclass_p.h>
+#include <private/qhashedstring_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeType;
struct Data {
inline Data();
+ inline Data(const Data &);
inline ~Data();
+ inline Data &operator=(const Data &);
QDeclarativeType *type;
QDeclarativeTypeNameCache *typeNamespace;
int importedScriptIndex;
void add(const QString &, QDeclarativeTypeNameCache *);
Data *data(const QString &) const;
- inline Data *data(const QScriptDeclarativeClass::Identifier &id) const;
+ inline Data *data(v8::Handle<v8::String>) const;
inline bool isEmpty() const;
inline QDeclarativeMetaType::ModuleApiInstance *moduleApi() const;
virtual void clear();
private:
- struct RData : public Data {
- QScriptDeclarativeClass::PersistentIdentifier identifier;
- };
- typedef QHash<QString, RData *> StringCache;
- typedef QHash<QScriptDeclarativeClass::Identifier, RData *> IdentifierCache;
+ typedef QStringHash<Data> StringCache;
StringCache stringCache;
- IdentifierCache identifierCache;
+
QDeclarativeEngine *engine;
QDeclarativeMetaType::ModuleApiInstance *m_moduleApi;
};
if (typeNamespace) typeNamespace->release();
}
-QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(const QScriptDeclarativeClass::Identifier &id) const
+bool QDeclarativeTypeNameCache::isEmpty() const
{
- return identifierCache.value(id);
+ return stringCache.isEmpty();
}
-bool QDeclarativeTypeNameCache::isEmpty() const
+QDeclarativeTypeNameCache::Data::Data(const QDeclarativeTypeNameCache::Data &o)
+: type(o.type), typeNamespace(o.typeNamespace), importedScriptIndex(o.importedScriptIndex)
+{
+ if (typeNamespace) typeNamespace->addref();
+}
+
+QDeclarativeTypeNameCache::Data &QDeclarativeTypeNameCache::Data::operator=(const QDeclarativeTypeNameCache::Data &o)
{
- return identifierCache.isEmpty();
+ if (o.typeNamespace) o.typeNamespace->addref();
+ if (typeNamespace) typeNamespace->release();
+ type = o.type;
+ typeNamespace = o.typeNamespace;
+ importedScriptIndex = o.importedScriptIndex;
+ return *this;
}
QDeclarativeMetaType::ModuleApiInstance *QDeclarativeTypeNameCache::moduleApi() const
return m_moduleApi;
}
+QDeclarativeTypeNameCache::Data *QDeclarativeTypeNameCache::data(v8::Handle<v8::String> name) const
+{
+ return stringCache.value(name);
+}
+
QT_END_NAMESPACE
#endif // QDECLARATIVETYPENAMECACHE_P_H
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativetypenamescriptclass_p.h"
-
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativetypenamecache_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct TypeNameData : public QScriptDeclarativeClass::Object {
- TypeNameData(QObject *o, QDeclarativeType *t, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(t), typeNamespace(0), mode(m) {}
- TypeNameData(QObject *o, QDeclarativeTypeNameCache *n, QDeclarativeTypeNameScriptClass::TypeNameMode m) : object(o), type(0), typeNamespace(n), mode(m) {
- if (typeNamespace) typeNamespace->addref();
- }
- ~TypeNameData() {
- if (typeNamespace) typeNamespace->release();
- }
-
- QObject *object;
- QDeclarativeType *type;
- QDeclarativeTypeNameCache *typeNamespace;
- QDeclarativeTypeNameScriptClass::TypeNameMode mode;
-};
-
-QDeclarativeTypeNameScriptClass::QDeclarativeTypeNameScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)),
- engine(bindEngine), object(0), type(0), api(0)
-{
-}
-
-QDeclarativeTypeNameScriptClass::~QDeclarativeTypeNameScriptClass()
-{
-}
-
-QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeType *type, TypeNameMode mode)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type, mode));
-}
-
-QScriptValue QDeclarativeTypeNameScriptClass::newObject(QObject *object, QDeclarativeTypeNameCache *ns, TypeNameMode mode)
-{
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns, mode));
-}
-
-QScriptClass::QueryFlags
-QDeclarativeTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name,
- QScriptClass::QueryFlags flags)
-{
- Q_UNUSED(flags);
-
- TypeNameData *data = (TypeNameData *)obj;
-
- object = 0;
- type = 0;
- api = 0;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-
- if (data->typeNamespace) {
- QDeclarativeTypeNameCache::Data *d = data->typeNamespace->data(name);
- if (d && d->type) {
- type = d->type;
- return QScriptClass::HandlesReadAccess;
- } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = data->typeNamespace->moduleApi()) {
- if (moduleApi->scriptCallback) {
- moduleApi->scriptApi = moduleApi->scriptCallback(engine, &ep->scriptEngine);
- moduleApi->scriptCallback = 0;
- moduleApi->qobjectCallback = 0;
- } else if (moduleApi->qobjectCallback) {
- moduleApi->qobjectApi = moduleApi->qobjectCallback(engine, &ep->scriptEngine);
- moduleApi->scriptCallback = 0;
- moduleApi->qobjectCallback = 0;
- }
-
- api = moduleApi;
- if (api->qobjectApi) {
- return ep->objectClass->queryProperty(api->qobjectApi, name, flags, 0,
- QDeclarativeObjectScriptClass::SkipAttachedProperties);
- } else {
- return QScriptClass::HandlesReadAccess;
- }
-
- return 0;
-
- } else {
- return 0;
- }
-
- } else if (data->type) {
-
- if (startsWithUpper(name)) {
- QString strName = toString(name);
- // Must be an enum
- if (data->mode == IncludeEnums) {
- // ### Optimize
- QByteArray enumName = strName.toUtf8();
- const QMetaObject *metaObject = data->type->baseMetaObject();
- for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- int value = e.keyToValue(enumName.constData());
- if (value != -1) {
- enumValue = value;
- return QScriptClass::HandlesReadAccess;
- }
- }
- }
- return 0;
- } else if (data->object) {
- // Must be an attached property
- object = qmlAttachedPropertiesObjectById(data->type->attachedPropertiesId(), data->object);
- if (!object) return 0;
- return ep->objectClass->queryProperty(object, name, flags, 0);
- }
-
- }
-
- return 0;
-}
-
-QDeclarativeTypeNameScriptClass::Value
-QDeclarativeTypeNameScriptClass::property(Object *obj, const Identifier &name)
-{
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- if (type) {
- return Value(scriptEngine, newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode));
- } else if (object) {
- return ep->objectClass->property(object, name);
- } else if (api && api->qobjectApi) {
- return ep->objectClass->property(api->qobjectApi, name);
- } else if (api) {
- return propertyValue(api->scriptApi, name);
- } else {
- return Value(scriptEngine, enumValue);
- }
-}
-
-void QDeclarativeTypeNameScriptClass::setProperty(Object *, const Identifier &n, const QScriptValue &v)
-{
- Q_ASSERT(!type);
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- if (api) {
- Q_ASSERT(api->qobjectApi);
- ep->objectClass->setProperty(api->qobjectApi, n, v, context());
- } else {
- Q_ASSERT(object);
- ep->objectClass->setProperty(object, n, v, context());
- }
-}
-
-QT_END_NAMESPACE
-
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "private/qdeclarativevaluetypescriptclass_p.h"
-
-#include "private/qdeclarativebinding_p.h"
-#include "private/qdeclarativeproperty_p.h"
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativeguard_p.h"
-
-#include <QtScript/qscriptcontextinfo.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QDeclarativeValueTypeObject : public QScriptDeclarativeClass::Object {
- enum Type { Reference, Copy };
- QDeclarativeValueTypeObject(Type t) : objectType(t) {}
- Type objectType;
- QDeclarativeValueType *type;
-};
-
-struct QDeclarativeValueTypeReference : public QDeclarativeValueTypeObject {
- QDeclarativeValueTypeReference() : QDeclarativeValueTypeObject(Reference) {}
- QDeclarativeGuard<QObject> object;
- int property;
-};
-
-struct QDeclarativeValueTypeCopy : public QDeclarativeValueTypeObject {
- QDeclarativeValueTypeCopy() : QDeclarativeValueTypeObject(Copy) {}
- QVariant value;
-};
-
-QDeclarativeValueTypeScriptClass::QDeclarativeValueTypeScriptClass(QDeclarativeEngine *bindEngine)
-: QScriptDeclarativeClass(QDeclarativeEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine)
-{
-}
-
-QDeclarativeValueTypeScriptClass::~QDeclarativeValueTypeScriptClass()
-{
-}
-
-QScriptValue QDeclarativeValueTypeScriptClass::newObject(QObject *object, int coreIndex, QDeclarativeValueType *type)
-{
- QDeclarativeValueTypeReference *ref = new QDeclarativeValueTypeReference;
- ref->type = type;
- ref->object = object;
- ref->property = coreIndex;
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return QScriptDeclarativeClass::newObject(scriptEngine, this, ref);
-}
-
-QScriptValue QDeclarativeValueTypeScriptClass::newObject(const QVariant &v, QDeclarativeValueType *type)
-{
- QDeclarativeValueTypeCopy *copy = new QDeclarativeValueTypeCopy;
- copy->type = type;
- copy->value = v;
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return QScriptDeclarativeClass::newObject(scriptEngine, this, copy);
-}
-
-QScriptClass::QueryFlags
-QDeclarativeValueTypeScriptClass::queryProperty(Object *obj, const Identifier &name,
- QScriptClass::QueryFlags)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- m_lastIndex = -1;
-
- QByteArray propName = toString(name).toUtf8();
-
- m_lastIndex = o->type->metaObject()->indexOfProperty(propName.constData());
- if (m_lastIndex == -1)
- return 0;
-
- QScriptClass::QueryFlags rv = 0;
-
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(o);
-
- if (!ref->object)
- return 0;
-
- QMetaProperty prop = ref->object->metaObject()->property(m_lastIndex);
-
- rv = QScriptClass::HandlesReadAccess;
- if (prop.isWritable())
- rv |= QScriptClass::HandlesWriteAccess;
- } else {
- rv = QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess;
- }
-
- return rv;
-}
-
-QDeclarativeValueTypeScriptClass::Value QDeclarativeValueTypeScriptClass::property(Object *obj, const Identifier &)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- QVariant rv;
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
-
- QMetaProperty p = ref->type->metaObject()->property(m_lastIndex);
- ref->type->read(ref->object, ref->property);
- rv = p.read(ref->type);
- } else {
- QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
-
- QMetaProperty p = copy->type->metaObject()->property(m_lastIndex);
- copy->type->setValue(copy->value);
- rv = p.read(copy->type);
- }
-
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
- return Value(scriptEngine, static_cast<QDeclarativeEnginePrivate *>(QObjectPrivate::get(engine))->scriptValueFromVariant(rv));
-}
-
-void QDeclarativeValueTypeScriptClass::setProperty(Object *obj, const Identifier &,
- const QScriptValue &value)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- QVariant v = QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value);
-
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
-
- ref->type->read(ref->object, ref->property);
- QMetaProperty p = ref->type->metaObject()->property(m_lastIndex);
-
- QDeclarativeBinding *newBinding = 0;
- if (value.isFunction() && !value.isRegExp()) {
- QDeclarativeContextData *ctxt = QDeclarativeEnginePrivate::get(engine)->getContext(context());
-
- QDeclarativePropertyCache::Data cacheData;
- cacheData.flags = QDeclarativePropertyCache::Data::IsWritable;
- cacheData.propType = ref->object->metaObject()->property(ref->property).userType();
- cacheData.coreIndex = ref->property;
-
- QDeclarativePropertyCache::ValueTypeData valueTypeData;
- valueTypeData.valueTypeCoreIdx = m_lastIndex;
- valueTypeData.valueTypePropType = p.userType();
-
- newBinding = new QDeclarativeBinding(value, ref->object, ctxt);
- QScriptContextInfo ctxtInfo(context());
- newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber());
- QDeclarativeProperty prop = QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, ref->object, ctxt);
- newBinding->setTarget(prop);
- if (newBinding->expression().contains(QLatin1String("this")))
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
- }
-
- QDeclarativeAbstractBinding *delBinding =
- QDeclarativePropertyPrivate::setBinding(ref->object, ref->property, m_lastIndex, newBinding);
- if (delBinding)
- delBinding->destroy();
-
- if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
- v = v.toInt();
- p.write(ref->type, v);
- ref->type->write(ref->object, ref->property, 0);
-
- } else {
- QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
- copy->type->setValue(copy->value);
- QMetaProperty p = copy->type->metaObject()->property(m_lastIndex);
- p.write(copy->type, v);
- copy->value = copy->type->value();
- }
-}
-
-QVariant QDeclarativeValueTypeScriptClass::toVariant(Object *obj, bool *ok)
-{
- QDeclarativeValueTypeObject *o = static_cast<QDeclarativeValueTypeObject *>(obj);
-
- if (o->objectType == QDeclarativeValueTypeObject::Reference) {
- QDeclarativeValueTypeReference *ref = static_cast<QDeclarativeValueTypeReference *>(obj);
-
- if (ok) *ok = true;
-
- if (ref->object) {
- ref->type->read(ref->object, ref->property);
- return ref->type->value();
- }
- } else {
- QDeclarativeValueTypeCopy *copy = static_cast<QDeclarativeValueTypeCopy *>(obj);
-
- if (ok) *ok = true;
-
- return copy->value;
- }
-
- return QVariant();
-}
-
-QVariant QDeclarativeValueTypeScriptClass::toVariant(const QScriptValue &value)
-{
- Q_ASSERT(scriptClass(value) == this);
-
- return toVariant(object(value), 0);
-}
-
-QT_END_NAMESPACE
-
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativev4bindings_p.h"
#include "private/qdeclarativeglobal_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include "qdeclarativescriptstring.h"
#include <QStack>
}
}
-QScriptValue QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
+v8::Persistent<v8::Object> QDeclarativeVME::run(QDeclarativeContextData *parentCtxt, QDeclarativeScriptData *script)
{
if (script->m_loaded)
- return script->m_value;
+ return v8::Persistent<v8::Object>::New(script->m_value);
- QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentCtxt->engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(parentCtxt->engine);
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(parentCtxt->engine);
+ QV8Engine *v8engine = &ep->v8engine;
bool shared = script->pragmas & QDeclarativeParser::Object::ScriptBlock::Shared;
// Create the script context if required
- QDeclarativeContextData *ctxt = 0;
- if (!shared) {
- ctxt = new QDeclarativeContextData;
- ctxt->isInternal = true;
- ctxt->url = script->url;
-
- // For backward compatibility, if there are no imports, we need to use the
- // imports from the parent context. See QTBUG-17518.
- if (!script->importCache->isEmpty()) {
- ctxt->imports = script->importCache;
- } else {
- ctxt->imports = parentCtxt->imports;
- }
-
- if (ctxt->imports) {
- ctxt->imports->addref();
- }
-
- ctxt->setParent(parentCtxt, true);
+ QDeclarativeContextData *ctxt = new QDeclarativeContextData;
+ ctxt->isInternal = true;
+ ctxt->isJSContext = true;
+ ctxt->url = script->url;
+
+ // For backward compatibility, if there are no imports, we need to use the
+ // imports from the parent context. See QTBUG-17518.
+ if (!script->importCache->isEmpty()) {
+ ctxt->imports = script->importCache;
+ } else {
+ ctxt->imports = parentCtxt->imports;
+ }
- for (int ii = 0; ii < script->scripts.count(); ++ii)
- ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
+ if (ctxt->imports) {
+ ctxt->imports->addref();
}
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- if (shared) {
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(script->url.toString())); // XXX toString()?
- } else {
- scriptContext->pushScope(enginePriv->contextClass->newUrlContext(ctxt, 0, script->url.toString()));
+ ctxt->setParent(parentCtxt, true);
+
+ for (int ii = 0; ii < script->scripts.count(); ++ii) {
+ ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
}
- scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject());
- QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine);
- scriptContext->pushScope(scope);
+ // XXX aakenned optimize
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
- scriptEngine->evaluate(script->m_program);
+ v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
- if (scriptEngine->hasUncaughtException()) {
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
- enginePriv->warning(error);
- }
+ v8::TryCatch try_catch;
+ script->m_program->Run(qmlglobal);
- scriptEngine->popContext();
+ v8::Persistent<v8::Object> rv;
+
+ if (try_catch.HasCaught()) {
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ ep->warning(error);
+ }
+ }
+ rv = v8::Persistent<v8::Object>::New(qmlglobal);
if (shared) {
+ script->m_value = v8::Persistent<v8::Object>::New(qmlglobal);
script->m_loaded = true;
- script->m_value = scope;
}
- return scope;
+ return rv;
}
QT_END_NAMESPACE
#include <QtCore/QString>
#include <QtCore/QStack>
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QObject;
QObject *run(QDeclarativeContextData *, QDeclarativeCompiledData *,
int start = -1, const QBitField & = QBitField());
- QScriptValue run(QDeclarativeContextData *, QDeclarativeScriptData *);
void runDeferred(QObject *);
QList<QDeclarativeError> errors() const;
private:
+ v8::Persistent<v8::Object> run(QDeclarativeContextData *, QDeclarativeScriptData *);
+
QObject *run(QDeclarativeVMEStack<QObject *> &,
QDeclarativeContextData *, QDeclarativeCompiledData *,
int start, const QBitField &);
const QDeclarativeVMEMetaData *meta,
QDeclarativeCompiledData *cdata)
: object(obj), compiledData(cdata), ctxt(QDeclarativeData::get(obj, true)->outerContext),
- metaData(meta), data(0), methods(0), parent(0)
+ metaData(meta), data(0), v8methods(0), parent(0)
{
compiledData->addref();
compiledData->release();
delete parent;
delete [] data;
- delete [] methods;
+
+ for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii)
+ v8methods[ii].Dispose();
}
int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- QScriptValue function = method(id);
-
- QScriptValueList args;
+ // XXX aakenned
+ v8::Handle<v8::Function> function = method(id);
QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id;
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(ep->v8engine.context());
+ v8::Handle<v8::Value> *args = 0;
+
if (data->parameterCount) {
- for (int ii = 0; ii < data->parameterCount; ++ii) {
- args << ep->scriptValueFromVariant(*(QVariant *)a[ii + 1]);
- }
+ args = new v8::Handle<v8::Value>[data->parameterCount];
+ for (int ii = 0; ii < data->parameterCount; ++ii)
+ args[ii] = ep->v8engine.fromVariant(*(QVariant *)a[ii + 1]);
}
- QScriptValue rv = function.call(ep->objectClass->newQObject(object), args);
- if (ep->scriptEngine.hasUncaughtException()) {
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Value> result = function->Call(ep->v8engine.global(), data->parameterCount, args);
+
+ QVariant rv;
+ if (try_catch.HasCaught()) {
QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(&ep->scriptEngine, error);
- if (error.isValid()) {
+ QDeclarativeExpressionPrivate::exceptionToError(try_catch.Message(), error);
+ if (error.isValid())
ep->warning(error);
- }
+ if (a[0]) *(QVariant *)a[0] = QVariant();
+ } else {
+ if (a[0]) *(QVariant *)a[0] = ep->v8engine.toVariant(result, 0);
}
- if (a[0]) *reinterpret_cast<QVariant *>(a[0]) = ep->scriptValueToVariant(rv);
-
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
return -1;
}
return object->qt_metacall(c, _id, a);
}
-QScriptValue QDeclarativeVMEMetaObject::method(int index)
+v8::Handle<v8::Function> QDeclarativeVMEMetaObject::method(int index)
{
- if (!methods)
- methods = new QScriptValue[metaData->methodCount];
+ if (!v8methods)
+ v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
- if (!methods[index].isValid()) {
+ if (v8methods[index].IsEmpty()) {
QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index;
const QChar *body =
QString code = QString::fromRawData(body, data->bodyLength);
- // XXX Use QScriptProgram
// XXX We should evaluate all methods in a single big script block to
// improve the call time between dynamic methods defined on the same
// object
- methods[index] = QDeclarativeExpressionPrivate::evalInObjectScope(ctxt, object, code, ctxt->url.toString(),
- data->lineNumber, 0);
+ v8methods[index] = QDeclarativeExpressionPrivate::evalFunction(ctxt, object, code, ctxt->url.toString(),
+ data->lineNumber);
}
- return methods[index];
+ return v8methods[index];
}
+#if 0
QScriptValue QDeclarativeVMEMetaObject::readVarProperty(int id)
{
if (data[id].dataType() == qMetaTypeId<QScriptValue>())
else
return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueFromVariant(data[id].asQVariant());
}
+#endif
QVariant QDeclarativeVMEMetaObject::readVarPropertyAsVariant(int id)
{
+#if 0
if (data[id].dataType() == qMetaTypeId<QScriptValue>())
return QDeclarativeEnginePrivate::get(ctxt->engine)->scriptValueToVariant(data[id].asQScriptValue());
- else if (data[id].dataType() == QMetaType::QObjectStar)
+ else
+#endif
+ if (data[id].dataType() == QMetaType::QObjectStar)
return QVariant::fromValue(data[id].asQObject());
else
return data[id].asQVariant();
}
+#if 0
void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QScriptValue &value)
{
data[id].setValue(value);
activate(object, methodOffset + id, 0);
}
+#endif
void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QVariant &value)
{
return data->lineNumber;
}
-QScriptValue QDeclarativeVMEMetaObject::vmeMethod(int index)
+v8::Handle<v8::Function> QDeclarativeVMEMetaObject::vmeMethod(int index)
{
if (index < methodOffset) {
Q_ASSERT(parent);
return method(index - methodOffset - plainSignals);
}
+// Used by debugger
void QDeclarativeVMEMetaObject::setVmeMethod(int index, const QScriptValue &value)
{
if (index < methodOffset) {
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
+#if 0
if (!methods)
methods = new QScriptValue[metaData->methodCount];
methods[index - methodOffset - plainSignals] = value;
+#endif
}
+#if 0
QScriptValue QDeclarativeVMEMetaObject::vmeProperty(int index)
{
if (index < propOffset) {
}
return writeVarProperty(index - propOffset, v);
}
+#endif
bool QDeclarativeVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
{
#include "private/qdeclarativecompiler_p.h"
#include "private/qdeclarativecontext_p.h"
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
#define QML_ALIAS_FLAG_PTR 0x00000001
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
void registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor);
- QScriptValue vmeMethod(int index);
+ v8::Handle<v8::Function> vmeMethod(int index);
int vmeMethodLineNumber(int index);
void setVmeMethod(int index, const QScriptValue &);
+#if 0
QScriptValue vmeProperty(int index);
void setVMEProperty(int index, const QScriptValue &);
+#endif
void connectAliasSignal(int index);
QHash<int, QPair<int, QDeclarativePropertyValueInterceptor*> > interceptors;
QScriptValue *methods;
- QScriptValue method(int);
+ v8::Persistent<v8::Function> *v8methods;
+ v8::Handle<v8::Function> method(int);
+#if 0
QScriptValue readVarProperty(int);
- QVariant readVarPropertyAsVariant(int);
void writeVarProperty(int, const QScriptValue &);
+#endif
+ QVariant readVarPropertyAsVariant(int);
void writeVarProperty(int, const QVariant &);
QAbstractDynamicMetaObject *parent;
#include <QtDeclarative/qdeclarativeinfo.h>
#include "qdeclarativenetworkaccessmanagerfactory.h"
+#include <private/qv8engine_p.h>
+#include <private/qv8worker_p.h>
QT_BEGIN_NAMESPACE
public:
enum Type { WorkerData = QEvent::User };
- WorkerDataEvent(int workerId, const QVariant &data);
+ WorkerDataEvent(int workerId, const QByteArray &data);
virtual ~WorkerDataEvent();
int workerId() const;
- QVariant data() const;
+ QByteArray data() const;
private:
int m_id;
- QVariant m_data;
+ QByteArray m_data;
};
class WorkerLoadEvent : public QEvent
QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *eng);
- struct ScriptEngine : public QDeclarativeScriptEngine
+ class WorkerEngine : public QV8Engine
{
- ScriptEngine(QDeclarativeWorkerScriptEnginePrivate *parent) : QDeclarativeScriptEngine(0), p(parent), accessManager(0) {}
- ~ScriptEngine() { delete accessManager; }
+ public:
+ WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent);
+ ~WorkerEngine();
+
+ void init();
+ virtual QNetworkAccessManager *networkAccessManager();
+
QDeclarativeWorkerScriptEnginePrivate *p;
- QNetworkAccessManager *accessManager;
- virtual QNetworkAccessManager *networkAccessManager() {
- if (!accessManager) {
- if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
- accessManager = p->qmlengine->networkAccessManagerFactory()->create(this);
- } else {
- accessManager = new QNetworkAccessManager(this);
- }
- }
- return accessManager;
- }
+ v8::Local<v8::Function> sendFunction(int id);
+ void callOnMessage(v8::Handle<v8::Object> object, v8::Handle<v8::Value> arg);
+ private:
+ v8::Persistent<v8::Function> onmessage;
+ v8::Persistent<v8::Function> createsend;
+ QNetworkAccessManager *accessManager;
};
- ScriptEngine *workerEngine;
- static QDeclarativeWorkerScriptEnginePrivate *get(QScriptEngine *e) {
- return static_cast<ScriptEngine *>(e)->p;
+
+ WorkerEngine *workerEngine;
+ static QDeclarativeWorkerScriptEnginePrivate *get(QV8Engine *e) {
+ return static_cast<WorkerEngine *>(e)->p;
}
QDeclarativeEngine *qmlengine;
struct WorkerScript {
WorkerScript();
+ ~WorkerScript();
int id;
QUrl source;
bool initialized;
QDeclarativeWorkerScript *owner;
- QScriptValue object;
-
- QScriptValue callback;
+ v8::Persistent<v8::Object> object;
};
QHash<int, WorkerScript *> workers;
- QScriptValue getWorker(int);
+ v8::Handle<v8::Object> getWorker(WorkerScript *);
int m_nextId;
- static QVariant scriptValueToVariant(const QScriptValue &);
- static QScriptValue variantToScriptValue(const QVariant &, QScriptEngine *);
-
- static QScriptValue onMessage(QScriptContext *ctxt, QScriptEngine *engine);
- static QScriptValue sendMessage(QScriptContext *ctxt, QScriptEngine *engine);
+ static v8::Handle<v8::Value> sendMessage(const v8::Arguments &args);
signals:
void stopThread();
virtual bool event(QEvent *);
private:
- void processMessage(int, const QVariant &);
+ void processMessage(int, const QByteArray &);
void processLoad(int, const QUrl &);
- void reportScriptException(WorkerScript *);
+ void reportScriptException(WorkerScript *, const QDeclarativeError &error);
};
-QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
-: workerEngine(0), qmlengine(engine), m_nextId(0)
+QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QDeclarativeWorkerScriptEnginePrivate *parent)
+: p(parent), accessManager(0)
{
}
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::onMessage(QScriptContext *ctxt, QScriptEngine *engine)
+QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine()
+{
+ createsend.Dispose(); createsend.Clear();
+ onmessage.Dispose(); onmessage.Clear();
+ delete accessManager;
+}
+
+void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::init()
{
- QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
+ QV8Engine::init(0);
- int id = ctxt->thisObject().data().toVariant().toInt();
+#define CALL_ONMESSAGE_SCRIPT \
+ "(function(object, message) { "\
+ "var isfunction = false; "\
+ "try { "\
+ "isfunction = object.WorkerScript.onMessage instanceof Function; "\
+ "} catch (e) {}" \
+ "if (isfunction) "\
+ "object.WorkerScript.onMessage(message); "\
+ "})"
- WorkerScript *script = p->workers.value(id);
- if (!script)
- return engine->undefinedValue();
+#define SEND_MESSAGE_CREATE_SCRIPT \
+ "(function(method, engine) { "\
+ "return (function(id) { "\
+ "return (function(message) { "\
+ "if (arguments.length) method(engine, id, message); "\
+ "}); "\
+ "}); "\
+ "})"
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(context());
- if (ctxt->argumentCount() >= 1)
- script->callback = ctxt->argument(0);
+ {
+ v8::Local<v8::Script> onmessagescript = v8::Script::New(v8::String::New(CALL_ONMESSAGE_SCRIPT));
+ onmessage = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(onmessagescript->Run()));
+ }
+ {
+ v8::Local<v8::Script> createsendscript = v8::Script::New(v8::String::New(SEND_MESSAGE_CREATE_SCRIPT));
+ v8::Local<v8::Function> createsendconstructor = v8::Local<v8::Function>::Cast(createsendscript->Run());
- return script->callback;
+ v8::Handle<v8::Value> args[] = {
+ V8FUNCTION(QDeclarativeWorkerScriptEnginePrivate::sendMessage, this)
+ };
+ v8::Local<v8::Value> createsendvalue = createsendconstructor->Call(global(), 1, args);
+
+ createsend = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(createsendvalue));
+ }
}
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::sendMessage(QScriptContext *ctxt, QScriptEngine *engine)
+// Requires handle and context scope
+v8::Local<v8::Function> QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id)
{
- if (!ctxt->argumentCount())
- return engine->undefinedValue();
+ v8::Handle<v8::Value> args[] = { v8::Integer::New(id) };
+ return v8::Local<v8::Function>::Cast(createsend->Call(global(), 1, args));
+}
- QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(engine);
+// Requires handle and context scope
+void QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::callOnMessage(v8::Handle<v8::Object> object,
+ v8::Handle<v8::Value> arg)
+{
+ v8::Handle<v8::Value> args[] = { object, arg };
+ onmessage->Call(global(), 2, args);
+}
- int id = ctxt->thisObject().data().toVariant().toInt();
+QNetworkAccessManager *QDeclarativeWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager()
+{
+ if (!accessManager) {
+ if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) {
+ accessManager = p->qmlengine->networkAccessManagerFactory()->create(p);
+ } else {
+ accessManager = new QNetworkAccessManager(p);
+ }
+ }
+ return accessManager;
+}
- WorkerScript *script = p->workers.value(id);
- if (!script)
- return engine->undefinedValue();
+QDeclarativeWorkerScriptEnginePrivate::QDeclarativeWorkerScriptEnginePrivate(QDeclarativeEngine *engine)
+: workerEngine(0), qmlengine(engine), m_nextId(0)
+{
+}
- QMutexLocker(&p->m_lock);
+v8::Handle<v8::Value> QDeclarativeWorkerScriptEnginePrivate::sendMessage(const v8::Arguments &args)
+{
+ WorkerEngine *engine = (WorkerEngine*)V8ENGINE();
+
+ int id = args[1]->Int32Value();
+
+ QByteArray data = QV8Worker::serialize(args[2], engine);
+
+ QMutexLocker(&engine->p->m_lock);
+ WorkerScript *script = engine->p->workers.value(id);
+ if (!script)
+ return v8::Undefined();
if (script->owner)
- QCoreApplication::postEvent(script->owner,
- new WorkerDataEvent(0, scriptValueToVariant(ctxt->argument(0))));
+ QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
- return engine->undefinedValue();
+ return v8::Undefined();
}
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::getWorker(int id)
+// Requires handle scope and context scope
+v8::Handle<v8::Object> QDeclarativeWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
{
- QHash<int, WorkerScript *>::ConstIterator iter = workers.find(id);
-
- if (iter == workers.end())
- return workerEngine->nullValue();
-
- WorkerScript *script = *iter;
if (!script->initialized) {
-
script->initialized = true;
- script->object = workerEngine->newObject();
- QScriptValue api = workerEngine->newObject();
- api.setData(script->id);
+ script->object = v8::Persistent<v8::Object>::New(workerEngine->contextWrapper()->urlScope(script->source));
- api.setProperty(QLatin1String("onMessage"), workerEngine->newFunction(onMessage),
- QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- api.setProperty(QLatin1String("sendMessage"), workerEngine->newFunction(sendMessage));
+ workerEngine->contextWrapper()->setReadOnly(script->object, false);
- script->object.setProperty(QLatin1String("WorkerScript"), api);
+ v8::Local<v8::Object> api = v8::Object::New();
+ api->Set(v8::String::New("sendMessage"), workerEngine->sendFunction(script->id));
+
+ script->object->Set(v8::String::New("WorkerScript"), api);
+
+ workerEngine->contextWrapper()->setReadOnly(script->object, true);
}
return script->object;
bool QDeclarativeWorkerScriptEnginePrivate::event(QEvent *event)
{
+ // XXX must handle remove request
if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
processMessage(workerEvent->workerId(), workerEvent->data());
}
}
-void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QVariant &data)
+void QDeclarativeWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data)
{
WorkerScript *script = workers.value(id);
if (!script)
return;
- if (script->callback.isFunction()) {
- QScriptValue args = workerEngine->newArray(1);
- args.setProperty(0, variantToScriptValue(data, workerEngine));
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(workerEngine->context());
- script->callback.call(script->object, args);
+ v8::Handle<v8::Value> value = QV8Worker::deserialize(data, workerEngine);
- if (workerEngine->hasUncaughtException()) {
- reportScriptException(script);
- workerEngine->clearExceptions();
- }
+ v8::TryCatch tc;
+ workerEngine->callOnMessage(script->object, value);
+
+ if (tc.HasCaught()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
+ reportScriptException(script, error);
}
}
if (f.open(QIODevice::ReadOnly)) {
QByteArray data = f.readAll();
QString sourceCode = QString::fromUtf8(data);
-
- QScriptValue activation = getWorker(id);
-
- QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine);
- QScriptValue urlContext = workerEngine->newObject();
- urlContext.setData(QScriptValue(workerEngine, url.toString()));
- ctxt->pushScope(urlContext);
- ctxt->pushScope(activation);
- ctxt->setActivationObject(activation);
QDeclarativeScriptParser::extractPragmas(sourceCode);
- workerEngine->baseUrl = url;
- workerEngine->evaluate(sourceCode);
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(workerEngine->context());
WorkerScript *script = workers.value(id);
- if (script) {
- script->source = url;
- if (workerEngine->hasUncaughtException()) {
- reportScriptException(script);
- workerEngine->clearExceptions();
- }
+ if (!script)
+ return;
+ script->source = url;
+ v8::Handle<v8::Object> activation = getWorker(script);
+ if (activation.IsEmpty())
+ return;
+
+ // XXX ???
+ // workerEngine->baseUrl = url;
+
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = workerEngine->qmlModeCompile(sourceCode, url.toString());
+
+ if (!tc.HasCaught())
+ program->Run(activation);
+
+ if (tc.HasCaught()) {
+ QDeclarativeError error;
+ QDeclarativeExpressionPrivate::exceptionToError(tc.Message(), error);
+ reportScriptException(script, error);
}
-
- workerEngine->popContext();
} else {
qWarning().nospace() << "WorkerScript: Cannot find source file " << url.toString();
}
}
-void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script)
+void QDeclarativeWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script,
+ const QDeclarativeError &error)
{
- if (!script || !workerEngine->hasUncaughtException())
- return;
-
- QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(workerEngine, error);
- error.setUrl(script->source);
-
QDeclarativeWorkerScriptEnginePrivate *p = QDeclarativeWorkerScriptEnginePrivate::get(workerEngine);
QMutexLocker(&p->m_lock);
QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error));
}
-QVariant QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(const QScriptValue &value)
-{
- if (value.isBool()) {
- return QVariant(value.toBool());
- } else if (value.isString()) {
- return QVariant(value.toString());
- } else if (value.isNumber()) {
- return QVariant((qreal)value.toNumber());
- } else if (value.isDate()) {
- return QVariant(value.toDateTime());
-#ifndef QT_NO_REGEXP
- } else if (value.isRegExp()) {
- return QVariant(value.toRegExp());
-#endif
- } else if (value.isArray()) {
- QVariantList list;
-
- quint32 length = (quint32)value.property(QLatin1String("length")).toNumber();
-
- for (quint32 ii = 0; ii < length; ++ii) {
- QVariant v = scriptValueToVariant(value.property(ii));
- list << v;
- }
-
- return QVariant(list);
- } else if (value.isQObject()) {
- QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject());
- if (lm) {
- QDeclarativeListModelWorkerAgent *agent = lm->agent();
- if (agent) {
- QDeclarativeListModelWorkerAgent::VariantRef v(agent);
- return QVariant::fromValue(v);
- } else {
- return QVariant();
- }
- } else {
- // No other QObject's are allowed to be sent
- return QVariant();
- }
- } else if (value.isObject()) {
- QVariantHash hash;
-
- QScriptValueIterator iter(value);
-
- while (iter.hasNext()) {
- iter.next();
- hash.insert(iter.name(), scriptValueToVariant(iter.value()));
- }
-
- return QVariant(hash);
- }
-
- return QVariant();
-
-}
-
-QScriptValue QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(const QVariant &value, QScriptEngine *engine)
-{
- if (value.userType() == QVariant::Bool) {
- return QScriptValue(value.toBool());
- } else if (value.userType() == QVariant::String) {
- return QScriptValue(value.toString());
- } else if (value.userType() == QMetaType::QReal) {
- return QScriptValue(value.toReal());
- } else if (value.userType() == QVariant::DateTime) {
- return engine->newDate(value.toDateTime());
-#ifndef QT_NO_REGEXP
- } else if (value.userType() == QVariant::RegExp) {
- return engine->newRegExp(value.toRegExp());
-#endif
- } else if (value.userType() == qMetaTypeId<QDeclarativeListModelWorkerAgent::VariantRef>()) {
- QDeclarativeListModelWorkerAgent::VariantRef vr = qvariant_cast<QDeclarativeListModelWorkerAgent::VariantRef>(value);
- if (vr.a->scriptEngine() == 0)
- vr.a->setScriptEngine(engine);
- else if (vr.a->scriptEngine() != engine)
- return engine->nullValue();
- QScriptValue o = engine->newQObject(vr.a);
- o.setData(engine->newVariant(value)); // Keeps the agent ref so that it is cleaned up on gc
- return o;
- } else if (value.userType() == QMetaType::QVariantList) {
- QVariantList list = qvariant_cast<QVariantList>(value);
- QScriptValue rv = engine->newArray(list.count());
-
- for (quint32 ii = 0; ii < quint32(list.count()); ++ii)
- rv.setProperty(ii, variantToScriptValue(list.at(ii), engine));
-
- return rv;
- } else if (value.userType() == QMetaType::QVariantHash) {
-
- QVariantHash hash = qvariant_cast<QVariantHash>(value);
-
- QScriptValue rv = engine->newObject();
-
- for (QVariantHash::ConstIterator iter = hash.begin(); iter != hash.end(); ++iter)
- rv.setProperty(iter.key(), variantToScriptValue(iter.value(), engine));
-
- return rv;
- } else {
- return engine->nullValue();
- }
-}
-
-WorkerDataEvent::WorkerDataEvent(int workerId, const QVariant &data)
+WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data)
: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data)
{
}
return m_id;
}
-QVariant WorkerDataEvent::data() const
+QByteArray WorkerDataEvent::data() const
{
return m_data;
}
{
}
+QDeclarativeWorkerScriptEnginePrivate::WorkerScript::~WorkerScript()
+{
+ object.Dispose(); object.Clear();
+}
+
int QDeclarativeWorkerScriptEngine::registerWorkerScript(QDeclarativeWorkerScript *owner)
{
- QDeclarativeWorkerScriptEnginePrivate::WorkerScript *script = new QDeclarativeWorkerScriptEnginePrivate::WorkerScript;
+ typedef QDeclarativeWorkerScriptEnginePrivate::WorkerScript WorkerScript;
+ WorkerScript *script = new WorkerScript;
+
script->id = d->m_nextId++;
script->owner = owner;
QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url));
}
-void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QVariant &data)
+void QDeclarativeWorkerScriptEngine::sendMessage(int id, const QByteArray &data)
{
QCoreApplication::postEvent(d, new WorkerDataEvent(id, data));
}
{
d->m_lock.lock();
- d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::ScriptEngine(d);
+ v8::Isolate *isolate = v8::Isolate::New();
+ isolate->Enter();
+
+ d->workerEngine = new QDeclarativeWorkerScriptEnginePrivate::WorkerEngine(d);
+ d->workerEngine->init();
d->m_wait.wakeAll();
exec();
delete d->workerEngine; d->workerEngine = 0;
+
+ isolate->Exit();
+ isolate->Dispose();
}
of ListModel objects, any modifications by the other thread to an object
passed in \c message will not be reflected in the original object.
*/
-void QDeclarativeWorkerScript::sendMessage(const QScriptValue &message)
+void QDeclarativeWorkerScript::sendMessage(QDeclarativeV8Function *args)
{
if (!engine()) {
qWarning("QDeclarativeWorkerScript: Attempt to send message before WorkerScript establishment");
return;
}
- m_engine->sendMessage(m_scriptId, QDeclarativeWorkerScriptEnginePrivate::scriptValueToVariant(message));
+ v8::Handle<v8::Value> argument = v8::Undefined();
+ if (args->Length() != 0)
+ argument = (*args)[0];
+
+ m_engine->sendMessage(m_scriptId, QV8Worker::serialize(argument, args->engine()));
}
void QDeclarativeWorkerScript::classBegin()
if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) {
QDeclarativeEngine *engine = qmlEngine(this);
if (engine) {
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
WorkerDataEvent *workerEvent = static_cast<WorkerDataEvent *>(event);
- QScriptValue value =
- QDeclarativeWorkerScriptEnginePrivate::variantToScriptValue(workerEvent->data(), scriptEngine);
- emit message(value);
+ QV8Engine *v8engine = &QDeclarativeEnginePrivate::get(engine)->v8engine;
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(v8engine->context());
+ v8::Handle<v8::Value> value = QV8Worker::deserialize(workerEvent->data(), v8engine);
+ emit message(QDeclarativeV8Handle::fromHandle(value));
}
return true;
} else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) {
int registerWorkerScript(QDeclarativeWorkerScript *);
void removeWorkerScript(int);
void executeUrl(int, const QUrl &);
- void sendMessage(int, const QVariant &);
+ void sendMessage(int, const QByteArray &);
protected:
virtual void run();
QDeclarativeWorkerScriptEnginePrivate *d;
};
+class QDeclarativeV8Function;
+class QDeclarativeV8Handle;
class Q_AUTOTEST_EXPORT QDeclarativeWorkerScript : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
void setSource(const QUrl &);
public slots:
- void sendMessage(const QScriptValue &);
+ void sendMessage(QDeclarativeV8Function*);
signals:
void sourceChanged();
- void message(const QScriptValue &messageObject);
+ void message(const QDeclarativeV8Handle &messageObject);
protected:
virtual void classBegin();
#include "private/qdeclarativexmlhttprequest_p.h"
+#include <private/qv8engine_p.h>
+
#include "qdeclarativeengine.h"
#include "private/qdeclarativeengine_p.h"
#include "private/qdeclarativerefcount_p.h"
#define VALIDATION_ERR 16
#define TYPE_MISMATCH_ERR 17
-#define THROW_DOM(error, desc) \
-{ \
- QScriptValue errorValue = context->throwError(QLatin1String(desc)); \
- errorValue.setProperty(QLatin1String("code"), error); \
- return errorValue; \
-}
+#define V8THROW_DOM(error, string) { \
+ v8::Local<v8::Value> v = v8::Exception::Error(v8::String::New(string)); \
+ v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
+ v8::ThrowException(v); \
+ return v8::Handle<v8::Value>(); \
+}
-#define THROW_SYNTAX(desc) \
- return context->throwError(QScriptContext::SyntaxError, QLatin1String(desc));
-#define THROW_REFERENCE(desc) \
- return context->throwError(QScriptContext::ReferenceError, QLatin1String(desc));
+#define V8THROW_REFERENCE(string) { \
+ v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
#define D(arg) (arg)->release()
#define A(arg) (arg)->addref()
DEFINE_BOOL_CONFIG_OPTION(xhrDump, QML_XHR_DUMP);
+struct QDeclarativeXMLHttpRequestData {
+ QDeclarativeXMLHttpRequestData();
+ ~QDeclarativeXMLHttpRequestData();
+
+ v8::Persistent<v8::Function> nodeFunction;
+
+ v8::Persistent<v8::Object> namedNodeMapPrototype;
+ v8::Persistent<v8::Object> nodeListPrototype;
+ v8::Persistent<v8::Object> nodePrototype;
+ v8::Persistent<v8::Object> elementPrototype;
+ v8::Persistent<v8::Object> attrPrototype;
+ v8::Persistent<v8::Object> characterDataPrototype;
+ v8::Persistent<v8::Object> textPrototype;
+ v8::Persistent<v8::Object> cdataPrototype;
+ v8::Persistent<v8::Object> documentPrototype;
+
+ v8::Local<v8::Object> newNode();
+};
+
+static inline QDeclarativeXMLHttpRequestData *xhrdata(QV8Engine *engine)
+{
+ return (QDeclarativeXMLHttpRequestData *)engine->xmlHttpRequestData();
+}
+
+QDeclarativeXMLHttpRequestData::QDeclarativeXMLHttpRequestData()
+{
+}
+
+QDeclarativeXMLHttpRequestData::~QDeclarativeXMLHttpRequestData()
+{
+ nodeFunction.Dispose(); nodeFunction.Clear();
+ namedNodeMapPrototype.Dispose(); namedNodeMapPrototype.Clear();
+ nodeListPrototype.Dispose(); nodeListPrototype.Clear();
+ nodePrototype.Dispose(); nodePrototype.Clear();
+ elementPrototype.Dispose(); elementPrototype.Clear();
+ attrPrototype.Dispose(); attrPrototype.Clear();
+ characterDataPrototype.Dispose(); characterDataPrototype.Clear();
+ textPrototype.Dispose(); textPrototype.Clear();
+ cdataPrototype.Dispose(); cdataPrototype.Clear();
+ documentPrototype.Dispose(); documentPrototype.Clear();
+}
+
+v8::Local<v8::Object> QDeclarativeXMLHttpRequestData::newNode()
+{
+ if (nodeFunction.IsEmpty()) {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ nodeFunction = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+
+ return nodeFunction->NewInstance();
+}
+
namespace {
class DocumentImpl;
{
public:
// JS API
- static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
+ static v8::Handle<v8::Value> named(v8::Local<v8::String> property, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *);
-
- NamedNodeMap();
- NamedNodeMap(const NamedNodeMap &);
- ~NamedNodeMap();
- bool isNull();
-
- NodeImpl *d;
- QList<NodeImpl *> *list;
-private:
- NamedNodeMap &operator=(const NamedNodeMap &);
-};
-
-class NamedNodeMapClass : public QScriptClass
-{
-public:
- NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {}
-
- virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
- virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *, QList<NodeImpl *> *);
};
class NodeList
{
public:
// JS API
- static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue create(QScriptEngine *, NodeImpl *);
-
- NodeList();
- NodeList(const NodeList &);
- ~NodeList();
- bool isNull();
-
- NodeImpl *d;
-private:
- NodeList &operator=(const NodeList &);
-};
-
-class NodeListClass : public QScriptClass
-{
-public:
- NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {}
- virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
- virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
};
class Node
{
public:
// JS API
- static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine);
-
- static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine);
-
- //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine);
- //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> nodeName(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nodeValue(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nodeType(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ static v8::Handle<v8::Value> parentNode(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> childNodes(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> firstChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> lastChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> previousSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> nextSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> attributes(v8::Local<v8::String>, const v8::AccessorInfo& args);
+
+ //static v8::Handle<v8::Value> ownerDocument(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> namespaceURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> prefix(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> localName(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> baseURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ //static v8::Handle<v8::Value> textContent(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue create(QScriptEngine *, NodeImpl *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
Node();
Node(const Node &o);
{
public:
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class Attr : public Node
{
public:
// JS API
- static QScriptValue name(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue specified(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue value(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue ownerElement(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue schemaTypeInfo(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue isId(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> name(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> specified(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> value(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> ownerElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> schemaTypeInfo(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> isId(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class CharacterData : public Node
{
public:
// JS API
- static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class Text : public CharacterData
{
public:
// JS API
- static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> wholeText(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class CDATA : public Text
{
public:
// C++ API
- static QScriptValue prototype(QScriptEngine *);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
};
class Document : public Node
{
public:
// JS API
- static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine);
- static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine);
+ static v8::Handle<v8::Value> xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static v8::Handle<v8::Value> documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
// C++ API
- static QScriptValue prototype(QScriptEngine *);
- static QScriptValue load(QScriptEngine *engine, const QByteArray &data);
+ static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static v8::Handle<v8::Value> load(QV8Engine *engine, const QByteArray &data);
};
}
+class QDeclarativeDOMNodeResource : public QV8ObjectResource, public Node
+{
+ V8_RESOURCE_TYPE(DOMNodeType);
+public:
+ QDeclarativeDOMNodeResource(QV8Engine *e);
+
+ QList<NodeImpl *> *list; // Only used in NamedNodeMap
+};
+
+QDeclarativeDOMNodeResource::QDeclarativeDOMNodeResource(QV8Engine *e)
+: QV8ObjectResource(e), list(0)
+{
+}
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Node)
D(document);
}
-QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nodeName(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- switch (node.d->type) {
+ switch (r->d->type) {
case NodeImpl::Document:
- return QScriptValue(QLatin1String("#document"));
+ return v8::String::New("#document");
case NodeImpl::CDATA:
- return QScriptValue(QLatin1String("#cdata-section"));
+ return v8::String::New("#cdata-section");
case NodeImpl::Text:
- return QScriptValue(QLatin1String("#text"));
+ return v8::String::New("#text");
default:
- return QScriptValue(node.d->name);
+ return engine->toString(r->d->name);
}
}
-QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nodeValue(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->type == NodeImpl::Document ||
- node.d->type == NodeImpl::DocumentFragment ||
- node.d->type == NodeImpl::DocumentType ||
- node.d->type == NodeImpl::Element ||
- node.d->type == NodeImpl::Entity ||
- node.d->type == NodeImpl::EntityReference ||
- node.d->type == NodeImpl::Notation)
- return engine->nullValue();
+ if (r->d->type == NodeImpl::Document ||
+ r->d->type == NodeImpl::DocumentFragment ||
+ r->d->type == NodeImpl::DocumentType ||
+ r->d->type == NodeImpl::Element ||
+ r->d->type == NodeImpl::Entity ||
+ r->d->type == NodeImpl::EntityReference ||
+ r->d->type == NodeImpl::Notation)
+ return v8::Null();
- return QScriptValue(node.d->data);
+ return engine->toString(r->d->data);
}
-QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nodeType(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
- return QScriptValue(node.d->type);
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ return v8::Integer::New(r->d->type);
}
-QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::parentNode(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->parent) return Node::create(engine, node.d->parent);
- else return engine->nullValue();
+ if (r->d->parent) return Node::create(engine, r->d->parent);
+ else return v8::Null();
}
-QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::childNodes(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return NodeList::create(engine, node.d);
+ return NodeList::create(engine, r->d);
}
-QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::firstChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->children.isEmpty()) return engine->nullValue();
- else return Node::create(engine, node.d->children.first());
+ if (r->d->children.isEmpty()) return v8::Null();
+ else return Node::create(engine, r->d->children.first());
}
-QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::lastChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->children.isEmpty()) return engine->nullValue();
- else return Node::create(engine, node.d->children.last());
+ if (r->d->children.isEmpty()) return v8::Null();
+ else return Node::create(engine, r->d->children.last());
}
-QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::previousSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (!node.d->parent) return engine->nullValue();
+ if (!r->d->parent) return v8::Null();
- for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
- if (node.d->parent->children.at(ii) == node.d) {
- if (ii == 0) return engine->nullValue();
- else return Node::create(engine, node.d->parent->children.at(ii - 1));
+ for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
+ if (r->d->parent->children.at(ii) == r->d) {
+ if (ii == 0) return v8::Null();
+ else return Node::create(engine, r->d->parent->children.at(ii - 1));
}
}
- return engine->nullValue();
+ return v8::Null();
}
-QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::nextSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (!node.d->parent) return engine->nullValue();
+ if (!r->d->parent) return v8::Null();
- for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
- if (node.d->parent->children.at(ii) == node.d) {
- if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue();
- else return Node::create(engine, node.d->parent->children.at(ii + 1));
+ for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
+ if (r->d->parent->children.at(ii) == r->d) {
+ if ((ii + 1) == r->d->parent->children.count()) return v8::Null();
+ else return Node::create(engine, r->d->parent->children.at(ii + 1));
}
}
- return engine->nullValue();
+ return v8::Null();
}
-QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Node::attributes(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- if (node.d->type != NodeImpl::Element)
- return engine->nullValue();
+ if (r->d->type != NodeImpl::Element)
+ return v8::Null();
else
- return NamedNodeMap::create(engine, node.d, &node.d->attributes);
-}
-
-QScriptValue Node::prototype(QScriptEngine *engine)
-{
- QScriptValue proto = engine->newObject();
-
- proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return NamedNodeMap::create(engine, r->d, &r->d->attributes);
+}
+
+v8::Handle<v8::Object> Node::prototype(QV8Engine *engine)
+{
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->nodePrototype.IsEmpty()) {
+ d->nodePrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+ d->nodePrototype->SetAccessor(v8::String::New("nodeName"), nodeName,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nodeValue"), nodeValue,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nodeType"), nodeType,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("parentNode"), parentNode,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("childNodes"), childNodes,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("firstChild"), firstChild,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("lastChild"), lastChild,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("previousSibling"), previousSibling,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("nextSibling"), nextSibling,
+ 0, v8::External::Wrap(engine));
+ d->nodePrototype->SetAccessor(v8::String::New("attributes"), attributes,
+ 0, v8::External::Wrap(engine));
+ // XXX freeze
+ }
+ return d->nodePrototype;
}
-QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
+v8::Handle<v8::Value> Node::create(QV8Engine *engine, NodeImpl *data)
{
- QScriptValue instance = engine->newObject();
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
switch (data->type) {
case NodeImpl::Attr:
- instance.setPrototype(Attr::prototype(engine));
+ instance->SetPrototype(Attr::prototype(engine));
break;
case NodeImpl::Comment:
case NodeImpl::Document:
case NodeImpl::EntityReference:
case NodeImpl::Notation:
case NodeImpl::ProcessingInstruction:
- return QScriptValue();
+ return v8::Undefined();
case NodeImpl::CDATA:
- instance.setPrototype(CDATA::prototype(engine));
+ instance->SetPrototype(CDATA::prototype(engine));
break;
case NodeImpl::Text:
- instance.setPrototype(Text::prototype(engine));
+ instance->SetPrototype(Text::prototype(engine));
break;
case NodeImpl::Element:
- instance.setPrototype(Element::prototype(engine));
+ instance->SetPrototype(Element::prototype(engine));
break;
}
- Node node;
- node.d = data;
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = data;
if (data) A(data);
+ instance->SetExternalResource(r);
- return engine->newVariant(instance, QVariant::fromValue(node));
-}
-
-QScriptValue Element::prototype(QScriptEngine *engine)
-{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
-
- proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
-}
-
-QScriptValue Attr::prototype(QScriptEngine *engine)
-{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
-
- proto.setProperty(QLatin1String("name"), engine->newFunction(name), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("value"), engine->newFunction(value), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("ownerElement"), engine->newFunction(ownerElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return instance;
}
-QScriptValue Attr::name(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Object> Element::prototype(QV8Engine *engine)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
-
- return QScriptValue(node.d->name);
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->elementPrototype.IsEmpty()) {
+ d->elementPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+ d->elementPrototype->SetPrototype(Node::prototype(engine));
+ d->elementPrototype->SetAccessor(v8::String::New("tagName"), nodeName,
+ 0, v8::External::Wrap(engine));
+ // XXX freeze
+ }
+ return d->elementPrototype;
+}
+
+v8::Handle<v8::Object> Attr::prototype(QV8Engine *engine)
+{
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->attrPrototype.IsEmpty()) {
+ d->attrPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+ d->attrPrototype->SetPrototype(Node::prototype(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("name"), name,
+ 0, v8::External::Wrap(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("value"), value,
+ 0, v8::External::Wrap(engine));
+ d->attrPrototype->SetAccessor(v8::String::New("ownerElement"), ownerElement,
+ 0, v8::External::Wrap(engine));
+ // XXX freeze
+ }
+ return d->attrPrototype;
}
-QScriptValue Attr::value(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Attr::name(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(node.d->data);
+ return engine->toString(r->d->name);
}
-QScriptValue Attr::ownerElement(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Attr::value(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return Node::create(engine, node.d->parent);
+ return engine->toString(r->d->data);
}
-QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Attr::ownerElement(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(node.d->data.length());
+ return Node::create(engine, r->d->parent);
}
-QScriptValue CharacterData::prototype(QScriptEngine *engine)
+v8::Handle<v8::Value> CharacterData::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return v8::Integer::New(r->d->data.length());
}
-QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Object> CharacterData::prototype(QV8Engine *engine)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
-
- return node.d->data.trimmed().isEmpty();
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->characterDataPrototype.IsEmpty()) {
+ d->characterDataPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+ d->characterDataPrototype->SetPrototype(Node::prototype(engine));
+ d->characterDataPrototype->SetAccessor(v8::String::New("data"), nodeValue,
+ 0, v8::External::Wrap(engine));
+ d->characterDataPrototype->SetAccessor(v8::String::New("length"), length,
+ 0, v8::External::Wrap(engine));
+ // XXX freeze
+ }
+ return d->characterDataPrototype;
}
-QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Text::isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- Node node = qscriptvalue_cast<Node>(context->thisObject());
- if (node.isNull()) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return node.d->data;
+ return v8::Boolean::New(r->d->data.trimmed().isEmpty());
}
-QScriptValue Text::prototype(QScriptEngine *engine)
+v8::Handle<v8::Value> Text::wholeText(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(CharacterData::prototype(engine));
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return engine->toString(r->d->data);
}
-QScriptValue CDATA::prototype(QScriptEngine *engine)
+v8::Handle<v8::Object> Text::prototype(QV8Engine *engine)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Text::prototype(engine));
- return proto;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->textPrototype.IsEmpty()) {
+ d->textPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+ d->textPrototype->SetPrototype(CharacterData::prototype(engine));
+ d->textPrototype->SetAccessor(v8::String::New("isElementContentWhitespace"), isElementContentWhitespace,
+ 0, v8::External::Wrap(engine));
+ d->textPrototype->SetAccessor(v8::String::New("wholeText"), wholeText,
+ 0, v8::External::Wrap(engine));
+ // XXX freeze
+ }
+ return d->textPrototype;
}
-QScriptValue Document::prototype(QScriptEngine *engine)
+v8::Handle<v8::Object> CDATA::prototype(QV8Engine *engine)
{
- QScriptValue proto = engine->newObject();
- proto.setPrototype(Node::prototype(engine));
-
- proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
- proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->cdataPrototype.IsEmpty()) {
+ d->cdataPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+ d->cdataPrototype->SetPrototype(Text::prototype(engine));
+ // XXX freeze
+ }
+ return d->cdataPrototype;
+}
+
+v8::Handle<v8::Object> Document::prototype(QV8Engine *engine)
+{
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->documentPrototype.IsEmpty()) {
+ d->documentPrototype = v8::Persistent<v8::Object>::New(v8::Object::New());
+ d->documentPrototype->SetPrototype(Node::prototype(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlVersion"), xmlVersion,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlEncoding"), xmlEncoding,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("xmlStandalone"), xmlStandalone,
+ 0, v8::External::Wrap(engine));
+ d->documentPrototype->SetAccessor(v8::String::New("documentElement"), documentElement,
+ 0, v8::External::Wrap(engine));
+ // XXX freeze
+ }
+ return d->documentPrototype;
}
-QScriptValue Document::load(QScriptEngine *engine, const QByteArray &data)
+v8::Handle<v8::Value> Document::load(QV8Engine *engine, const QByteArray &data)
{
Q_ASSERT(engine);
if (!document || reader.hasError()) {
if (document) D(document);
- return engine->nullValue();
+ return v8::Null();
}
- QScriptValue instance = engine->newObject();
- instance.setPrototype(Document::prototype(engine));
- Node documentNode;
- documentNode.d = document;
- return engine->newVariant(instance, QVariant::fromValue(documentNode));
+ v8::Local<v8::Object> instance = xhrdata(engine)->newNode();
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = document;
+ instance->SetExternalResource(r);
+ instance->SetPrototype(Document::prototype(engine));
+ return instance;
}
Node::Node()
return d == 0;
}
-QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine)
-{
- NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data());
- if (map.isNull()) return engine->undefinedValue();
-
- return QScriptValue(map.list->count());
-}
-
-QScriptValue NamedNodeMap::prototype(QScriptEngine *engine)
+v8::Handle<v8::Value> NamedNodeMap::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
{
- QScriptValue proto = engine->newObject();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ return v8::Integer::New(r->list->count());
}
-QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list)
+v8::Handle<v8::Value> NamedNodeMap::indexed(uint32_t index, const v8::AccessorInfo& args)
{
- QScriptValue instance = engine->newObject();
- instance.setPrototype(NamedNodeMap::prototype(engine));
-
- NamedNodeMap map;
- map.d = data;
- map.list = list;
- if (data) A(data);
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || !r->list) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- instance.setData(engine->newVariant(QVariant::fromValue(map)));
-
- if (!QDeclarativeScriptEngine::get(engine)->namedNodeMapClass)
- QDeclarativeScriptEngine::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine);
-
- instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->namedNodeMapClass);
-
- return instance;
-}
-
-NamedNodeMap::NamedNodeMap()
-: d(0), list(0)
-{
-}
-
-NamedNodeMap::NamedNodeMap(const NamedNodeMap &o)
-: d(o.d), list(o.list)
-{
- if (d) A(d);
-}
-
-NamedNodeMap::~NamedNodeMap()
-{
- if (d) D(d);
+ if (index < r->list->count()) {
+ return Node::create(engine, r->list->at(index));
+ } else {
+ return v8::Undefined();
+ }
}
-bool NamedNodeMap::isNull()
+v8::Handle<v8::Value> NamedNodeMap::named(v8::Local<v8::String> property, const v8::AccessorInfo& args)
{
- return d == 0;
-}
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || !r->list) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
-QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine)
-{
- NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
- if (list.isNull()) return engine->undefinedValue();
+ QString str = engine->toString(property);
+ for (int ii = 0; ii < r->list->count(); ++ii) {
+ if (r->list->at(ii)->name == str) {
+ return Node::create(engine, r->list->at(ii));
+ }
+ }
- return QScriptValue(list.d->children.count());
+ return v8::Undefined();
}
-QScriptValue NodeList::prototype(QScriptEngine *engine)
+v8::Handle<v8::Object> NamedNodeMap::prototype(QV8Engine *engine)
{
- QScriptValue proto = engine->newObject();
-
- proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
-
- return proto;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->namedNodeMapPrototype.IsEmpty()) {
+ v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
+ ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
+ ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
+ ot->SetFallbackPropertyHandler(named, 0, 0, 0, 0, v8::External::Wrap(engine));
+ d->namedNodeMapPrototype = v8::Persistent<v8::Object>::New(ot->NewInstance());
+ // XXX freeze
+ }
+ return d->namedNodeMapPrototype;
}
-QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data)
+v8::Handle<v8::Value> NamedNodeMap::create(QV8Engine *engine, NodeImpl *data, QList<NodeImpl *> *list)
{
- QScriptValue instance = engine->newObject();
- instance.setPrototype(NodeList::prototype(engine));
-
- NodeList list;
- list.d = data;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
+ instance->SetPrototype(NamedNodeMap::prototype(engine));
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = data;
+ r->list = list;
if (data) A(data);
-
- instance.setData(engine->newVariant(QVariant::fromValue(list)));
-
- if (!QDeclarativeScriptEngine::get(engine)->nodeListClass)
- QDeclarativeScriptEngine::get(engine)->nodeListClass= new NodeListClass(engine);
-
- instance.setScriptClass(QDeclarativeScriptEngine::get(engine)->nodeListClass);
-
+ instance->SetExternalResource(r);
return instance;
}
-NodeList::NodeList()
-: d(0)
-{
-}
-
-NodeList::NodeList(const NodeList &o)
-: d(o.d)
-{
- if (d) A(d);
-}
-
-NodeList::~NodeList()
-{
- if (d) D(d);
-}
-
-bool NodeList::isNull()
+v8::Handle<v8::Value> NodeList::indexed(uint32_t index, const v8::AccessorInfo& args)
{
- return d == 0;
-}
-
-NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
-{
- if (!(flags & HandlesReadAccess))
- return 0;
-
- NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
- Q_ASSERT(!map.isNull());
-
- bool ok = false;
- QString nameString = name.toString();
- uint index = nameString.toUInt(&ok);
- if (ok) {
- if ((uint)map.list->count() <= index)
- return 0;
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- *id = index;
- return HandlesReadAccess;
+ if (index < r->d->children.count()) {
+ return Node::create(engine, r->d->children.at(index));
} else {
- for (int ii = 0; ii < map.list->count(); ++ii) {
- if (map.list->at(ii) && map.list->at(ii)->name == nameString) {
- *id = ii;
- return HandlesReadAccess;
- }
- }
+ // XXX RangeError exception?
+ return v8::Undefined();
}
-
- return 0;
}
-QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id)
+v8::Handle<v8::Value> NodeList::length(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
- return Node::create(engine(), map.list->at(id));
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
+
+ return v8::Integer::New(r->d->children.count());
}
-NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+v8::Handle<v8::Object> NodeList::prototype(QV8Engine *engine)
{
- if (!(flags & HandlesReadAccess))
- return 0;
-
- bool ok = false;
- uint index = name.toString().toUInt(&ok);
- if (!ok)
- return 0;
-
- NodeList list = qscriptvalue_cast<NodeList>(object.data());
- if (list.isNull() || (uint)list.d->children.count() <= index)
- return 0; // ### I think we're meant to raise an exception
-
- *id = index;
- return HandlesReadAccess;
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ if (d->nodeListPrototype.IsEmpty()) {
+ v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
+ ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::Wrap(engine));
+ ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::Wrap(engine));
+ d->nodeListPrototype = v8::Persistent<v8::Object>::New(ot->NewInstance());
+ // XXX freeze
+ }
+ return d->nodeListPrototype;
}
-QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id)
+v8::Handle<v8::Value> NodeList::create(QV8Engine *engine, NodeImpl *data)
{
- NodeList list = qscriptvalue_cast<NodeList>(object.data());
- return Node::create(engine(), list.d->children.at(id));
+ QDeclarativeXMLHttpRequestData *d = xhrdata(engine);
+ v8::Local<v8::Object> instance = d->newNode();
+ instance->SetPrototype(NodeList::prototype(engine));
+ QDeclarativeDOMNodeResource *r = new QDeclarativeDOMNodeResource(engine);
+ r->d = data;
+ if (data) A(data);
+ instance->SetExternalResource(r);
+ return instance;
}
-QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return Node::create(engine, static_cast<DocumentImpl *>(document.d)->root);
+ return Node::create(engine, static_cast<DocumentImpl *>(r->d)->root);
}
-QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(static_cast<DocumentImpl *>(document.d)->isStandalone);
+ return v8::Boolean::New(static_cast<DocumentImpl *>(r->d)->isStandalone);
}
-QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(static_cast<DocumentImpl *>(document.d)->version);
+ return engine->toString(static_cast<DocumentImpl *>(r->d)->version);
}
-QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine)
+v8::Handle<v8::Value> Document::xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args)
{
- Node document = qscriptvalue_cast<Node>(context->thisObject());
- if (document.isNull() || document.d->type != NodeImpl::Document) return engine->undefinedValue();
+ QDeclarativeDOMNodeResource *r = v8_resource_cast<QDeclarativeDOMNodeResource>(args.This());
+ if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
+ QV8Engine *engine = V8ENGINE();
- return QScriptValue(static_cast<DocumentImpl *>(document.d)->encoding);
+ return engine->toString(static_cast<DocumentImpl *>(r->d)->encoding);
}
-class QDeclarativeXMLHttpRequest : public QObject
+class QDeclarativeXMLHttpRequest : public QObject, public QV8ObjectResource
{
Q_OBJECT
+V8_RESOURCE_TYPE(XMLHttpRequestType)
public:
enum State { Unsent = 0,
Opened = 1, HeadersReceived = 2,
Loading = 3, Done = 4 };
- QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager);
+ QDeclarativeXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager);
virtual ~QDeclarativeXMLHttpRequest();
bool sendFlag() const;
int replyStatus() const;
QString replyStatusText() const;
- QScriptValue open(QScriptValue *me, const QString &, const QUrl &);
+ v8::Handle<v8::Value> open(v8::Handle<v8::Object> me, const QString &, const QUrl &);
+ v8::Handle<v8::Value> send(v8::Handle<v8::Object> me, const QByteArray &);
+ v8::Handle<v8::Value> abort(v8::Handle<v8::Object> me);
void addHeader(const QString &, const QString &);
QString header(const QString &name);
QString headers();
- QScriptValue send(QScriptValue *me, const QByteArray &);
- QScriptValue abort(QScriptValue *me);
+
QString responseBody();
const QByteArray & rawResponseBody() const;
#endif
void readEncoding();
- QScriptValue m_me; // Set to the data object while a send() is ongoing (to access the callback)
+ v8::Handle<v8::Object> getMe() const;
+ void setMe(v8::Handle<v8::Object> me);
+ v8::Persistent<v8::Object> m_me;
- QScriptValue dispatchCallback(QScriptValue *me);
- void printError(const QScriptValue&);
+ void dispatchCallback(v8::Handle<v8::Object> me);
+ void printError(v8::Handle<v8::Message>);
int m_status;
QString m_statusText;
QNetworkAccessManager *networkAccessManager() { return m_nam; }
};
-QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QNetworkAccessManager *manager)
-: m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
+QDeclarativeXMLHttpRequest::QDeclarativeXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager)
+: QV8ObjectResource(engine), m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager)
{
}
return m_statusText;
}
-QScriptValue QDeclarativeXMLHttpRequest::open(QScriptValue *me, const QString &method, const QUrl &url)
+v8::Handle<v8::Value> QDeclarativeXMLHttpRequest::open(v8::Handle<v8::Object> me, const QString &method,
+ const QUrl &url)
{
destroyNetwork();
m_sendFlag = false;
m_method = method;
m_url = url;
m_state = Opened;
- return dispatchCallback(me);
+ dispatchCallback(me);
+ return v8::Undefined();
}
void QDeclarativeXMLHttpRequest::addHeader(const QString &name, const QString &value)
this, SLOT(finished()));
}
-QScriptValue QDeclarativeXMLHttpRequest::send(QScriptValue *me, const QByteArray &data)
+v8::Handle<v8::Value> QDeclarativeXMLHttpRequest::send(v8::Handle<v8::Object> me, const QByteArray &data)
{
m_errorFlag = false;
m_sendFlag = true;
m_redirectCount = 0;
m_data = data;
- m_me = *me;
+
+ setMe(me);
requestFromUrl(m_url);
- return QScriptValue();
+ return v8::Undefined();
}
-QScriptValue QDeclarativeXMLHttpRequest::abort(QScriptValue *me)
+v8::Handle<v8::Value> QDeclarativeXMLHttpRequest::abort(v8::Handle<v8::Object> me)
{
destroyNetwork();
m_responseEntityBody = QByteArray();
m_state = Done;
m_sendFlag = false;
- QScriptValue cbv = dispatchCallback(me);
- if (cbv.isError()) return cbv;
+ dispatchCallback(me);
}
m_state = Unsent;
- return QScriptValue();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Object> QDeclarativeXMLHttpRequest::getMe() const
+{
+ return m_me;
+}
+
+void QDeclarativeXMLHttpRequest::setMe(v8::Handle<v8::Object> me)
+{
+ m_me.Dispose();
+ m_me = v8::Persistent<v8::Object>();
+
+ if (!me.IsEmpty())
+ m_me = v8::Persistent<v8::Object>::New(me);
}
void QDeclarativeXMLHttpRequest::downloadProgress(qint64 bytes)
{
+ v8::HandleScope handle_scope;
+
Q_UNUSED(bytes)
m_status =
m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
bool wasEmpty = m_responseEntityBody.isEmpty();
m_responseEntityBody.append(m_network->readAll());
if (wasEmpty && !m_responseEntityBody.isEmpty()) {
m_state = Loading;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
}
void QDeclarativeXMLHttpRequest::error(QNetworkReply::NetworkError error)
{
+ v8::HandleScope handle_scope;
+
Q_UNUSED(error)
m_status =
m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
error == QNetworkReply::AuthenticationRequiredError ||
error == QNetworkReply::ContentReSendError) {
m_state = Loading;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
} else {
m_errorFlag = true;
}
m_state = Done;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
void QDeclarativeXMLHttpRequest::finished()
{
+ v8::HandleScope handle_scope;
+
m_redirectCount++;
if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
m_responseEntityBody.append(m_network->readAll());
readEncoding();
destroyNetwork();
if (m_state < Loading) {
m_state = Loading;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
}
m_state = Done;
- QScriptValue cbv = dispatchCallback(&m_me);
- if (cbv.isError()) printError(cbv);
- m_me = QScriptValue();
+ v8::TryCatch tc;
+ dispatchCallback(m_me);
+ if (tc.HasCaught()) printError(tc.Message());
+
+ setMe(v8::Handle<v8::Object>());
}
return m_responseEntityBody;
}
-QScriptValue QDeclarativeXMLHttpRequest::dispatchCallback(QScriptValue *me)
+// Requires a TryCatch scope
+void QDeclarativeXMLHttpRequest::dispatchCallback(v8::Handle<v8::Object> me)
{
- QScriptValue v = me->property(QLatin1String("callback"));
- return v.call();
+ v8::Local<v8::Value> callback = me->Get(v8::String::New("onreadystatechange"));
+ if (callback->IsFunction()) {
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
+
+ f->Call(me, 0, 0);
+ }
}
-void QDeclarativeXMLHttpRequest::printError(const QScriptValue& sv)
+// Must have a handle scope
+void QDeclarativeXMLHttpRequest::printError(v8::Handle<v8::Message> message)
{
+ v8::Context::Scope scope(engine->context());
+
QDeclarativeError error;
- QDeclarativeExpressionPrivate::exceptionToError(sv.engine(), error);
- QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(sv.engine()), error);
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ QDeclarativeEnginePrivate::warning(QDeclarativeEnginePrivate::get(engine->engine()), error);
}
void QDeclarativeXMLHttpRequest::destroyNetwork()
}
// XMLHttpRequest methods
-static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_open(const v8::Arguments &args)
{
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (context->argumentCount() < 2 || context->argumentCount() > 5)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ if (args.Length() < 2 || args.Length() > 5)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+
+ QV8Engine *engine = r->engine;
// Argument 0 - Method
- QString method = context->argument(0).toString().toUpper();
+ QString method = engine->toString(args[0]).toUpper();
if (method != QLatin1String("GET") &&
method != QLatin1String("PUT") &&
method != QLatin1String("HEAD") &&
method != QLatin1String("POST"))
- THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type");
-
+ V8THROW_DOM(SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
- QUrl url = QUrl::fromEncoded(context->argument(1).toString().toUtf8());
+ QUrl url = QUrl::fromEncoded(engine->toString(args[1]).toUtf8());
- if (url.isRelative()) {
- url = QDeclarativeScriptEngine::get(engine)->resolvedUrl(context,url);
- }
+ if (url.isRelative())
+ url = engine->callingContext()->resolvedUrl(url);
// Argument 2 - async (optional)
- if (context->argumentCount() > 2 && !context->argument(2).toBoolean())
- THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
-
+ if (args.Length() > 2 && !args[2]->BooleanValue())
+ V8THROW_DOM(NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
// Argument 3/4 - user/pass (optional)
QString username, password;
- if (context->argumentCount() > 3)
- username = context->argument(3).toString();
- if (context->argumentCount() > 4)
- password = context->argument(4).toString();
-
+ if (args.Length() > 3)
+ username = engine->toString(args[3]);
+ if (args.Length() > 4)
+ password = engine->toString(args[4]);
// Clear the fragment (if any)
url.setFragment(QString());
+
// Set username/password
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return request->open(&dataObject, method, url);
+ return r->open(args.This(), method, url);
}
-static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_setRequestHeader(const v8::Arguments &args)
{
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
-
- if (context->argumentCount() != 2)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ if (args.Length() != 2)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
- if (request->readyState() != QDeclarativeXMLHttpRequest::Opened ||
- request->sendFlag())
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Opened || r->sendFlag())
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ QV8Engine *engine = r->engine;
- QString name = context->argument(0).toString();
- QString value = context->argument(1).toString();
+ QString name = engine->toString(args[0]);
+ QString value = engine->toString(args[1]);
// ### Check that name and value are well formed
nameUpper == QLatin1String("VIA") ||
nameUpper.startsWith(QLatin1String("PROXY-")) ||
nameUpper.startsWith(QLatin1String("SEC-")))
- return engine->undefinedValue();
+ return v8::Undefined();
- request->addHeader(nameUpper, value);
+ r->addHeader(nameUpper, value);
- return engine->undefinedValue();
+ return v8::Undefined();
}
-static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngine *)
+static v8::Handle<v8::Value> qmlxmlhttprequest_send(const v8::Arguments &args)
{
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (request->readyState() != QDeclarativeXMLHttpRequest::Opened)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ QV8Engine *engine = r->engine;
- if (request->sendFlag())
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Opened ||
+ r->sendFlag())
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
QByteArray data;
- if (context->argumentCount() > 0)
- data = context->argument(0).toString().toUtf8();
+ if (args.Length() > 0)
+ data = engine->toString(args[0]).toUtf8();
- return request->send(&dataObject, data);
+ return r->send(args.This(), data);
}
-static QScriptValue qmlxmlhttprequest_abort(QScriptContext *context, QScriptEngine *)
+static v8::Handle<v8::Value> qmlxmlhttprequest_abort(const v8::Arguments &args)
{
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- return request->abort(&dataObject);
+ return r->abort(args.This());
}
-static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_getResponseHeader(const v8::Arguments &args)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (context->argumentCount() != 1)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ QV8Engine *engine = r->engine;
- if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done &&
- request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (args.Length() != 1)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
- QString headerName = context->argument(0).toString();
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done &&
+ r->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
- return QScriptValue(request->header(headerName));
+ return engine->toString(r->header(engine->toString(args[0])));
}
-static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_getAllResponseHeaders(const v8::Arguments &args)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(args.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
- if (context->argumentCount() != 0)
- THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
+ if (args.Length() != 0)
+ V8THROW_DOM(SYNTAX_ERR, "Incorrect argument count");
- if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done &&
- request->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done &&
+ r->readyState() != QDeclarativeXMLHttpRequest::HeadersReceived)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
- return QScriptValue(request->headers());
+ return engine->toString(r->headers());
}
// XMLHttpRequest properties
-static QScriptValue qmlxmlhttprequest_readyState(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_readyState(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- return QScriptValue(request->readyState());
+ return v8::Integer::NewFromUnsigned(r->readyState());
}
-static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_status(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
- request->readyState() == QDeclarativeXMLHttpRequest::Opened)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ if (r->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+ r->readyState() == QDeclarativeXMLHttpRequest::Opened)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
- if (request->errorFlag())
- return QScriptValue(0);
+ if (r->errorFlag())
+ return v8::Integer::New(0);
else
- return QScriptValue(request->replyStatus());
+ return v8::Integer::New(r->replyStatus());
}
-static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_statusText(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (request->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
- request->readyState() == QDeclarativeXMLHttpRequest::Opened)
- THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+ QV8Engine *engine = r->engine;
- if (request->errorFlag())
- return QScriptValue(0);
+ if (r->readyState() == QDeclarativeXMLHttpRequest::Unsent ||
+ r->readyState() == QDeclarativeXMLHttpRequest::Opened)
+ V8THROW_DOM(INVALID_STATE_ERR, "Invalid state");
+
+ if (r->errorFlag())
+ return engine->toString(QString());
else
- return QScriptValue(request->replyStatusText());
+ return engine->toString(r->replyStatusText());
}
-static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_responseText(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- Q_UNUSED(engine)
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
+
+ QV8Engine *engine = r->engine;
- if (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done)
- return QScriptValue(QString());
+ if (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done)
+ return engine->toString(QString());
else
- return QScriptValue(request->responseBody());
+ return engine->toString(r->responseBody());
}
-static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_responseXML(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info)
{
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(context->thisObject().data().toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ QDeclarativeXMLHttpRequest *r = v8_resource_cast<QDeclarativeXMLHttpRequest>(info.This());
+ if (!r)
+ V8THROW_REFERENCE("Not an XMLHttpRequest object");
- if (!request->receivedXml() ||
- (request->readyState() != QDeclarativeXMLHttpRequest::Loading &&
- request->readyState() != QDeclarativeXMLHttpRequest::Done))
- return engine->nullValue();
- else
- return Document::load(engine, request->rawResponseBody());
+ if (!r->receivedXml() ||
+ (r->readyState() != QDeclarativeXMLHttpRequest::Loading &&
+ r->readyState() != QDeclarativeXMLHttpRequest::Done)) {
+ return v8::Null();
+ } else {
+ return Document::load(r->engine, r->rawResponseBody());
+ }
}
-static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine)
+static v8::Handle<v8::Value> qmlxmlhttprequest_new(const v8::Arguments &args)
{
- Q_UNUSED(engine);
- QScriptValue dataObject = context->thisObject().data();
- QDeclarativeXMLHttpRequest *request = qobject_cast<QDeclarativeXMLHttpRequest *>(dataObject.toQObject());
- if (!request)
- THROW_REFERENCE("Not an XMLHttpRequest object");
+ if (args.IsConstructCall()) {
+ QV8Engine *engine = V8ENGINE();
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+
+ QDeclarativeXMLHttpRequest *r = new QDeclarativeXMLHttpRequest(engine, engine->networkAccessManager());
+ args.This()->SetExternalResource(r);
- if (context->argumentCount()) {
- QScriptValue v = context->argument(0);
- dataObject.setProperty(QLatin1String("callback"), v);
- return v;
+ return args.This();
} else {
- return dataObject.property(QLatin1String("callback"));
+ return v8::Undefined();
}
}
-// Constructor
-static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine)
+#define NEWFUNCTION(function) v8::FunctionTemplate::New(function)->GetFunction()
+
+void qt_rem_qmlxmlhttprequest(QV8Engine *engine, void *d)
{
- if (context->isCalledAsConstructor()) {
- context->thisObject().setData(engine->newQObject(new QDeclarativeXMLHttpRequest(QDeclarativeScriptEngine::get(engine)->networkAccessManager()), QScriptEngine::ScriptOwnership));
- }
- return engine->undefinedValue();
+ QDeclarativeXMLHttpRequestData *data = (QDeclarativeXMLHttpRequestData *)d;
+ delete data;
}
-void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
+void *qt_add_qmlxmlhttprequest(QV8Engine *engine)
{
- QScriptValue prototype = engine->newObject();
+ v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+
+ // XMLHttpRequest
+ v8::Local<v8::FunctionTemplate> xmlhttprequest = v8::FunctionTemplate::New(qmlxmlhttprequest_new,
+ v8::External::Wrap(engine));
+ xmlhttprequest->InstanceTemplate()->SetHasExternalResource(true);
// Methods
- prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2));
- prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2));
- prototype.setProperty(QLatin1String("send"), engine->newFunction(qmlxmlhttprequest_send));
- prototype.setProperty(QLatin1String("abort"), engine->newFunction(qmlxmlhttprequest_abort));
- prototype.setProperty(QLatin1String("getResponseHeader"), engine->newFunction(qmlxmlhttprequest_getResponseHeader, 1));
- prototype.setProperty(QLatin1String("getAllResponseHeaders"), engine->newFunction(qmlxmlhttprequest_getAllResponseHeaders));
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("open"), NEWFUNCTION(qmlxmlhttprequest_open), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("setRequestHeader"), NEWFUNCTION(qmlxmlhttprequest_setRequestHeader), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("send"), NEWFUNCTION(qmlxmlhttprequest_send), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("abort"), NEWFUNCTION(qmlxmlhttprequest_abort), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getResponseHeader"), NEWFUNCTION(qmlxmlhttprequest_getResponseHeader), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getAllResponseHeaders"), NEWFUNCTION(qmlxmlhttprequest_getAllResponseHeaders), attributes);
// Read-only properties
- prototype.setProperty(QLatin1String("readyState"), engine->newFunction(qmlxmlhttprequest_readyState), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
- prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("readyState"), qmlxmlhttprequest_readyState, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("status"),qmlxmlhttprequest_status, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("statusText"),qmlxmlhttprequest_statusText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseText"),qmlxmlhttprequest_responseText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
+ xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseXML"),qmlxmlhttprequest_responseXML, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
// State values
- prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
+ xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
// Constructor
- QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype);
- constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor);
+ xmlhttprequest->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
+ xmlhttprequest->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
+ xmlhttprequest->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
+ xmlhttprequest->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
+ xmlhttprequest->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
+ engine->global()->Set(v8::String::New("XMLHttpRequest"), xmlhttprequest->GetFunction());
// DOM Exception
- QScriptValue domExceptionPrototype = engine->newObject();
- domExceptionPrototype.setProperty(QLatin1String("INDEX_SIZE_ERR"), INDEX_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("DOMSTRING_SIZE_ERR"), DOMSTRING_SIZE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("HIERARCHY_REQUEST_ERR"), HIERARCHY_REQUEST_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("WRONG_DOCUMENT_ERR"), WRONG_DOCUMENT_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_CHARACTER_ERR"), INVALID_CHARACTER_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NO_DATA_ALLOWED_ERR"), NO_DATA_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NO_MODIFICATION_ALLOWED_ERR"), NO_MODIFICATION_ALLOWED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NOT_FOUND_ERR"), NOT_FOUND_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NOT_SUPPORTED_ERR"), NOT_SUPPORTED_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INUSE_ATTRIBUTE_ERR"), INUSE_ATTRIBUTE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_STATE_ERR"), INVALID_STATE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("SYNTAX_ERR"), SYNTAX_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_MODIFICATION_ERR"), INVALID_MODIFICATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("NAMESPACE_ERR"), NAMESPACE_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("INVALID_ACCESS_ERR"), INVALID_ACCESS_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("VALIDATION_ERR"), VALIDATION_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- domExceptionPrototype.setProperty(QLatin1String("TYPE_MISMATCH_ERR"), TYPE_MISMATCH_ERR, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
-
- engine->globalObject().setProperty(QLatin1String("DOMException"), domExceptionPrototype);
+ v8::Local<v8::Object> domexception = v8::Object::New();
+ domexception->Set(v8::String::New("INDEX_SIZE_ERR"), v8::Integer::New(INDEX_SIZE_ERR), attributes);
+ domexception->Set(v8::String::New("DOMSTRING_SIZE_ERR"), v8::Integer::New(DOMSTRING_SIZE_ERR), attributes);
+ domexception->Set(v8::String::New("HIERARCHY_REQUEST_ERR"), v8::Integer::New(HIERARCHY_REQUEST_ERR), attributes);
+ domexception->Set(v8::String::New("WRONG_DOCUMENT_ERR"), v8::Integer::New(WRONG_DOCUMENT_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_CHARACTER_ERR"), v8::Integer::New(INVALID_CHARACTER_ERR), attributes);
+ domexception->Set(v8::String::New("NO_DATA_ALLOWED_ERR"), v8::Integer::New(NO_DATA_ALLOWED_ERR), attributes);
+ domexception->Set(v8::String::New("NO_MODIFICATION_ALLOWED_ERR"), v8::Integer::New(NO_MODIFICATION_ALLOWED_ERR), attributes);
+ domexception->Set(v8::String::New("NOT_FOUND_ERR"), v8::Integer::New(NOT_FOUND_ERR), attributes);
+ domexception->Set(v8::String::New("NOT_SUPPORTED_ERR"), v8::Integer::New(NOT_SUPPORTED_ERR), attributes);
+ domexception->Set(v8::String::New("INUSE_ATTRIBUTE_ERR"), v8::Integer::New(INUSE_ATTRIBUTE_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_STATE_ERR"), v8::Integer::New(INVALID_STATE_ERR), attributes);
+ domexception->Set(v8::String::New("SYNTAX_ERR"), v8::Integer::New(SYNTAX_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_MODIFICATION_ERR"), v8::Integer::New(INVALID_MODIFICATION_ERR), attributes);
+ domexception->Set(v8::String::New("NAMESPACE_ERR"), v8::Integer::New(NAMESPACE_ERR), attributes);
+ domexception->Set(v8::String::New("INVALID_ACCESS_ERR"), v8::Integer::New(INVALID_ACCESS_ERR), attributes);
+ domexception->Set(v8::String::New("VALIDATION_ERR"), v8::Integer::New(VALIDATION_ERR), attributes);
+ domexception->Set(v8::String::New("TYPE_MISMATCH_ERR"), v8::Integer::New(TYPE_MISMATCH_ERR), attributes);
+ engine->global()->Set(v8::String::New("DOMException"), domexception);
+
+ QDeclarativeXMLHttpRequestData *data = new QDeclarativeXMLHttpRequestData;
+ return data;
}
QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
-class QScriptEngine;
-void qt_add_qmlxmlhttprequest(QScriptEngine *engine);
+class QV8Engine;
+
+void *qt_add_qmlxmlhttprequest(QV8Engine *engine);
+void qt_rem_qmlxmlhttprequest(QV8Engine *engine, void *);
QT_END_NAMESPACE
inline QIntrusiveList();
inline ~QIntrusiveList();
+ inline bool isEmpty() const;
inline void insert(N *n);
inline void remove(N *n);
}
template<class N, QIntrusiveListNode N::*member>
+bool QIntrusiveList<N, member>::isEmpty() const
+{
+ return __first == 0;
+}
+
+template<class N, QIntrusiveListNode N::*member>
void QIntrusiveList<N, member>::insert(N *n)
{
QIntrusiveListNode *nnode = &(n->*member);
$$PWD/qdeclarativeproperty.cpp \
$$PWD/qdeclarativecomponent.cpp \
$$PWD/qdeclarativecontext.cpp \
- $$PWD/qdeclarativeinclude.cpp \
$$PWD/qdeclarativecustomparser.cpp \
$$PWD/qdeclarativepropertyvaluesource.cpp \
$$PWD/qdeclarativepropertyvalueinterceptor.cpp \
$$PWD/qdeclarativetypenotavailable.cpp \
$$PWD/qdeclarativetypenamecache.cpp \
$$PWD/qdeclarativescriptstring.cpp \
- $$PWD/qdeclarativeobjectscriptclass.cpp \
- $$PWD/qdeclarativescarceresourcescriptclass.cpp \
- $$PWD/qdeclarativecontextscriptclass.cpp \
- $$PWD/qdeclarativeglobalscriptclass.cpp \
- $$PWD/qdeclarativevaluetypescriptclass.cpp \
- $$PWD/qdeclarativetypenamescriptclass.cpp \
- $$PWD/qdeclarativelistscriptclass.cpp \
$$PWD/qdeclarativeworkerscript.cpp \
$$PWD/qdeclarativeimageprovider.cpp \
$$PWD/qdeclarativenetworkaccessmanagerfactory.cpp \
$$PWD/qdeclarativeinfo.h \
$$PWD/qdeclarativeproperty_p.h \
$$PWD/qdeclarativecontext_p.h \
- $$PWD/qdeclarativeinclude_p.h \
$$PWD/qdeclarativetypeloader_p.h \
$$PWD/qdeclarativelist.h \
$$PWD/qdeclarativelist_p.h \
$$PWD/qdeclarativetypenotavailable_p.h \
$$PWD/qdeclarativetypenamecache_p.h \
$$PWD/qdeclarativescriptstring.h \
- $$PWD/qdeclarativeobjectscriptclass_p.h \
- $$PWD/qdeclarativescarceresourcescriptclass_p.h \
- $$PWD/qdeclarativecontextscriptclass_p.h \
- $$PWD/qdeclarativeglobalscriptclass_p.h \
- $$PWD/qdeclarativevaluetypescriptclass_p.h \
- $$PWD/qdeclarativetypenamescriptclass_p.h \
- $$PWD/qdeclarativelistscriptclass_p.h \
$$PWD/qdeclarativeworkerscript_p.h \
$$PWD/qdeclarativeguard_p.h \
$$PWD/qdeclarativeimageprovider.h \
include(parser/parser.pri)
include(rewriter/rewriter.pri)
include(v4/v4.pri)
+include(v8/v8.pri)
# mirrors logic in corelib/kernel/kernel.pri
unix:!symbian: contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri)
QString str = QString::fromRawData(strdata, len);
- identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
+ // XXX not applicable in v8
+ // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
}
QML_V4_END_INSTR(InitString, initstring)
#include "qdeclarativev4irbuilder_p.h"
-#include <private/qdeclarativeglobalscriptclass_p.h> // For illegalNames
#include <private/qdeclarativeanchors_p_p.h> // For AnchorLine
#include <private/qsganchors_p_p.h> // For AnchorLine
#include <private/qdeclarativetypenamecache_p.h>
if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) {
_expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value
- } else if(m_engine->globalClass->illegalNames().contains(name) ) {
+ } else if(m_engine->v8engine.illegalNames().contains(name) ) {
if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
return false;
} else if (const QDeclarativeParser::Object *obj = m_expression->ids.value(name)) {
--- /dev/null
+Removed backwards compatible imports - QTBUG-17518
+
+autotest print() taking objects that don't ToString()
+autotest QDeclarativeV8Function
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhashedstring_p.h"
+
+inline unsigned stringHash(const QChar* data, unsigned length)
+{
+ return v8::String::ComputeHash((uint16_t *)data, length);
+}
+
+void QHashedString::computeHash() const
+{
+ m_hash = stringHash(constData(), length());
+}
+
+void QHashedStringRef::computeHash() const
+{
+ m_hash = stringHash(m_data, m_length);
+}
+
+/*
+ A QHash has initially around pow(2, MinNumBits) buckets. For
+ example, if MinNumBits is 4, it has 17 buckets.
+*/
+const int MinNumBits = 4;
+
+/*
+ The prime_deltas array is a table of selected prime values, even
+ though it doesn't look like one. The primes we are using are 1,
+ 2, 5, 11, 17, 37, 67, 131, 257, ..., i.e. primes in the immediate
+ surrounding of a power of two.
+
+ The primeForNumBits() function returns the prime associated to a
+ power of two. For example, primeForNumBits(8) returns 257.
+*/
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+void QStringHashData::rehash()
+{
+ numBits = qMax(MinNumBits, numBits + 1);
+ numBuckets = primeForNumBits(numBits);
+
+ delete [] buckets;
+ buckets = new QStringHashNode *[numBuckets];
+ ::memset(buckets, 0, sizeof(QStringHashNode *) * numBuckets);
+
+ QStringHashNode *nodeList = nodes;
+ while (nodeList) {
+ int bucket = nodeList->key.hash() % numBuckets;
+ nodeList->next = buckets[bucket];
+ buckets[bucket] = nodeList;
+
+ nodeList = nodeList->nlist;
+ }
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHASHEDSTRING_P_H
+#define QHASHEDSTRING_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHashedStringRef;
+class QHashedString : public QString
+{
+public:
+ inline QHashedString();
+ inline QHashedString(const QString &string);
+ inline QHashedString(const QString &string, quint32);
+ inline QHashedString(const QHashedString &string);
+
+ inline QHashedString &operator=(const QHashedString &string);
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+
+ inline quint32 hash() const;
+ inline quint32 existingHash() const;
+
+ static inline bool isUpper(const QChar &);
+private:
+ friend class QHashedStringRef;
+
+ void computeHash() const;
+ mutable quint32 m_hash;
+};
+
+class QHashedStringRef
+{
+public:
+ inline QHashedStringRef();
+ inline QHashedStringRef(const QString &);
+ inline QHashedStringRef(const QChar *, int);
+ inline QHashedStringRef(const QChar *, int, quint32);
+ inline QHashedStringRef(const QHashedString &);
+ inline QHashedStringRef(const QHashedStringRef &);
+
+ inline bool operator==(const QHashedString &string) const;
+ inline bool operator==(const QHashedStringRef &string) const;
+
+ inline quint32 hash() const;
+
+ inline const QChar *constData() const;
+ inline quint32 length() const;
+ inline bool startsWithUpper() const;
+
+private:
+ friend class QHashedString;
+
+ void computeHash() const;
+
+ const QChar *m_data;
+ quint32 m_length;
+ mutable quint32 m_hash;
+};
+
+class QStringHashData;
+class QStringHashNode
+{
+public:
+ QStringHashNode(const QHashedString &key)
+ : nlist(0), next(0), key(key) {}
+
+ QStringHashNode *nlist;
+ QStringHashNode *next;
+ QHashedString key;
+};
+
+struct QStringHashData
+{
+public:
+ QStringHashData()
+ : nodes(0), buckets(0), numBuckets(0), size(0), numBits(0) {}
+
+ QStringHashNode *nodes;
+ QStringHashNode **buckets;
+ int numBuckets;
+ int size;
+ short numBits;
+
+ void rehash();
+};
+
+template<class T>
+class QStringHash
+{
+private:
+ struct Node : public QStringHashNode {
+ Node(const QHashedString &key, const T &value) : QStringHashNode(key), value(value) {}
+ T value;
+ };
+
+ QStringHashData data;
+
+ inline Node *findNode(const QHashedStringRef &) const;
+ inline Node *findNode(v8::Handle<v8::String> &, quint32) const;
+ Node *createNode(const QHashedString &, const T &);
+
+public:
+ inline QStringHash();
+ inline QStringHash(const QStringHash &);
+ inline ~QStringHash();
+
+ QStringHash &operator=(const QStringHash<T> &);
+
+ inline bool isEmpty() const;
+ inline void clear();
+ inline int count() const;
+
+ inline void insert(const QString &, const T &);
+ inline void insert(const QHashedString &, const T &);
+ inline void insert(const QHashedStringRef &, const T &);
+
+ inline T *value(const QString &) const;
+ inline T *value(const QHashedString &) const;
+ inline T *value(const QHashedStringRef &) const;
+ inline T *value(v8::Handle<v8::String> &) const;
+ inline T *value(v8::Handle<v8::String> &, quint32 hash) const;
+
+ inline bool contains(const QString &) const;
+ inline bool contains(const QHashedString &) const;
+ inline bool contains(const QHashedStringRef &) const;
+
+ T &operator[](const QString &);
+ T &operator[](const QHashedString &);
+ T &operator[](const QHashedStringRef &);
+
+ class ConstIterator {
+ public:
+ ConstIterator() : n(0) {}
+ ConstIterator(Node *n) : n(n) {}
+
+ ConstIterator &operator++() { n = (Node *)n->nlist; return *this; }
+ bool operator==(const ConstIterator &o) const { return n == o.n; }
+ bool operator!=(const ConstIterator &o) const { return n != o.n; }
+
+ const QHashedString &key() const { return n->key; }
+ const T &value() const { return n->value; }
+ const T &operator*() const { return n->value; }
+ private:
+ Node *n;
+ };
+
+ ConstIterator begin() const { return ConstIterator((Node *)data.nodes); }
+ ConstIterator end() const { return ConstIterator(); }
+};
+
+template<class T>
+QStringHash<T>::QStringHash()
+{
+}
+
+template<class T>
+QStringHash<T>::QStringHash(const QStringHash<T> &other)
+: data(other.data)
+{
+ data.nodes = 0;
+ data.buckets = 0;
+
+ QStringHashNode *n = other.data.nodes;
+ while (n) {
+ Node *o = (Node *)n;
+ Node *mynode = new Node(o->key, o->value);
+ mynode->nlist = data.nodes;
+ data.nodes = mynode;
+ n = o->nlist;
+ }
+
+ data.rehash();
+}
+
+template<class T>
+QStringHash<T> &QStringHash<T>::operator=(const QStringHash<T> &other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+ data = other.data;
+ data.nodes = 0;
+ data.buckets = 0;
+
+ QStringHashNode *n = other.data.nodes;
+ while (n) {
+ Node *o = (Node *)n;
+ Node *mynode = new Node(o->key, o->value);
+ mynode->nlist = data.nodes;
+ data.nodes = mynode;
+ n = o->nlist;
+ }
+
+ data.rehash();
+
+ return *this;
+}
+
+template<class T>
+QStringHash<T>::~QStringHash()
+{
+ clear();
+}
+
+template<class T>
+void QStringHash<T>::clear()
+{
+ QStringHashNode *n = data.nodes;
+ while (n) {
+ Node *o = (Node *)n;
+ n = n->nlist;
+ delete o;
+ }
+
+ delete [] data.buckets;
+
+ data = QStringHashData();
+}
+
+template<class T>
+bool QStringHash<T>::isEmpty() const
+{
+ return data.nodes == 0;
+}
+
+template<class T>
+int QStringHash<T>::count() const
+{
+ return data.size;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::createNode(const QHashedString &key, const T &value)
+{
+ if (data.size == data.numBuckets)
+ data.rehash();
+
+ Node *n = new Node(key, value);
+ n->nlist = data.nodes;
+ data.nodes = n;
+
+ int bucket = key.hash() % data.numBuckets;
+ n->next = data.buckets[bucket];
+ data.buckets[bucket] = n;
+
+ data.size++;
+
+ return n;
+}
+
+template<class T>
+void QStringHash<T>::insert(const QString &key, const T &value)
+{
+ QHashedStringRef ch(key);
+ Node *n = findNode(key);
+ if (n) n->value = value;
+ else createNode(QHashedString(key, ch.hash()), value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedString &key, const T &value)
+{
+ Node *n = findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+void QStringHash<T>::insert(const QHashedStringRef &key, const T &value)
+{
+ Node *n = findNode(key);
+ if (n) n->value = value;
+ else createNode(key, value);
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(const QHashedStringRef &string) const
+{
+ QStringHashNode *node = 0;
+ if (data.numBuckets) {
+ node = data.buckets[string.hash() % data.numBuckets];
+ while (node && !(node->key == string))
+ node = node->next;
+ }
+
+ return (Node *)node;
+}
+
+template<class T>
+typename QStringHash<T>::Node *QStringHash<T>::findNode(v8::Handle<v8::String> &string, quint32 hash) const
+{
+ QStringHashNode *node = 0;
+ if (data.numBuckets) {
+ node = data.buckets[hash % data.numBuckets];
+ int length = string->Length();
+ while (node && (length != node->key.length() || !string->Equals((uint16_t*)node->key.constData(), length)))
+ node = node->next;
+ }
+
+ return (Node *)node;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedString &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(const QHashedStringRef &key) const
+{
+ Node *n = findNode(key);
+ return n?&n->value:0;
+}
+
+template<class T>
+T *QStringHash<T>::value(v8::Handle<v8::String> &key) const
+{
+ return value(key, (quint32)key->Hash());
+}
+
+template<class T>
+T *QStringHash<T>::value(v8::Handle<v8::String> &key, quint32 hash) const
+{
+ Node *n = findNode(key, hash);
+ return n?&n->value:0;
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QString &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+bool QStringHash<T>::contains(const QHashedString &s) const
+{
+ return 0 != value(s);
+}
+template<class T>
+bool QStringHash<T>::contains(const QHashedStringRef &s) const
+{
+ return 0 != value(s);
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QString &key)
+{
+ QHashedStringRef cs(key);
+ Node *n = findNode(cs);
+ if (n) return n->value;
+ else return createNode(QHashedString(key, cs.hash()), T())->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedString &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key)->value;
+}
+
+template<class T>
+T &QStringHash<T>::operator[](const QHashedStringRef &key)
+{
+ Node *n = findNode(key);
+ if (n) return n->value;
+ else return createNode(key)->value;
+}
+
+inline uint qHash(const QHashedString &string)
+{
+ return uint(string.hash());
+}
+
+inline uint qHash(const QHashedStringRef &string)
+{
+ return uint(string.hash());
+}
+
+QHashedString::QHashedString()
+: QString(), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string)
+: QString(string), m_hash(0)
+{
+}
+
+QHashedString::QHashedString(const QString &string, quint32 hash)
+: QString(string), m_hash(hash)
+{
+}
+
+QHashedString::QHashedString(const QHashedString &string)
+: QString(string), m_hash(string.m_hash)
+{
+}
+
+QHashedString &QHashedString::operator=(const QHashedString &string)
+{
+ static_cast<QString &>(*this) = string;
+ m_hash = string.m_hash;
+ return *this;
+}
+
+bool QHashedString::operator==(const QHashedString &string) const
+{
+ return (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ static_cast<const QString &>(*this) == static_cast<const QString &>(string);
+}
+
+bool QHashedString::operator==(const QHashedStringRef &string) const
+{
+ return (uint)length() == string.m_length &&
+ (string.m_hash == m_hash || !string.m_hash || !m_hash) &&
+ 0 == ::memcmp(constData(), string.m_data, string.m_length * sizeof(QChar));
+}
+
+quint32 QHashedString::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+quint32 QHashedString::existingHash() const
+{
+ return m_hash;
+}
+
+bool QHashedString::isUpper(const QChar &qc)
+{
+ ushort c = qc.unicode();
+ // Optimize for _, a-z and A-Z.
+ return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
+ ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
+}
+
+QHashedStringRef::QHashedStringRef()
+: m_data(0), m_length(0), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QString &str)
+: m_data(str.constData()), m_length(str.length()), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length)
+: m_data(data), m_length(length), m_hash(0)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
+: m_data(data), m_length(length), m_hash(hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedString &string)
+: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
+{
+}
+
+QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
+: m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash)
+{
+}
+
+bool QHashedStringRef::operator==(const QHashedString &string) const
+{
+ return m_length == (uint)string.length() &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ 0 == ::memcmp(string.constData(), m_data, m_length * sizeof(QChar));
+}
+
+bool QHashedStringRef::operator==(const QHashedStringRef &string) const
+{
+ return m_length == string.m_length &&
+ (m_hash == string.m_hash || !m_hash || !string.m_hash) &&
+ 0 == ::memcmp(string.m_data, m_data, m_length * sizeof(QChar));
+}
+
+const QChar *QHashedStringRef::constData() const
+{
+ return m_data;
+}
+
+quint32 QHashedStringRef::length() const
+{
+ return m_length;
+}
+
+bool QHashedStringRef::startsWithUpper() const
+{
+ if (m_length < 1) return false;
+ return QHashedString::isUpper(m_data[0]);
+}
+
+quint32 QHashedStringRef::hash() const
+{
+ if (!m_hash) computeHash();
+ return m_hash;
+}
+
+QT_END_NAMESPACE
+
+#endif // QHASHEDSTRING_P_H
--- /dev/null
+#include "../../../3rdparty/v8/include/v8.h"
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QString internal(QLatin1String("You've stumbled onto an internal implementation detail "
+ "that should never have been exposed."));
+
+class QV8ContextResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ContextType);
+
+public:
+ QV8ContextResource(QV8Engine *engine, QDeclarativeContextData *context, QObject *scopeObject);
+ ~QV8ContextResource();
+
+ inline QDeclarativeContextData *getContext() const;
+
+ QDeclarativeGuard<QObject> scopeObject;
+
+ quint32 hasSubContexts:1;
+ quint32 ownsContext:1;
+ quint32 readOnly:1;
+ quint32 dummy:29;
+
+ QObject *secondaryScope;
+
+ // XXX aakenned - this is somewhat of a horrible abuse of external strings :)
+ struct SubContext : public v8::String::ExternalStringResource {
+ SubContext(QDeclarativeContextData *context) : context(context) {}
+ QDeclarativeGuardedContextData context;
+
+ virtual const uint16_t* data() const { return (const uint16_t *)internal.constData(); }
+ virtual size_t length() const { return internal.length(); }
+ };
+
+private:
+ QDeclarativeGuardedContextData context;
+};
+
+QV8ContextResource::QV8ContextResource(QV8Engine *engine, QDeclarativeContextData *context, QObject *scopeObject)
+: QV8ObjectResource(engine), scopeObject(scopeObject), hasSubContexts(false), ownsContext(false),
+ readOnly(true), secondaryScope(0), context(context)
+{
+}
+
+QV8ContextResource::~QV8ContextResource()
+{
+ if (ownsContext && context)
+ context->destroy();
+}
+
+// Returns the context, including resolving a subcontext
+QDeclarativeContextData *QV8ContextResource::getContext() const
+{
+ if (!hasSubContexts)
+ return context;
+
+ v8::Local<v8::Value> callingdata = v8::Context::GetCallingScriptData();
+ if (callingdata.IsEmpty() || !callingdata->IsString())
+ return context;
+
+ v8::Local<v8::String> callingstring = callingdata->ToString();
+ Q_ASSERT(callingstring->IsExternal());
+ Q_ASSERT(callingstring->GetExternalStringResource());
+
+ SubContext *sc = static_cast<SubContext *>(callingstring->GetExternalStringResource());
+ return sc->context;
+}
+
+QV8ContextWrapper::QV8ContextWrapper()
+: m_engine(0)
+{
+}
+
+QV8ContextWrapper::~QV8ContextWrapper()
+{
+}
+
+void QV8ContextWrapper::destroy()
+{
+ m_urlConstructor.Dispose(); m_urlConstructor.Clear();
+ m_constructor.Dispose(); m_constructor.Clear();
+}
+
+void QV8ContextWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(NullGetter, NullSetter);
+ m_urlConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+}
+
+v8::Local<v8::Object> QV8ContextWrapper::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
+{
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ContextResource *r = new QV8ContextResource(m_engine, ctxt, scope);
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8ContextWrapper::urlScope(const QUrl &url)
+{
+ QDeclarativeContextData *context = new QDeclarativeContextData;
+ context->url = url;
+ context->isInternal = true;
+ context->isJSContext = true;
+
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_urlConstructor->NewInstance();
+ QV8ContextResource *r = new QV8ContextResource(m_engine, context, 0);
+ r->ownsContext = true;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+void QV8ContextWrapper::setReadOnly(v8::Handle<v8::Object> qmlglobal, bool readOnly)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ Q_ASSERT(resource);
+ resource->readOnly = readOnly;
+}
+
+void QV8ContextWrapper::addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script> script,
+ QDeclarativeContextData *ctxt)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ Q_ASSERT(resource);
+ resource->hasSubContexts = true;
+ script->SetData(v8::String::NewExternal(new QV8ContextResource::SubContext(ctxt)));
+}
+
+QObject *QV8ContextWrapper::setSecondaryScope(v8::Handle<v8::Object> ctxt, QObject *scope)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(ctxt);
+ if (!resource) return 0;
+
+ QObject *rv = resource->secondaryScope;
+ resource->secondaryScope = scope;
+ return rv;
+}
+
+QDeclarativeContextData *QV8ContextWrapper::callingContext()
+{
+ v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
+ if (qmlglobal.IsEmpty()) return 0;
+
+ QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ return r?r->getContext():0;
+}
+
+QDeclarativeContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
+{
+ if (!value->IsObject())
+ return 0;
+
+ v8::Handle<v8::Object> qmlglobal = v8::Handle<v8::Object>::Cast(value);
+ QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
+ return r?r->getContext():0;
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined(); // XXX Should we throw here?
+
+ QV8Engine *engine = resource->engine;
+
+ QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
+ v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined(); // XXX Should we throw here?
+
+ // XXX aakenned too agressive
+ QDeclarativeContextData *context = resource->getContext();
+
+ if (!context)
+ return v8::Undefined(); // XXX Should we throw here?
+
+ // Search type (attached property/enum/imported scripts) names
+ // Secondary scope object
+ // while (context) {
+ // Search context properties
+ // Search scope object
+ // Search context object
+ // context = context->parent
+ // }
+
+ QV8Engine *engine = resource->engine;
+ QObject *scopeObject = resource->scopeObject;
+
+ if (context->imports && QV8Engine::startsWithUpper(property)) {
+ // Search for attached properties, enums and imported scripts
+ QDeclarativeTypeNameCache::Data *data = context->imports->data(property);
+
+ if (data) {
+ if (data->importedScriptIndex != -1) {
+ int index = data->importedScriptIndex;
+ if (index < context->importedScripts.count())
+ return context->importedScripts.at(index);
+ else
+ return v8::Undefined();
+ } else if (data->type) {
+ return engine->typeWrapper()->newObject(scopeObject, data->type);
+ } else if (data->typeNamespace) {
+ return engine->typeWrapper()->newObject(scopeObject, data->typeNamespace);
+ }
+ Q_ASSERT(!"Unreachable");
+ }
+
+ // Fall through
+ }
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+
+ if (resource->secondaryScope) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(resource->secondaryScope, property,
+ QV8QObjectWrapper::IgnoreRevision);
+ if (!result.IsEmpty()) return result;
+ }
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames) {
+ int propertyIdx = context->propertyNames->value(property);
+
+ if (propertyIdx != -1) {
+ typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty;
+
+ if (propertyIdx < context->idValueCount) {
+
+ if (ep->captureProperties)
+ ep->capturedProperties << CapturedProperty(&context->idValues[propertyIdx].bindings);
+
+ return engine->newQObject(context->idValues[propertyIdx]);
+ } else {
+
+ QDeclarativeContextPrivate *cp = context->asQDeclarativeContextPrivate();
+
+ if (ep->captureProperties)
+ ep->capturedProperties << CapturedProperty(context->asQDeclarativeContext(), -1,
+ propertyIdx + cp->notifyIndex);
+
+ const QVariant &value = cp->propertyValues.at(propertyIdx);
+ if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
+ QDeclarativeListProperty<QObject> prop(context->asQDeclarativeContext(), (void*)propertyIdx,
+ 0,
+ QDeclarativeContextPrivate::context_count,
+ QDeclarativeContextPrivate::context_at);
+ return engine->listWrapper()->newList(prop, qMetaTypeId<QDeclarativeListProperty<QObject> >());
+ } else {
+ return engine->fromVariant(cp->propertyValues.at(propertyIdx));
+ }
+ }
+ }
+ }
+
+ // Search scope object
+ if (scopeObject) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, property,
+ QV8QObjectWrapper::CheckRevision);
+ if (!result.IsEmpty()) return result;
+ }
+ scopeObject = 0;
+
+
+ // Search context object
+ if (context->contextObject) {
+ v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, property,
+ QV8QObjectWrapper::CheckRevision);
+ if (!result.IsEmpty()) return result;
+ }
+
+ context = context->parent;
+ }
+
+ QString error = QLatin1String("Can't find variable: ") + engine->toString(property);
+ v8::ThrowException(v8::Exception::ReferenceError(engine->toString(error)));
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property,
+ v8::Local<v8::Value>,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined(); // XXX Should we throw here?
+
+ QV8Engine *engine = resource->engine;
+
+ if (!resource->readOnly) {
+ return v8::Handle<v8::Value>();
+ } else {
+ QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
+ QLatin1String("\"");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined(); // XXX Should we throw here?
+
+ // XXX aakenned too agressive
+ QDeclarativeContextData *context = resource->getContext();
+
+ if (!context)
+ return v8::Undefined(); // XXX Should we throw here?
+
+ // See QV8ContextWrapper::Getter for resolution order
+
+ QV8Engine *engine = resource->engine;
+ QObject *scopeObject = resource->scopeObject;
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+
+ // Search scope object
+ if (resource->secondaryScope && qobjectWrapper->setProperty(resource->secondaryScope, property, value,
+ QV8QObjectWrapper::IgnoreRevision))
+ return value;
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames && -1 != context->propertyNames->value(property))
+ return value;
+
+ // Search scope object
+ if (scopeObject &&
+ qobjectWrapper->setProperty(scopeObject, property, value, QV8QObjectWrapper::CheckRevision))
+ return value;
+ scopeObject = 0;
+
+ // Search context object
+ if (context->contextObject &&
+ qobjectWrapper->setProperty(context->contextObject, property, value, QV8QObjectWrapper::CheckRevision))
+ return value;
+
+ context = context->parent;
+ }
+
+ if (!resource->readOnly) {
+ return v8::Handle<v8::Value>();
+ } else {
+ QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
+ QLatin1String("\"");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Undefined();
+ }
+}
+
+QT_END_NAMESPACE
**
****************************************************************************/
-#ifndef QDECLARATIVECONTEXTSCRIPTCLASS_P_H
-#define QDECLARATIVECONTEXTSCRIPTCLASS_P_H
+#ifndef QV8CONTEXTWRAPPER_P_H
+#define QV8CONTEXTWRAPPER_P_H
//
// W A R N I N G
// We mean it.
//
-#include "private/qdeclarativetypenamecache_p.h"
-#include <private/qscriptdeclarativeclass_p.h>
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
-class QDeclarativeContext;
+class QUrl;
+class QObject;
+class QV8Engine;
class QDeclarativeContextData;
-class QDeclarativeContextScriptClass : public QScriptDeclarativeClass
+class QV8ContextWrapper
{
public:
- QDeclarativeContextScriptClass(QDeclarativeEngine *);
- ~QDeclarativeContextScriptClass();
+ QV8ContextWrapper();
+ ~QV8ContextWrapper();
- QScriptValue newContext(QDeclarativeContextData *, QObject * = 0);
- QScriptValue newUrlContext(QDeclarativeContextData *, QObject *, const QString &);
- QScriptValue newUrlContext(const QString &);
- QScriptValue newSharedContext();
+ void init(QV8Engine *);
+ void destroy();
- QDeclarativeContextData *contextFromValue(const QScriptValue &);
- QUrl urlFromValue(const QScriptValue &);
+ v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
+ v8::Local<v8::Object> urlScope(const QUrl &);
- QObject *setOverrideObject(QScriptValue &, QObject *);
+ void setReadOnly(v8::Handle<v8::Object>, bool);
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ void addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script>,
+ QDeclarativeContextData *ctxt);
-private:
- QScriptClass::QueryFlags queryProperty(QDeclarativeContextData *, QObject *scopeObject,
- const Identifier &,
- QScriptClass::QueryFlags flags,
- bool includeTypes);
-
- QDeclarativeEngine *engine;
+ // XXX aakenned - remove this abomination
+ QObject *setSecondaryScope(v8::Handle<v8::Object>, QObject *);
- QObject *lastScopeObject;
- QDeclarativeContextData *lastContext;
- QDeclarativeTypeNameCache::Data *lastData;
- int lastPropertyIndex;
- QScriptValue lastFunction;
-
- uint m_id;
+ QDeclarativeContextData *callingContext();
+ QDeclarativeContextData *context(v8::Handle<v8::Value>);
+private:
+ static v8::Handle<v8::Value> NullGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> NullSetter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_urlConstructor;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVECONTEXTSCRIPTCLASS_P_H
+#endif // QV8CONTEXTWRAPPER_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8engine_p.h"
+
+#include "qv8contextwrapper_p.h"
+#include "qv8include_p.h"
+#include "../../../3rdparty/javascriptcore/DateMath.h"
+
+#include <private/qdeclarativelist_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecomponent_p.h>
+#include <private/qdeclarativestringconverters_p.h>
+
+#include <QtDeclarative/qdeclarativecomponent.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qnumeric.h>
+#include <QtGui/qdesktopservices.h>
+#include <QtGui/qfontdatabase.h>
+#include <private/qdeclarativeapplication_p.h>
+#include <private/qdeclarativexmlhttprequest_p.h>
+#include <private/qdeclarativesqldatabase_p.h>
+
+// XXX Need to check all the global functions will also work in a worker script where the QDeclarativeEngine
+// is not available
+QT_BEGIN_NAMESPACE
+
+QV8Engine::QV8Engine()
+: m_xmlHttpRequestData(0), m_sqlDatabaseData(0)
+{
+}
+
+QV8Engine::~QV8Engine()
+{
+ qt_rem_qmlsqldatabase(this, m_sqlDatabaseData);
+ m_sqlDatabaseData = 0;
+ qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData);
+ m_xmlHttpRequestData = 0;
+
+ m_getOwnPropertyNames.Dispose(); m_getOwnPropertyNames.Clear();
+
+ m_valueTypeWrapper.destroy();
+ m_variantWrapper.destroy();
+ m_listWrapper.destroy();
+ m_typeWrapper.destroy();
+ m_qobjectWrapper.destroy();
+ m_contextWrapper.destroy();
+ m_stringWrapper.destroy();
+ m_context.Dispose();
+}
+
+void QV8Engine::init(QDeclarativeEngine *engine)
+{
+ m_engine = engine;
+
+ QByteArray v8args = qgetenv("V8ARGS");
+ if (!v8args.isEmpty())
+ v8::V8::SetFlagsFromString(v8args.constData(), v8args.length());
+
+ v8::HandleScope handle_scope;
+ m_context = v8::Context::New();
+ v8::Context::Scope context_scope(m_context);
+
+ m_stringWrapper.init();
+ m_contextWrapper.init(this);
+ m_qobjectWrapper.init(this);
+ m_typeWrapper.init(this);
+ m_listWrapper.init(this);
+ m_variantWrapper.init(this);
+ m_valueTypeWrapper.init(this);
+
+ {
+ v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
+ m_getOwnPropertyNames = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(v));
+ }
+
+ initializeGlobal(m_context->Global());
+ freezeGlobal();
+}
+
+QString QV8Engine::toStringStatic(v8::Handle<v8::Value> jsstr)
+{
+ return toStringStatic(jsstr->ToString());
+}
+
+QString QV8Engine::toStringStatic(v8::Handle<v8::String> jsstr)
+{
+ QString qstr;
+ qstr.resize(jsstr->Length());
+ jsstr->Write((uint16_t*)qstr.data());
+ return qstr;
+}
+
+QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
+{
+ if (value.IsEmpty())
+ return QVariant();
+
+ if (value->IsObject()) {
+ QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
+ if (r) {
+ switch (r->resourceType()) {
+ case QV8ObjectResource::ContextType:
+ case QV8ObjectResource::TypeType:
+ case QV8ObjectResource::XMLHttpRequestType:
+ case QV8ObjectResource::DOMNodeType:
+ case QV8ObjectResource::SQLDatabaseType:
+ return QVariant();
+ case QV8ObjectResource::QObjectType:
+ return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r));
+ case QV8ObjectResource::ListType:
+ return m_listWrapper.toVariant(r);
+ case QV8ObjectResource::VariantType:
+ return m_variantWrapper.toVariant(r);
+ case QV8ObjectResource::ValueTypeType:
+ return m_valueTypeWrapper.toVariant(r);
+ }
+ }
+ }
+
+ if (typeHint == qMetaTypeId<QList<QObject *> >() && value->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+
+ QList<QObject *> list;
+ uint32_t length = array->Length();
+ for (uint32_t ii = 0; ii < length; ++ii) {
+ v8::Local<v8::Value> arrayItem = array->Get(ii);
+ if (arrayItem->IsObject()) {
+ list << toQObject(arrayItem->ToObject());
+ } else {
+ list << 0;
+ }
+ }
+
+ return qVariantFromValue<QList<QObject*> >(list);
+ }
+
+ return toBasicVariant(value);
+}
+
+static v8::Handle<v8::Array> arrayFromStringList(QV8Engine *engine, const QStringList &list)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Array> result = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ result->Set(ii, engine->toString(list.at(ii)));
+ return result;
+}
+
+static v8::Handle<v8::Array> arrayFromVariantList(QV8Engine *engine, const QVariantList &list)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Array> result = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ result->Set(ii, engine->fromVariant(list.at(ii)));
+ return result;
+}
+
+static v8::Handle<v8::Object> objectFromVariantMap(QV8Engine *engine, const QVariantMap &map)
+{
+ v8::Context::Scope scope(engine->context());
+ v8::Local<v8::Object> object = v8::Object::New();
+ for (QVariantMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter)
+ object->Set(engine->toString(iter.key()), engine->fromVariant(iter.value()));
+ return object;
+}
+
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+
+// Converts a QRegExp to a JS RegExp.
+// The conversion is not 100% exact since ECMA regexp and QRegExp
+// have different semantics/flags, but we try to do our best.
+static v8::Handle<v8::RegExp> regexpFromQRegExp(QV8Engine *engine, const QRegExp &re)
+{
+ // Convert the pattern to a ECMAScript pattern.
+ QString pattern = qt_regexp_toCanonical(re.pattern(), re.patternSyntax());
+ if (re.isMinimal()) {
+ QString ecmaPattern;
+ int len = pattern.length();
+ ecmaPattern.reserve(len);
+ int i = 0;
+ const QChar *wc = pattern.unicode();
+ bool inBracket = false;
+ while (i < len) {
+ QChar c = wc[i++];
+ ecmaPattern += c;
+ switch (c.unicode()) {
+ case '?':
+ case '+':
+ case '*':
+ case '}':
+ if (!inBracket)
+ ecmaPattern += QLatin1Char('?');
+ break;
+ case '\\':
+ if (i < len)
+ ecmaPattern += wc[i++];
+ break;
+ case '[':
+ inBracket = true;
+ break;
+ case ']':
+ inBracket = false;
+ break;
+ default:
+ break;
+ }
+ }
+ pattern = ecmaPattern;
+ }
+
+ int flags = v8::RegExp::kNone;
+ if (re.caseSensitivity() == Qt::CaseInsensitive)
+ flags |= v8::RegExp::kIgnoreCase;
+
+ return v8::RegExp::New(engine->toString(pattern), static_cast<v8::RegExp::Flags>(flags));
+}
+
+v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
+{
+ int type = variant.userType();
+ const void *ptr = variant.constData();
+
+ if (type < QMetaType::User) {
+ switch (QMetaType::Type(type)) {
+ case QMetaType::Void:
+ return v8::Undefined();
+ case QMetaType::Bool:
+ return v8::Boolean::New(*reinterpret_cast<const bool*>(ptr));
+ case QMetaType::Int:
+ return v8::Integer::New(*reinterpret_cast<const int*>(ptr));
+ case QMetaType::UInt:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const uint*>(ptr));
+ case QMetaType::LongLong:
+ return v8::Number::New(*reinterpret_cast<const qlonglong*>(ptr));
+ case QMetaType::ULongLong:
+ return v8::Number::New(*reinterpret_cast<const qulonglong*>(ptr));
+ case QMetaType::Double:
+ return v8::Number::New(*reinterpret_cast<const double*>(ptr));
+ case QMetaType::QString:
+ return m_stringWrapper.toString(*reinterpret_cast<const QString*>(ptr));
+ case QMetaType::Float:
+ return v8::Number::New(*reinterpret_cast<const float*>(ptr));
+ case QMetaType::Short:
+ return v8::Integer::New(*reinterpret_cast<const short*>(ptr));
+ case QMetaType::UShort:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned short*>(ptr));
+ case QMetaType::Char:
+ return v8::Integer::New(*reinterpret_cast<const char*>(ptr));
+ case QMetaType::UChar:
+ return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned char*>(ptr));
+ case QMetaType::QChar:
+ return v8::Integer::New((*reinterpret_cast<const QChar*>(ptr)).unicode());
+ case QMetaType::QDateTime:
+ return v8::Date::New(qtDateTimeToJsDate(*reinterpret_cast<const QDateTime *>(ptr)));
+ case QMetaType::QDate:
+ return v8::Date::New(qtDateTimeToJsDate(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
+ case QMetaType::QTime:
+ return v8::Date::New(qtDateTimeToJsDate(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr))));
+ case QMetaType::QRegExp:
+ return regexpFromQRegExp(this, *reinterpret_cast<const QRegExp *>(ptr));
+ case QMetaType::QObjectStar:
+ case QMetaType::QWidgetStar:
+ return newQObject(*reinterpret_cast<QObject* const *>(ptr));
+ case QMetaType::QStringList:
+ return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr));
+ case QMetaType::QVariantList:
+ return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
+ case QMetaType::QVariantMap:
+ return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
+
+ default:
+ break;
+ }
+
+ if (QDeclarativeValueType *vt = QDeclarativeEnginePrivate::get(m_engine)->valueTypes[type])
+ return m_valueTypeWrapper.newValueType(variant, vt);
+
+ } else {
+ if (type == qMetaTypeId<QDeclarativeListReference>()) {
+ typedef QDeclarativeListReferencePrivate QDLRP;
+ QDLRP *p = QDLRP::get((QDeclarativeListReference*)ptr);
+ if (p->object) {
+ return m_listWrapper.newList(p->property, p->propertyType);
+ } else {
+ return v8::Null();
+ }
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ // XXX aakenned Can this be more optimal? Just use Array as a prototype and
+ // implement directly against QList<QObject*>?
+ const QList<QObject *> &list = *(QList<QObject *>*)ptr;
+ v8::Local<v8::Array> array = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ array->Set(ii, newQObject(list.at(ii)));
+ return array;
+ }
+
+ bool objOk;
+ QObject *obj = QDeclarativeMetaType::toQObject(variant, &objOk);
+ if (objOk)
+ return newQObject(obj);
+ }
+
+ return m_variantWrapper.newVariant(variant);
+
+ // XXX aakenned
+#if 0
+#ifndef QT_NO_REGEXP
+ case QMetaType::QRegExp:
+ result = newRegExp(exec, *reinterpret_cast<const QRegExp *>(ptr));
+ break;
+#endif
+#ifndef QT_NO_QOBJECT
+#endif
+ case QMetaType::QVariant:
+ result = eng->newVariant(*reinterpret_cast<const QVariant*>(ptr));
+ break;
+ default:
+ if (type == qMetaTypeId<QScriptValue>()) {
+ result = eng->scriptValueToJSCValue(*reinterpret_cast<const QScriptValue*>(ptr));
+ if (!result)
+ return JSC::jsUndefined();
+ }
+
+#ifndef QT_NO_QOBJECT
+ // lazy registration of some common list types
+ else if (type == qMetaTypeId<QObjectList>()) {
+ qScriptRegisterSequenceMetaType<QObjectList>(eng->q_func());
+ return create(exec, type, ptr);
+ }
+#endif
+ else if (type == qMetaTypeId<QList<int> >()) {
+ qScriptRegisterSequenceMetaType<QList<int> >(eng->q_func());
+ return create(exec, type, ptr);
+ }
+
+ else {
+ QByteArray typeName = QMetaType::typeName(type);
+ if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(ptr))
+ return JSC::jsNull();
+ else
+ result = eng->newVariant(QVariant(type, ptr));
+ }
+ }
+ }
+#endif
+}
+
+// A handle scope and context must be entered
+v8::Local<v8::Script> QV8Engine::qmlModeCompile(const QString &source, const QString &fileName, int lineNumber)
+{
+ v8::Local<v8::String> v8source = m_stringWrapper.toString(source);
+ v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
+
+ v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1));
+
+ v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(),
+ v8::Script::QmlMode);
+
+ return script;
+}
+
+QNetworkAccessManager *QV8Engine::networkAccessManager()
+{
+ return QDeclarativeEnginePrivate::get(m_engine)->getNetworkAccessManager();
+}
+
+const QSet<QString> &QV8Engine::illegalNames() const
+{
+ return m_illegalNames;
+}
+
+// Requires a handle scope
+v8::Local<v8::Array> QV8Engine::getOwnPropertyNames(v8::Handle<v8::Object> o)
+{
+ v8::TryCatch tc;
+ v8::Handle<v8::Value> args[] = { o };
+ v8::Local<v8::Value> r = m_getOwnPropertyNames->Call(global(), 1, args);
+ if (tc.HasCaught())
+ return v8::Array::New();
+ else
+ return v8::Local<v8::Array>::Cast(r);
+}
+
+QDeclarativeContextData *QV8Engine::callingContext()
+{
+ return m_contextWrapper.callingContext();
+}
+
+// Converts a JS value to a QVariant.
+// Null, Undefined -> QVariant() (invalid)
+// Boolean -> QVariant(bool)
+// Number -> QVariant(double)
+// String -> QVariant(QString)
+// Array -> QVariantList(...)
+// Date -> QVariant(QDateTime)
+// RegExp -> QVariant(QRegExp)
+// [Any other object] -> QVariantMap(...)
+QVariant QV8Engine::toBasicVariant(v8::Handle<v8::Value> value)
+{
+ if (value->IsNull() || value->IsUndefined())
+ return QVariant();
+ else if (value->IsBoolean())
+ return value->ToBoolean()->Value();
+ else if (value->IsInt32())
+ return value->ToInt32()->Value();
+ else if (value->IsNumber())
+ return value->ToNumber()->Value();
+ else if (value->IsString())
+ return m_stringWrapper.toString(value->ToString());
+ if (value->IsDate())
+ return qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(value)->NumberValue());
+ // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
+
+ Q_ASSERT(value->IsObject());
+
+ if (value->IsRegExp()) {
+ v8::Context::Scope scope(context());
+ v8::Handle<v8::RegExp> jsRegExp = v8::Handle<v8::RegExp>::Cast(value);
+ // Copied from QtScript
+ // Converts a JS RegExp to a QRegExp.
+ // The conversion is not 100% exact since ECMA regexp and QRegExp
+ // have different semantics/flags, but we try to do our best.
+ QString pattern = toString(jsRegExp->GetSource());
+ Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
+ if (jsRegExp->GetFlags() & v8::RegExp::kIgnoreCase)
+ caseSensitivity = Qt::CaseInsensitive;
+ return QRegExp(pattern, caseSensitivity, QRegExp::RegExp2);
+ } else if (value->IsArray()) {
+ v8::Context::Scope scope(context());
+ QVariantList rv;
+
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ int length = array->Length();
+ for (int ii = 0; ii < length; ++ii)
+ rv << toVariant(array->Get(ii), -1);
+
+ return rv;
+ } else if (!value->IsFunction()) {
+ v8::Context::Scope scope(context());
+ v8::Handle<v8::Object> object = value->ToObject();
+ v8::Local<v8::Array> properties = object->GetPropertyNames();
+ int length = properties->Length();
+ if (length == 0)
+ return QVariant();
+
+ QVariantMap map;
+ for (int ii = 0; ii < length; ++ii) {
+ v8::Handle<v8::Value> property = properties->Get(ii);
+ map.insert(toString(property), toVariant(object->Get(property), -1));
+ }
+ return map;
+ }
+
+ return QVariant();
+}
+
+
+
+#include <QtGui/qvector3d.h>
+
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
+{
+ v8::Local<v8::Function> printFn = V8FUNCTION(print, this);
+
+ v8::Local<v8::Object> console = v8::Object::New();
+ console->Set(v8::String::New("log"), printFn);
+ console->Set(v8::String::New("debug"), printFn);
+
+ // XXX - Qt global object properties
+
+ v8::Local<v8::Object> qt = v8::Object::New();
+
+ // Set all the enums from the "Qt" namespace
+ const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
+ for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
+ QMetaEnum enumerator = qtMetaObject->enumerator(ii);
+ for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
+ qt->Set(v8::String::New(enumerator.key(jj)), v8::Integer::New(enumerator.value(jj)));
+ }
+ }
+
+ if (m_engine)
+ qt->Set(v8::String::New("application"), newQObject(new QDeclarativeApplication(m_engine)));
+
+ qt->Set(v8::String::New("include"), V8FUNCTION(QV8Include::include, this));
+ qt->Set(v8::String::New("isQtObject"), V8FUNCTION(isQtObject, this));
+ qt->Set(v8::String::New("rgba"), V8FUNCTION(rgba, this));
+ qt->Set(v8::String::New("hsla"), V8FUNCTION(hsla, this));
+ qt->Set(v8::String::New("rect"), V8FUNCTION(rect, this));
+ qt->Set(v8::String::New("point"), V8FUNCTION(point, this));
+ qt->Set(v8::String::New("size"), V8FUNCTION(size, this));
+ qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this));
+
+ if (m_engine) {
+ qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this));
+ qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this));
+ qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this));
+ }
+
+ qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this));
+ qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this));
+ qt->Set(v8::String::New("formatDateTime"), V8FUNCTION(formatDateTime, this));
+
+ qt->Set(v8::String::New("openUrlExternally"), V8FUNCTION(openUrlExternally, this));
+ qt->Set(v8::String::New("fontFamilies"), V8FUNCTION(fontFamilies, this));
+ qt->Set(v8::String::New("md5"), V8FUNCTION(md5, this));
+ qt->Set(v8::String::New("btoa"), V8FUNCTION(btoa, this));
+ qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this));
+ qt->Set(v8::String::New("quit"), V8FUNCTION(quit, this));
+ qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this));
+
+ if (m_engine) {
+ qt->Set(v8::String::New("createQmlObject"), V8FUNCTION(createQmlObject, this));
+ qt->Set(v8::String::New("createComponent"), V8FUNCTION(createComponent, this));
+ }
+
+ // XXX translator functions
+
+ global->Set(v8::String::New("print"), printFn);
+ global->Set(v8::String::New("console"), console);
+ global->Set(v8::String::New("Qt"), qt);
+
+ // XXX mainthread only
+ m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this);
+ m_sqlDatabaseData = qt_add_qmlsqldatabase(this);
+
+ {
+ v8::Handle<v8::Value> args[] = { global };
+ v8::Local<v8::Value> names = m_getOwnPropertyNames->Call(global, 1, args);
+ v8::Local<v8::Array> namesArray = v8::Local<v8::Array>::Cast(names);
+ for (quint32 ii = 0; ii < namesArray->Length(); ++ii)
+ m_illegalNames.insert(toString(namesArray->Get(ii)));
+ }
+}
+
+void QV8Engine::freezeGlobal()
+{
+ // Freeze the global object
+ // XXX I don't think this is sufficient as it misses non-enumerable properties
+#define FREEZE "(function freeze_recur(obj) { "\
+ " if (Qt.isQtObject(obj)) return;"\
+ " for (var prop in obj) { " \
+ " if (prop == \"connect\" || prop == \"disconnect\") {" \
+ " Object.freeze(obj[prop]); "\
+ " continue;" \
+ " }" \
+ " freeze_recur(obj[prop]);" \
+ " }" \
+ " if (obj instanceof Object) {" \
+ " Object.freeze(obj);" \
+ " }"\
+ "})(this);"
+ v8::Local<v8::Script> test = v8::Script::New(v8::String::New(FREEZE));
+#undef FREEZE
+
+ test->Run();
+}
+
+v8::Handle<v8::Value> QV8Engine::print(const v8::Arguments &args)
+{
+ QString result;
+ for (int i = 0; i < args.Length(); ++i) {
+ if (i != 0)
+ result.append(QLatin1Char(' '));
+
+ v8::Local<v8::String> jsstr = args[i]->ToString();
+ if (!jsstr.IsEmpty()) {
+ QString qstr;
+ qstr.resize(jsstr->Length());
+ jsstr->Write((uint16_t*)qstr.data());
+ result.append(qstr);
+ }
+ }
+ qDebug("%s", qPrintable(result));
+ return v8::Undefined();
+}
+
+/*!
+\qmlmethod bool Qt::isQtObject(object)
+Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
+*/
+v8::Handle<v8::Value> QV8Engine::isQtObject(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ return v8::Boolean::New(false);
+
+ return v8::Boolean::New(0 != V8ENGINE()->toQObject(args[0]));
+}
+
+/*!
+\qmlmethod color Qt::rgba(real red, real green, real blue, real alpha)
+
+Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
+All components should be in the range 0-1 inclusive.
+*/
+v8::Handle<v8::Value> QV8Engine::rgba(const v8::Arguments &args)
+{
+ int argCount = args.Length();
+ if (argCount < 3 || argCount > 4)
+ V8THROW_ERROR("Qt.rgba(): Invalid arguments");
+
+ double r = args[0]->NumberValue();
+ double g = args[1]->NumberValue();
+ double b = args[2]->NumberValue();
+ double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+
+ if (r < 0.0) r=0.0;
+ if (r > 1.0) r=1.0;
+ if (g < 0.0) g=0.0;
+ if (g > 1.0) g=1.0;
+ if (b < 0.0) b=0.0;
+ if (b > 1.0) b=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromRgbF(r, g, b, a)));
+}
+
+/*!
+\qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha)
+
+Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
+All components should be in the range 0-1 inclusive.
+*/
+v8::Handle<v8::Value> QV8Engine::hsla(const v8::Arguments &args)
+{
+ int argCount = args.Length();
+ if (argCount < 3 || argCount > 4)
+ V8THROW_ERROR("Qt.hsla(): Invalid arguments");
+
+ double h = args[0]->NumberValue();
+ double s = args[1]->NumberValue();
+ double l = args[2]->NumberValue();
+ double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+
+ if (h < 0.0) h=0.0;
+ if (h > 1.0) h=1.0;
+ if (s < 0.0) s=0.0;
+ if (s > 1.0) s=1.0;
+ if (l < 0.0) l=0.0;
+ if (l > 1.0) l=1.0;
+ if (a < 0.0) a=0.0;
+ if (a > 1.0) a=1.0;
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QColor::fromHslF(h, s, l, a)));
+}
+
+/*!
+\qmlmethod rect Qt::rect(int x, int y, int width, int height)
+
+Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height.
+
+The returned object has \c x, \c y, \c width and \c height attributes with the given values.
+*/
+v8::Handle<v8::Value> QV8Engine::rect(const v8::Arguments &args)
+{
+ if (args.Length() != 4)
+ V8THROW_ERROR("Qt.rect(): Invalid arguments");
+
+ double x = args[0]->NumberValue();
+ double y = args[1]->NumberValue();
+ double w = args[2]->NumberValue();
+ double h = args[3]->NumberValue();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+}
+
+/*!
+\qmlmethod point Qt::point(int x, int y)
+Returns a Point with the specified \c x and \c y coordinates.
+*/
+v8::Handle<v8::Value> QV8Engine::point(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.point(): Invalid arguments");
+
+ double x = args[0]->ToNumber()->Value();
+ double y = args[1]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QPointF(x, y)));
+}
+
+/*!
+\qmlmethod Qt::size(int width, int height)
+Returns a Size with the specified \c width and \c height.
+*/
+v8::Handle<v8::Value> QV8Engine::size(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.size(): Invalid arguments");
+
+ double w = args[0]->ToNumber()->Value();
+ double h = args[1]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+}
+
+/*!
+\qmlmethod Qt::vector3d(real x, real y, real z)
+Returns a Vector3D with the specified \c x, \c y and \c z.
+*/
+v8::Handle<v8::Value> QV8Engine::vector3d(const v8::Arguments &args)
+{
+ if (args.Length() != 3)
+ V8THROW_ERROR("Qt.vector(): Invalid arguments");
+
+ double x = args[0]->ToNumber()->Value();
+ double y = args[1]->ToNumber()->Value();
+ double z = args[2]->ToNumber()->Value();
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(QVector3D(x, y, z)));
+}
+
+/*!
+\qmlmethod color Qt::lighter(color baseColor, real factor)
+Returns a color lighter than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this functions returns a lighter color.
+Setting factor to 1.5 returns a color that is 50% brighter. If the factor is less than 1.0,
+the return color is darker, but we recommend using the Qt.darker() function for this purpose.
+If the factor is 0 or negative, the return value is unspecified.
+
+The function converts the current RGB color to HSV, multiplies the value (V) component
+by factor and converts the color back to RGB.
+
+If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
+*/
+v8::Handle<v8::Value> QV8Engine::lighter(const v8::Arguments &args)
+{
+ if (args.Length() != 1 && args.Length() != 2)
+ V8THROW_ERROR("Qt.lighter(): Invalid arguments");
+
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ qreal factor = 1.5;
+ if (args.Length() == 2)
+ factor = args[1]->ToNumber()->Value();
+
+ color = color.lighter(int(qRound(factor*100.)));
+ return V8ENGINE()->fromVariant(QVariant::fromValue(color));
+}
+
+/*!
+\qmlmethod color Qt::darker(color baseColor, real factor)
+Returns a color darker than \c baseColor by the \c factor provided.
+
+If the factor is greater than 1.0, this function returns a darker color.
+Setting factor to 3.0 returns a color that has one-third the brightness.
+If the factor is less than 1.0, the return color is lighter, but we recommend using
+the Qt.lighter() function for this purpose. If the factor is 0 or negative, the return
+value is unspecified.
+
+The function converts the current RGB color to HSV, divides the value (V) component
+by factor and converts the color back to RGB.
+
+If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
+*/
+v8::Handle<v8::Value> QV8Engine::darker(const v8::Arguments &args)
+{
+ if (args.Length() != 1 && args.Length() != 2)
+ V8THROW_ERROR("Qt.darker(): Invalid arguments");
+
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ qreal factor = 2.0;
+ if (args.Length() == 2)
+ factor = args[1]->ToNumber()->Value();
+
+ color = color.darker(int(qRound(factor*100.)));
+ return V8ENGINE()->fromVariant(QVariant::fromValue(color));
+}
+
+/*!
+ \qmlmethod color Qt::tint(color baseColor, color tintColor)
+ This function allows tinting one color with another.
+
+ The tint color should usually be mostly transparent, or you will not be
+ able to see the underlying color. The below example provides a slight red
+ tint by having the tint color be pure red which is only 1/16th opaque.
+
+ \qml
+ Item {
+ Rectangle {
+ x: 0; width: 80; height: 80
+ color: "lightsteelblue"
+ }
+ Rectangle {
+ x: 100; width: 80; height: 80
+ color: Qt.tint("lightsteelblue", "#10FF0000")
+ }
+ }
+ \endqml
+ \image declarative-rect_tint.png
+
+ Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
+*/
+v8::Handle<v8::Value> QV8Engine::tint(const v8::Arguments &args)
+{
+ if (args.Length() != 2)
+ V8THROW_ERROR("Qt.tint(): Invalid arguments");
+
+ // base color
+ QColor color;
+ QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ if (v.userType() == QVariant::Color) {
+ color = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ color = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ // tint color
+ QColor tintColor;
+ v = V8ENGINE()->toVariant(args[1], -1);
+ if (v.userType() == QVariant::Color) {
+ tintColor = v.value<QColor>();
+ } else if (v.userType() == QVariant::String) {
+ bool ok = false;
+ tintColor = QDeclarativeStringConverters::colorFromString(v.toString(), &ok);
+ if (!ok) {
+ return v8::Null();
+ }
+ } else {
+ return v8::Null();
+ }
+
+ // tint the base color and return the final color
+ QColor finalColor;
+ int a = tintColor.alpha();
+ if (a == 0xFF)
+ finalColor = tintColor;
+ else if (a == 0x00)
+ finalColor = color;
+ else {
+ qreal a = tintColor.alphaF();
+ qreal inv_a = 1.0 - a;
+
+ finalColor.setRgbF(tintColor.redF() * a + color.redF() * inv_a,
+ tintColor.greenF() * a + color.greenF() * inv_a,
+ tintColor.blueF() * a + color.blueF() * inv_a,
+ a + inv_a * color.alphaF());
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(finalColor));
+}
+
+/*!
+\qmlmethod string Qt::formatDate(datetime date, variant format)
+
+Returns a string representation of \c date, optionally formatted according
+to \c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, or QDateTime value. The \a format parameter may be any of
+the possible format values as described for
+\l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a date is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+*/
+v8::Handle<v8::Value> QV8Engine::formatDate(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatDate(): Invalid arguments");
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QDate date = V8ENGINE()->toVariant(args[0], -1).toDateTime().date();
+ QString formattedDate;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedDate = date.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedDate = date.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatDate(): Invalid date format");
+ }
+ } else {
+ formattedDate = date.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDate));
+}
+
+/*!
+\qmlmethod string Qt::formatTime(datetime time, variant format)
+
+Returns a string representation of \c time, optionally formatted according to
+\c format.
+
+The \a time parameter may be a JavaScript \c Date object, a QTime, or QDateTime
+value. The \a format parameter may be any of the possible format values as
+described for \l{QML:Qt::formatDateTime()}{Qt.formatDateTime()}.
+
+If \a format is not specified, \a time is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}.
+*/
+v8::Handle<v8::Value> QV8Engine::formatTime(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatTime(): Invalid arguments");
+
+ QVariant argVariant = V8ENGINE()->toVariant(args[0], -1);
+ QTime time;
+ if (args[0]->IsDate() || (argVariant.type() == QVariant::String))
+ time = argVariant.toDateTime().time();
+ else // if (argVariant.type() == QVariant::Time), or invalid.
+ time = argVariant.toTime();
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QString formattedTime;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedTime = time.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedTime = time.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatTime(): Invalid time format");
+ }
+ } else {
+ formattedTime = time.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedTime));
+}
+
+/*!
+\qmlmethod string Qt::formatDateTime(datetime dateTime, variant format)
+
+Returns a string representation of \c datetime, optionally formatted according to
+\c format.
+
+The \a date parameter may be a JavaScript \c Date object, a \l{date}{date}
+property, a QDate, QTime, or QDateTime value.
+
+If \a format is not provided, \a dateTime is formatted using
+\l {Qt::DefaultLocaleShortDate}{Qt.DefaultLocaleShortDate}. Otherwise,
+\a format should be either:
+
+\list
+\o One of the Qt::DateFormat enumeration values, such as
+ \c Qt.DefaultLocaleShortDate or \c Qt.ISODate
+\o A string that specifies the format of the returned string, as detailed below.
+\endlist
+
+If \a format specifies a format string, it should use the following expressions
+to specify the date:
+
+ \table
+ \header \i Expression \i Output
+ \row \i d \i the day as number without a leading zero (1 to 31)
+ \row \i dd \i the day as number with a leading zero (01 to 31)
+ \row \i ddd
+ \i the abbreviated localized day name (e.g. 'Mon' to 'Sun').
+ Uses QDate::shortDayName().
+ \row \i dddd
+ \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday').
+ Uses QDate::longDayName().
+ \row \i M \i the month as number without a leading zero (1-12)
+ \row \i MM \i the month as number with a leading zero (01-12)
+ \row \i MMM
+ \i the abbreviated localized month name (e.g. 'Jan' to 'Dec').
+ Uses QDate::shortMonthName().
+ \row \i MMMM
+ \i the long localized month name (e.g. 'January' to 'December').
+ Uses QDate::longMonthName().
+ \row \i yy \i the year as two digit number (00-99)
+ \row \i yyyy \i the year as four digit number
+ \endtable
+
+In addition the following expressions can be used to specify the time:
+
+ \table
+ \header \i Expression \i Output
+ \row \i h
+ \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
+ \row \i hh
+ \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \i m \i the minute without a leading zero (0 to 59)
+ \row \i mm \i the minute with a leading zero (00 to 59)
+ \row \i s \i the second without a leading zero (0 to 59)
+ \row \i ss \i the second with a leading zero (00 to 59)
+ \row \i z \i the milliseconds without leading zeroes (0 to 999)
+ \row \i zzz \i the milliseconds with leading zeroes (000 to 999)
+ \row \i AP
+ \i use AM/PM display. \e AP will be replaced by either "AM" or "PM".
+ \row \i ap
+ \i use am/pm display. \e ap will be replaced by either "am" or "pm".
+ \endtable
+
+ All other input characters will be ignored. Any sequence of characters that
+ are enclosed in single quotes will be treated as text and not be used as an
+ expression. Two consecutive single quotes ("''") are replaced by a single quote
+ in the output.
+
+For example, if the following date/time value was specified:
+
+ \code
+ // 21 May 2001 14:13:09
+ var dateTime = new Date(2001, 5, 21, 14, 13, 09)
+ \endcode
+
+This \a dateTime value could be passed to \c Qt.formatDateTime(),
+\l {QML:Qt::formatDate()}{Qt.formatDate()} or \l {QML:Qt::formatTime()}{Qt.formatTime()}
+with the \a format values below to produce the following results:
+
+ \table
+ \header \i Format \i Result
+ \row \i "dd.MM.yyyy" \i 21.05.2001
+ \row \i "ddd MMMM d yy" \i Tue May 21 01
+ \row \i "hh:mm:ss.zzz" \i 14:13:09.042
+ \row \i "h:m:s ap" \i 2:13:9 pm
+ \endtable
+*/
+v8::Handle<v8::Value> QV8Engine::formatDateTime(const v8::Arguments &args)
+{
+ if (args.Length() < 1 || args.Length() > 2)
+ V8THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
+
+ Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
+ QDateTime dt = V8ENGINE()->toVariant(args[0], -1).toDateTime();
+ QString formattedDt;
+ if (args.Length() == 2) {
+ if (args[1]->IsString()) {
+ QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ formattedDt = dt.toString(format);
+ } else if (args[1]->IsNumber()) {
+ quint32 intFormat = args[1]->ToNumber()->Value();
+ Qt::DateFormat format = Qt::DateFormat(intFormat);
+ formattedDt = dt.toString(format);
+ } else {
+ V8THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
+ }
+ } else {
+ formattedDt = dt.toString(enumFormat);
+ }
+
+ return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDt));
+}
+
+double QV8Engine::qtDateTimeToJsDate(const QDateTime &dt)
+{
+ // from QScriptEngine::DateTimeToMs()
+ if (!dt.isValid()) {
+ return qSNaN();
+ }
+ QDateTime utc = dt.toUTC();
+ QDate date = utc.date();
+ QTime time = utc.time();
+ QV8DateConverter::JSC::GregorianDateTime tm;
+ tm.year = date.year() - 1900;
+ tm.month = date.month() - 1;
+ tm.monthDay = date.day();
+ tm.weekDay = date.dayOfWeek();
+ tm.yearDay = date.dayOfYear();
+ tm.hour = time.hour();
+ tm.minute = time.minute();
+ tm.second = time.second();
+ return QV8DateConverter::JSC::gregorianDateTimeToMS(tm, time.msec());
+}
+
+QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate)
+{
+ // from QScriptEngine::MsToDateTime()
+ if (qIsNaN(jsDate))
+ return QDateTime();
+ QV8DateConverter::JSC::GregorianDateTime tm;
+ QV8DateConverter::JSC::msToGregorianDateTime(jsDate, tm);
+
+ // from QScriptEngine::MsFromTime()
+ int ms = int(::fmod(jsDate, 1000.0));
+ if (ms < 0)
+ ms += int(1000.0);
+
+ QDateTime convertedUTC = QDateTime(QDate(tm.year + 1900, tm.month + 1, tm.monthDay),
+ QTime(tm.hour, tm.minute, tm.second, ms), Qt::UTC);
+ return convertedUTC.toLocalTime();
+}
+
+/*!
+\qmlmethod bool Qt::openUrlExternally(url target)
+Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
+*/
+v8::Handle<v8::Value> QV8Engine::openUrlExternally(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ return V8ENGINE()->fromVariant(false);
+
+ bool ret = false;
+#ifndef QT_NO_DESKTOPSERVICES
+ ret = QDesktopServices::openUrl(V8ENGINE()->toVariant(resolvedUrl(args), -1).toUrl());
+#endif
+ return V8ENGINE()->fromVariant(ret);
+}
+
+/*!
+ \qmlmethod url Qt::resolvedUrl(url url)
+ Returns \a url resolved relative to the URL of the caller.
+*/
+v8::Handle<v8::Value> QV8Engine::resolvedUrl(const v8::Arguments &args)
+{
+ QUrl url = V8ENGINE()->toVariant(args[0], -1).toUrl();
+ // XXX uses QDeclarativeEngine which means it wont work in worker script?
+ QDeclarativeEngine *e = V8ENGINE()->engine();
+ QDeclarativeEnginePrivate *p = 0;
+ if (e) p = QDeclarativeEnginePrivate::get(e);
+ if (p) {
+ QDeclarativeContextData *ctxt = V8ENGINE()->callingContext();
+ if (ctxt)
+ return V8ENGINE()->fromVariant(ctxt->resolvedUrl(url));
+ else
+ return V8ENGINE()->fromVariant(url);
+ }
+
+ return V8ENGINE()->fromVariant(e->baseUrl().resolved(url));
+}
+
+/*!
+\qmlmethod list<string> Qt::fontFamilies()
+Returns a list of the font families available to the application.
+*/
+v8::Handle<v8::Value> QV8Engine::fontFamilies(const v8::Arguments &args)
+{
+ if (args.Length() != 0)
+ V8THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
+
+ QFontDatabase database;
+ return V8ENGINE()->fromVariant(database.families());
+}
+
+/*!
+\qmlmethod string Qt::md5(data)
+Returns a hex string of the md5 hash of \c data.
+*/
+v8::Handle<v8::Value> QV8Engine::md5(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.md5(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+ QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
+ return V8ENGINE()->toString(QLatin1String(result.toHex()));
+}
+
+/*!
+\qmlmethod string Qt::btoa(data)
+Binary to ASCII - this function returns a base64 encoding of \c data.
+*/
+v8::Handle<v8::Value> QV8Engine::btoa(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.btoa(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+
+ return V8ENGINE()->toString(QLatin1String(data.toBase64()));
+}
+
+/*!
+\qmlmethod string Qt::atob(data)
+ASCII to binary - this function returns a base64 decoding of \c data.
+*/
+v8::Handle<v8::Value> QV8Engine::atob(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.atob(): Invalid arguments");
+
+ QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+
+ return V8ENGINE()->toString(QLatin1String(QByteArray::fromBase64(data)));
+}
+
+/*!
+\qmlmethod Qt::quit()
+This function causes the QDeclarativeEngine::quit() signal to be emitted.
+Within the \l {QML Viewer}, this causes the launcher application to exit;
+to quit a C++ application when this method is called, connect the
+QDeclarativeEngine::quit() signal to the QCoreApplication::quit() slot.
+*/
+v8::Handle<v8::Value> QV8Engine::quit(const v8::Arguments &args)
+{
+ // XXX worker script?
+ QDeclarativeEnginePrivate::get(V8ENGINE()->engine())->sendQuit();
+ return v8::Undefined();
+}
+
+/*!
+\qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath)
+
+Returns a new object created from the given \a string of QML which will have the specified \a parent,
+or \c null if there was an error in creating the object.
+
+If \a filepath is specified, it will be used for error reporting for the created object.
+
+Example (where \c parentItem is the id of an existing QML item):
+
+\snippet doc/src/snippets/declarative/createQmlObject.qml 0
+
+In the case of an error, a QtScript Error object is thrown. This object has an additional property,
+\c qmlErrors, which is an array of the errors encountered.
+Each object in this array has the members \c lineNumber, \c columnNumber, \c fileName and \c message.
+For example, if the above snippet had misspelled color as 'colro' then the array would contain an object like the following:
+{ "lineNumber" : 1, "columnNumber" : 32, "fileName" : "dynamicSnippet1", "message" : "Cannot assign to non-existent property \"colro\""}.
+
+Note that this function returns immediately, and therefore may not work if
+the \a qml string loads new components (that is, external QML files that have not yet been loaded).
+If this is the case, consider using \l{QML:Qt::createComponent()}{Qt.createComponent()} instead.
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+*/
+v8::Handle<v8::Value> QV8Engine::createQmlObject(const v8::Arguments &args)
+{
+ if (args.Length() < 2 || args.Length() > 3)
+ V8THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
+
+ struct Error {
+ static v8::Local<v8::Value> create(QV8Engine *engine, const QList<QDeclarativeError> &errors) {
+ QString errorstr = QLatin1String("Qt.createQmlObject(): failed to create object: ");
+
+ v8::Local<v8::Array> qmlerrors = v8::Array::New(errors.count());
+ for (int ii = 0; ii < errors.count(); ++ii) {
+ const QDeclarativeError &error = errors.at(ii);
+ errorstr += QLatin1String("\n ") + error.toString();
+ v8::Local<v8::Object> qmlerror = v8::Object::New();
+ qmlerror->Set(v8::String::New("lineNumber"), v8::Integer::New(error.line()));
+ qmlerror->Set(v8::String::New("columnNumber"), v8::Integer::New(error.line()));
+ qmlerror->Set(v8::String::New("fileName"), engine->toString(error.url().toString()));
+ qmlerror->Set(v8::String::New("message"), engine->toString(error.description()));
+ qmlerrors->Set(ii, qmlerror);
+ }
+
+ v8::Local<v8::Value> error = v8::Exception::Error(engine->toString(errorstr));
+ v8::Local<v8::Object> errorObject = error->ToObject();
+ errorObject->Set(v8::String::New("qmlErrors"), qmlerrors);
+ return error;
+ }
+ };
+
+ QV8Engine *v8engine = V8ENGINE();
+ QDeclarativeEngine *engine = v8engine->engine();
+
+ QDeclarativeContextData *context = v8engine->callingContext();
+ Q_ASSERT(context);
+
+ QString qml = v8engine->toString(args[0]->ToString());
+ if (qml.isEmpty())
+ return v8::Null();
+
+ QUrl url;
+ if(args.Length() > 2)
+ url = QUrl(v8engine->toString(args[2]->ToString()));
+ else
+ url = QUrl(QLatin1String("inline"));
+
+ if (url.isValid() && url.isRelative())
+ url = context->resolvedUrl(url);
+
+ QObject *parentArg = v8engine->toQObject(args[1]);
+ if(!parentArg)
+ V8THROW_ERROR("Qt.createQmlObject(): Missing parent object");
+
+ QDeclarativeComponent component(engine);
+ component.setData(qml.toUtf8(), url);
+
+ if(component.isError()) {
+ v8::ThrowException(Error::create(v8engine, component.errors()));
+ return v8::Undefined();
+ }
+
+ if (!component.isReady())
+ V8THROW_ERROR("Qt.createQmlObject(): Component is not ready");
+
+ QObject *obj = component.beginCreate(context->asQDeclarativeContext());
+ if(obj)
+ QDeclarativeData::get(obj, true)->setImplicitDestructible();
+ component.completeCreate();
+
+ if(component.isError()) {
+ v8::ThrowException(Error::create(v8engine, component.errors()));
+ return v8::Undefined();
+ }
+
+ Q_ASSERT(obj);
+
+ obj->setParent(parentArg);
+
+ QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
+ for (int ii = 0; ii < functions.count(); ++ii) {
+ if (QDeclarativePrivate::Parented == functions.at(ii)(obj, parentArg))
+ break;
+ }
+
+ return v8engine->newQObject(obj);
+}
+
+/*!
+\qmlmethod object Qt::createComponent(url)
+
+Returns a \l Component object created using the QML file at the specified \a url,
+or \c null if an empty string was given.
+
+The returned component's \l Component::status property indicates whether the
+component was successfully created. If the status is \c Component.Error,
+see \l Component::errorString() for an error description.
+
+Call \l {Component::createObject()}{Component.createObject()} on the returned
+component to create an object instance of the component.
+
+For example:
+
+\snippet doc/src/snippets/declarative/createComponent-simple.qml 0
+
+See \l {Dynamic Object Management in QML} for more information on using this function.
+
+To create a QML object from an arbitrary string of QML (instead of a file),
+use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}.
+*/
+v8::Handle<v8::Value> QV8Engine::createComponent(const v8::Arguments &args)
+{
+ if (args.Length() != 1)
+ V8THROW_ERROR("Qt.createComponent(): Invalid arguments");
+
+ QV8Engine *v8engine = V8ENGINE();
+ QDeclarativeEngine *engine = v8engine->engine();
+
+ QDeclarativeContextData *context = v8engine->callingContext();
+ Q_ASSERT(context);
+
+ QString arg = v8engine->toString(args[0]->ToString());
+ if (arg.isEmpty())
+ return v8::Null();
+
+ QUrl url = context->resolvedUrl(QUrl(arg));
+ QDeclarativeComponent *c = new QDeclarativeComponent(engine, url, engine);
+ QDeclarativeComponentPrivate::get(c)->creationContext = context;
+ QDeclarativeData::get(c, true)->setImplicitDestructible();
+ return v8engine->newQObject(c);
+}
+
+QT_END_NAMESPACE
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDECLARATIVEV8ENGINE_P_H
+#define QDECLARATIVEV8ENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qset.h>
+#include <private/qv8_p.h>
+
+#include <private/qdeclarativepropertycache_p.h>
+
+#include "qv8contextwrapper_p.h"
+#include "qv8qobjectwrapper_p.h"
+#include "qv8stringwrapper_p.h"
+#include "qv8typewrapper_p.h"
+#include "qv8listwrapper_p.h"
+#include "qv8variantwrapper_p.h"
+#include "qv8valuetypewrapper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#define V8_RESOURCE_TYPE(resourcetype) \
+public: \
+ enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
+ virtual QV8ObjectResource::ResourceType resourceType() const { return QV8ObjectResource:: resourcetype; } \
+private:
+
+#define V8ENGINE() ((QV8Engine *)v8::External::Unwrap(args.Data()))
+#define V8FUNCTION(function, engine) v8::FunctionTemplate::New(function, v8::External::Wrap((QV8Engine*)engine))->GetFunction()
+// XXX Are we mean to return a value here, or is an empty handle ok?
+#define V8THROW_ERROR(string) { \
+ v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
+ return v8::Handle<v8::Value>(); \
+}
+
+class QV8Engine;
+class QV8ObjectResource : public v8::Object::ExternalResource
+{
+public:
+ QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
+ enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType,
+ ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType };
+ virtual ResourceType resourceType() const = 0;
+
+ QV8Engine *engine;
+};
+
+template<class T>
+T *v8_resource_cast(v8::Handle<v8::Object> object) {
+ QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
+ return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
+}
+
+// Used to allow a QObject method take and return raw V8 handles without having to expose
+// v8 in the public API.
+// Use like this:
+// class MyClass : public QObject {
+// Q_OBJECT
+// ...
+// Q_INVOKABLE void myMethod(QDeclarativeV8Function*);
+// };
+// The QDeclarativeV8Function - and consequently the arguments and return value - only remains
+// valid during the call. If the return value isn't set within myMethod(), the will return
+// undefined.
+class QV8Engine;
+class QDeclarativeV8Function
+{
+public:
+ int Length() const { return _ac; }
+ v8::Local<v8::Value> operator[](int idx) { return (*_a)->Get(idx); }
+ QDeclarativeContextData *context() { return _c; }
+ v8::Handle<v8::Object> qmlGlobal() { return *_g; }
+ void returnValue(v8::Handle<v8::Value> rv) { *_r = rv; }
+ QV8Engine *engine() const { return _e; }
+private:
+ friend class QV8QObjectWrapper;
+ QDeclarativeV8Function();
+ QDeclarativeV8Function(const QDeclarativeV8Function &);
+ QDeclarativeV8Function &operator=(const QDeclarativeV8Function &);
+
+ QDeclarativeV8Function(int length, v8::Handle<v8::Object> &args,
+ v8::Handle<v8::Value> &rv, v8::Handle<v8::Object> &global,
+ QDeclarativeContextData *c, QV8Engine *e)
+ : _ac(length), _a(&args), _r(&rv), _g(&global), _c(c), _e(e) {}
+
+ int _ac;
+ v8::Handle<v8::Object> *_a;
+ v8::Handle<v8::Value> *_r;
+ v8::Handle<v8::Object> *_g;
+ QDeclarativeContextData *_c;
+ QV8Engine *_e;
+};
+
+class QDeclarativeV8Handle
+{
+public:
+ QDeclarativeV8Handle() : d(0) {}
+ QDeclarativeV8Handle(const QDeclarativeV8Handle &other) : d(other.d) {}
+ QDeclarativeV8Handle &operator=(const QDeclarativeV8Handle &other) { d = other.d; return *this; }
+
+ static QDeclarativeV8Handle fromHandle(v8::Handle<v8::Value> h) {
+ return reinterpret_cast<QDeclarativeV8Handle &>(h);
+ }
+ v8::Handle<v8::Value> toHandle() const {
+ return reinterpret_cast<const v8::Handle<v8::Value> &>(*this);
+ }
+private:
+ void *d;
+};
+
+class QObject;
+class QDeclarativeEngine;
+class QDeclarativeValueType;
+class QNetworkAccessManager;
+class QDeclarativeContextData;
+class Q_AUTOTEST_EXPORT QV8Engine
+{
+public:
+ QV8Engine();
+ ~QV8Engine();
+
+ void init(QDeclarativeEngine *);
+
+ QDeclarativeEngine *engine() { return m_engine; }
+ v8::Local<v8::Object> global() { return m_context->Global(); }
+ v8::Handle<v8::Context> context() { return m_context; }
+ QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
+ QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
+ QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
+ QV8ListWrapper *listWrapper() { return &m_listWrapper; }
+ QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
+
+ void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
+ void *sqlDatabaseData() { return m_sqlDatabaseData; }
+
+ QDeclarativeContextData *callingContext();
+
+ v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
+
+ inline QString toString(v8::Handle<v8::Value> string);
+ inline QString toString(v8::Handle<v8::String> string);
+ static QString toStringStatic(v8::Handle<v8::Value>);
+ static QString toStringStatic(v8::Handle<v8::String>);
+ static inline bool startsWithUpper(v8::Handle<v8::String>);
+
+ QVariant toVariant(v8::Handle<v8::Value>, int typeHint);
+ v8::Handle<v8::Value> fromVariant(const QVariant &);
+ inline bool isVariant(v8::Handle<v8::Value>);
+
+ // Compile \a source (from \a fileName at \a lineNumber) in QML mode
+ v8::Local<v8::Script> qmlModeCompile(const QString &source,
+ const QString &fileName = QString(),
+ int lineNumber = 1);
+
+ // Return the QML global "scope" object for the \a ctxt context and \a scope object.
+ inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
+
+ // Return a JS wrapper for the given QObject \a object
+ inline v8::Handle<v8::Value> newQObject(QObject *object);
+ inline bool isQObject(v8::Handle<v8::Value>);
+ inline QObject *toQObject(v8::Handle<v8::Value>);
+
+ // Return a JS string for the given QString \a string
+ inline v8::Local<v8::String> toString(const QString &string);
+
+ // Create a new value type object
+ inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *);
+ inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *);
+
+ // Create a new QVariant object. This doesn't examine the type of the variant, but always returns
+ // a QVariant wrapper
+ inline v8::Handle<v8::Value> newQVariant(const QVariant &);
+
+ // Return the network access manager for this engine. By default this returns the network
+ // access manager of the QDeclarativeEngine. It is overridden in the case of a threaded v8
+ // instance (like in WorkerScript).
+ virtual QNetworkAccessManager *networkAccessManager();
+
+ // Return the list of illegal id names (the names of the properties on the global object)
+ const QSet<QString> &illegalNames() const;
+
+private:
+ QDeclarativeEngine *m_engine;
+ v8::Persistent<v8::Context> m_context;
+
+ QV8StringWrapper m_stringWrapper;
+ QV8ContextWrapper m_contextWrapper;
+ QV8QObjectWrapper m_qobjectWrapper;
+ QV8TypeWrapper m_typeWrapper;
+ QV8ListWrapper m_listWrapper;
+ QV8VariantWrapper m_variantWrapper;
+ QV8ValueTypeWrapper m_valueTypeWrapper;
+
+ v8::Persistent<v8::Function> m_getOwnPropertyNames;
+
+ void *m_xmlHttpRequestData;
+ void *m_sqlDatabaseData;
+
+ QSet<QString> m_illegalNames;
+
+ QVariant toBasicVariant(v8::Handle<v8::Value>);
+
+ void initializeGlobal(v8::Handle<v8::Object>);
+ void freezeGlobal();
+
+ static v8::Handle<v8::Value> print(const v8::Arguments &args);
+ static v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
+ static v8::Handle<v8::Value> rgba(const v8::Arguments &args);
+ static v8::Handle<v8::Value> hsla(const v8::Arguments &args);
+ static v8::Handle<v8::Value> rect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> point(const v8::Arguments &args);
+ static v8::Handle<v8::Value> size(const v8::Arguments &args);
+ static v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
+ static v8::Handle<v8::Value> lighter(const v8::Arguments &args);
+ static v8::Handle<v8::Value> darker(const v8::Arguments &args);
+ static v8::Handle<v8::Value> tint(const v8::Arguments &args);
+ static v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
+ static v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
+ static v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
+ static v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
+ static v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
+ static v8::Handle<v8::Value> md5(const v8::Arguments &args);
+ static v8::Handle<v8::Value> btoa(const v8::Arguments &args);
+ static v8::Handle<v8::Value> atob(const v8::Arguments &args);
+ static v8::Handle<v8::Value> quit(const v8::Arguments &args);
+ static v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
+ static v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
+ static v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
+
+ double qtDateTimeToJsDate(const QDateTime &dt);
+ QDateTime qtDateTimeFromJsDate(double jsDate);
+};
+
+QString QV8Engine::toString(v8::Handle<v8::Value> string)
+{
+ return m_stringWrapper.toString(string->ToString());
+}
+
+QString QV8Engine::toString(v8::Handle<v8::String> string)
+{
+ return m_stringWrapper.toString(string);
+}
+
+bool QV8Engine::isVariant(v8::Handle<v8::Value> value)
+{
+ return m_variantWrapper.isVariant(value);
+}
+
+v8::Local<v8::Object> QV8Engine::qmlScope(QDeclarativeContextData *ctxt, QObject *scope)
+{
+ return m_contextWrapper.qmlScope(ctxt, scope);
+}
+
+bool QV8Engine::isQObject(v8::Handle<v8::Value> obj)
+{
+ return obj->IsObject()?m_qobjectWrapper.isQObject(v8::Handle<v8::Object>::Cast(obj)):false;
+}
+
+QObject *QV8Engine::toQObject(v8::Handle<v8::Value> obj)
+{
+ return obj->IsObject()?m_qobjectWrapper.toQObject(v8::Handle<v8::Object>::Cast(obj)):0;
+}
+
+v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
+{
+ return m_qobjectWrapper.newQObject(object);
+}
+
+v8::Local<v8::String> QV8Engine::toString(const QString &string)
+{
+ return m_stringWrapper.toString(string);
+}
+
+v8::Handle<v8::Value> QV8Engine::newValueType(QObject *object, int property, QDeclarativeValueType *type)
+{
+ return m_valueTypeWrapper.newValueType(object, property, type);
+}
+
+v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativeValueType *type)
+{
+ return m_valueTypeWrapper.newValueType(value, type);
+}
+
+// XXX perf?
+bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
+{
+ uint16_t buffer[2];
+ int written = string->Write(buffer, 0, 1);
+ if (written == 0) return false;
+ uint16_t c = buffer[0];
+ return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
+ ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
+}
+
+QT_END_NAMESPACE
+
+#endif // QDECLARATIVEV8ENGINE_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8include_p.h"
+
+#include <QtScript/qscriptengine.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qfile.h>
+
+#include <private/qdeclarativeengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QV8Include::QV8Include(const QUrl &url, QV8Engine *engine, QDeclarativeContextData *context,
+ v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Function> callback)
+: m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context)
+{
+ m_qmlglobal = v8::Persistent<v8::Object>::New(qmlglobal);
+ if (!callback.IsEmpty())
+ m_callbackFunction = v8::Persistent<v8::Function>::New(callback);
+
+ m_resultObject = v8::Persistent<v8::Object>::New(resultValue());
+
+ m_network = engine->networkAccessManager();
+
+ QNetworkRequest request;
+ request.setUrl(url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+}
+
+QV8Include::~QV8Include()
+{
+ delete m_reply; m_reply = 0;
+ m_callbackFunction.Dispose();
+ m_resultObject.Dispose();
+}
+
+v8::Local<v8::Object> QV8Include::resultValue(Status status)
+{
+ // XXX aakenned inefficient
+ v8::Local<v8::Object> result = v8::Object::New();
+ result->Set(v8::String::New("OK"), v8::Integer::New(Ok));
+ result->Set(v8::String::New("LOADING"), v8::Integer::New(Loading));
+ result->Set(v8::String::New("NETWORK_ERROR"), v8::Integer::New(NetworkError));
+ result->Set(v8::String::New("EXCEPTION"), v8::Integer::New(Exception));
+
+ result->Set(v8::String::New("status"), v8::Integer::New(status));
+
+ return result;
+}
+
+void QV8Include::callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status)
+{
+ if (!callback.IsEmpty()) {
+ v8::Handle<v8::Value> args[] = { status };
+ // XXX TryCatch?
+ callback->Call(engine->global(), 1, args);
+ }
+}
+
+v8::Handle<v8::Object> QV8Include::result()
+{
+ return m_resultObject;
+}
+
+#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
+void QV8Include::finished()
+{
+ m_redirectCount++;
+
+ if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ m_url = m_url.resolved(redirect.toUrl());
+ delete m_reply;
+
+ QNetworkRequest request;
+ request.setUrl(m_url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ return;
+ }
+ }
+
+ v8::HandleScope handle_scope;
+
+ if (m_reply->error() == QNetworkReply::NoError) {
+ QByteArray data = m_reply->readAll();
+
+ QString code = QString::fromUtf8(data);
+ QDeclarativeScriptParser::extractPragmas(code);
+
+ QDeclarativeContextData *importContext = new QDeclarativeContextData;
+ importContext->isInternal = true;
+ importContext->isJSContext = true;
+ importContext->url = m_url;
+ importContext->setParent(m_context, true);
+
+ v8::Context::Scope ctxtscope(m_engine->context());
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Script> script = m_engine->qmlModeCompile(code, m_url.toString());
+
+ if (!try_catch.HasCaught()) {
+ m_engine->contextWrapper()->addSubContext(m_qmlglobal, script, importContext);
+ script->Run(m_qmlglobal);
+ }
+
+ if (try_catch.HasCaught()) {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Exception));
+ m_resultObject->Set(v8::String::New("exception"), try_catch.Exception());
+ } else {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Ok));
+ }
+ } else {
+ m_resultObject->Set(v8::String::New("status"), v8::Integer::New(NetworkError));
+ }
+
+ callback(m_engine, m_callbackFunction, m_resultObject);
+
+ disconnect();
+ deleteLater();
+}
+
+/*
+ Documented in qv8engine.cpp
+*/
+v8::Handle<v8::Value> QV8Include::include(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ return v8::Undefined();
+
+ QV8Engine *engine = V8ENGINE();
+ QDeclarativeContextData *context = engine->callingContext();
+
+ if (!context || !context->isJSContext)
+ V8THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
+
+ QUrl url(context->resolvedUrl(QUrl(engine->toString(args[0]->ToString()))));
+
+ v8::Local<v8::Function> callbackFunction;
+ if (args.Length() >= 2 && args[1]->IsFunction())
+ callbackFunction = v8::Local<v8::Function>::Cast(args[1]);
+
+ QString localFile = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+
+ v8::Local<v8::Object> result;
+
+ if (localFile.isEmpty()) {
+
+ QV8Include *i = new QV8Include(url, engine, context,
+ v8::Context::GetCallingQmlGlobal(),
+ callbackFunction);
+ result = v8::Local<v8::Object>::New(i->result());
+
+ } else {
+
+ QFile f(localFile);
+
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString code = QString::fromUtf8(data);
+ QDeclarativeScriptParser::extractPragmas(code);
+
+ QDeclarativeContextData *importContext = new QDeclarativeContextData;
+ importContext->isInternal = true;
+ importContext->isJSContext = true;
+ importContext->url = url;
+ importContext->setParent(context, true);
+
+ v8::TryCatch try_catch;
+
+ v8::Local<v8::Script> script = engine->qmlModeCompile(code, url.toString());
+
+ if (!try_catch.HasCaught()) {
+ v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
+ engine->contextWrapper()->addSubContext(qmlglobal, script, importContext);
+ script->Run(qmlglobal);
+ }
+
+ if (try_catch.HasCaught()) {
+ result = resultValue(Exception);
+ result->Set(v8::String::New("exception"), try_catch.Exception());
+ } else {
+ result = resultValue(Ok);
+ }
+
+ } else {
+ result = resultValue(NetworkError);
+ }
+
+ callback(engine, callbackFunction, result);
+ }
+
+ if (result.IsEmpty())
+ return v8::Undefined();
+ else
+ return result;
+}
+
+QT_END_NAMESPACE
**
****************************************************************************/
-#ifndef QDECLARATIVEINCLUDE_P_H
-#define QDECLARATIVEINCLUDE_P_H
+#ifndef QV8INCLUDE_P_H
+#define QV8INCLUDE_P_H
//
// W A R N I N G
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
-#include <QtScript/qscriptvalue.h>
#include <private/qdeclarativecontext_p.h>
#include <private/qdeclarativeguard_p.h>
+#include <private/qv8_p.h>
+
QT_BEGIN_NAMESPACE
class QDeclarativeEngine;
-class QScriptContext;
-class QScriptEngine;
class QNetworkAccessManager;
class QNetworkReply;
-class QDeclarativeInclude : public QObject
+class QV8Engine;
+class QV8Include : public QObject
{
Q_OBJECT
public:
Exception = 3
};
- QDeclarativeInclude(const QUrl &, QDeclarativeEngine *, QScriptContext *ctxt);
- ~QDeclarativeInclude();
-
- void setCallback(const QScriptValue &);
- QScriptValue callback() const;
+ static v8::Handle<v8::Value> include(const v8::Arguments &args);
- QScriptValue result() const;
+private slots:
+ void finished();
- static QScriptValue resultValue(QScriptEngine *, Status status = Loading);
- static void callback(QScriptEngine *, QScriptValue &callback, QScriptValue &status);
+private:
+ QV8Include(const QUrl &, QV8Engine *, QDeclarativeContextData *,
+ v8::Handle<v8::Object>, v8::Handle<v8::Function>);
+ ~QV8Include();
- static QScriptValue include(QScriptContext *ctxt, QScriptEngine *engine);
- static QScriptValue worker_include(QScriptContext *ctxt, QScriptEngine *engine);
+ v8::Handle<v8::Object> result();
-public slots:
- void finished();
+ static v8::Local<v8::Object> resultValue(Status status = Loading);
+ static void callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status);
-private:
- QDeclarativeEngine *m_engine;
- QScriptEngine *m_scriptEngine;
+ QV8Engine *m_engine;
QNetworkAccessManager *m_network;
QDeclarativeGuard<QNetworkReply> m_reply;
QUrl m_url;
int m_redirectCount;
- QScriptValue m_callback;
- QScriptValue m_result;
+
+ v8::Persistent<v8::Function> m_callbackFunction;
+ v8::Persistent<v8::Object> m_resultObject;
+
QDeclarativeGuardedContextData m_context;
- QScriptValue m_scope[2];
+ v8::Persistent<v8::Object> m_qmlglobal;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVEINCLUDE_P_H
+#endif // QV8INCLUDE_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8listwrapper_p.h"
+#include "qv8engine_p.h"
+#include <private/qdeclarativelist_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8ListResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ListType);
+public:
+ QV8ListResource(QV8Engine *engine) : QV8ObjectResource(engine) {}
+
+ QDeclarativeGuard<QObject> object;
+ QDeclarativeListProperty<QObject> property;
+ int propertyType;
+};
+
+QV8ListWrapper::QV8ListWrapper()
+: m_engine(0)
+{
+}
+
+QV8ListWrapper::~QV8ListWrapper()
+{
+}
+
+void QV8ListWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, 0,
+ v8::Handle<v8::Value>(), v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+}
+
+void QV8ListWrapper::destroy()
+{
+ m_constructor.Dispose();
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::newList(QObject *object, int propId, int propType)
+{
+ if (!object || propId == -1)
+ return v8::Null();
+
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ListResource *r = new QV8ListResource(m_engine);
+ r->object = object;
+ r->propertyType = propType;
+ void *args[] = { &r->property, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::newList(const QDeclarativeListProperty<QObject> &prop, int propType)
+{
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ListResource *r = new QV8ListResource(m_engine);
+ r->object = prop.object;
+ r->property = prop;
+ r->propertyType = propType;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+QVariant QV8ListWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(obj);
+ if (resource) return toVariant(resource);
+ else return QVariant();
+}
+
+QVariant QV8ListWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::ListType);
+ QV8ListResource *resource = static_cast<QV8ListResource *>(r);
+
+ if (!resource->object)
+ return QVariant();
+
+ return QVariant::fromValue(QDeclarativeListReferencePrivate::init(resource->property, resource->propertyType,
+ m_engine->engine()));
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ Q_UNUSED(info);
+ return value;
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::IndexedGetter(uint32_t index, const v8::AccessorInfo &info)
+{
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ quint32 count = resource->property.count?resource->property.count(&resource->property):0;
+ if (index < count && resource->property.at) {
+ return resource->engine->newQObject(resource->property.at(&resource->property, index));
+ } else {
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> QV8ListWrapper::LengthGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+
+ QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ quint32 count = resource->property.count?resource->property.count(&resource->property):0;
+
+ return v8::Integer::NewFromUnsigned(count);
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8LISTWRAPPER_P_H
+#define QV8LISTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtDeclarative/qdeclarativelist.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QV8ObjectResource;
+class QV8ListWrapper
+{
+public:
+ QV8ListWrapper();
+ ~QV8ListWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Handle<v8::Value> newList(QObject *, int, int);
+ v8::Handle<v8::Value> newList(const QDeclarativeListProperty<QObject> &, int);
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
+
+private:
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8LISTWRAPPER_P_H
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8qobjectwrapper_p.h"
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativeguard_p.h>
+#include <private/qdeclarativepropertycache_p.h>
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativevmemetaobject_p.h>
+#include <private/qdeclarativebinding_p.h>
+
+#include <QtScript/qscriptvalue.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_METATYPE(QScriptValue);
+Q_DECLARE_METATYPE(QDeclarativeV8Handle);
+
+#if defined(__GNUC__)
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+// The code in this file does not violate strict aliasing, but GCC thinks it does
+// so turn off the warnings for us to have a clean build
+# pragma GCC diagnostic ignored "-Wstrict-aliasing"
+# endif
+#endif
+
+#define QOBJECT_TOSTRING_INDEX -2
+#define QOBJECT_DESTROY_INDEX -3
+
+class QV8QObjectResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(QObjectType);
+
+public:
+ QV8QObjectResource(QV8Engine *engine, QObject *object);
+
+ QDeclarativeGuard<QObject> object;
+};
+
+namespace {
+struct MetaCallArgument {
+ inline MetaCallArgument();
+ inline ~MetaCallArgument();
+ inline void *dataPtr();
+
+ inline void initAsType(int type);
+ inline void fromValue(int type, QV8Engine *, v8::Handle<v8::Value>);
+ inline v8::Handle<v8::Value> toValue(QV8Engine *);
+
+private:
+ MetaCallArgument(const MetaCallArgument &);
+
+ inline void cleanup();
+
+ char data[4 * sizeof(void *)];
+ int type;
+ bool isObjectType;
+};
+}
+
+QV8QObjectResource::QV8QObjectResource(QV8Engine *engine, QObject *object)
+: QV8ObjectResource(engine), object(object)
+{
+}
+
+QV8QObjectWrapper::QV8QObjectWrapper()
+: m_engine(0)
+{
+}
+
+QV8QObjectWrapper::~QV8QObjectWrapper()
+{
+}
+
+void QV8QObjectWrapper::destroy()
+{
+ qDeleteAll(m_connections);
+ m_connections.clear();
+
+ m_hiddenObject.Dispose();
+ m_destroySymbol.Dispose();
+ m_toStringSymbol.Dispose();
+ m_methodConstructor.Dispose();
+ m_constructor.Dispose();
+}
+
+#define FAST_VALUE_GETTER(name, cpptype, defaultvalue, constructor) \
+static v8::Handle<v8::Value> name ## ValueGetter(v8::Local<v8::String>, const v8::AccessorInfo &info) \
+{ \
+ v8::Handle<v8::Object> This = info.This(); \
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(This); \
+ \
+ if (!resource || resource->object.isNull()) return v8::Undefined(); \
+ \
+ QObject *object = resource->object; \
+ \
+ uint32_t data = info.Data()->Uint32Value(); \
+ int index = data & 0x7FFF; \
+ int notify = (data & 0x7FFF0000) >> 16; \
+ if (notify == 0x7FFF) notify = -1; \
+ \
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(resource->engine->engine()); \
+ if (notify /* 0 means constant */ && ep->captureProperties) { \
+ typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; \
+ ep->capturedProperties << CapturedProperty(object, index, notify); \
+ } \
+ \
+ cpptype value = defaultvalue; \
+ void *args[] = { &value, 0 }; \
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, index, args); \
+ \
+ return constructor(value); \
+}
+
+#define CREATE_FUNCTION \
+ "(function(method) { "\
+ "return (function(object, data, qmlglobal) { "\
+ "return (function() { "\
+ "return method(object, data, qmlglobal, arguments.length, arguments); "\
+ "});"\
+ "});"\
+ "})"
+
+void QV8QObjectWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+
+ m_toStringSymbol = v8::Persistent<v8::String>::New(v8::String::NewSymbol("toString"));
+ m_destroySymbol = v8::Persistent<v8::String>::New(v8::String::NewSymbol("destroy"));
+ m_hiddenObject = v8::Persistent<v8::Object>::New(v8::Object::New());
+
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, Query, 0, Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+ {
+ v8::ScriptOrigin origin(m_hiddenObject); // Hack to allow us to identify these functions
+ v8::Local<v8::Script> script = v8::Script::New(v8::String::New(CREATE_FUNCTION), &origin);
+ v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(script->Run());
+ v8::Handle<v8::Value> invokeFn = v8::FunctionTemplate::New(Invoke)->GetFunction();
+ v8::Handle<v8::Value> args[] = { invokeFn };
+ v8::Local<v8::Function> createFn = v8::Local<v8::Function>::Cast(fn->Call(engine->global(), 1, args));
+ m_methodConstructor = v8::Persistent<v8::Function>::New(createFn);
+ }
+
+ {
+ v8::Local<v8::Object> prototype = engine->global()->Get(v8::String::New("Function"))->ToObject()->Get(v8::String::New("prototype"))->ToObject();
+ prototype->Set(v8::String::New("connect"), V8FUNCTION(Connect, engine));
+ prototype->Set(v8::String::New("disconnect"), V8FUNCTION(Disconnect, engine));
+ }
+}
+
+bool QV8QObjectWrapper::isQObject(v8::Handle<v8::Object> obj)
+{
+ return v8_resource_cast<QV8QObjectResource>(obj) != 0;
+}
+
+QObject *QV8QObjectWrapper::toQObject(v8::Handle<v8::Object> obj)
+{
+ QV8QObjectResource *r = v8_resource_cast<QV8QObjectResource>(obj);
+ return r?r->object:0;
+}
+
+// r *MUST* be a QV8ObjectResource (r->type() == QV8ObjectResource::QObjectType)
+QObject *QV8QObjectWrapper::QV8QObjectWrapper::toQObject(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::QObjectType);
+ return static_cast<QV8QObjectResource *>(r)->object;
+}
+
+// Load value properties
+static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
+ const QDeclarativePropertyCache::Data &property)
+{
+ Q_ASSERT(!property.isFunction());
+
+#define PROPERTY_LOAD(metatype, cpptype, constructor) \
+ if (property.propType == QMetaType:: metatype) { \
+ cpptype type = cpptype(); \
+ void *args[] = { &type, 0 }; \
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args); \
+ return constructor(type); \
+ }
+
+ if (property.isQObject()) {
+ QObject *rv = 0;
+ void *args[] = { &rv, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
+ return engine->newQObject(rv);
+ } else if (property.isQList()) {
+ return engine->listWrapper()->newList(object, property.coreIndex, property.propType);
+ } else PROPERTY_LOAD(QReal, qreal, v8::Number::New)
+ else PROPERTY_LOAD(Int || property.isEnum(), int, v8::Number::New)
+ else PROPERTY_LOAD(Bool, bool, v8::Boolean::New)
+ else PROPERTY_LOAD(QString, QString, engine->toString)
+ else PROPERTY_LOAD(UInt, uint, v8::Integer::NewFromUnsigned)
+ else PROPERTY_LOAD(Float, float, v8::Number::New)
+ else PROPERTY_LOAD(Double, double, v8::Number::New)
+ else if(property.isV8Handle()) {
+ QDeclarativeV8Handle handle;
+ void *args[] = { &handle, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
+ return reinterpret_cast<v8::Handle<v8::Value> &>(handle);
+ } else if (QDeclarativeValueTypeFactory::isValueType((uint)property.propType)) {
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+ QDeclarativeValueType *valueType = ep->valueTypes[property.propType];
+ if (valueType)
+ return engine->newValueType(object, property.coreIndex, valueType);
+ }
+
+ QVariant var = object->metaObject()->property(property.coreIndex).read(object);
+ return engine->fromVariant(var);
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ v8::Handle<v8::String> property,
+ QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ // XXX aakenned This can't possibly be the best solution!!!
+ struct MethodClosure {
+ static v8::Handle<v8::Value> create(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ int index) {
+ v8::Handle<v8::Value> argv[] = {
+ objectHandle?*objectHandle:engine->newQObject(object),
+ v8::Integer::New(index)
+ };
+ return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 2, argv);
+ }
+ static v8::Handle<v8::Value> createWithGlobal(QV8Engine *engine, QObject *object,
+ v8::Handle<v8::Value> *objectHandle,
+ int index) {
+ v8::Handle<v8::Value> argv[] = {
+ objectHandle?*objectHandle:engine->newQObject(object),
+ v8::Integer::New(index),
+ v8::Context::GetCallingQmlGlobal()
+ };
+ return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 3, argv);
+ }
+ };
+
+ if (engine->qobjectWrapper()->m_toStringSymbol->StrictEquals(property)) {
+ return MethodClosure::create(engine, object, objectHandle, QOBJECT_TOSTRING_INDEX);
+ } else if (engine->qobjectWrapper()->m_destroySymbol->StrictEquals(property)) {
+ return MethodClosure::create(engine, object, objectHandle, QOBJECT_DESTROY_INDEX);
+ }
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *result = 0;
+ result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
+
+ if (!result)
+ return v8::Handle<v8::Value>();
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+
+ if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
+ return v8::Handle<v8::Value>();
+ }
+
+ typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty;
+
+ if (result->isFunction()) {
+ if (result->flags & QDeclarativePropertyCache::Data::IsVMEFunction) {
+ return ((QDeclarativeVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex);
+ } else if (result->flags & QDeclarativePropertyCache::Data::IsV8Function) {
+ return MethodClosure::createWithGlobal(engine, object, objectHandle, result->coreIndex);
+ } else {
+ return MethodClosure::create(engine, object, objectHandle, result->coreIndex);
+ }
+ }
+
+ if (ep->captureProperties && !result->isConstant()) {
+ if (result->coreIndex == 0)
+ ep->capturedProperties << CapturedProperty(QDeclarativeData::get(object, true)->objectNameNotifier());
+ else
+ ep->capturedProperties << CapturedProperty(object, result->coreIndex, result->notifyIndex);
+ }
+
+ return LoadProperty(engine, object, *result);
+}
+
+// Setter for writable properties. Shared between the interceptor and fast property accessor
+static inline void StoreProperty(QV8Engine *engine, QObject *object, QDeclarativePropertyCache::Data *property,
+ v8::Handle<v8::Value> value)
+{
+ QDeclarativeBinding *newBinding = 0;
+
+ if (value->IsFunction()) {
+ QDeclarativeContextData *context = engine->callingContext();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+ v8::Local<v8::StackTrace> trace =
+ v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+ v8::StackTrace::kScriptName));
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+ int lineNumber = frame->GetLineNumber();
+ QString url = engine->toString(frame->GetScriptName());
+
+ QDeclarativePropertyCache::ValueTypeData valueTypeData;
+ newBinding = new QDeclarativeBinding(&function, object, context);
+ newBinding->setSourceLocation(url, lineNumber);
+ newBinding->setTarget(QDeclarativePropertyPrivate::restore(*property, valueTypeData, object, context));
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
+ }
+
+ QDeclarativeAbstractBinding *oldBinding =
+ QDeclarativePropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+#define PROPERTY_STORE(cpptype, value) \
+ cpptype o = value; \
+ int status = -1; \
+ int flags = 0; \
+ void *argv[] = { &o, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv);
+
+
+ if (value->IsNull() && property->isQObject()) {
+ PROPERTY_STORE(QObject*, 0);
+ } else if (value->IsUndefined() && property->isResettable()) {
+ void *a[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
+ } else if (value->IsUndefined() && property->propType == qMetaTypeId<QVariant>()) {
+ PROPERTY_STORE(QVariant, QVariant());
+ } else if (value->IsUndefined()) {
+ QString error = QLatin1String("Cannot assign [undefined] to ") +
+ QLatin1String(QMetaType::typeName(property->propType));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ } else if (value->IsFunction()) {
+ // this is handled by the binding creation above
+ } else if (property->propType == QMetaType::Int && value->IsNumber()) {
+ PROPERTY_STORE(int, qRound(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::QReal && value->IsNumber()) {
+ PROPERTY_STORE(qreal, qreal(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::Float && value->IsNumber()) {
+ PROPERTY_STORE(float, float(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::Double && value->IsNumber()) {
+ PROPERTY_STORE(double, double(value->ToNumber()->Value()));
+ } else if (property->propType == QMetaType::QString && value->IsString()) {
+ PROPERTY_STORE(QString, engine->toString(value->ToString()));
+ } else {
+ QVariant v;
+ if (property->isQList())
+ v = engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
+ else
+ v = engine->toVariant(value, property->propType);
+
+ QDeclarativeContextData *context = engine->callingContext();
+
+ if (!QDeclarativePropertyPrivate::write(object, *property, v, context)) {
+ const char *valueType = 0;
+ if (v.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(v.userType());
+
+ QString error = QLatin1String("Cannot assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(QMetaType::typeName(property->propType));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ }
+ }
+}
+
+bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, v8::Handle<v8::String> property,
+ v8::Handle<v8::Value> value, QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ if (engine->qobjectWrapper()->m_toStringSymbol->StrictEquals(property) ||
+ engine->qobjectWrapper()->m_destroySymbol->StrictEquals(property))
+ return true;
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *result = 0;
+ result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
+
+ if (!result)
+ return false;
+
+ if (revisionMode == QV8QObjectWrapper::CheckRevision && result->revision != 0) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
+ return false;
+ }
+
+ if (!result->isWritable() && !result->isQList()) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return true;
+ }
+
+ StoreProperty(engine, object, result, value);
+
+ return true;
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+ v8::Handle<v8::Value> This = info.This();
+
+ if (!resource || resource->object.isNull()) return v8::Undefined();
+
+ QObject *object = resource->object;
+
+ QV8Engine *v8engine = resource->engine;
+ v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, property, QV8QObjectWrapper::IgnoreRevision);
+ if (!result.IsEmpty())
+ return result;
+
+ if (QV8Engine::startsWithUpper(property)) {
+ // Check for attached properties
+ QDeclarativeContextData *context = v8engine->callingContext();
+ QDeclarativeTypeNameCache::Data *data = context && (context->imports)?context->imports->data(property):0;
+
+ if (data) {
+ if (data->type) {
+ return v8engine->typeWrapper()->newObject(object, data->type, QV8TypeWrapper::ExcludeEnums);
+ } else if (data->typeNamespace) {
+ return v8engine->typeWrapper()->newObject(object, data->typeNamespace, QV8TypeWrapper::ExcludeEnums);
+ }
+ }
+
+ return v8::Undefined();
+ } else {
+ // XXX throw?
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return value;
+
+ QObject *object = resource->object;
+
+ QV8Engine *v8engine = resource->engine;
+ bool result = SetProperty(v8engine, object, property, value, QV8QObjectWrapper::IgnoreRevision);
+
+ if (!result) {
+ QString error = QLatin1String("Cannot assign to non-existent property \"") +
+ v8engine->toString(property) + QLatin1Char('\"');
+ v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+ return value;
+ }
+
+ return value;
+}
+
+v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return v8::Handle<v8::Integer>();
+
+ QV8Engine *engine = resource->engine;
+ QObject *object = resource->object;
+
+ QDeclarativePropertyCache::Data local;
+ QDeclarativePropertyCache::Data *result = 0;
+ result = QDeclarativePropertyCache::property(engine->engine(), object, property, local);
+
+ if (!result)
+ return v8::Handle<v8::Integer>();
+ else if (!result->isWritable() && !result->isQList())
+ return v8::Integer::New(v8::ReadOnly | v8::DontDelete);
+ else
+ return v8::Integer::New(v8::DontDelete);
+}
+
+v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return v8::Array::New();
+
+ QObject *object = resource->object;
+
+ QStringList result;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(resource->engine->engine());
+
+ QDeclarativePropertyCache *cache = 0;
+ QDeclarativeData *ddata = QDeclarativeData::get(object);
+ if (ddata)
+ cache = ddata->propertyCache;
+
+ if (!cache) {
+ cache = ep->cache(object);
+ if (cache) {
+ if (ddata) { cache->addref(); ddata->propertyCache = cache; }
+ } else {
+ // Not cachable - fall back to QMetaObject (eg. dynamic meta object)
+ // XXX QDeclarativeOpenMetaObject has a cache, so this is suboptimal.
+ // XXX This is a workaround for QTBUG-9420.
+ const QMetaObject *mo = object->metaObject();
+ int pc = mo->propertyCount();
+ int po = mo->propertyOffset();
+ for (int i=po; i<pc; ++i)
+ result << QString::fromUtf8(mo->property(i).name());
+ }
+ } else {
+ result = cache->propertyNames();
+ }
+
+ v8::Local<v8::Array> rv = v8::Array::New(result.count());
+
+ for (int ii = 0; ii < result.count(); ++ii)
+ rv->Set(ii, resource->engine->toString(result.at(ii)));
+
+ return rv;
+}
+
+FAST_VALUE_GETTER(QObject, QObject*, 0, resource->engine->newQObject);
+FAST_VALUE_GETTER(Int, int, 0, v8::Integer::New);
+FAST_VALUE_GETTER(Bool, bool, false, v8::Boolean::New);
+FAST_VALUE_GETTER(QString, QString, QString(), resource->engine->toString);
+FAST_VALUE_GETTER(UInt, uint, 0, v8::Integer::NewFromUnsigned);
+FAST_VALUE_GETTER(Float, float, 0, v8::Number::New);
+FAST_VALUE_GETTER(Double, double, 0, v8::Number::New);
+
+static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info)
+{
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(info.This());
+
+ if (!resource || resource->object.isNull())
+ return;
+
+ QObject *object = resource->object;
+
+ uint32_t data = info.Data()->Uint32Value();
+ int index = data & 0x7FFF; // So that we can use the same data for Setter and Getter
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ Q_ASSERT(ddata);
+ Q_ASSERT(ddata->propertyCache);
+
+ QDeclarativePropertyCache::Data *pdata = ddata->propertyCache->property(index);
+ Q_ASSERT(pdata);
+
+ Q_ASSERT(pdata->isWritable() || pdata->isQList());
+
+ StoreProperty(resource->engine, object, pdata, value);
+}
+
+static void WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void *)
+{
+ Q_ASSERT(handle->IsObject());
+
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(handle->ToObject());
+
+ Q_ASSERT(resource);
+
+ QObject *object = resource->object;
+ if (object) {
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ if (ddata) {
+ ddata->v8object.Clear();
+ if (!object->parent() && !ddata->indestructible)
+ object->deleteLater();
+ }
+ }
+
+ // XXX do we want to use the objectDataRefCount to support multiple concurrent engines?
+
+ handle.Dispose();
+}
+
+v8::Local<v8::Object> QDeclarativePropertyCache::newQObject(QObject *object, QV8Engine *engine)
+{
+ Q_ASSERT(object);
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+
+ Q_ASSERT(ddata && ddata->propertyCache && ddata->propertyCache == this);
+ Q_ASSERT(ddata->v8object.IsEmpty());
+
+ // Setup constructor
+ if (constructor.IsEmpty()) {
+ v8::Local<v8::FunctionTemplate> ft;
+
+ QString toString = QLatin1String("toString");
+ QString destroy = QLatin1String("destroy");
+
+ // XXX Enables fast property accessors. These more than double the property access
+ // performance, but the cost of setting up this structure hasn't been measured so
+ // its not guarenteed that this is a win overall
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
+ Data *property = *iter;
+ if (property->isFunction() || !property->isWritable() ||
+ property->coreIndex >= 0x7FFF || property->notifyIndex >= 0x7FFF ||
+ property->coreIndex == 0)
+ continue;
+
+ v8::AccessorGetter fastgetter = 0;
+
+
+ if (property->isQObject())
+ fastgetter = QObjectValueGetter;
+ else if (property->propType == QMetaType::Int || property->isEnum())
+ fastgetter = IntValueGetter;
+ else if (property->propType == QMetaType::Bool)
+ fastgetter = BoolValueGetter;
+ else if (property->propType == QMetaType::QString)
+ fastgetter = QStringValueGetter;
+ else if (property->propType == QMetaType::UInt)
+ fastgetter = UIntValueGetter;
+ else if (property->propType == QMetaType::Float)
+ fastgetter = FloatValueGetter;
+ else if (property->propType == QMetaType::Double)
+ fastgetter = DoubleValueGetter;
+
+ if (fastgetter) {
+ int notifyIndex = property->notifyIndex;
+ if (property->isConstant()) notifyIndex = 0;
+ else if (notifyIndex == -1) notifyIndex = 0x7FFF;
+ uint32_t data = (property->notifyIndex & 0x7FFF) << 16 | property->coreIndex;
+
+ QString name = iter.key();
+ if (name == toString || name == destroy)
+ continue;
+
+ if (ft.IsEmpty()) {
+ ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
+ QV8QObjectWrapper::Setter,
+ QV8QObjectWrapper::Query,
+ 0,
+ QV8QObjectWrapper::Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ }
+
+ ft->InstanceTemplate()->SetAccessor(engine->toString(name), fastgetter, FastValueSetter,
+ v8::Integer::NewFromUnsigned(data));
+ }
+ }
+
+ if (ft.IsEmpty()) {
+ constructor = v8::Persistent<v8::Function>::New(engine->qobjectWrapper()->m_constructor);
+ } else {
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
+ QV8QObjectWrapper::Setter,
+ QV8QObjectWrapper::Query,
+ 0,
+ QV8QObjectWrapper::Enumerator);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+ }
+
+ v8::Local<v8::Object> result = constructor->NewInstance();
+ QV8QObjectResource *r = new QV8QObjectResource(engine, object);
+ result->SetExternalResource(r);
+
+ ddata->v8object = v8::Persistent<v8::Object>::New(result);
+ ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
+ return result;
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
+{
+ // XXX aakenned QDeclarativeObjectScriptClass::newQObject() does a lot more
+
+ if (!object)
+ return v8::Null();
+
+ if (QObjectPrivate::get(object)->wasDeleted)
+ return v8::Undefined();
+
+ QDeclarativeData *ddata = QDeclarativeData::get(object, true);
+
+ if (!ddata)
+ return v8::Undefined();
+
+ if (ddata->v8object.IsEmpty()) {
+
+ if (ddata->propertyCache) {
+ return ddata->propertyCache->newQObject(object, m_engine);
+ }
+
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8QObjectResource *r = new QV8QObjectResource(m_engine, object);
+ rv->SetExternalResource(r);
+ ddata->v8object = v8::Persistent<v8::Object>::New(rv);
+ }
+
+ // XXX do we have to check that the v8object isn't "owned" by another engine?
+
+ ddata->v8object.MakeWeak(0, WeakQObjectReferenceCallback);
+ return v8::Local<v8::Object>::New(ddata->v8object);
+}
+
+QPair<QObject *, int> QV8QObjectWrapper::ExtractQtMethod(QV8Engine *engine, v8::Handle<v8::Function> function)
+{
+ v8::ScriptOrigin origin = function->GetScriptOrigin();
+ if (origin.ResourceName()->StrictEquals(engine->qobjectWrapper()->m_hiddenObject)) {
+
+ // This is one of our special QObject method wrappers
+ v8::Handle<v8::Value> args[] = { engine->qobjectWrapper()->m_hiddenObject };
+ v8::Local<v8::Value> data = function->Call(engine->global(), 1, args);
+
+ if (data->IsArray()) {
+ v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(data);
+ return qMakePair(engine->toQObject(array->Get(0)), array->Get(1)->Int32Value());
+ }
+
+ // In theory this can't fall through, but I suppose V8 might run out of memory or something
+ }
+
+ return qMakePair((QObject *)0, -1);
+}
+
+struct QV8QObjectConnectionList : public QObject, public QDeclarativeGuard<QObject>
+{
+ QV8QObjectConnectionList(QObject *object, QV8Engine *engine);
+ ~QV8QObjectConnectionList();
+
+ struct Connection {
+ v8::Persistent<v8::Object> thisObject;
+ v8::Persistent<v8::Function> function;
+ };
+
+ QV8Engine *engine;
+
+ typedef QHash<int, QList<Connection> > SlotHash;
+ SlotHash slotHash;
+
+ virtual void objectDestroyed(QObject *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **);
+};
+
+QV8QObjectConnectionList::QV8QObjectConnectionList(QObject *object, QV8Engine *engine)
+: QDeclarativeGuard<QObject>(object), engine(engine)
+{
+}
+
+QV8QObjectConnectionList::~QV8QObjectConnectionList()
+{
+ for (SlotHash::Iterator iter = slotHash.begin(); iter != slotHash.end(); ++iter) {
+ QList<Connection> &connections = *iter;
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ connections[ii].thisObject.Dispose();
+ connections[ii].function.Dispose();
+ }
+ }
+ slotHash.clear();
+}
+
+void QV8QObjectConnectionList::objectDestroyed(QObject *object)
+{
+ engine->qobjectWrapper()->m_connections.remove(object);
+ delete this;
+}
+
+int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, void **metaArgs)
+{
+ if (method == QMetaObject::InvokeMetaMethod) {
+ SlotHash::Iterator iter = slotHash.find(index);
+ if (iter == slotHash.end())
+ return -1;
+ QList<Connection> &connections = *iter;
+ if (connections.isEmpty())
+ return -1;
+
+ // XXX optimize
+ QMetaMethod method = data()->metaObject()->method(index);
+ Q_ASSERT(method.methodType() == QMetaMethod::Signal);
+ QList<QByteArray> params = method.parameterTypes();
+
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
+
+ QVarLengthArray<v8::Handle<v8::Value> > args(params.count());
+ int argCount = params.count();
+
+ for (int ii = 0; ii < argCount; ++ii) {
+ int type = QMetaType::type(params.at(ii).constData());
+ if (type == qMetaTypeId<QVariant>()) {
+ args[ii] = engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
+ } else {
+ args[ii] = engine->fromVariant(QVariant(type, metaArgs[ii + 1]));
+ }
+ }
+
+ // XXX what if this list changes or this object is deleted during the calls?
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ Connection &connection = connections[ii];
+ if (connection.thisObject.IsEmpty()) {
+ connection.function->Call(engine->global(), argCount, args.data());
+ } else {
+ connection.function->Call(connection.thisObject, argCount, args.data());
+ }
+ }
+ }
+
+ return -1;
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Connect(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("Function.prototype.connect: no arguments given");
+
+ QV8Engine *engine = V8ENGINE();
+
+ if (!args.This()->IsFunction())
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ QPair<QObject *, int> signalInfo = ExtractQtMethod(engine, v8::Handle<v8::Function>::Cast(args.This()));
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ if (!signalObject)
+ V8THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
+
+ if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ v8::Local<v8::Value> functionValue;
+ v8::Local<v8::Value> functionThisValue;
+
+ if (args.Length() == 1) {
+ functionValue = args[0];
+ } else {
+ functionThisValue = args[0];
+ functionValue = args[1];
+ }
+
+ if (!functionValue->IsFunction())
+ V8THROW_ERROR("Function.prototype.connect: target is not a function");
+
+ if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
+ V8THROW_ERROR("Function.prototype.connect: target this is not an object");
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+ QHash<QObject *, QV8QObjectConnectionList *> &connections = qobjectWrapper->m_connections;
+ QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connections.find(signalObject);
+ if (iter == connections.end())
+ iter = connections.insert(signalObject, new QV8QObjectConnectionList(signalObject, engine));
+
+ QV8QObjectConnectionList *connectionList = *iter;
+ QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
+ if (slotIter == connectionList->slotHash.end()) {
+ slotIter = connectionList->slotHash.insert(signalIndex, QList<QV8QObjectConnectionList::Connection>());
+ QMetaObject::connect(signalObject, signalIndex, connectionList, signalIndex);
+ }
+
+ QV8QObjectConnectionList::Connection connection;
+ if (!functionThisValue.IsEmpty())
+ connection.thisObject = v8::Persistent<v8::Object>::New(functionThisValue->ToObject());
+ connection.function = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(functionValue));
+
+ slotIter->append(connection);
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
+{
+ if (args.Length() == 0)
+ V8THROW_ERROR("Function.prototype.disconnect: no arguments given");
+
+ QV8Engine *engine = V8ENGINE();
+
+ if (!args.This()->IsFunction())
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ QPair<QObject *, int> signalInfo = ExtractQtMethod(engine, v8::Handle<v8::Function>::Cast(args.This()));
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ if (!signalObject)
+ V8THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
+
+ if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
+ V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ v8::Local<v8::Value> functionValue;
+ v8::Local<v8::Value> functionThisValue;
+
+ if (args.Length() == 1) {
+ functionValue = args[0];
+ } else {
+ functionThisValue = args[0];
+ functionValue = args[1];
+ }
+
+ if (!functionValue->IsFunction())
+ V8THROW_ERROR("Function.prototype.disconnect: target is not a function");
+
+ if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
+ V8THROW_ERROR("Function.prototype.disconnect: target this is not an object");
+
+ QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
+ QHash<QObject *, QV8QObjectConnectionList *> &connectionsList = qobjectWrapper->m_connections;
+ QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connectionsList.find(signalObject);
+ if (iter == connectionsList.end())
+ return v8::Undefined(); // Nothing to disconnect from
+
+ QV8QObjectConnectionList *connectionList = *iter;
+ QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
+ if (slotIter == connectionList->slotHash.end())
+ return v8::Undefined(); // Nothing to disconnect from
+
+ QList<QV8QObjectConnectionList::Connection> &connections = *slotIter;
+
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(functionValue);
+ QPair<QObject *, int> functionData = ExtractQtMethod(engine, function);
+
+ if (functionData.second != -1) {
+ // This is a QObject function wrapper
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ QV8QObjectConnectionList::Connection &connection = connections[ii];
+
+ if (connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
+ (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
+
+ QPair<QObject *, int> connectedFunctionData = ExtractQtMethod(engine, connection.function);
+ if (connectedFunctionData == functionData) {
+ // Match!
+ connection.thisObject.Dispose();
+ connection.function.Dispose();
+ connections.removeAt(ii);
+ return v8::Undefined();
+ }
+ }
+ }
+
+ } else {
+ // This is a normal JS function
+ for (int ii = 0; ii < connections.count(); ++ii) {
+ QV8QObjectConnectionList::Connection &connection = connections[ii];
+ if (connection.function->StrictEquals(function) &&
+ connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
+ (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
+ // Match!
+ connection.thisObject.Dispose();
+ connection.function.Dispose();
+ connections.removeAt(ii);
+ return v8::Undefined();
+ }
+ }
+ }
+
+ return v8::Undefined();
+}
+
+/*!
+ Get the \a property of \a object. Returns an empty handle if the property doesn't exist.
+
+ Only searches for real properties of \a object (including methods), not attached properties etc.
+*/
+v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, v8::Handle<v8::String> property,
+ QV8QObjectWrapper::RevisionMode revisionMode)
+{
+ return GetProperty(m_engine, object, 0, property, revisionMode);
+}
+
+/*
+ Set the \a property of \a object to \a value.
+
+ Returns true if the property was "set" - even if this results in an exception being thrown -
+ and false if the object has no such property.
+
+ Only searches for real properties of \a object (including methods), not attached properties etc.
+*/
+bool QV8QObjectWrapper::setProperty(QObject *object, v8::Handle<v8::String> property,
+ v8::Handle<v8::Value> value, RevisionMode revisionMode)
+{
+ return SetProperty(m_engine, object, property, value, revisionMode);
+}
+
+namespace {
+struct CallArgs
+{
+ CallArgs(int length, v8::Handle<v8::Object> *args) : _length(length), _args(args) {}
+ int Length() const { return _length; }
+ v8::Local<v8::Value> operator[](int idx) { return (*_args)->Get(idx); }
+
+private:
+ int _length;
+ v8::Handle<v8::Object> *_args;
+};
+}
+
+static v8::Handle<v8::Value> CallMethod(QObject *object, int index, int returnType, int argCount,
+ int *argTypes, QV8Engine *engine, CallArgs &callArgs)
+{
+ if (argCount > 0) {
+
+ QVarLengthArray<MetaCallArgument, 9> args(argCount + 1);
+ args[0].initAsType(returnType);
+
+ for (int ii = 0; ii < argCount; ++ii)
+ args[ii + 1].fromValue(argTypes[ii], engine, callArgs[ii]);
+
+ QVarLengthArray<void *, 9> argData(args.count());
+ for (int ii = 0; ii < args.count(); ++ii)
+ argData[ii] = args[ii].dataPtr();
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
+
+ return args[0].toValue(engine);
+
+ } else if (returnType != 0) {
+
+ MetaCallArgument arg;
+ arg.initAsType(returnType);
+
+ void *args[] = { arg.dataPtr() };
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+
+ return arg.toValue(engine);
+
+ } else {
+
+ void *args[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+ return v8::Undefined();
+
+ }
+}
+
+static int EnumType(const QMetaObject *meta, const QString &strname)
+{
+ QByteArray str = strname.toUtf8();
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = str.lastIndexOf("::");
+ if (scopeIdx != -1) {
+ scope = str.left(scopeIdx);
+ name = str.mid(scopeIdx + 2);
+ } else {
+ name = str;
+ }
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
+ return QVariant::Int;
+ }
+ return QVariant::Invalid;
+}
+
+/*!
+ Returns the match score for converting \a actual to be of type \a conversionType. A
+ zero score means "perfect match" whereas a higher score is worse.
+
+ The conversion table is copied out of the QtScript callQtMethod() function.
+*/
+static int MatchScore(v8::Handle<v8::Value> actual, int conversionType,
+ const QByteArray &conversionTypeName)
+{
+ if (actual->IsNumber()) {
+ switch (conversionType) {
+ case QMetaType::Double:
+ return 0;
+ case QMetaType::Float:
+ return 1;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ return 2;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ return 3;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ return 4;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ return 5;
+ break;
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ return 6;
+ default:
+ return 10;
+ }
+ } else if (actual->IsString()) {
+ switch (conversionType) {
+ case QMetaType::QString:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsBoolean()) {
+ switch (conversionType) {
+ case QMetaType::Bool:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsDate()) {
+ switch (conversionType) {
+ case QMetaType::QDateTime:
+ return 0;
+ case QMetaType::QDate:
+ return 1;
+ case QMetaType::QTime:
+ return 2;
+ default:
+ return 10;
+ }
+ } else if (actual->IsRegExp()) {
+ switch (conversionType) {
+ case QMetaType::QRegExp:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual->IsArray()) {
+ switch (conversionType) {
+ case QMetaType::QStringList:
+ case QMetaType::QVariantList:
+ return 5;
+ default:
+ return 10;
+ }
+ } else if (actual->IsNull()) {
+ switch (conversionType) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ if (!conversionTypeName.endsWith('*'))
+ return 10;
+ else
+ return 0;
+ }
+ } else if (actual->IsObject()) {
+ v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(actual);
+
+ QV8ObjectResource *r = static_cast<QV8ObjectResource *>(obj->GetExternalResource());
+ if (r && r->resourceType() == QV8ObjectResource::QObjectType) {
+ switch (conversionType) {
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (r && r->resourceType() == QV8ObjectResource::VariantType) {
+ if (conversionType == qMetaTypeId<QVariant>())
+ return 0;
+ else if (r->engine->toVariant(actual, -1).userType() == conversionType)
+ return 0;
+ else
+ return 10;
+ } else {
+ return 10;
+ }
+
+ } else {
+ return 10;
+ }
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+static QByteArray QMetaMethod_name(const QMetaMethod &m)
+{
+ QByteArray sig = m.signature();
+ int paren = sig.indexOf('(');
+ if (paren == -1)
+ return sig;
+ else
+ return sig.left(paren);
+}
+
+/*!
+Returns the next related method, if one, or 0.
+*/
+static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object,
+ const QDeclarativePropertyCache::Data *current,
+ QDeclarativePropertyCache::Data &dummy)
+{
+ QDeclarativePropertyCache *cache = QDeclarativeData::get(object)->propertyCache;
+ if (current->relatedIndex == -1)
+ return 0;
+
+ if (cache) {
+ return cache->method(current->relatedIndex);
+ } else {
+ const QMetaObject *mo = object->metaObject();
+ int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
+
+ while (methodOffset > current->relatedIndex) {
+ mo = mo->superClass();
+ methodOffset -= QMetaObject_methods(mo);
+ }
+
+ QMetaMethod method = mo->method(current->relatedIndex);
+ dummy.load(method);
+
+ // Look for overloaded methods
+ QByteArray methodName = QMetaMethod_name(method);
+ for (int ii = current->relatedIndex - 1; ii >= methodOffset; --ii) {
+ if (methodName == QMetaMethod_name(mo->method(ii))) {
+ dummy.relatedIndex = ii;
+ return &dummy;
+ }
+ }
+
+ return &dummy;
+ }
+}
+
+static v8::Handle<v8::Value> CallPrecise(QObject *object, const QDeclarativePropertyCache::Data &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ if (data.flags & QDeclarativePropertyCache::Data::HasArguments) {
+
+ QMetaMethod m = object->metaObject()->method(data.coreIndex);
+ QList<QByteArray> argTypeNames = m.parameterTypes();
+ QVarLengthArray<int, 9> argTypes(argTypeNames.count());
+
+ // ### Cache
+ for (int ii = 0; ii < argTypeNames.count(); ++ii) {
+ argTypes[ii] = QMetaType::type(argTypeNames.at(ii));
+ if (argTypes[ii] == QVariant::Invalid)
+ argTypes[ii] = EnumType(object->metaObject(), QString::fromLatin1(argTypeNames.at(ii)));
+ if (argTypes[ii] == QVariant::Invalid) {
+ QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(QLatin1String(argTypeNames.at(ii)));
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+ }
+
+ if (argTypes.count() > callArgs.Length()) {
+ QString error = QLatin1String("Insufficient arguments");
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+
+ return CallMethod(object, data.coreIndex, data.propType, argTypes.count(),
+ argTypes.data(), engine, callArgs);
+
+ } else {
+
+ return CallMethod(object, data.coreIndex, data.propType, 0, 0, engine, callArgs);
+
+ }
+}
+
+/*!
+Resolve the overloaded method to call. The algorithm works conceptually like this:
+ 1. Resolve the set of overloads it is *possible* to call.
+ Impossible overloads include those that have too many parameters or have parameters
+ of unknown type.
+ 2. Filter the set of overloads to only contain those with the closest number of
+ parameters.
+ For example, if we are called with 3 parameters and there are 2 overloads that
+ take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
+ 3. Find the best remaining overload based on its match score.
+ If two or more overloads have the same match score, call the last one. The match
+ score is constructed by adding the matchScore() result for each of the parameters.
+*/
+static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativePropertyCache::Data &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ int argumentCount = callArgs.Length();
+
+ const QDeclarativePropertyCache::Data *best = 0;
+ int bestParameterScore = INT_MAX;
+ int bestMatchScore = INT_MAX;
+
+ QDeclarativePropertyCache::Data dummy;
+ const QDeclarativePropertyCache::Data *attempt = &data;
+
+ do {
+ QList<QByteArray> methodArgTypeNames;
+
+ if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments)
+ methodArgTypeNames = object->metaObject()->method(attempt->coreIndex).parameterTypes();
+
+ int methodArgumentCount = methodArgTypeNames.count();
+
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ int methodParameterScore = argumentCount - methodArgumentCount;
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ int methodMatchScore = 0;
+ QVarLengthArray<int, 9> methodArgTypes(methodArgumentCount);
+
+ bool unknownArgument = false;
+ for (int ii = 0; ii < methodArgumentCount; ++ii) {
+ methodArgTypes[ii] = QMetaType::type(methodArgTypeNames.at(ii));
+ if (methodArgTypes[ii] == QVariant::Invalid)
+ methodArgTypes[ii] = EnumType(object->metaObject(),
+ QString::fromLatin1(methodArgTypeNames.at(ii)));
+ if (methodArgTypes[ii] == QVariant::Invalid) {
+ unknownArgument = true;
+ break;
+ }
+ methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii], methodArgTypeNames.at(ii));
+ }
+ if (unknownArgument)
+ continue; // We don't understand all the parameters
+
+ if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ best = attempt;
+ bestParameterScore = methodParameterScore;
+ bestMatchScore = methodMatchScore;
+ }
+
+ if (bestParameterScore == 0 && bestMatchScore == 0)
+ break; // We can't get better than that
+
+ } while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
+
+ if (best) {
+ return CallPrecise(object, *best, engine, callArgs);
+ } else {
+ QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
+ const QDeclarativePropertyCache::Data *candidate = &data;
+ while (candidate) {
+ error += QLatin1String("\n ") +
+ QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).signature());
+ candidate = RelatedMethod(object, candidate, dummy);
+ }
+
+ v8::ThrowException(v8::Exception::Error(engine->toString(error)));
+ return v8::Handle<v8::Value>();
+ }
+}
+
+static v8::Handle<v8::Value> ToString(QV8Engine *engine, QObject *object, int, v8::Handle<v8::Object>)
+{
+ QString result;
+ if (object) {
+ QString objectName = object->objectName();
+
+ result += QString::fromUtf8(object->metaObject()->className());
+ result += QLatin1String("(0x");
+ result += QString::number((quintptr)object,16);
+
+ if (!objectName.isEmpty()) {
+ result += QLatin1String(", \"");
+ result += objectName;
+ result += QLatin1Char('\"');
+ }
+
+ result += QLatin1Char(')');
+ } else {
+ result = QLatin1String("null");
+ }
+
+ return engine->toString(result);
+}
+
+static v8::Handle<v8::Value> Destroy(QV8Engine *, QObject *object, int argCount, v8::Handle<v8::Object> args)
+{
+ QDeclarativeData *ddata = QDeclarativeData::get(object, false);
+ if (!ddata || ddata->indestructible) {
+ const char *error = "Invalid attempt to destroy() an indestructible object";
+ v8::ThrowException(v8::Exception::Error(v8::String::New(error)));
+ return v8::Undefined();
+ }
+
+ int delay = 0;
+ if (argCount > 0)
+ delay = args->Get(0)->Uint32Value();
+
+ if (delay > 0)
+ QTimer::singleShot(delay, object, SLOT(deleteLater()));
+ else
+ object->deleteLater();
+
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
+{
+ // object, index, qmlglobal, argCount, args
+ Q_ASSERT(args.Length() == 5);
+ Q_ASSERT(args[0]->IsObject());
+
+ QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(args[0]->ToObject());
+
+ if (!resource)
+ return v8::Undefined();
+
+ int argCount = args[3]->Int32Value();
+ v8::Handle<v8::Object> arguments = v8::Handle<v8::Object>::Cast(args[4]);
+
+ // Special hack to return info about this closure.
+ if (argCount == 1 && arguments->Get(0)->StrictEquals(resource->engine->qobjectWrapper()->m_hiddenObject)) {
+ v8::Local<v8::Array> data = v8::Array::New(2);
+ data->Set(0, args[0]);
+ data->Set(1, args[1]);
+ return data;
+ }
+
+ QObject *object = resource->object;
+ int index = args[1]->Int32Value();
+
+ if (!object)
+ return v8::Undefined();
+
+ if (index < 0) {
+ // Builtin functions
+ if (index == QOBJECT_TOSTRING_INDEX) {
+ return ToString(resource->engine, object, argCount, arguments);
+ } else if (index == QOBJECT_DESTROY_INDEX) {
+ return Destroy(resource->engine, object, argCount, arguments);
+ } else {
+ return v8::Undefined();
+ }
+ }
+
+ QDeclarativePropertyCache::Data method;
+
+ if (QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(object)->declarativeData)) {
+ if (ddata->propertyCache) {
+ QDeclarativePropertyCache::Data *d = ddata->propertyCache->method(index);
+ if (!d)
+ return v8::Undefined();
+ method = *d;
+ }
+ }
+
+ if (method.coreIndex == -1) {
+ QMetaMethod mm = object->metaObject()->method(index);
+ method.load(object->metaObject()->method(index));
+
+ if (method.coreIndex == -1)
+ return v8::Undefined();
+ }
+
+ if (method.flags & QDeclarativePropertyCache::Data::IsV8Function) {
+ v8::Handle<v8::Value> rv;
+ v8::Handle<v8::Object> qmlglobal = args[2]->ToObject();
+
+ QDeclarativeV8Function func(argCount, arguments, rv, qmlglobal,
+ resource->engine->contextWrapper()->context(qmlglobal),
+ resource->engine);
+ QDeclarativeV8Function *funcptr = &func;
+
+ void *args[] = { 0, &funcptr };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method.coreIndex, args);
+
+ if (rv.IsEmpty()) return v8::Undefined();
+ return rv;
+ }
+
+ CallArgs callArgs(argCount, &arguments);
+ if (method.relatedIndex == -1) {
+ return CallPrecise(object, method, resource->engine, callArgs);
+ } else {
+ return CallOverloaded(object, method, resource->engine, callArgs);
+ }
+}
+
+MetaCallArgument::MetaCallArgument()
+: type(QVariant::Invalid), isObjectType(false)
+{
+}
+
+MetaCallArgument::~MetaCallArgument()
+{
+ cleanup();
+}
+
+void MetaCallArgument::cleanup()
+{
+ if (type == QMetaType::QString) {
+ ((QString *)&data)->~QString();
+ } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
+ ((QVariant *)&data)->~QVariant();
+ } else if (type == qMetaTypeId<QScriptValue>()) {
+ ((QScriptValue *)&data)->~QScriptValue();
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ ((QList<QObject *> *)&data)->~QList<QObject *>();
+ }
+}
+
+void *MetaCallArgument::dataPtr()
+{
+ if (type == -1)
+ return ((QVariant *)data)->data();
+ else
+ return (void *)&data;
+}
+
+void MetaCallArgument::initAsType(int callType)
+{
+ if (type != 0) { cleanup(); type = 0; }
+ if (callType == 0) return;
+
+ if (callType == qMetaTypeId<QScriptValue>()) {
+ new (&data) QScriptValue();
+ type = callType;
+ } else if (callType == QMetaType::Int ||
+ callType == QMetaType::UInt ||
+ callType == QMetaType::Bool ||
+ callType == QMetaType::Double ||
+ callType == QMetaType::Float) {
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ *((QObject **)&data) = 0;
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ new (&data) QString();
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ type = callType;
+ new (&data) QVariant();
+ } else if (callType == qMetaTypeId<QList<QObject *> >()) {
+ type = callType;
+ new (&data) QList<QObject *>();
+ } else if (callType == qMetaTypeId<QDeclarativeV8Handle>()) {
+ type = callType;
+ new (&data) v8::Handle<v8::Value>();
+ } else {
+ type = -1;
+ new (&data) QVariant(callType, (void *)0);
+ }
+}
+
+void MetaCallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Value> value)
+{
+ if (type != 0) { cleanup(); type = 0; }
+
+ if (callType == qMetaTypeId<QScriptValue>()) {
+ new (&data) QScriptValue();
+ type = qMetaTypeId<QScriptValue>();
+ } else if (callType == QMetaType::Int) {
+ *((int *)&data) = int(value->Int32Value());
+ type = callType;
+ } else if (callType == QMetaType::UInt) {
+ *((uint *)&data) = uint(value->Uint32Value());
+ type = callType;
+ } else if (callType == QMetaType::Bool) {
+ *((bool *)&data) = value->BooleanValue();
+ type = callType;
+ } else if (callType == QMetaType::Double) {
+ *((double *)&data) = double(value->NumberValue());
+ type = callType;
+ } else if (callType == QMetaType::Float) {
+ *((float *)&data) = float(value->NumberValue());
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ if (value->IsNull() || value->IsUndefined())
+ new (&data) QString();
+ else
+ new (&data) QString(engine->toString(value->ToString()));
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ *((QObject **)&data) = engine->toQObject(value);
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ new (&data) QVariant(engine->toVariant(value, -1));
+ type = callType;
+ } else if (callType == qMetaTypeId<QList<QObject*> >()) {
+ QList<QObject *> *list = new (&data) QList<QObject *>();
+ if (value->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ uint32_t length = array->Length();
+ for (uint32_t ii = 0; ii < length; ++ii)
+ list->append(engine->toQObject(array->Get(ii)));
+ } else {
+ list->append(engine->toQObject(value));
+ }
+ type = callType;
+ } else if (callType == qMetaTypeId<QDeclarativeV8Handle>()) {
+ new (&data) v8::Handle<v8::Value>(value);
+ type = callType;
+ } else {
+ new (&data) QVariant();
+ type = -1;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine->engine());
+ QVariant v = engine->toVariant(value, -1);
+
+ if (v.userType() == callType) {
+ *((QVariant *)&data) = v;
+ } else if (v.canConvert((QVariant::Type)callType)) {
+ *((QVariant *)&data) = v;
+ ((QVariant *)&data)->convert((QVariant::Type)callType);
+ } else if (const QMetaObject *mo = ep->rawMetaObjectForType(callType)) {
+ QObject *obj = ep->toQObject(v);
+
+ if (obj) {
+ const QMetaObject *objMo = obj->metaObject();
+ while (objMo && objMo != mo) objMo = objMo->superClass();
+ if (!objMo) obj = 0;
+ }
+
+ *((QVariant *)&data) = QVariant(callType, &obj);
+ } else {
+ *((QVariant *)&data) = QVariant(callType, (void *)0);
+ }
+ }
+}
+
+v8::Handle<v8::Value> MetaCallArgument::toValue(QV8Engine *engine)
+{
+ if (type == qMetaTypeId<QScriptValue>()) {
+ return v8::Undefined();
+ } else if (type == QMetaType::Int) {
+ return v8::Integer::New(*((int *)&data));
+ } else if (type == QMetaType::UInt) {
+ return v8::Integer::NewFromUnsigned(*((uint *)&data));
+ } else if (type == QMetaType::Bool) {
+ return v8::Boolean::New(*((bool *)&data));
+ } else if (type == QMetaType::Double) {
+ return v8::Number::New(*((double *)&data));
+ } else if (type == QMetaType::Float) {
+ return v8::Number::New(*((float *)&data));
+ } else if (type == QMetaType::QString) {
+ return engine->toString(*((QString *)&data));
+ } else if (type == QMetaType::QObjectStar) {
+ QObject *object = *((QObject **)&data);
+ if (object)
+ QDeclarativeData::get(object, true)->setImplicitDestructible();
+ return engine->newQObject(object);
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ // XXX aakenned Can this be more optimal? Just use Array as a prototype and
+ // implement directly against QList<QObject*>?
+ QList<QObject *> &list = *(QList<QObject *>*)&data;
+ v8::Local<v8::Array> array = v8::Array::New(list.count());
+ for (int ii = 0; ii < list.count(); ++ii)
+ array->Set(ii, engine->newQObject(list.at(ii)));
+ return array;
+ } else if (type == qMetaTypeId<QDeclarativeV8Handle>()) {
+ return *(v8::Handle<v8::Value>*)&data;
+ } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
+ QVariant value = *((QVariant *)&data);
+ v8::Handle<v8::Value> rv = engine->fromVariant(value);
+ if (QObject *object = engine->toQObject(rv))
+ QDeclarativeData::get(object, true)->setImplicitDestructible();
+ return rv;
+ } else {
+ return v8::Undefined();
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8QOBJECTWRAPPER_P_H
+#define QV8QOBJECTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qhash.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QV8Engine;
+class QV8ObjectResource;
+class QDeclarativePropertyCache;
+class QV8QObjectConnectionList;
+class Q_AUTOTEST_EXPORT QV8QObjectWrapper
+{
+public:
+ QV8QObjectWrapper();
+ ~QV8QObjectWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Handle<v8::Value> newQObject(QObject *object);
+ bool isQObject(v8::Handle<v8::Object>);
+ QObject *toQObject(v8::Handle<v8::Object>);
+ QObject *toQObject(QV8ObjectResource *);
+
+ enum RevisionMode { IgnoreRevision, CheckRevision };
+ v8::Handle<v8::Value> getProperty(QObject *, v8::Handle<v8::String>, RevisionMode);
+ bool setProperty(QObject *, v8::Handle<v8::String>, v8::Handle<v8::Value>, RevisionMode);
+
+private:
+ friend class QDeclarativePropertyCache;
+ friend class QV8QObjectConnectionList;
+
+ static v8::Handle<v8::Value> GetProperty(QV8Engine *, QObject *, v8::Handle<v8::Value> *,
+ v8::Handle<v8::String>, QV8QObjectWrapper::RevisionMode);
+ static bool SetProperty(QV8Engine *, QObject *, v8::Handle<v8::String>,
+ v8::Handle<v8::Value>, QV8QObjectWrapper::RevisionMode);
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Integer> Query(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Connect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Disconnect(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Invoke(const v8::Arguments &args);
+ static QPair<QObject *, int> ExtractQtMethod(QV8Engine *, v8::Handle<v8::Function>);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_methodConstructor;
+ v8::Persistent<v8::String> m_toStringSymbol;
+ v8::Persistent<v8::String> m_destroySymbol;
+ v8::Persistent<v8::Object> m_hiddenObject;
+ QHash<QObject *, QV8QObjectConnectionList *> m_connections;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8QOBJECTWRAPPER_P_H
+
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8stringwrapper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QV8StringResource : public v8::String::ExternalStringResource
+{
+public:
+ QV8StringResource(const QString &str) : str(str) {}
+ virtual const uint16_t* data() const { return (uint16_t*)str.constData(); }
+ virtual size_t length() const { return str.length(); }
+ virtual void Dispose() { delete this; }
+
+ QString str;
+};
+
+QV8StringWrapper::QV8StringWrapper()
+{
+}
+
+QV8StringWrapper::~QV8StringWrapper()
+{
+}
+
+void QV8StringWrapper::init()
+{
+}
+
+void QV8StringWrapper::destroy()
+{
+}
+
+v8::Local<v8::String> QV8StringWrapper::toString(const QString &qstr)
+{
+// return v8::String::NewExternal(new QV8StringResource(qstr));
+ return v8::String::New((uint16_t*)qstr.constData(), qstr.length());
+}
+
+QString QV8StringWrapper::toString(v8::Handle<v8::String> jsstr)
+{
+ if (jsstr.IsEmpty()) {
+ return QString();
+ } else if (jsstr->IsExternal()) {
+ QV8StringResource *r = (QV8StringResource *)jsstr->GetExternalStringResource();
+ return r->str;
+ } else {
+ QString qstr;
+ qstr.resize(jsstr->Length());
+ jsstr->Write((uint16_t*)qstr.data());
+ return qstr;
+ }
+}
+
+QT_END_NAMESPACE
**
****************************************************************************/
-#ifndef QDECLARATIVEGLOBALSCRIPTCLASS_P_H
-#define QDECLARATIVEGLOBALSCRIPTCLASS_P_H
+#ifndef QDECLARATIVEV8STRINGWRAPPER_P_H
+#define QDECLARATIVEV8STRINGWRAPPER_P_H
//
// W A R N I N G
// We mean it.
//
-#include <QtScript/qscriptclass.h>
-#include <QtCore/qset.h>
+#include <QtCore/qstring.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class Q_AUTOTEST_EXPORT QDeclarativeGlobalScriptClass : public QScriptClass
+class Q_AUTOTEST_EXPORT QV8StringWrapper
{
public:
- QDeclarativeGlobalScriptClass(QScriptEngine *);
+ QV8StringWrapper();
+ ~QV8StringWrapper();
- virtual QueryFlags queryProperty(const QScriptValue &object,
- const QScriptString &name,
- QueryFlags flags, uint *id);
+ void init();
+ void destroy();
- virtual void setProperty(QScriptValue &object, const QScriptString &name,
- uint id, const QScriptValue &value);
-
- void explicitSetProperty(const QStringList &, const QList<QScriptValue> &);
-
- const QScriptValue &staticGlobalObject() const { return m_staticGlobalObject; }
-
- const QSet<QString> &illegalNames() const { return m_illegalNames; }
-
-private:
- QSet<QString> m_illegalNames;
- QScriptValue m_staticGlobalObject;
+ v8::Local<v8::String> toString(const QString &);
+ QString toString(v8::Handle<v8::String>);
};
QT_END_NAMESPACE
-#endif // QDECLARATIVEGLOBALSCRIPTCLASS_P_H
+#endif // QDECLARATIVEV8STRINGWRAPPER_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8contextwrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativeengine_p.h>
+#include <private/qdeclarativecontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8TypeResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(TypeType);
+
+public:
+ QV8TypeResource(QV8Engine *engine);
+ virtual ~QV8TypeResource();
+
+ QV8TypeWrapper::TypeNameMode mode;
+
+ QDeclarativeGuard<QObject> object;
+ QDeclarativeType *type;
+ QDeclarativeTypeNameCache *typeNamespace;
+};
+
+QV8TypeResource::QV8TypeResource(QV8Engine *engine)
+: QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0)
+{
+}
+
+QV8TypeResource::~QV8TypeResource()
+{
+ if (typeNamespace) typeNamespace->release();
+}
+
+QV8TypeWrapper::QV8TypeWrapper()
+: m_engine(0)
+{
+}
+
+QV8TypeWrapper::~QV8TypeWrapper()
+{
+}
+
+void QV8TypeWrapper::destroy()
+{
+ m_constructor.Dispose();
+}
+
+void QV8TypeWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+}
+
+v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeType *t, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8TypeResource *r = new QV8TypeResource(m_engine);
+ r->mode = mode; r->object = o; r->type = t;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeTypeNameCache *t, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8TypeResource *r = new QV8TypeResource(m_engine);
+ t->addref();
+ r->mode = mode; r->object = o; r->typeNamespace = t;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ v8::Object::ExternalResource *r = info.This()->GetExternalResource();
+ QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
+
+ if (!resource)
+ return v8::Undefined();
+
+ QV8Engine *v8engine = resource->engine;
+ QObject *object = resource->object;
+
+ if (resource->type) {
+ QDeclarativeType *type = resource->type;
+
+ if (QV8Engine::startsWithUpper(property)) {
+ if (resource->mode == IncludeEnums) {
+ QString name = v8engine->toString(property);
+
+ // ### Optimize
+ QByteArray enumName = name.toUtf8();
+ const QMetaObject *metaObject = type->baseMetaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ int value = e.keyToValue(enumName.constData());
+ if (value != -1)
+ return v8::Integer::New(value);
+ }
+ }
+
+ // Fall through to undefined
+
+ } else if (resource->object) {
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ return v8engine->qobjectWrapper()->getProperty(ao, property, QV8QObjectWrapper::IgnoreRevision);
+
+ // Fall through to undefined
+ }
+
+ // Fall through to undefined
+
+ } else if (resource->typeNamespace) {
+
+ QDeclarativeTypeNameCache *typeNamespace = resource->typeNamespace;
+ QDeclarativeTypeNameCache::Data *d = typeNamespace->data(property);
+ Q_ASSERT(!d || !d->typeNamespace); // Nested namespaces not supported
+
+ if (d && d->type) {
+ return v8engine->typeWrapper()->newObject(object, d->type, resource->mode);
+ } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = typeNamespace->moduleApi()) {
+
+ // XXX QtScript/JSC required
+ return v8::Undefined();
+
+ }
+
+ // Fall through to undefined
+
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ v8::Object::ExternalResource *r = info.This()->GetExternalResource();
+ QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
+
+ if (!resource)
+ return value;
+
+ QV8Engine *v8engine = resource->engine;
+
+ // XXX module api
+
+ if (resource->type && resource->object) {
+ QDeclarativeType *type = resource->type;
+ QObject *object = resource->object;
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ v8engine->qobjectWrapper()->setProperty(ao, property, value, QV8QObjectWrapper::IgnoreRevision);
+ }
+
+ return value;
+}
+
+QT_END_NAMESPACE
**
****************************************************************************/
-#ifndef QDECLARATIVETYPENAMESCRIPTCLASS_P_H
-#define QDECLARATIVETYPENAMESCRIPTCLASS_P_H
+#ifndef QV8TYPEWRAPPER_P_H
+#define QV8TYPEWRAPPER_P_H
//
// W A R N I N G
//
// We mean it.
//
-#include "private/qdeclarativeengine_p.h"
-#include <private/qscriptdeclarativeclass_p.h>
-#include <QtScript/qscriptclass.h>
+#include <QtCore/qglobal.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
+class QObject;
+class QV8Engine;
class QDeclarativeType;
class QDeclarativeTypeNameCache;
-class QDeclarativeTypeNameScriptClass : public QScriptDeclarativeClass
+class QV8TypeWrapper
{
public:
- QDeclarativeTypeNameScriptClass(QDeclarativeEngine *);
- ~QDeclarativeTypeNameScriptClass();
+ QV8TypeWrapper();
+ ~QV8TypeWrapper();
- enum TypeNameMode { IncludeEnums, ExcludeEnums };
- QScriptValue newObject(QObject *, QDeclarativeType *, TypeNameMode = IncludeEnums);
- QScriptValue newObject(QObject *, QDeclarativeTypeNameCache *, TypeNameMode = IncludeEnums);
-
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
+ void init(QV8Engine *);
+ void destroy();
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ enum TypeNameMode { IncludeEnums, ExcludeEnums };
+ v8::Local<v8::Object> newObject(QObject *, QDeclarativeType *, TypeNameMode = IncludeEnums);
+ v8::Local<v8::Object> newObject(QObject *, QDeclarativeTypeNameCache *, TypeNameMode = IncludeEnums);
private:
- QDeclarativeEngine *engine;
- QObject *object;
- QDeclarativeType *type;
- QDeclarativeMetaType::ModuleApiInstance *api;
- quint32 enumValue;
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVETYPENAMESCRIPTCLASS_P_H
+#endif // QV8TYPEWRAPPER_P_H
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8valuetypewrapper_p.h"
+#include "qv8engine_p.h"
+
+#include <private/qdeclarativevaluetype_p.h>
+#include <private/qdeclarativebinding_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8ValueTypeResource : public QV8ObjectResource
+{
+ V8_RESOURCE_TYPE(ValueTypeType);
+
+public:
+ enum ObjectType { Reference, Copy };
+
+ QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType);
+
+ ObjectType objectType;
+ QDeclarativeValueType *type;
+};
+
+class QV8ValueTypeReferenceResource : public QV8ValueTypeResource
+{
+public:
+ QV8ValueTypeReferenceResource(QV8Engine *engine);
+
+ QDeclarativeGuard<QObject> object;
+ int property;
+};
+
+class QV8ValueTypeCopyResource : public QV8ValueTypeResource
+{
+public:
+ QV8ValueTypeCopyResource(QV8Engine *engine);
+
+ QVariant value;
+};
+
+QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType)
+: QV8ObjectResource(engine), objectType(objectType)
+{
+}
+
+QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine)
+: QV8ValueTypeResource(engine, Reference)
+{
+}
+
+QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine)
+: QV8ValueTypeResource(engine, Copy)
+{
+}
+
+QV8ValueTypeWrapper::QV8ValueTypeWrapper()
+: m_engine(0)
+{
+}
+
+QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
+{
+}
+
+void QV8ValueTypeWrapper::destroy()
+{
+ m_constructor.Dispose();
+}
+
+void QV8ValueTypeWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+}
+
+v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
+{
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine);
+ r->type = type; r->object = object; r->property = property;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QDeclarativeValueType *type)
+{
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv = m_constructor->NewInstance();
+ QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine);
+ r->type = type; r->value = value;
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
+ if (r) return toVariant(r);
+ else return QVariant();
+}
+
+QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
+ QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
+
+ if (resource->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
+
+ if (reference->object) {
+ reference->type->read(reference->object, reference->property);
+ return reference->type->value();
+ } else {
+ return QVariant();
+ }
+
+ } else {
+ Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
+
+ return copy->value;
+ }
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
+ if (!r) return v8::Undefined();
+
+ // XXX aakenned - this is horribly inefficient. People seem to have taken a
+ // liking to value type properties, so we should probably try and optimize it
+ // a little.
+
+ QByteArray propName = r->engine->toString(property).toUtf8();
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return v8::Undefined();
+
+ if (r->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+
+ if (!reference->object)
+ return v8::Undefined();
+
+ r->type->read(reference->object, reference->property);
+ } else {
+ Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+
+ r->type->setValue(copy->value);
+ }
+
+ QMetaProperty prop = r->type->metaObject()->property(index);
+ QVariant result = prop.read(r->type);
+
+ return r->engine->fromVariant(result);
+}
+
+v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
+ if (!r) return value;
+
+ QByteArray propName = r->engine->toString(property).toUtf8();
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return value;
+
+ if (r->objectType == QV8ValueTypeResource::Reference) {
+ QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
+
+ if (!reference->object ||
+ !reference->object->metaObject()->property(reference->property).isWritable())
+ return value;
+
+ r->type->read(reference->object, reference->property);
+ QMetaProperty p = r->type->metaObject()->property(index);
+
+ QDeclarativeBinding *newBinding = 0;
+
+ if (value->IsFunction()) {
+ QDeclarativeContextData *context = r->engine->callingContext();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
+
+ QDeclarativePropertyCache::Data cacheData;
+ cacheData.flags = QDeclarativePropertyCache::Data::IsWritable;
+ cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
+ cacheData.coreIndex = reference->property;
+
+ QDeclarativePropertyCache::ValueTypeData valueTypeData;
+ valueTypeData.valueTypeCoreIdx = index;
+ valueTypeData.valueTypePropType = p.userType();
+
+ v8::Local<v8::StackTrace> trace =
+ v8::StackTrace::CurrentStackTrace(1,
+ (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
+ v8::StackTrace::kScriptName));
+ v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
+ int lineNumber = frame->GetLineNumber();
+ QString url = r->engine->toString(frame->GetScriptName());
+
+ newBinding = new QDeclarativeBinding(&function, reference->object, context);
+ newBinding->setSourceLocation(url, lineNumber);
+ newBinding->setTarget(QDeclarativePropertyPrivate::restore(cacheData, valueTypeData,
+ reference->object, context));
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
+ }
+
+ QDeclarativeAbstractBinding *oldBinding =
+ QDeclarativePropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+ if (!value->IsFunction()) {
+ QVariant v = r->engine->toVariant(value, -1);
+
+ if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
+ v = v.toInt();
+
+ p.write(reference->type, v);
+
+ reference->type->write(reference->object, reference->property, 0);
+ }
+
+ } else {
+ Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
+
+ QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
+
+ QVariant v = r->engine->toVariant(value, -1);
+
+ r->type->setValue(copy->value);
+ QMetaProperty p = r->type->metaObject()->property(index);
+ p.write(r->type, v);
+ copy->value = r->type->value();
+ }
+
+ return value;
+}
+
+QT_END_NAMESPACE
**
****************************************************************************/
-#ifndef QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
-#define QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
+#ifndef QV8VALUETYPEWRAPPER_P_H
+#define QV8VALUETYPEWRAPPER_P_H
//
// W A R N I N G
// We mean it.
//
-
-#include <private/qscriptdeclarativeclass_p.h>
+#include <QtCore/qglobal.h>
+#include <QtDeclarative/qdeclarativelist.h>
+#include <private/qv8_p.h>
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
+class QV8Engine;
+class QV8ObjectResource;
class QDeclarativeValueType;
-class QDeclarativeValueTypeScriptClass : public QScriptDeclarativeClass
+class QV8ValueTypeWrapper
{
public:
- QDeclarativeValueTypeScriptClass(QDeclarativeEngine *);
- ~QDeclarativeValueTypeScriptClass();
+ QV8ValueTypeWrapper();
+ ~QV8ValueTypeWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
- QScriptValue newObject(QObject *object, int coreIndex, QDeclarativeValueType *);
- QScriptValue newObject(const QVariant &, QDeclarativeValueType *);
+ v8::Local<v8::Object> newValueType(QObject *, int, QDeclarativeValueType *);
+ v8::Local<v8::Object> newValueType(const QVariant &, QDeclarativeValueType *);
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual void setProperty(Object *, const Identifier &name, const QScriptValue &);
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
- virtual QVariant toVariant(Object *, bool *ok = 0);
- QVariant toVariant(const QScriptValue &);
private:
- QDeclarativeEngine *engine;
- int m_lastIndex;
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
};
QT_END_NAMESPACE
-#endif // QDECLARATIVEVALUETYPESCRIPTCLASS_P_H
+#endif // QV8VALUETYPEWRAPPER_P_H
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8variantwrapper_p.h"
+#include "qv8engine_p.h"
+#include "qdeclarativeengine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QV8VariantResource : public QV8ObjectResource,
+ public QDeclarativeEnginePrivate::ScarceResourceData
+{
+ V8_RESOURCE_TYPE(VariantType);
+public:
+ QV8VariantResource(QV8Engine *engine, const QVariant &data);
+};
+
+QV8VariantResource::QV8VariantResource(QV8Engine *engine, const QVariant &data)
+: QV8ObjectResource(engine), QDeclarativeEnginePrivate::ScarceResourceData(data)
+{
+}
+
+QV8VariantWrapper::QV8VariantWrapper()
+: m_engine(0)
+{
+}
+
+QV8VariantWrapper::~QV8VariantWrapper()
+{
+}
+
+void QV8VariantWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+ {
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ m_constructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+ {
+ m_preserve = v8::Persistent<v8::Function>::New(v8::FunctionTemplate::New(Preserve)->GetFunction());
+ m_destroy = v8::Persistent<v8::Function>::New(v8::FunctionTemplate::New(Destroy)->GetFunction());
+ v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
+ ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
+ ft->InstanceTemplate()->SetHasExternalResource(true);
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("preserve"), PreserveGetter, 0,
+ m_preserve, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ ft->InstanceTemplate()->SetAccessor(v8::String::New("destroy"), DestroyGetter, 0,
+ m_destroy, v8::DEFAULT,
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ m_scarceConstructor = v8::Persistent<v8::Function>::New(ft->GetFunction());
+ }
+
+}
+
+void QV8VariantWrapper::destroy()
+{
+ m_destroy.Dispose();
+ m_preserve.Dispose();
+ m_scarceConstructor.Dispose();
+ m_constructor.Dispose();
+}
+
+v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
+{
+ bool scarceResource = value.type() == QVariant::Pixmap ||
+ value.type() == QVariant::Image;
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(m_engine->engine());
+
+ // XXX aakenned - NewInstance() is slow for our case
+ v8::Local<v8::Object> rv;
+ QV8VariantResource *r = new QV8VariantResource(m_engine, value);
+
+ if (scarceResource) {
+ Q_ASSERT(ep->scarceResourcesRefCount);
+ rv = m_scarceConstructor->NewInstance();
+ ep->scarceResources.insert(r);
+ } else {
+ rv = m_constructor->NewInstance();
+ }
+
+ rv->SetExternalResource(r);
+ return rv;
+}
+
+bool QV8VariantWrapper::isVariant(v8::Handle<v8::Value> value)
+{
+ return value->IsObject() && v8_resource_cast<QV8VariantResource>(value->ToObject());
+}
+
+QVariant QV8VariantWrapper::toVariant(v8::Handle<v8::Object> obj)
+{
+ QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(obj);
+ return r?r->data:QVariant();
+}
+
+QVariant QV8VariantWrapper::toVariant(QV8ObjectResource *r)
+{
+ Q_ASSERT(r->resourceType() == QV8ObjectResource::VariantType);
+ return static_cast<QV8VariantResource *>(r)->data;
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info)
+{
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::PreserveGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::DestroyGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info)
+{
+ Q_UNUSED(property);
+ return info.Data();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Preserve(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ resource->node.remove();
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> QV8VariantWrapper::Destroy(const v8::Arguments &args)
+{
+ QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
+ if (resource) {
+ resource->data = QVariant();
+ resource->node.remove();
+ }
+ return v8::Undefined();
+}
+
+QT_END_NAMESPACE
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV8VARIANTWRAPPER_P_H
+#define QV8VARIANTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtDeclarative/qdeclarativelist.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+class QV8ObjectResource;
+class QV8VariantWrapper
+{
+public:
+ QV8VariantWrapper();
+ ~QV8VariantWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Local<v8::Object> newVariant(const QVariant &);
+ bool isVariant(v8::Handle<v8::Value>);
+ QVariant toVariant(v8::Handle<v8::Object>);
+ QVariant toVariant(QV8ObjectResource *);
+
+private:
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> PreserveGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> DestroyGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo &info);
+ static v8::Handle<v8::Value> Preserve(const v8::Arguments &args);
+ static v8::Handle<v8::Value> Destroy(const v8::Arguments &args);
+
+ QV8Engine *m_engine;
+ v8::Persistent<v8::Function> m_constructor;
+ v8::Persistent<v8::Function> m_scarceConstructor;
+ v8::Persistent<v8::Function> m_preserve;
+ v8::Persistent<v8::Function> m_destroy;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8VARIANTWRAPPER_P_H
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv8worker_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// We allow the following JavaScript types to be passed between the main and
+// the secondary thread:
+// + undefined
+// + null
+// + Boolean
+// + String
+// + Function
+// + Array
+// + "Simple" Objects
+// + Number
+// + Date
+// + RegExp
+// <quint8 type><quint24 size><data>
+
+enum Type {
+ WorkerUndefined,
+ WorkerNull,
+ WorkerTrue,
+ WorkerFalse,
+ WorkerString,
+ WorkerFunction,
+ WorkerArray,
+ WorkerObject,
+ WorkerInt32,
+ WorkerUint32,
+ WorkerNumber,
+ WorkerDate,
+ WorkerRegexp
+};
+
+static inline quint32 valueheader(Type type, quint32 size = 0)
+{
+ return quint8(type) << 24 | (size & 0xFFFFFF);
+}
+
+static inline Type headertype(quint32 header)
+{
+ return (Type)(header >> 24);
+}
+
+static inline quint32 headersize(quint32 header)
+{
+ return header & 0xFFFFFF;
+}
+
+static inline void push(QByteArray &data, quint32 value)
+{
+ data.append((const char *)&value, sizeof(quint32));
+}
+
+static inline void push(QByteArray &data, double value)
+{
+ data.append((const char *)&value, sizeof(double));
+}
+
+static inline void reserve(QByteArray &data, int extra)
+{
+ data.reserve(data.size() + extra);
+}
+
+static inline quint32 popUint32(const char *&data)
+{
+ quint32 rv = *((quint32 *)data);
+ data += sizeof(quint32);
+ return rv;
+}
+
+static inline double popDouble(const char *&data)
+{
+ double rv = *((double *)data);
+ data += sizeof(double);
+ return rv;
+}
+
+// XXX double check exception safety
+
+#include <QDebug>
+#define ALIGN(size) (((size) + 3) & ~3)
+void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *engine)
+{
+ if (v.IsEmpty()) {
+ } else if (v->IsUndefined()) {
+ push(data, valueheader(WorkerUndefined));
+ } else if (v->IsNull()) {
+ push(data, valueheader(WorkerNull));
+ } else if (v->IsTrue()) {
+ push(data, valueheader(WorkerTrue));
+ } else if (v->IsFalse()) {
+ push(data, valueheader(WorkerFalse));
+ } else if (v->IsString()) {
+ v8::Handle<v8::String> string = v->ToString();
+ int length = string->Length() + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ int utf16size = ALIGN(length * sizeof(uint16_t));
+
+ reserve(data, utf16size + sizeof(quint32));
+ push(data, valueheader(WorkerString, length));
+
+ int offset = data.size();
+ data.resize(data.size() + utf16size);
+ char *buffer = data.data() + offset;
+
+ string->Write((uint16_t*)buffer);
+ } else if (v->IsFunction()) {
+ // XXX
+ push(data, valueheader(WorkerUndefined));
+ } else if (v->IsArray()) {
+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(v);
+ uint32_t length = array->Length();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ reserve(data, sizeof(quint32) + length * sizeof(quint32));
+ push(data, valueheader(WorkerArray, length));
+ for (uint32_t ii = 0; ii < length; ++ii)
+ serialize(data, array->Get(ii), engine);
+ } else if (v->IsInt32()) {
+ reserve(data, 2 * sizeof(quint32));
+ push(data, valueheader(WorkerInt32));
+ push(data, (quint32)v->Int32Value());
+ } else if (v->IsUint32()) {
+ reserve(data, 2 * sizeof(quint32));
+ push(data, valueheader(WorkerUint32));
+ push(data, v->Uint32Value());
+ } else if (v->IsNumber()) {
+ reserve(data, sizeof(quint32) + sizeof(double));
+ push(data, valueheader(WorkerNumber));
+ push(data, v->NumberValue());
+ } else if (v->IsDate()) {
+ reserve(data, sizeof(quint32) + sizeof(double));
+ push(data, valueheader(WorkerDate));
+ push(data, v8::Handle<v8::Date>::Cast(v)->NumberValue());
+ } else if (v->IsRegExp()) {
+ v8::Handle<v8::RegExp> regexp = v8::Handle<v8::RegExp>::Cast(v);
+ quint32 flags = regexp->GetFlags();
+ v8::Local<v8::String> source = regexp->GetSource();
+
+ int length = source->Length() + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ int utf16size = ALIGN(length * sizeof(uint16_t));
+
+ reserve(data, sizeof(quint32) + utf16size);
+ push(data, valueheader(WorkerRegexp, flags));
+ push(data, (quint32)length);
+ int offset = data.size();
+ data.resize(data.size() + utf16size);
+ char *buffer = data.data() + offset;
+
+ source->Write((uint16_t*)buffer);
+ } else if (v->IsObject() && !v->ToObject()->GetExternalResource()) {
+ v8::Handle<v8::Object> object = v->ToObject();
+ v8::Local<v8::Array> properties = engine->getOwnPropertyNames(object);
+ quint32 length = properties->Length();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
+ }
+ push(data, valueheader(WorkerObject, length));
+ v8::TryCatch tc;
+ for (quint32 ii = 0; ii < length; ++ii) {
+ v8::Local<v8::String> str = properties->Get(ii)->ToString();
+ serialize(data, str, engine);
+
+ v8::Local<v8::Value> val = object->Get(str);
+ if (tc.HasCaught()) {
+ serialize(data, v8::Undefined(), engine);
+ tc.Reset();
+ } else {
+ serialize(data, val, engine);
+ }
+ }
+ } else {
+ push(data, valueheader(WorkerUndefined));
+ }
+
+ // XXX Need to serialize QDeclarativeListModel
+ /*
+ QDeclarativeListModel *lm = qobject_cast<QDeclarativeListModel *>(value.toQObject());
+ if (lm) {
+ QDeclarativeListModelWorkerAgent *agent = lm->agent();
+ if (agent) {
+ QDeclarativeListModelWorkerAgent::VariantRef v(agent);
+ return QVariant::fromValue(v);
+ } else {
+ return QVariant();
+ }
+ }
+ */
+}
+
+v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engine)
+{
+ quint32 header = popUint32(data);
+ Type type = headertype(header);
+
+ switch (type) {
+ case WorkerUndefined:
+ return v8::Undefined();
+ case WorkerNull:
+ return v8::Null();
+ case WorkerTrue:
+ return v8::True();
+ case WorkerFalse:
+ return v8::False();
+ case WorkerString:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::String> string = v8::String::New((uint16_t*)data, size - 1);
+ data += ALIGN(size * sizeof(uint16_t));
+ return string;
+ }
+ case WorkerFunction:
+ Q_ASSERT(!"Unreachable");
+ break;
+ case WorkerArray:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::Array> array = v8::Array::New(size);
+ for (quint32 ii = 0; ii < size; ++ii) {
+ array->Set(ii, deserialize(data, engine));
+ }
+ return array;
+ }
+ case WorkerObject:
+ {
+ quint32 size = headersize(header);
+ v8::Local<v8::Object> o = v8::Object::New();
+ for (quint32 ii = 0; ii < size; ++ii) {
+ v8::Handle<v8::Value> name = deserialize(data, engine);
+ v8::Handle<v8::Value> value = deserialize(data, engine);
+ o->Set(name, value);
+ }
+ return o;
+ }
+ case WorkerInt32:
+ return v8::Integer::New((qint32)popUint32(data));
+ case WorkerUint32:
+ return v8::Integer::NewFromUnsigned(popUint32(data));
+ case WorkerNumber:
+ return v8::Number::New(popDouble(data));
+ case WorkerDate:
+ return v8::Date::New(popDouble(data));
+ case WorkerRegexp:
+ {
+ quint32 flags = headersize(header);
+ quint32 length = popUint32(data);
+ v8::Local<v8::String> source = v8::String::New((uint16_t*)data, length - 1);
+ data += ALIGN(length * sizeof(uint16_t));
+ return v8::RegExp::New(source, (v8::RegExp::Flags)flags);
+ }
+ }
+ Q_ASSERT(!"Unreachable");
+ return v8::Undefined();
+}
+
+QByteArray QV8Worker::serialize(v8::Handle<v8::Value> value, QV8Engine *engine)
+{
+ QByteArray rv;
+ serialize(rv, value, engine);
+ return rv;
+}
+
+v8::Handle<v8::Value> QV8Worker::deserialize(const QByteArray &data, QV8Engine *engine)
+{
+ const char *stream = data.constData();
+ return deserialize(stream, engine);
+}
+
+QT_END_NAMESPACE
+
**
****************************************************************************/
-#ifndef QDECLARATIVELISTSCRIPTCLASS_P_H
-#define QDECLARATIVELISTSCRIPTCLASS_P_H
+#ifndef QV8WORKER_P_H
+#define QV8WORKER_P_H
//
// W A R N I N G
// We mean it.
//
-#include <private/qscriptdeclarativeclass_p.h>
-#include "qdeclarativelist.h"
+#include "qv8engine_p.h"
QT_BEGIN_NAMESPACE
-class QDeclarativeEngine;
-class QDeclarativeListScriptClass : public QScriptDeclarativeClass
-{
+class QV8Worker {
public:
- QDeclarativeListScriptClass(QDeclarativeEngine *);
- ~QDeclarativeListScriptClass();
+ struct SavedData {
+ };
- QScriptValue newList(QObject *, int, int);
- QScriptValue newList(const QDeclarativeListProperty<QObject> &, int);
-
-protected:
- virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &,
- QScriptClass::QueryFlags flags);
- virtual Value property(Object *, const Identifier &);
- virtual QVariant toVariant(Object *, bool *ok);
+ static QByteArray serialize(v8::Handle<v8::Value>, QV8Engine *);
+ static v8::Handle<v8::Value> deserialize(const QByteArray &, QV8Engine *);
private:
- PersistentIdentifier m_lengthId;
- QDeclarativeEngine *engine;
-
- quint32 lastIndex;
+ static void serialize(QByteArray &, v8::Handle<v8::Value>, QV8Engine *);
+ static v8::Handle<v8::Value> deserialize(const char *&, QV8Engine *);
};
QT_END_NAMESPACE
-#endif // QDECLARATIVELISTSCRIPTCLASS_P_H
-
+#endif // QV8WORKER_P_H
--- /dev/null
+INCLUDEPATH += $$PWD/../../../3rdparty/javascriptcore
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qv8_p.h \
+ $$PWD/qv8stringwrapper_p.h \
+ $$PWD/qv8engine_p.h \
+ $$PWD/qhashedstring_p.h \
+ $$PWD/qv8contextwrapper_p.h \
+ $$PWD/qv8qobjectwrapper_p.h \
+ $$PWD/qv8typewrapper_p.h \
+ $$PWD/qv8listwrapper_p.h \
+ $$PWD/qv8variantwrapper_p.h \
+ $$PWD/qv8valuetypewrapper_p.h \
+ $$PWD/qv8include_p.h \
+ $$PWD/qv8worker_p.h \
+ $$PWD/../../../3rdparty/javascriptcore/DateMath.h \
+
+SOURCES += \
+ $$PWD/qv8stringwrapper.cpp \
+ $$PWD/qv8engine.cpp \
+ $$PWD/qhashedstring.cpp \
+ $$PWD/qv8contextwrapper.cpp \
+ $$PWD/qv8qobjectwrapper.cpp \
+ $$PWD/qv8typewrapper.cpp \
+ $$PWD/qv8listwrapper.cpp \
+ $$PWD/qv8variantwrapper.cpp \
+ $$PWD/qv8valuetypewrapper.cpp \
+ $$PWD/qv8include.cpp \
+ $$PWD/qv8worker.cpp \
+ $$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \
+
if (!node)
return 0;
+#if 0
return QDeclarativeEnginePrivate::qmlScriptObject(node->object(this), eng);
+#endif
}
void NestedListModel::set(int index, const QScriptValue& valuemap, QList<int> *roles)
TEMPLATE = subdirs
CONFIG += ordered
-SUBDIRS += declarative plugins
+SUBDIRS += v8 declarative plugins
contains(QT_CONFIG, qmltest): SUBDIRS += qmltest
SUBDIRS += imports
--- /dev/null
+From be15626304572957f432160bb0fa35af5e6663b2 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Mon, 23 May 2011 15:47:20 +1000
+Subject: [PATCH 1/7] Add hashing and comparison methods to v8::String
+
+This allows us to more rapidly search for a v8::String inside
+a hash of QStrings.
+---
+ include/v8.h | 17 +++++++++++++++++
+ src/api.cc | 15 +++++++++++++++
+ src/objects.cc | 29 +++++++++++++++++++++++++++++
+ src/objects.h | 2 ++
+ 4 files changed, 63 insertions(+), 0 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index d15d024..ac3c062 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -994,6 +994,23 @@ class String : public Primitive {
+ V8EXPORT int Utf8Length() const;
+
+ /**
++ * Returns the hash of this string.
++ */
++ V8EXPORT uint32_t Hash() const;
++
++ /**
++ * Compute a hash value for the passed UTF16 string
++ * data.
++ */
++ V8EXPORT static uint32_t ComputeHash(uint16_t *string, int length);
++
++ /**
++ * Returns true if this string is equal to the external
++ * string data provided.
++ */
++ V8EXPORT bool Equals(uint16_t *string, int length);
++
++ /**
+ * Write the contents of the string to an external buffer.
+ * If no arguments are given, expects the buffer to be large
+ * enough to hold the entire string and NULL terminator. Copies
+diff --git a/src/api.cc b/src/api.cc
+index a2373cd..09b6b93 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3284,6 +3284,21 @@ int String::Utf8Length() const {
+ return str->Utf8Length();
+ }
+
++uint32_t String::Hash() const {
++ i::Handle<i::String> str = Utils::OpenHandle(this);
++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Hash()")) return 0;
++ return str->Hash();
++}
++
++uint32_t String::ComputeHash(uint16_t *string, int length) {
++ return i::HashSequentialString<i::uc16>(string, length) >> i::String::kHashShift;
++}
++
++bool String::Equals(uint16_t *string, int length) {
++ i::Handle<i::String> str = Utils::OpenHandle(this);
++ if (IsDeadCheck(str->GetIsolate(), "v8::String::Equals()")) return 0;
++ return str->SlowEqualsExternal(string, length);
++}
+
+ int String::WriteUtf8(char* buffer,
+ int capacity,
+diff --git a/src/objects.cc b/src/objects.cc
+index df61956..bbdb37b 100644
+--- a/src/objects.cc
++++ b/src/objects.cc
+@@ -5346,6 +5346,35 @@ static inline bool CompareStringContentsPartial(Isolate* isolate,
+ }
+ }
+
++bool String::SlowEqualsExternal(uc16 *string, int length) {
++ int len = this->length();
++ if (len != length) return false;
++ if (len == 0) return true;
++
++ // We know the strings are both non-empty. Compare the first chars
++ // before we try to flatten the strings.
++ if (this->Get(0) != string[0]) return false;
++
++ String* lhs = this->TryFlattenGetString();
++
++ Isolate* isolate = GetIsolate();
++ if (lhs->IsFlat()) {
++ if (lhs->IsAsciiRepresentation()) {
++ Vector<const char> vec1 = lhs->ToAsciiVector();
++ VectorIterator<char> buf1(vec1);
++ VectorIterator<uc16> ib(string, length);
++ return CompareStringContents(&buf1, &ib);
++ } else {
++ Vector<const uc16> vec1 = lhs->ToUC16Vector();
++ Vector<const uc16> vec2(string, length);
++ return CompareRawStringContents(vec1, vec2);
++ }
++ } else {
++ isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
++ VectorIterator<uc16> ib(string, length);
++ return CompareStringContents(isolate->objects_string_compare_buffer_a(), &ib);
++ }
++}
+
+ bool String::SlowEquals(String* other) {
+ // Fast check: negative check with lengths.
+diff --git a/src/objects.h b/src/objects.h
+index e966b3d..cd11c88 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -5359,6 +5359,8 @@ class String: public HeapObject {
+ bool IsAsciiEqualTo(Vector<const char> str);
+ bool IsTwoByteEqualTo(Vector<const uc16> str);
+
++ bool SlowEqualsExternal(uc16 *string, int length);
++
+ // Return a UTF8 representation of the string. The string is null
+ // terminated but may optionally contain nulls. Length is returned
+ // in length_output if length_output is not a null pointer The string
+--
+1.7.2.3
+
--- /dev/null
+From edf12cdcd4ec04bc6de8c031c0b9c13a664ba7a9 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Mon, 23 May 2011 15:55:26 +1000
+Subject: [PATCH 2/7] Add a bit field 3 to Map
+
+Bit field 3 will be used to add QML specific map flags.
+---
+ src/heap.cc | 2 ++
+ src/objects-inl.h | 10 ++++++++++
+ src/objects.cc | 2 ++
+ src/objects.h | 9 ++++++++-
+ 4 files changed, 22 insertions(+), 1 deletions(-)
+
+diff --git a/src/heap.cc b/src/heap.cc
+index 2b6c11f..4a58bf6 100644
+--- a/src/heap.cc
++++ b/src/heap.cc
+@@ -1573,6 +1573,7 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
+ reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
+ reinterpret_cast<Map*>(result)->set_bit_field(0);
+ reinterpret_cast<Map*>(result)->set_bit_field2(0);
++ reinterpret_cast<Map*>(result)->set_bit_field3(0);
+ return result;
+ }
+
+@@ -1599,6 +1600,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
+ map->set_unused_property_fields(0);
+ map->set_bit_field(0);
+ map->set_bit_field2((1 << Map::kIsExtensible) | (1 << Map::kHasFastElements));
++ map->set_bit_field3(0);
+
+ // If the map object is aligned fill the padding area with Smi 0 objects.
+ if (Map::kPadStart < Map::kSize) {
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index 65aec5d..bbe05f6 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -2429,6 +2429,16 @@ void Map::set_bit_field2(byte value) {
+ }
+
+
++byte Map::bit_field3() {
++ return READ_BYTE_FIELD(this, kBitField3Offset);
++}
++
++
++void Map::set_bit_field3(byte value) {
++ WRITE_BYTE_FIELD(this, kBitField3Offset, value);
++}
++
++
+ void Map::set_non_instance_prototype(bool value) {
+ if (value) {
+ set_bit_field(bit_field() | (1 << kHasNonInstancePrototype));
+diff --git a/src/objects.cc b/src/objects.cc
+index bbdb37b..fcde7eb 100644
+--- a/src/objects.cc
++++ b/src/objects.cc
+@@ -3614,6 +3614,7 @@ MaybeObject* Map::CopyDropDescriptors() {
+ }
+ Map::cast(result)->set_bit_field(bit_field());
+ Map::cast(result)->set_bit_field2(bit_field2());
++ Map::cast(result)->set_bit_field3(bit_field3());
+ Map::cast(result)->set_is_shared(false);
+ Map::cast(result)->ClearCodeCache(heap);
+ return result;
+@@ -3642,6 +3643,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
+
+ Map::cast(result)->set_bit_field(bit_field());
+ Map::cast(result)->set_bit_field2(bit_field2());
++ Map::cast(result)->set_bit_field3(bit_field3());
+
+ Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
+
+diff --git a/src/objects.h b/src/objects.h
+index cd11c88..124c353 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -3597,6 +3597,10 @@ class Map: public HeapObject {
+ inline byte bit_field2();
+ inline void set_bit_field2(byte value);
+
++ // Bit field 3.
++ inline byte bit_field3();
++ inline void set_bit_field3(byte value);
++
+ // Tells whether the object in the prototype property will be used
+ // for instances created from this function. If the prototype
+ // property is set to a value that is not a JSObject, the prototype
+@@ -3844,7 +3848,7 @@ class Map: public HeapObject {
+ // Layout description.
+ static const int kInstanceSizesOffset = HeapObject::kHeaderSize;
+ static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize;
+- static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize;
++ static const int kPrototypeOffset = POINTER_SIZE_ALIGN(kInstanceAttributesOffset + 2 * kIntSize);
+ static const int kConstructorOffset = kPrototypeOffset + kPointerSize;
+ static const int kInstanceDescriptorsOffset =
+ kConstructorOffset + kPointerSize;
+@@ -3876,6 +3880,7 @@ class Map: public HeapObject {
+ static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1;
+ static const int kBitFieldOffset = kInstanceAttributesOffset + 2;
+ static const int kBitField2Offset = kInstanceAttributesOffset + 3;
++ static const int kBitField3Offset = kInstanceAttributesOffset + 4;
+
+ STATIC_CHECK(kInstanceTypeOffset == Internals::kMapInstanceTypeOffset);
+
+@@ -3898,6 +3903,8 @@ class Map: public HeapObject {
+ static const int kIsShared = 5;
+ static const int kHasExternalArrayElements = 6;
+
++ // Bit positions for bit field 3
++
+ // Layout of the default cache. It holds alternating name and code objects.
+ static const int kCodeCacheEntrySize = 2;
+ static const int kCodeCacheEntryNameOffset = 0;
+--
+1.7.2.3
+
--- /dev/null
+From 001373a7856d8a6f4620552c62ae87866c4194c0 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Mon, 23 May 2011 16:21:02 +1000
+Subject: [PATCH 3/7] Add a "fallback" mode for named property interceptors
+
+By default interceptors are called before the normal property
+resolution on objects. When an interceptor is installed as a
+"fallback" interceptor, it is only called if the object doesn't
+already have the property.
+
+In the case of a global object having an fallback interceptor,
+the interceptor is not invoked at all for var or function
+declarations.
+---
+ include/v8.h | 8 ++++++++
+ src/api.cc | 29 +++++++++++++++++++++++++++++
+ src/factory.cc | 4 ++++
+ src/handles.cc | 6 ++++--
+ src/handles.h | 3 ++-
+ src/objects-inl.h | 16 ++++++++++++++++
+ src/objects.cc | 22 ++++++++++++++++------
+ src/objects.h | 18 ++++++++++++++----
+ src/runtime.cc | 11 ++++++-----
+ 9 files changed, 99 insertions(+), 18 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index ac3c062..beaaca4 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -2142,6 +2142,7 @@ class V8EXPORT FunctionTemplate : public Template {
+ NamedPropertyQuery query,
+ NamedPropertyDeleter remover,
+ NamedPropertyEnumerator enumerator,
++ bool is_fallback,
+ Handle<Value> data);
+ void SetIndexedInstancePropertyHandler(IndexedPropertyGetter getter,
+ IndexedPropertySetter setter,
+@@ -2226,6 +2227,13 @@ class V8EXPORT ObjectTemplate : public Template {
+ NamedPropertyEnumerator enumerator = 0,
+ Handle<Value> data = Handle<Value>());
+
++ void SetFallbackPropertyHandler(NamedPropertyGetter getter,
++ NamedPropertySetter setter = 0,
++ NamedPropertyQuery query = 0,
++ NamedPropertyDeleter deleter = 0,
++ NamedPropertyEnumerator enumerator = 0,
++ Handle<Value> data = Handle<Value>());
++
+ /**
+ * Sets an indexed property handler on the object template.
+ *
+diff --git a/src/api.cc b/src/api.cc
+index 09b6b93..ebca4f9 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -981,6 +981,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
+ NamedPropertyQuery query,
+ NamedPropertyDeleter remover,
+ NamedPropertyEnumerator enumerator,
++ bool is_fallback,
+ Handle<Value> data) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate,
+@@ -999,6 +1000,7 @@ void FunctionTemplate::SetNamedInstancePropertyHandler(
+ if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query);
+ if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover);
+ if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator);
++ obj->set_is_fallback(i::Smi::FromInt(is_fallback));
+
+ if (data.IsEmpty()) data = v8::Undefined();
+ obj->set_data(*Utils::OpenHandle(*data));
+@@ -1143,6 +1145,33 @@ void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter,
+ query,
+ remover,
+ enumerator,
++ false,
++ data);
++}
++
++
++void ObjectTemplate::SetFallbackPropertyHandler(NamedPropertyGetter getter,
++ NamedPropertySetter setter,
++ NamedPropertyQuery query,
++ NamedPropertyDeleter remover,
++ NamedPropertyEnumerator enumerator,
++ Handle<Value> data) {
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetFallbackPropertyHandler()")) {
++ return;
++ }
++ ENTER_V8(isolate);
++ i::HandleScope scope(isolate);
++ EnsureConstructor(this);
++ i::FunctionTemplateInfo* constructor =
++ i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
++ i::Handle<i::FunctionTemplateInfo> cons(constructor);
++ Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter,
++ setter,
++ query,
++ remover,
++ enumerator,
++ true,
+ data);
+ }
+
+diff --git a/src/factory.cc b/src/factory.cc
+index 7dee66f..dcdc645 100644
+--- a/src/factory.cc
++++ b/src/factory.cc
+@@ -1058,6 +1058,10 @@ Handle<JSFunction> Factory::CreateApiFunction(
+ // Set interceptor information in the map.
+ if (!obj->named_property_handler()->IsUndefined()) {
+ map->set_has_named_interceptor();
++
++ InterceptorInfo *nph = InterceptorInfo::cast(obj->named_property_handler());
++ bool is_fallback = nph->is_fallback()->IsUndefined()?false:nph->is_fallback()->value();
++ map->set_named_interceptor_is_fallback(is_fallback);
+ }
+ if (!obj->indexed_property_handler()->IsUndefined()) {
+ map->set_has_indexed_interceptor();
+diff --git a/src/handles.cc b/src/handles.cc
+index 326de86..dd3a86c 100644
+--- a/src/handles.cc
++++ b/src/handles.cc
+@@ -262,9 +262,11 @@ Handle<Object> SetProperty(Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool skip_fallback_interceptor) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+- object->SetProperty(*key, *value, attributes, strict_mode),
++ object->SetProperty(*key, *value, attributes, strict_mode,
++ skip_fallback_interceptor),
+ Object);
+ }
+
+diff --git a/src/handles.h b/src/handles.h
+index 3839f37..4b42506 100644
+--- a/src/handles.h
++++ b/src/handles.h
+@@ -188,7 +188,8 @@ Handle<Object> SetProperty(Handle<JSObject> object,
+ Handle<String> key,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+- StrictModeFlag strict_mode);
++ StrictModeFlag strict_mode,
++ bool skip_fallback_interceptor = false);
+
+ Handle<Object> SetProperty(Handle<Object> object,
+ Handle<Object> key,
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index bbe05f6..0c09e84 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -2520,6 +2520,21 @@ bool Map::is_shared() {
+ }
+
+
++void Map::set_named_interceptor_is_fallback(bool value)
++{
++ if (value) {
++ set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback));
++ } else {
++ set_bit_field3(bit_field3() & ~(1 << kNamedInterceptorIsFallback));
++ }
++}
++
++bool Map::named_interceptor_is_fallback()
++{
++ return ((1 << kNamedInterceptorIsFallback) & bit_field3()) != 0;
++}
++
++
+ JSFunction* Map::unchecked_constructor() {
+ return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset));
+ }
+@@ -2969,6 +2984,7 @@ ACCESSORS(InterceptorInfo, query, Object, kQueryOffset)
+ ACCESSORS(InterceptorInfo, deleter, Object, kDeleterOffset)
+ ACCESSORS(InterceptorInfo, enumerator, Object, kEnumeratorOffset)
+ ACCESSORS(InterceptorInfo, data, Object, kDataOffset)
++ACCESSORS(InterceptorInfo, is_fallback, Smi, kFallbackOffset)
+
+ ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset)
+ ACCESSORS(CallHandlerInfo, data, Object, kDataOffset)
+diff --git a/src/objects.cc b/src/objects.cc
+index fcde7eb..d72e30b 100644
+--- a/src/objects.cc
++++ b/src/objects.cc
+@@ -1712,9 +1712,10 @@ MaybeObject* JSObject::SetPropertyWithInterceptor(
+ MaybeObject* JSObject::SetProperty(String* name,
+ Object* value,
+ PropertyAttributes attributes,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool skip_fallback_interceptor) {
+ LookupResult result;
+- LocalLookup(name, &result);
++ LocalLookup(name, &result, skip_fallback_interceptor);
+ return SetProperty(&result, name, value, attributes, strict_mode);
+ }
+
+@@ -3148,7 +3149,8 @@ AccessorDescriptor* Map::FindAccessor(String* name) {
+ }
+
+
+-void JSObject::LocalLookup(String* name, LookupResult* result) {
++void JSObject::LocalLookup(String* name, LookupResult* result,
++ bool skip_fallback_interceptor) {
+ ASSERT(name->IsString());
+
+ Heap* heap = GetHeap();
+@@ -3174,22 +3176,30 @@ void JSObject::LocalLookup(String* name, LookupResult* result) {
+ }
+
+ // Check for lookup interceptor except when bootstrapping.
+- if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
++ bool wouldIntercept = HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive();
++ if (wouldIntercept && !map()->named_interceptor_is_fallback()) {
+ result->InterceptorResult(this);
+ return;
+ }
+
+ LocalLookupRealNamedProperty(name, result);
++
++ if (wouldIntercept && !skip_fallback_interceptor && !result->IsProperty() &&
++ map()->named_interceptor_is_fallback()) {
++ result->InterceptorResult(this);
++ return;
++ }
+ }
+
+
+-void JSObject::Lookup(String* name, LookupResult* result) {
++void JSObject::Lookup(String* name, LookupResult* result,
++ bool skip_fallback_interceptor) {
+ // Ecma-262 3rd 8.6.2.4
+ Heap* heap = GetHeap();
+ for (Object* current = this;
+ current != heap->null_value();
+ current = JSObject::cast(current)->GetPrototype()) {
+- JSObject::cast(current)->LocalLookup(name, result);
++ JSObject::cast(current)->LocalLookup(name, result, skip_fallback_interceptor);
+ if (result->IsProperty()) return;
+ }
+ result->NotFound();
+diff --git a/src/objects.h b/src/objects.h
+index 124c353..4389456 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -1405,7 +1405,8 @@ class JSObject: public HeapObject {
+ MUST_USE_RESULT MaybeObject* SetProperty(String* key,
+ Object* value,
+ PropertyAttributes attributes,
+- StrictModeFlag strict_mode);
++ StrictModeFlag strict_mode,
++ bool skip_fallback_interceptor = false);
+ MUST_USE_RESULT MaybeObject* SetProperty(LookupResult* result,
+ String* key,
+ Object* value,
+@@ -1637,8 +1638,8 @@ class JSObject: public HeapObject {
+
+ // Lookup a property. If found, the result is valid and has
+ // detailed information.
+- void LocalLookup(String* name, LookupResult* result);
+- void Lookup(String* name, LookupResult* result);
++ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
++ void Lookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
+
+ // The following lookup functions skip interceptors.
+ void LocalLookupRealNamedProperty(String* name, LookupResult* result);
+@@ -3714,6 +3715,12 @@ class Map: public HeapObject {
+ inline void set_is_access_check_needed(bool access_check_needed);
+ inline bool is_access_check_needed();
+
++
++ // Whether the named interceptor is a fallback interceptor or not
++ inline void set_named_interceptor_is_fallback(bool value);
++ inline bool named_interceptor_is_fallback();
++
++
+ // [prototype]: implicit prototype object.
+ DECL_ACCESSORS(prototype, Object)
+
+@@ -3904,6 +3911,7 @@ class Map: public HeapObject {
+ static const int kHasExternalArrayElements = 6;
+
+ // Bit positions for bit field 3
++ static const int kNamedInterceptorIsFallback = 0;
+
+ // Layout of the default cache. It holds alternating name and code objects.
+ static const int kCodeCacheEntrySize = 2;
+@@ -6267,6 +6275,7 @@ class InterceptorInfo: public Struct {
+ DECL_ACCESSORS(deleter, Object)
+ DECL_ACCESSORS(enumerator, Object)
+ DECL_ACCESSORS(data, Object)
++ DECL_ACCESSORS(is_fallback, Smi)
+
+ static inline InterceptorInfo* cast(Object* obj);
+
+@@ -6286,7 +6295,8 @@ class InterceptorInfo: public Struct {
+ static const int kDeleterOffset = kQueryOffset + kPointerSize;
+ static const int kEnumeratorOffset = kDeleterOffset + kPointerSize;
+ static const int kDataOffset = kEnumeratorOffset + kPointerSize;
+- static const int kSize = kDataOffset + kPointerSize;
++ static const int kFallbackOffset = kDataOffset + kPointerSize;
++ static const int kSize = kFallbackOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptorInfo);
+diff --git a/src/runtime.cc b/src/runtime.cc
+index 7335da8..660352c 100644
+--- a/src/runtime.cc
++++ b/src/runtime.cc
+@@ -1097,7 +1097,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+ // Lookup the property in the global object, and don't set the
+ // value of the variable if the property is already there.
+ LookupResult lookup;
+- global->Lookup(*name, &lookup);
++ global->Lookup(*name, &lookup, true);
+ if (lookup.IsProperty()) {
+ // Determine if the property is local by comparing the holder
+ // against the global object. The information will be used to
+@@ -1152,7 +1152,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+ }
+
+ LookupResult lookup;
+- global->LocalLookup(*name, &lookup);
++ global->LocalLookup(*name, &lookup, true);
+
+ PropertyAttributes attributes = is_const_property
+ ? static_cast<PropertyAttributes>(base | READ_ONLY)
+@@ -1196,7 +1196,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+ name,
+ value,
+ attributes,
+- strict_mode));
++ strict_mode,
++ true));
+ }
+ }
+
+@@ -1343,7 +1344,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ JSObject* real_holder = global;
+ LookupResult lookup;
+ while (true) {
+- real_holder->LocalLookup(*name, &lookup);
++ real_holder->LocalLookup(*name, &lookup, true);
+ if (lookup.IsProperty()) {
+ // Determine if this is a redeclaration of something read-only.
+ if (lookup.IsReadOnly()) {
+@@ -1400,7 +1401,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+
+ global = isolate->context()->global();
+ if (assign) {
+- return global->SetProperty(*name, args[2], attributes, strict_mode);
++ return global->SetProperty(*name, args[2], attributes, strict_mode, true);
+ }
+ return isolate->heap()->undefined_value();
+ }
+--
+1.7.2.3
+
--- /dev/null
+From d5dbc0acceb9cc848dfd994b2f54bc37c624fe98 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Mon, 23 May 2011 16:55:35 +1000
+Subject: [PATCH 4/7] Generalize external object resources
+
+V8 was already able to manage and finalize an external string
+resource. This change generalizes that mechanism to handle a
+single generic external resource - a v8::Object::ExternalResource
+derived instance - on normal JSObject's.
+
+This is useful for mapping C++ objects to JS objects where the
+C++ object's memory is effectively owned by the JS Object, and
+thus needs to destroyed when the JS Object is garbage collected.
+The V8 mailing list suggests using a weak persistent handle for
+this purpose, but that seems to incur a fairly massive performance
+penalty for short lived objects as weak persistent handle callbacks
+are not called until the object has been promoted into the old
+object space.
+---
+ include/v8.h | 25 ++++++
+ src/api.cc | 64 ++++++++++++++-
+ src/extensions/externalize-string-extension.cc | 4 +-
+ src/factory.cc | 11 +++
+ src/heap-inl.h | 101 +++++++++++++++---------
+ src/heap.cc | 68 ++++++++--------
+ src/heap.h | 42 +++++-----
+ src/liveobjectlist.cc | 4 +-
+ src/mark-compact.cc | 21 +++---
+ src/objects-inl.h | 41 +++++++++-
+ src/objects.h | 14 +++-
+ 11 files changed, 280 insertions(+), 115 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index beaaca4..eaa0ec4 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -1603,6 +1603,25 @@ class Object : public Value {
+ /** Sets a native pointer in an internal field. */
+ V8EXPORT void SetPointerInInternalField(int index, void* value);
+
++ class V8EXPORT ExternalResource { // NOLINT
++ public:
++ ExternalResource() {}
++ virtual ~ExternalResource() {}
++
++ protected:
++ virtual void Dispose() { delete this; }
++
++ private:
++ // Disallow copying and assigning.
++ ExternalResource(const ExternalResource&);
++ void operator=(const ExternalResource&);
++
++ friend class v8::internal::Heap;
++ };
++
++ V8EXPORT void SetExternalResource(ExternalResource *);
++ V8EXPORT ExternalResource *GetExternalResource();
++
+ // Testers for local properties.
+ V8EXPORT bool HasRealNamedProperty(Handle<String> key);
+ V8EXPORT bool HasRealIndexedProperty(uint32_t index);
+@@ -2304,6 +2323,12 @@ class V8EXPORT ObjectTemplate : public Template {
+ */
+ void SetInternalFieldCount(int value);
+
++ /**
++ * Sets whether the object can store an "external resource" object.
++ */
++ bool HasExternalResource();
++ void SetHasExternalResource(bool value);
++
+ private:
+ ObjectTemplate();
+ static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
+diff --git a/src/api.cc b/src/api.cc
+index ebca4f9..f62c5a0 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -1294,6 +1294,34 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
+ }
+
+
++bool ObjectTemplate::HasExternalResource()
++{
++ if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(),
++ "v8::ObjectTemplate::HasExternalResource()")) {
++ return 0;
++ }
++ return !Utils::OpenHandle(this)->has_external_resource()->IsUndefined();
++}
++
++
++void ObjectTemplate::SetHasExternalResource(bool value)
++{
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) {
++ return;
++ }
++ ENTER_V8(isolate);
++ if (value) {
++ EnsureConstructor(this);
++ }
++ if (value) {
++ Utils::OpenHandle(this)->set_has_external_resource(i::Smi::FromInt(1));
++ } else {
++ Utils::OpenHandle(this)->set_has_external_resource(Utils::OpenHandle(this)->GetHeap()->undefined_value());
++ }
++}
++
++
+ // --- S c r i p t D a t a ---
+
+
+@@ -3624,6 +3652,34 @@ void v8::Object::SetPointerInInternalField(int index, void* value) {
+ }
+
+
++void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) {
++ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
++ ENTER_V8(isolate);
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ if (CanBeEncodedAsSmi(resource)) {
++ obj->SetExternalResourceObject(EncodeAsSmi(resource));
++ } else {
++ obj->SetExternalResourceObject(*isolate->factory()->NewProxy(static_cast<i::Address>((void *)resource)));
++ }
++ if (!obj->IsSymbol()) {
++ isolate->heap()->external_resource_table()->AddObject(*obj);
++ }
++}
++
++
++v8::Object::ExternalResource *v8::Object::GetExternalResource() {
++ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
++ i::Object* value = obj->GetExternalResourceObject();
++ if (value->IsSmi()) {
++ return reinterpret_cast<v8::Object::ExternalResource*>(i::Internals::GetExternalPointerFromSmi(value));
++ } else if (value->IsProxy()) {
++ return reinterpret_cast<v8::Object::ExternalResource*>(i::Proxy::cast(value)->proxy());
++ } else {
++ return NULL;
++ }
++}
++
++
+ // --- E n v i r o n m e n t ---
+
+
+@@ -4116,7 +4172,7 @@ Local<String> v8::String::NewExternal(
+ LOG_API(isolate, "String::NewExternal");
+ ENTER_V8(isolate);
+ i::Handle<i::String> result = NewExternalStringHandle(isolate, resource);
+- isolate->heap()->external_string_table()->AddString(*result);
++ isolate->heap()->external_resource_table()->AddString(*result);
+ return Utils::ToLocal(result);
+ }
+
+@@ -4134,7 +4190,7 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
+ }
+ bool result = obj->MakeExternal(resource);
+ if (result && !obj->IsSymbol()) {
+- isolate->heap()->external_string_table()->AddString(*obj);
++ isolate->heap()->external_resource_table()->AddString(*obj);
+ }
+ return result;
+ }
+@@ -4147,7 +4203,7 @@ Local<String> v8::String::NewExternal(
+ LOG_API(isolate, "String::NewExternal");
+ ENTER_V8(isolate);
+ i::Handle<i::String> result = NewExternalAsciiStringHandle(isolate, resource);
+- isolate->heap()->external_string_table()->AddString(*result);
++ isolate->heap()->external_resource_table()->AddString(*result);
+ return Utils::ToLocal(result);
+ }
+
+@@ -4166,7 +4222,7 @@ bool v8::String::MakeExternal(
+ }
+ bool result = obj->MakeExternal(resource);
+ if (result && !obj->IsSymbol()) {
+- isolate->heap()->external_string_table()->AddString(*obj);
++ isolate->heap()->external_resource_table()->AddString(*obj);
+ }
+ return result;
+ }
+diff --git a/src/extensions/externalize-string-extension.cc b/src/extensions/externalize-string-extension.cc
+index b3f83fe..8e50904 100644
+--- a/src/extensions/externalize-string-extension.cc
++++ b/src/extensions/externalize-string-extension.cc
+@@ -100,7 +100,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
+ data, string->length());
+ result = string->MakeExternal(resource);
+ if (result && !string->IsSymbol()) {
+- HEAP->external_string_table()->AddString(*string);
++ HEAP->external_resource_table()->AddString(*string);
+ }
+ if (!result) delete resource;
+ } else {
+@@ -110,7 +110,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
+ data, string->length());
+ result = string->MakeExternal(resource);
+ if (result && !string->IsSymbol()) {
+- HEAP->external_string_table()->AddString(*string);
++ HEAP->external_resource_table()->AddString(*string);
+ }
+ if (!result) delete resource;
+ }
+diff --git a/src/factory.cc b/src/factory.cc
+index dcdc645..d530a75 100644
+--- a/src/factory.cc
++++ b/src/factory.cc
+@@ -997,15 +997,21 @@ Handle<JSFunction> Factory::CreateApiFunction(
+ Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi();
+
+ int internal_field_count = 0;
++ bool has_external_resource = false;
++
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance_template =
+ Handle<ObjectTemplateInfo>(
+ ObjectTemplateInfo::cast(obj->instance_template()));
+ internal_field_count =
+ Smi::cast(instance_template->internal_field_count())->value();
++ has_external_resource =
++ !instance_template->has_external_resource()->IsUndefined();
+ }
+
+ int instance_size = kPointerSize * internal_field_count;
++ if (has_external_resource) instance_size += kPointerSize;
++
+ InstanceType type = INVALID_TYPE;
+ switch (instance_type) {
+ case JavaScriptObject:
+@@ -1040,6 +1046,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
+
+ Handle<Map> map = Handle<Map>(result->initial_map());
+
++ // Mark as having external data object if needed
++ if (has_external_resource) {
++ map->set_has_external_resource(true);
++ }
++
+ // Mark as undetectable if needed.
+ if (obj->undetectable()) {
+ map->set_is_undetectable();
+diff --git a/src/heap-inl.h b/src/heap-inl.h
+index 99737ed..84f8b39 100644
+--- a/src/heap-inl.h
++++ b/src/heap-inl.h
+@@ -203,21 +203,36 @@ MaybeObject* Heap::NumberFromUint32(uint32_t value) {
+ }
+
+
+-void Heap::FinalizeExternalString(String* string) {
+- ASSERT(string->IsExternalString());
+- v8::String::ExternalStringResourceBase** resource_addr =
+- reinterpret_cast<v8::String::ExternalStringResourceBase**>(
+- reinterpret_cast<byte*>(string) +
+- ExternalString::kResourceOffset -
+- kHeapObjectTag);
+-
+- // Dispose of the C++ object if it has not already been disposed.
+- if (*resource_addr != NULL) {
+- (*resource_addr)->Dispose();
+- }
++void Heap::FinalizeExternalString(HeapObject* string) {
++ ASSERT(string->IsExternalString() || string->map()->has_external_resource());
++
++ if (string->IsExternalString()) {
++ v8::String::ExternalStringResourceBase** resource_addr =
++ reinterpret_cast<v8::String::ExternalStringResourceBase**>(
++ reinterpret_cast<byte*>(string) +
++ ExternalString::kResourceOffset -
++ kHeapObjectTag);
++
++ // Dispose of the C++ object if it has not already been disposed.
++ if (*resource_addr != NULL) {
++ (*resource_addr)->Dispose();
++ }
+
+- // Clear the resource pointer in the string.
+- *resource_addr = NULL;
++ // Clear the resource pointer in the string.
++ *resource_addr = NULL;
++ } else {
++ JSObject *object = JSObject::cast(string);
++ Object *value = object->GetExternalResourceObject();
++ v8::Object::ExternalResource *resource = 0;
++ if (value->IsSmi()) {
++ resource = reinterpret_cast<v8::Object::ExternalResource*>(Internals::GetExternalPointerFromSmi(value));
++ } else if (value->IsProxy()) {
++ resource = reinterpret_cast<v8::Object::ExternalResource*>(Proxy::cast(value)->proxy());
++ }
++ if (resource) {
++ resource->Dispose();
++ }
++ }
+ }
+
+
+@@ -554,53 +569,63 @@ inline bool Heap::allow_allocation(bool new_state) {
+ #endif
+
+
+-void ExternalStringTable::AddString(String* string) {
+- ASSERT(string->IsExternalString());
++void ExternalResourceTable::AddString(String* string) {
++ ASSERT(string->IsExternalString() );
+ if (heap_->InNewSpace(string)) {
+- new_space_strings_.Add(string);
++ new_space_objects_.Add(string);
++ } else {
++ old_space_objects_.Add(string);
++ }
++}
++
++
++void ExternalResourceTable::AddObject(HeapObject* object) {
++ ASSERT(object->map()->has_external_resource());
++ if (heap_->InNewSpace(object)) {
++ new_space_objects_.Add(object);
+ } else {
+- old_space_strings_.Add(string);
++ old_space_objects_.Add(object);
+ }
+ }
+
+
+-void ExternalStringTable::Iterate(ObjectVisitor* v) {
+- if (!new_space_strings_.is_empty()) {
+- Object** start = &new_space_strings_[0];
+- v->VisitPointers(start, start + new_space_strings_.length());
++void ExternalResourceTable::Iterate(ObjectVisitor* v) {
++ if (!new_space_objects_.is_empty()) {
++ Object** start = &new_space_objects_[0];
++ v->VisitPointers(start, start + new_space_objects_.length());
+ }
+- if (!old_space_strings_.is_empty()) {
+- Object** start = &old_space_strings_[0];
+- v->VisitPointers(start, start + old_space_strings_.length());
++ if (!old_space_objects_.is_empty()) {
++ Object** start = &old_space_objects_[0];
++ v->VisitPointers(start, start + old_space_objects_.length());
+ }
+ }
+
+
+ // Verify() is inline to avoid ifdef-s around its calls in release
+ // mode.
+-void ExternalStringTable::Verify() {
++void ExternalResourceTable::Verify() {
+ #ifdef DEBUG
+- for (int i = 0; i < new_space_strings_.length(); ++i) {
+- ASSERT(heap_->InNewSpace(new_space_strings_[i]));
+- ASSERT(new_space_strings_[i] != HEAP->raw_unchecked_null_value());
++ for (int i = 0; i < new_space_objects_.length(); ++i) {
++ ASSERT(heap_->InNewSpace(new_space_objects_[i]));
++ ASSERT(new_space_objects_[i] != HEAP->raw_unchecked_null_value());
+ }
+- for (int i = 0; i < old_space_strings_.length(); ++i) {
+- ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
+- ASSERT(old_space_strings_[i] != HEAP->raw_unchecked_null_value());
++ for (int i = 0; i < old_space_objects_.length(); ++i) {
++ ASSERT(!heap_->InNewSpace(old_space_objects_[i]));
++ ASSERT(old_space_objects_[i] != HEAP->raw_unchecked_null_value());
+ }
+ #endif
+ }
+
+
+-void ExternalStringTable::AddOldString(String* string) {
+- ASSERT(string->IsExternalString());
+- ASSERT(!heap_->InNewSpace(string));
+- old_space_strings_.Add(string);
++void ExternalResourceTable::AddOldObject(HeapObject* object) {
++ ASSERT(object->IsExternalString() || object->map()->has_external_resource());
++ ASSERT(!heap_->InNewSpace(object));
++ old_space_objects_.Add(object);
+ }
+
+
+-void ExternalStringTable::ShrinkNewStrings(int position) {
+- new_space_strings_.Rewind(position);
++void ExternalResourceTable::ShrinkNewObjects(int position) {
++ new_space_objects_.Rewind(position);
+ Verify();
+ }
+
+diff --git a/src/heap.cc b/src/heap.cc
+index 4a58bf6..46df787 100644
+--- a/src/heap.cc
++++ b/src/heap.cc
+@@ -155,7 +155,7 @@ Heap::Heap()
+ memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
+ global_contexts_list_ = NULL;
+ mark_compact_collector_.heap_ = this;
+- external_string_table_.heap_ = this;
++ external_resource_table_.heap_ = this;
+ }
+
+
+@@ -1030,8 +1030,8 @@ void Heap::Scavenge() {
+
+ new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
+
+- UpdateNewSpaceReferencesInExternalStringTable(
+- &UpdateNewSpaceReferenceInExternalStringTableEntry);
++ UpdateNewSpaceReferencesInExternalResourceTable(
++ &UpdateNewSpaceReferenceInExternalResourceTableEntry);
+
+ LiveObjectList::UpdateReferencesForScavengeGC();
+ isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
+@@ -1053,38 +1053,38 @@ void Heap::Scavenge() {
+ }
+
+
+-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
+- Object** p) {
++HeapObject* Heap::UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap,
++ Object** p) {
+ MapWord first_word = HeapObject::cast(*p)->map_word();
+
+ if (!first_word.IsForwardingAddress()) {
+ // Unreachable external string can be finalized.
+- heap->FinalizeExternalString(String::cast(*p));
++ heap->FinalizeExternalString(HeapObject::cast(*p));
+ return NULL;
+ }
+
+ // String is still reachable.
+- return String::cast(first_word.ToForwardingAddress());
++ return HeapObject::cast(first_word.ToForwardingAddress());
+ }
+
+
+-void Heap::UpdateNewSpaceReferencesInExternalStringTable(
+- ExternalStringTableUpdaterCallback updater_func) {
+- external_string_table_.Verify();
++void Heap::UpdateNewSpaceReferencesInExternalResourceTable(
++ ExternalResourceTableUpdaterCallback updater_func) {
++ external_resource_table_.Verify();
+
+- if (external_string_table_.new_space_strings_.is_empty()) return;
++ if (external_resource_table_.new_space_objects_.is_empty()) return;
+
+- Object** start = &external_string_table_.new_space_strings_[0];
+- Object** end = start + external_string_table_.new_space_strings_.length();
++ Object** start = &external_resource_table_.new_space_objects_[0];
++ Object** end = start + external_resource_table_.new_space_objects_.length();
+ Object** last = start;
+
+ for (Object** p = start; p < end; ++p) {
+ ASSERT(InFromSpace(*p));
+- String* target = updater_func(this, p);
++ HeapObject* target = updater_func(this, p);
+
+ if (target == NULL) continue;
+
+- ASSERT(target->IsExternalString());
++ ASSERT(target->IsExternalString() || target->map()->has_external_resource());
+
+ if (InNewSpace(target)) {
+ // String is still in new space. Update the table entry.
+@@ -1092,12 +1092,12 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
+ ++last;
+ } else {
+ // String got promoted. Move it to the old string list.
+- external_string_table_.AddOldString(target);
++ external_resource_table_.AddOldObject(target);
+ }
+ }
+
+ ASSERT(last <= end);
+- external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
++ external_resource_table_.ShrinkNewObjects(static_cast<int>(last - start));
+ }
+
+
+@@ -4465,7 +4465,7 @@ void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
+ v->Synchronize("symbol_table");
+ if (mode != VISIT_ALL_IN_SCAVENGE) {
+ // Scavenge collections have special processing for this.
+- external_string_table_.Iterate(v);
++ external_resource_table_.Iterate(v);
+ }
+ v->Synchronize("external_string_table");
+ }
+@@ -4967,7 +4967,7 @@ void Heap::TearDown() {
+
+ isolate_->global_handles()->TearDown();
+
+- external_string_table_.TearDown();
++ external_resource_table_.TearDown();
+
+ new_space_.TearDown();
+
+@@ -5832,31 +5832,31 @@ void TranscendentalCache::Clear() {
+ }
+
+
+-void ExternalStringTable::CleanUp() {
++void ExternalResourceTable::CleanUp() {
+ int last = 0;
+- for (int i = 0; i < new_space_strings_.length(); ++i) {
+- if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+- if (heap_->InNewSpace(new_space_strings_[i])) {
+- new_space_strings_[last++] = new_space_strings_[i];
++ for (int i = 0; i < new_space_objects_.length(); ++i) {
++ if (new_space_objects_[i] == heap_->raw_unchecked_null_value()) continue;
++ if (heap_->InNewSpace(new_space_objects_[i])) {
++ new_space_objects_[last++] = new_space_objects_[i];
+ } else {
+- old_space_strings_.Add(new_space_strings_[i]);
++ old_space_objects_.Add(new_space_objects_[i]);
+ }
+ }
+- new_space_strings_.Rewind(last);
++ new_space_objects_.Rewind(last);
+ last = 0;
+- for (int i = 0; i < old_space_strings_.length(); ++i) {
+- if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+- ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
+- old_space_strings_[last++] = old_space_strings_[i];
++ for (int i = 0; i < old_space_objects_.length(); ++i) {
++ if (old_space_objects_[i] == heap_->raw_unchecked_null_value()) continue;
++ ASSERT(!heap_->InNewSpace(old_space_objects_[i]));
++ old_space_objects_[last++] = old_space_objects_[i];
+ }
+- old_space_strings_.Rewind(last);
++ old_space_objects_.Rewind(last);
+ Verify();
+ }
+
+
+-void ExternalStringTable::TearDown() {
+- new_space_strings_.Free();
+- old_space_strings_.Free();
++void ExternalResourceTable::TearDown() {
++ new_space_objects_.Free();
++ old_space_objects_.Free();
+ }
+
+
+diff --git a/src/heap.h b/src/heap.h
+index ae4e9e7..8cbf378 100644
+--- a/src/heap.h
++++ b/src/heap.h
+@@ -237,8 +237,8 @@ class Isolate;
+ class WeakObjectRetainer;
+
+
+-typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap,
+- Object** pointer);
++typedef HeapObject* (*ExternalResourceTableUpdaterCallback)(Heap* heap,
++ Object** pointer);
+
+ typedef bool (*DirtyRegionCallback)(Heap* heap,
+ Address start,
+@@ -284,43 +284,45 @@ class PromotionQueue {
+ };
+
+
+-// External strings table is a place where all external strings are
+-// registered. We need to keep track of such strings to properly
+-// finalize them.
+-class ExternalStringTable {
++// External resource table is a place where all external strings and
++// objects with an external resource are registered. We need to keep
++// track of such strings to properly finalize them.
++class ExternalResourceTable {
+ public:
+ // Registers an external string.
+ inline void AddString(String* string);
++ // Registers an external object.
++ inline void AddObject(HeapObject* object);
+
+ inline void Iterate(ObjectVisitor* v);
+
+ // Restores internal invariant and gets rid of collected strings.
+- // Must be called after each Iterate() that modified the strings.
++ // Must be called after each Iterate() that modified the objects.
+ void CleanUp();
+
+ // Destroys all allocated memory.
+ void TearDown();
+
+ private:
+- ExternalStringTable() { }
++ ExternalResourceTable() { }
+
+ friend class Heap;
+
+ inline void Verify();
+
+- inline void AddOldString(String* string);
++ inline void AddOldObject(HeapObject* object);
+
+ // Notifies the table that only a prefix of the new list is valid.
+- inline void ShrinkNewStrings(int position);
++ inline void ShrinkNewObjects(int position);
+
+ // To speed up scavenge collections new space string are kept
+ // separate from old space strings.
+- List<Object*> new_space_strings_;
+- List<Object*> old_space_strings_;
++ List<Object*> new_space_objects_;
++ List<Object*> old_space_objects_;
+
+ Heap* heap_;
+
+- DISALLOW_COPY_AND_ASSIGN(ExternalStringTable);
++ DISALLOW_COPY_AND_ASSIGN(ExternalResourceTable);
+ };
+
+
+@@ -753,7 +755,7 @@ class Heap {
+
+ // Finalizes an external string by deleting the associated external
+ // data and clearing the resource pointer.
+- inline void FinalizeExternalString(String* string);
++ inline void FinalizeExternalString(HeapObject* string);
+
+ // Allocates an uninitialized object. The memory is non-executable if the
+ // hardware and OS allow.
+@@ -1191,8 +1193,8 @@ class Heap {
+ survived_since_last_expansion_ += survived;
+ }
+
+- void UpdateNewSpaceReferencesInExternalStringTable(
+- ExternalStringTableUpdaterCallback updater_func);
++ void UpdateNewSpaceReferencesInExternalResourceTable(
++ ExternalResourceTableUpdaterCallback updater_func);
+
+ void ProcessWeakReferences(WeakObjectRetainer* retainer);
+
+@@ -1228,8 +1230,8 @@ class Heap {
+ return &mark_compact_collector_;
+ }
+
+- ExternalStringTable* external_string_table() {
+- return &external_string_table_;
++ ExternalResourceTable* external_resource_table() {
++ return &external_resource_table_;
+ }
+
+ inline Isolate* isolate();
+@@ -1462,7 +1464,7 @@ class Heap {
+ // Performs a minor collection in new generation.
+ void Scavenge();
+
+- static String* UpdateNewSpaceReferenceInExternalStringTableEntry(
++ static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry(
+ Heap* heap,
+ Object** pointer);
+
+@@ -1593,7 +1595,7 @@ class Heap {
+ // configured through the API until it is setup.
+ bool configured_;
+
+- ExternalStringTable external_string_table_;
++ ExternalResourceTable external_resource_table_;
+
+ bool is_safe_to_read_maps_;
+
+diff --git a/src/liveobjectlist.cc b/src/liveobjectlist.cc
+index 5795a6b..8866e58 100644
+--- a/src/liveobjectlist.cc
++++ b/src/liveobjectlist.cc
+@@ -1989,7 +1989,7 @@ Object* LiveObjectList::PrintObj(int obj_id) {
+ ASSERT(resource->IsAscii());
+ Handle<String> dump_string =
+ Factory::NewExternalStringFromAscii(resource);
+- ExternalStringTable::AddString(*dump_string);
++ ExternalResourceTable::AddString(*dump_string);
+ return *dump_string;
+ } else {
+ delete resource;
+@@ -2193,7 +2193,7 @@ Object* LiveObjectList::GetPathPrivate(HeapObject* obj1, HeapObject* obj2) {
+ ASSERT(resource->IsAscii());
+ Handle<String> path_string =
+ Factory::NewExternalStringFromAscii(resource);
+- ExternalStringTable::AddString(*path_string);
++ ExternalResourceTable::AddString(*path_string);
+ return *path_string;
+ } else {
+ delete resource;
+diff --git a/src/mark-compact.cc b/src/mark-compact.cc
+index 68a5062..1b1e361 100644
+--- a/src/mark-compact.cc
++++ b/src/mark-compact.cc
+@@ -163,7 +163,7 @@ void MarkCompactCollector::Finish() {
+ // objects (empty string, illegal builtin).
+ heap()->isolate()->stub_cache()->Clear();
+
+- heap()->external_string_table_.CleanUp();
++ heap()->external_resource_table_.CleanUp();
+
+ // If we've just compacted old space there's no reason to check the
+ // fragmentation limit. Just return.
+@@ -1019,8 +1019,9 @@ class SymbolTableCleaner : public ObjectVisitor {
+
+ // Since no objects have yet been moved we can safely access the map of
+ // the object.
+- if ((*p)->IsExternalString()) {
+- heap_->FinalizeExternalString(String::cast(*p));
++ if ((*p)->IsExternalString() ||
++ (*p)->IsHeapObject() && HeapObject::cast(*p)->map()->has_external_resource()) {
++ heap_->FinalizeExternalString(HeapObject::cast(*p));
+ }
+ // Set the entry to null_value (as deleted).
+ *p = heap_->raw_unchecked_null_value();
+@@ -1433,8 +1434,8 @@ void MarkCompactCollector::MarkLiveObjects() {
+ SymbolTableCleaner v(heap());
+ symbol_table->IterateElements(&v);
+ symbol_table->ElementsRemoved(v.PointersRemoved());
+- heap()->external_string_table_.Iterate(&v);
+- heap()->external_string_table_.CleanUp();
++ heap()->external_resource_table_.Iterate(&v);
++ heap()->external_resource_table_.CleanUp();
+
+ // Process the weak references.
+ MarkCompactWeakObjectRetainer mark_compact_object_retainer;
+@@ -1948,11 +1949,11 @@ static void UpdatePointerToNewGen(HeapObject** p) {
+ }
+
+
+-static String* UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
+- Object** p) {
++static HeapObject* UpdateNewSpaceReferenceInExternalResourceTableEntry(Heap* heap,
++ Object** p) {
+ Address old_addr = HeapObject::cast(*p)->address();
+ Address new_addr = Memory::Address_at(old_addr);
+- return String::cast(HeapObject::FromAddress(new_addr));
++ return HeapObject::FromAddress(new_addr);
+ }
+
+
+@@ -2083,8 +2084,8 @@ static void SweepNewSpace(Heap* heap, NewSpace* space) {
+ updating_visitor.VisitPointer(heap->global_contexts_list_address());
+
+ // Update pointers from external string table.
+- heap->UpdateNewSpaceReferencesInExternalStringTable(
+- &UpdateNewSpaceReferenceInExternalStringTableEntry);
++ heap->UpdateNewSpaceReferencesInExternalResourceTable(
++ &UpdateNewSpaceReferenceInExternalResourceTableEntry);
+
+ // All pointers were updated. Update auxiliary allocation info.
+ heap->IncrementYoungSurvivorsCounter(survivors_size);
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index 0c09e84..a205f02 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -1392,13 +1392,13 @@ int JSObject::GetInternalFieldCount() {
+ // Make sure to adjust for the number of in-object properties. These
+ // properties do contribute to the size, but are not internal fields.
+ return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) -
+- map()->inobject_properties();
++ map()->inobject_properties() - map()->has_external_resource()?1:0;
+ }
+
+
+ int JSObject::GetInternalFieldOffset(int index) {
+ ASSERT(index < GetInternalFieldCount() && index >= 0);
+- return GetHeaderSize() + (kPointerSize * index);
++ return GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0));
+ }
+
+
+@@ -1407,7 +1407,7 @@ Object* JSObject::GetInternalField(int index) {
+ // Internal objects do follow immediately after the header, whereas in-object
+ // properties are at the end of the object. Therefore there is no need
+ // to adjust the index here.
+- return READ_FIELD(this, GetHeaderSize() + (kPointerSize * index));
++ return READ_FIELD(this, GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0)));
+ }
+
+
+@@ -1416,12 +1416,29 @@ void JSObject::SetInternalField(int index, Object* value) {
+ // Internal objects do follow immediately after the header, whereas in-object
+ // properties are at the end of the object. Therefore there is no need
+ // to adjust the index here.
+- int offset = GetHeaderSize() + (kPointerSize * index);
++ int offset = GetHeaderSize() + (kPointerSize * (index + map()->has_external_resource()?1:0));
+ WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(this, offset);
+ }
+
+
++void JSObject::SetExternalResourceObject(Object *value) {
++ ASSERT(map()->has_external_resource());
++ int offset = GetHeaderSize();
++ WRITE_FIELD(this, offset, value);
++ WRITE_BARRIER(this, offset);
++}
++
++
++Object *JSObject::GetExternalResourceObject() {
++ if (map()->has_external_resource()) {
++ return READ_FIELD(this, GetHeaderSize());
++ } else {
++ return GetHeap()->undefined_value();
++ }
++}
++
++
+ // Access fast-case object properties at index. The use of these routines
+ // is needed to correctly distinguish between properties stored in-object and
+ // properties stored in the properties array.
+@@ -2520,6 +2537,20 @@ bool Map::is_shared() {
+ }
+
+
++void Map::set_has_external_resource(bool value) {
++ if (value) {
++ set_bit_field3(bit_field3() | (1 << kHasExternalResource));
++ } else {
++ set_bit_field3(bit_field3() & ~(1 << kHasExternalResource));
++ }
++}
++
++bool Map::has_external_resource()
++{
++ return ((1 << kHasExternalResource) & bit_field3()) != 0;
++}
++
++
+ void Map::set_named_interceptor_is_fallback(bool value)
+ {
+ if (value) {
+@@ -3016,6 +3047,8 @@ ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset)
+ ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset)
+ ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
+ kInternalFieldCountOffset)
++ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
++ kHasExternalResourceOffset)
+
+ ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
+ ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
+diff --git a/src/objects.h b/src/objects.h
+index 4389456..61685cc 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -1636,6 +1636,9 @@ class JSObject: public HeapObject {
+ inline Object* GetInternalField(int index);
+ inline void SetInternalField(int index, Object* value);
+
++ inline void SetExternalResourceObject(Object *);
++ inline Object *GetExternalResourceObject();
++
+ // Lookup a property. If found, the result is valid and has
+ // detailed information.
+ void LocalLookup(String* name, LookupResult* result, bool skip_fallback_interceptor = false);
+@@ -3715,6 +3718,12 @@ class Map: public HeapObject {
+ inline void set_is_access_check_needed(bool access_check_needed);
+ inline bool is_access_check_needed();
+
++
++ // Tells whether the instance has the space for an external resource
++ // object
++ inline void set_has_external_resource(bool value);
++ inline bool has_external_resource();
++
+
+ // Whether the named interceptor is a fallback interceptor or not
+ inline void set_named_interceptor_is_fallback(bool value);
+@@ -3912,6 +3921,7 @@ class Map: public HeapObject {
+
+ // Bit positions for bit field 3
+ static const int kNamedInterceptorIsFallback = 0;
++ static const int kHasExternalResource = 1;
+
+ // Layout of the default cache. It holds alternating name and code objects.
+ static const int kCodeCacheEntrySize = 2;
+@@ -6417,6 +6427,7 @@ class ObjectTemplateInfo: public TemplateInfo {
+ public:
+ DECL_ACCESSORS(constructor, Object)
+ DECL_ACCESSORS(internal_field_count, Object)
++ DECL_ACCESSORS(has_external_resource, Object)
+
+ static inline ObjectTemplateInfo* cast(Object* obj);
+
+@@ -6433,7 +6444,8 @@ class ObjectTemplateInfo: public TemplateInfo {
+ static const int kConstructorOffset = TemplateInfo::kHeaderSize;
+ static const int kInternalFieldCountOffset =
+ kConstructorOffset + kPointerSize;
+- static const int kSize = kInternalFieldCountOffset + kPointerSize;
++ static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
++ static const int kSize = kHasExternalResourceOffset + kPointerSize;
+ };
+
+
+--
+1.7.2.3
+
--- /dev/null
+From 6311077b6acd840a5b877e293fdc8eda3f83701e Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Mon, 23 May 2011 18:26:19 +1000
+Subject: [PATCH 5/7] Introduce a QML compilation mode
+
+In QML mode, there is a second global object - known as the QML
+global object. During property resolution, if a property is not
+present on the JS global object, it is resolve on the QML global
+object.
+
+This global object behavior is only enabled if a script is being
+compiled in QML mode. The object to use as the QML global object
+is passed as a parameter to the Script::Run() method. Any function
+closures etc. created during the run will retain a reference to this
+object, so different objects can be passed in different script
+runs.
+---
+ include/v8.h | 18 ++++++++--
+ src/api.cc | 46 +++++++++++++++++++++-----
+ src/ast-inl.h | 5 +++
+ src/ast.h | 1 +
+ src/compiler.cc | 15 +++++++-
+ src/compiler.h | 24 +++++++++++---
+ src/contexts.cc | 23 +++++++++++++
+ src/contexts.h | 4 ++
+ src/execution.cc | 28 ++++++++++++++--
+ src/execution.h | 6 +++
+ src/full-codegen.cc | 3 +-
+ src/full-codegen.h | 1 +
+ src/heap.cc | 2 +
+ src/ia32/code-stubs-ia32.cc | 7 ++++
+ src/ia32/full-codegen-ia32.cc | 21 +++++++-----
+ src/ia32/macro-assembler-ia32.h | 5 +++
+ src/objects-inl.h | 12 +++++++
+ src/objects.h | 5 +++
+ src/parser.cc | 27 +++++++++++++--
+ src/parser.h | 4 ++-
+ src/prettyprinter.cc | 3 ++
+ src/runtime.cc | 68 +++++++++++++++++++++++++--------------
+ src/runtime.h | 8 ++--
+ src/scopes.cc | 16 +++++++++
+ src/scopes.h | 7 ++++
+ src/variables.cc | 3 +-
+ src/variables.h | 5 +++
+ src/x64/code-stubs-x64.cc | 4 ++
+ src/x64/full-codegen-x64.cc | 21 +++++++-----
+ src/x64/macro-assembler-x64.h | 5 +++
+ 30 files changed, 320 insertions(+), 77 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index eaa0ec4..62715ec 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -577,6 +577,10 @@ class ScriptOrigin {
+ */
+ class V8EXPORT Script {
+ public:
++ enum CompileFlags {
++ Default = 0x00,
++ QmlMode = 0x01
++ };
+
+ /**
+ * Compiles the specified script (context-independent).
+@@ -596,7 +600,8 @@ class V8EXPORT Script {
+ static Local<Script> New(Handle<String> source,
+ ScriptOrigin* origin = NULL,
+ ScriptData* pre_data = NULL,
+- Handle<String> script_data = Handle<String>());
++ Handle<String> script_data = Handle<String>(),
++ CompileFlags = Default);
+
+ /**
+ * Compiles the specified script using the specified file name
+@@ -609,7 +614,8 @@ class V8EXPORT Script {
+ * will use the currently entered context).
+ */
+ static Local<Script> New(Handle<String> source,
+- Handle<Value> file_name);
++ Handle<Value> file_name,
++ CompileFlags = Default);
+
+ /**
+ * Compiles the specified script (bound to current context).
+@@ -630,7 +636,8 @@ class V8EXPORT Script {
+ static Local<Script> Compile(Handle<String> source,
+ ScriptOrigin* origin = NULL,
+ ScriptData* pre_data = NULL,
+- Handle<String> script_data = Handle<String>());
++ Handle<String> script_data = Handle<String>(),
++ CompileFlags = Default);
+
+ /**
+ * Compiles the specified script using the specified file name
+@@ -647,7 +654,8 @@ class V8EXPORT Script {
+ */
+ static Local<Script> Compile(Handle<String> source,
+ Handle<Value> file_name,
+- Handle<String> script_data = Handle<String>());
++ Handle<String> script_data = Handle<String>(),
++ CompileFlags = Default);
+
+ /**
+ * Runs the script returning the resulting value. If the script is
+@@ -657,6 +665,7 @@ class V8EXPORT Script {
+ * compiled.
+ */
+ Local<Value> Run();
++ Local<Value> Run(Handle<Object> qml);
+
+ /**
+ * Returns the script id value.
+@@ -3299,6 +3308,7 @@ class V8EXPORT Context {
+ * JavaScript frames an empty handle is returned.
+ */
+ static Local<Context> GetCalling();
++ static Local<Object> GetCallingQmlGlobal();
+
+ /**
+ * Sets the security token for the context. To access an object in
+diff --git a/src/api.cc b/src/api.cc
+index f62c5a0..e2efcaa 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -1372,7 +1372,8 @@ ScriptData* ScriptData::New(const char* data, int length) {
+ Local<Script> Script::New(v8::Handle<String> source,
+ v8::ScriptOrigin* origin,
+ v8::ScriptData* pre_data,
+- v8::Handle<String> script_data) {
++ v8::Handle<String> script_data,
++ v8::Script::CompileFlags compile_flags) {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
+ LOG_API(isolate, "Script::New");
+@@ -1409,7 +1410,8 @@ Local<Script> Script::New(v8::Handle<String> source,
+ NULL,
+ pre_data_impl,
+ Utils::OpenHandle(*script_data),
+- i::NOT_NATIVES_CODE);
++ i::NOT_NATIVES_CODE,
++ compile_flags);
+ has_pending_exception = result.is_null();
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
+ return Local<Script>(ToApi<Script>(result));
+@@ -1417,21 +1419,23 @@ Local<Script> Script::New(v8::Handle<String> source,
+
+
+ Local<Script> Script::New(v8::Handle<String> source,
+- v8::Handle<Value> file_name) {
++ v8::Handle<Value> file_name,
++ v8::Script::CompileFlags compile_flags) {
+ ScriptOrigin origin(file_name);
+- return New(source, &origin);
++ return New(source, &origin, 0, Handle<String>(), compile_flags);
+ }
+
+
+ Local<Script> Script::Compile(v8::Handle<String> source,
+ v8::ScriptOrigin* origin,
+ v8::ScriptData* pre_data,
+- v8::Handle<String> script_data) {
++ v8::Handle<String> script_data,
++ v8::Script::CompileFlags compile_flags) {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
+ LOG_API(isolate, "Script::Compile");
+ ENTER_V8(isolate);
+- Local<Script> generic = New(source, origin, pre_data, script_data);
++ Local<Script> generic = New(source, origin, pre_data, script_data, compile_flags);
+ if (generic.IsEmpty())
+ return generic;
+ i::Handle<i::Object> obj = Utils::OpenHandle(*generic);
+@@ -1447,13 +1451,18 @@ Local<Script> Script::Compile(v8::Handle<String> source,
+
+ Local<Script> Script::Compile(v8::Handle<String> source,
+ v8::Handle<Value> file_name,
+- v8::Handle<String> script_data) {
++ v8::Handle<String> script_data,
++ v8::Script::CompileFlags compile_flags) {
+ ScriptOrigin origin(file_name);
+- return Compile(source, &origin, 0, script_data);
++ return Compile(source, &origin, 0, script_data, compile_flags);
+ }
+
+
+ Local<Value> Script::Run() {
++ return Run(Handle<Object>());
++}
++
++Local<Value> Script::Run(Handle<Object> qml) {
+ i::Isolate* isolate = i::Isolate::Current();
+ ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>());
+ LOG_API(isolate, "Script::Run");
+@@ -1472,10 +1481,11 @@ Local<Value> Script::Run() {
+ fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
+ }
+ EXCEPTION_PREAMBLE(isolate);
++ i::Handle<i::Object> qmlglobal = Utils::OpenHandle(*qml);
+ i::Handle<i::Object> receiver(
+ isolate->context()->global_proxy(), isolate);
+ i::Handle<i::Object> result =
+- i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
++ i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception, qmlglobal);
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+ raw_result = *result;
+ }
+@@ -3915,6 +3925,24 @@ v8::Local<v8::Context> Context::GetCalling() {
+ }
+
+
++v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
++ i::Isolate* isolate = i::Isolate::Current();
++ if (IsDeadCheck(isolate, "v8::Context::GetCallingQmlGlobal()")) {
++ return Local<Object>();
++ }
++
++ i::JavaScriptFrameIterator it;
++ if (it.done()) return Local<Object>();
++ i::Context *context = i::Context::cast(it.frame()->context());
++ if (!context->qml_global()->IsUndefined()) {
++ i::Handle<i::Object> qmlglobal(context->qml_global());
++ return Utils::ToLocal(i::Handle<i::JSObject>::cast(qmlglobal));
++ } else {
++ return Local<Object>();
++ }
++}
++
++
+ v8::Local<v8::Object> Context::Global() {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) {
+ return Local<v8::Object>();
+diff --git a/src/ast-inl.h b/src/ast-inl.h
+index d80684a..adc5a1f 100644
+--- a/src/ast-inl.h
++++ b/src/ast-inl.h
+@@ -106,6 +106,11 @@ bool FunctionLiteral::strict_mode() const {
+ }
+
+
++bool FunctionLiteral::qml_mode() const {
++ return scope()->is_qml_mode();
++}
++
++
+ } } // namespace v8::internal
+
+ #endif // V8_AST_INL_H_
+diff --git a/src/ast.h b/src/ast.h
+index 65a25a9..f790dc0 100644
+--- a/src/ast.h
++++ b/src/ast.h
+@@ -1712,6 +1712,7 @@ class FunctionLiteral: public Expression {
+ int end_position() const { return end_position_; }
+ bool is_expression() const { return is_expression_; }
+ bool strict_mode() const;
++ bool qml_mode() const;
+
+ int materialized_literal_count() { return materialized_literal_count_; }
+ int expected_property_count() { return expected_property_count_; }
+diff --git a/src/compiler.cc b/src/compiler.cc
+index 86d5de3..d2191b9 100755
+--- a/src/compiler.cc
++++ b/src/compiler.cc
+@@ -462,7 +462,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
+ v8::Extension* extension,
+ ScriptDataImpl* input_pre_data,
+ Handle<Object> script_data,
+- NativesFlag natives) {
++ NativesFlag natives,
++ v8::Script::CompileFlags compile_flags) {
+ Isolate* isolate = source->GetIsolate();
+ int source_length = source->length();
+ isolate->counters()->total_load_size()->Increment(source_length);
+@@ -523,6 +524,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
+ info.MarkAsGlobal();
+ info.SetExtension(extension);
+ info.SetPreParseData(pre_data);
++ if (compile_flags & v8::Script::QmlMode) info.MarkAsQmlMode();
+ if (natives == NATIVES_CODE) info.MarkAsAllowingNativesSyntax();
+ result = MakeFunctionInfo(&info);
+ if (extension == NULL && !result.is_null()) {
+@@ -543,7 +545,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
+ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
+ Handle<Context> context,
+ bool is_global,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool qml_mode) {
+ Isolate* isolate = source->GetIsolate();
+ int source_length = source->length();
+ isolate->counters()->total_eval_size()->Increment(source_length);
+@@ -567,6 +570,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
+ CompilationInfo info(script);
+ info.MarkAsEval();
+ if (is_global) info.MarkAsGlobal();
++ if (qml_mode) info.MarkAsQmlMode();
+ if (strict_mode == kStrictMode) info.MarkAsStrictMode();
+ info.SetCallingContext(context);
+ result = MakeFunctionInfo(&info);
+@@ -610,6 +614,12 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
+ info->MarkAsStrictMode();
+ }
+
++ // After parsing we know function's qml mode. Remember it.
++ if (info->function()->qml_mode()) {
++ shared->set_qml_mode(true);
++ info->MarkAsQmlMode();
++ }
++
+ // Compile the code.
+ if (!MakeCode(info)) {
+ if (!isolate->has_pending_exception()) {
+@@ -755,6 +765,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
+ *lit->this_property_assignments());
+ function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
+ function_info->set_strict_mode(lit->strict_mode());
++ function_info->set_qml_mode(lit->qml_mode());
+ }
+
+
+diff --git a/src/compiler.h b/src/compiler.h
+index e75e869..ca4b62d 100644
+--- a/src/compiler.h
++++ b/src/compiler.h
+@@ -54,6 +54,7 @@ class CompilationInfo BASE_EMBEDDED {
+ bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
+ bool is_strict_mode() const { return (flags_ & IsStrictMode::mask()) != 0; }
+ bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
++ bool is_qml_mode() const { return (flags_ & IsQmlMode::mask()) != 0; }
+ FunctionLiteral* function() const { return function_; }
+ Scope* scope() const { return scope_; }
+ Handle<Code> code() const { return code_; }
+@@ -83,6 +84,9 @@ class CompilationInfo BASE_EMBEDDED {
+ ASSERT(is_lazy());
+ flags_ |= IsInLoop::encode(true);
+ }
++ void MarkAsQmlMode() {
++ flags_ |= IsQmlMode::encode(true);
++ }
+ void MarkAsAllowingNativesSyntax() {
+ flags_ |= IsNativesSyntaxAllowed::encode(true);
+ }
+@@ -141,7 +145,8 @@ class CompilationInfo BASE_EMBEDDED {
+
+ // Determine whether or not we can adaptively optimize.
+ bool AllowOptimize() {
+- return V8::UseCrankshaft() && !closure_.is_null();
++ // XXX - fix qml mode optimizations
++ return V8::UseCrankshaft() && !closure_.is_null() && !is_qml_mode();
+ }
+
+ private:
+@@ -163,8 +168,13 @@ class CompilationInfo BASE_EMBEDDED {
+
+ void Initialize(Mode mode) {
+ mode_ = V8::UseCrankshaft() ? mode : NONOPT;
+- if (!shared_info_.is_null() && shared_info_->strict_mode()) {
+- MarkAsStrictMode();
++ if (!shared_info_.is_null()) {
++ if (shared_info_->strict_mode()) {
++ MarkAsStrictMode();
++ }
++ if (shared_info_->qml_mode()) {
++ MarkAsQmlMode();
++ }
+ }
+ }
+
+@@ -187,6 +197,8 @@ class CompilationInfo BASE_EMBEDDED {
+ class IsStrictMode: public BitField<bool, 4, 1> {};
+ // Native syntax (%-stuff) allowed?
+ class IsNativesSyntaxAllowed: public BitField<bool, 5, 1> {};
++ // Qml mode
++ class IsQmlMode: public BitField<bool, 6, 1> {};
+
+ unsigned flags_;
+
+@@ -252,13 +264,15 @@ class Compiler : public AllStatic {
+ v8::Extension* extension,
+ ScriptDataImpl* pre_data,
+ Handle<Object> script_data,
+- NativesFlag is_natives_code);
++ NativesFlag is_natives_code,
++ v8::Script::CompileFlags compile_flags = v8::Script::Default);
+
+ // Compile a String source within a context for Eval.
+ static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
+ Handle<Context> context,
+ bool is_global,
+- StrictModeFlag strict_mode);
++ StrictModeFlag strict_mode,
++ bool qml_mode);
+
+ // Compile from function info (used for lazy compilation). Returns true on
+ // success and false if the compilation resulted in a stack overflow.
+diff --git a/src/contexts.cc b/src/contexts.cc
+index 520f3dd..da5cacb 100644
+--- a/src/contexts.cc
++++ b/src/contexts.cc
+@@ -89,6 +89,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
+ PrintF(")\n");
+ }
+
++ Handle<JSObject> qml_global;
++
+ do {
+ if (FLAG_trace_contexts) {
+ PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
+@@ -119,6 +121,10 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
+ }
+ }
+
++ if (qml_global.is_null() && !context->qml_global()->IsUndefined()) {
++ qml_global = Handle<JSObject>(context->qml_global(), isolate);
++ }
++
+ if (context->is_function_context()) {
+ // we have context-local slots
+
+@@ -198,6 +204,23 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
+ }
+ } while (follow_context_chain);
+
++ if (!qml_global.is_null()) {
++ if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) {
++ *attributes = qml_global->GetLocalPropertyAttribute(*name);
++ } else {
++ *attributes = qml_global->GetPropertyAttribute(*name);
++ }
++
++ if (*attributes != ABSENT) {
++ // property found
++ if (FLAG_trace_contexts) {
++ PrintF("=> found property in qml global object %p\n",
++ reinterpret_cast<void*>(*qml_global));
++ }
++ return qml_global;
++ }
++ }
++
+ // slot not found
+ if (FLAG_trace_contexts) {
+ PrintF("=> no property/slot found\n");
+diff --git a/src/contexts.h b/src/contexts.h
+index e46619e..57d8e7b 100644
+--- a/src/contexts.h
++++ b/src/contexts.h
+@@ -182,6 +182,7 @@ class Context: public FixedArray {
+ FCONTEXT_INDEX,
+ PREVIOUS_INDEX,
+ EXTENSION_INDEX,
++ QML_GLOBAL_INDEX,
+ GLOBAL_INDEX,
+ MIN_CONTEXT_SLOTS,
+
+@@ -273,6 +274,9 @@ class Context: public FixedArray {
+ }
+ void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); }
+
++ JSObject *qml_global() { return reinterpret_cast<JSObject *>(get(QML_GLOBAL_INDEX)); }
++ void set_qml_global(JSObject *qml_global) { set(QML_GLOBAL_INDEX, qml_global); }
++
+ // Returns a JSGlobalProxy object or null.
+ JSObject* global_proxy();
+ void set_global_proxy(JSObject* global);
+diff --git a/src/execution.cc b/src/execution.cc
+index eb26438..1632076 100644
+--- a/src/execution.cc
++++ b/src/execution.cc
+@@ -70,7 +70,8 @@ static Handle<Object> Invoke(bool construct,
+ Handle<Object> receiver,
+ int argc,
+ Object*** args,
+- bool* has_pending_exception) {
++ bool* has_pending_exception,
++ Handle<Object> qml) {
+ Isolate* isolate = func->GetIsolate();
+
+ // Entering JavaScript.
+@@ -107,6 +108,12 @@ static Handle<Object> Invoke(bool construct,
+ // make the current one is indeed a global object.
+ ASSERT(func->context()->global()->IsGlobalObject());
+
++ Handle<JSObject> oldqml;
++ if (!qml.is_null()) {
++ oldqml = Handle<JSObject>(func->context()->qml_global());
++ func->context()->set_qml_global(JSObject::cast(*qml));
++ }
++
+ {
+ // Save and restore context around invocation and block the
+ // allocation of handles without explicit handle scopes.
+@@ -122,6 +129,9 @@ static Handle<Object> Invoke(bool construct,
+ receiver_pointer, argc, args);
+ }
+
++ if (!qml.is_null())
++ func->context()->set_qml_global(*oldqml);
++
+ #ifdef DEBUG
+ value->Verify();
+ #endif
+@@ -150,14 +160,24 @@ Handle<Object> Execution::Call(Handle<JSFunction> func,
+ int argc,
+ Object*** args,
+ bool* pending_exception) {
+- return Invoke(false, func, receiver, argc, args, pending_exception);
++ return Invoke(false, func, receiver, argc, args, pending_exception, Handle<Object>());
++}
++
++
++Handle<Object> Execution::Call(Handle<JSFunction> func,
++ Handle<Object> receiver,
++ int argc,
++ Object*** args,
++ bool* pending_exception,
++ Handle<Object> qml) {
++ return Invoke(false, func, receiver, argc, args, pending_exception, qml);
+ }
+
+
+ Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
+ Object*** args, bool* pending_exception) {
+ return Invoke(true, func, Isolate::Current()->global(), argc, args,
+- pending_exception);
++ pending_exception, Handle<Object>());
+ }
+
+
+@@ -175,7 +195,7 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
+ catcher.SetCaptureMessage(false);
+
+ Handle<Object> result = Invoke(false, func, receiver, argc, args,
+- caught_exception);
++ caught_exception, Handle<Object>());
+
+ if (*caught_exception) {
+ ASSERT(catcher.HasCaught());
+diff --git a/src/execution.h b/src/execution.h
+index d4b80d2..a476eb4 100644
+--- a/src/execution.h
++++ b/src/execution.h
+@@ -56,6 +56,12 @@ class Execution : public AllStatic {
+ int argc,
+ Object*** args,
+ bool* pending_exception);
++ static Handle<Object> Call(Handle<JSFunction> func,
++ Handle<Object> receiver,
++ int argc,
++ Object*** args,
++ bool* pending_exception,
++ Handle<Object> qml);
+
+ // Construct object from function, the caller supplies an array of
+ // arguments. Arguments are Object* type. After function returns,
+diff --git a/src/full-codegen.cc b/src/full-codegen.cc
+index d6ba56e..2eaef0f 100644
+--- a/src/full-codegen.cc
++++ b/src/full-codegen.cc
+@@ -542,7 +542,7 @@ void FullCodeGenerator::VisitDeclarations(
+ // Do nothing in case of no declared global functions or variables.
+ if (globals > 0) {
+ Handle<FixedArray> array =
+- isolate()->factory()->NewFixedArray(2 * globals, TENURED);
++ isolate()->factory()->NewFixedArray(3 * globals, TENURED);
+ for (int j = 0, i = 0; i < length; i++) {
+ Declaration* decl = declarations->at(i);
+ Variable* var = decl->proxy()->var();
+@@ -567,6 +567,7 @@ void FullCodeGenerator::VisitDeclarations(
+ }
+ array->set(j++, *function);
+ }
++ array->set(j++, Smi::FromInt(var->is_qml_global()));
+ }
+ }
+ // Invoke the platform-dependent code generator to do the actual
+diff --git a/src/full-codegen.h b/src/full-codegen.h
+index d6ed1b9..e3241aa 100644
+--- a/src/full-codegen.h
++++ b/src/full-codegen.h
+@@ -505,6 +505,7 @@ class FullCodeGenerator: public AstVisitor {
+ StrictModeFlag strict_mode_flag() {
+ return is_strict_mode() ? kStrictMode : kNonStrictMode;
+ }
++ bool is_qml_mode() { return function()->qml_mode(); }
+ FunctionLiteral* function() { return info_->function(); }
+ Scope* scope() { return info_->scope(); }
+
+diff --git a/src/heap.cc b/src/heap.cc
+index 46df787..6e02262 100644
+--- a/src/heap.cc
++++ b/src/heap.cc
+@@ -3792,6 +3792,7 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
+ context->set_previous(NULL);
+ context->set_extension(NULL);
+ context->set_global(function->context()->global());
++ context->set_qml_global(function->context()->qml_global());
+ ASSERT(!context->IsGlobalContext());
+ ASSERT(context->is_function_context());
+ ASSERT(result->IsContext());
+@@ -3814,6 +3815,7 @@ MaybeObject* Heap::AllocateWithContext(Context* previous,
+ context->set_previous(previous);
+ context->set_extension(extension);
+ context->set_global(previous->global());
++ context->set_qml_global(previous->qml_global());
+ ASSERT(!context->IsGlobalContext());
+ ASSERT(!context->is_function_context());
+ ASSERT(result->IsContext());
+diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
+index 5d32095..afa599e 100644
+--- a/src/ia32/code-stubs-ia32.cc
++++ b/src/ia32/code-stubs-ia32.cc
+@@ -147,6 +147,13 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
+ __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx);
+
++ // Copy the qml global object from the surrounding context. We go through the
++ // context in the function (ecx) to match the allocation behavior we have
++ // in the runtime system (see Heap::AllocateFunctionContext).
++ __ mov(ebx, FieldOperand(ecx, JSFunction::kContextOffset));
++ __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
++ __ mov(Operand(eax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), ebx);
++
+ // Initialize the rest of the slots to undefined.
+ __ mov(ebx, factory->undefined_value());
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
+diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
+index 5d153a8..28b78ba 100644
+--- a/src/ia32/full-codegen-ia32.cc
++++ b/src/ia32/full-codegen-ia32.cc
+@@ -1107,10 +1107,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
+
+ // All extension objects were empty and it is safe to use a global
+ // load IC call.
+- __ mov(eax, GlobalObjectOperand());
++ __ mov(eax, slot->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(ecx, slot->var()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global())
+ ? RelocInfo::CODE_TARGET
+ : RelocInfo::CODE_TARGET_CONTEXT;
+ EmitCallIC(ic, mode);
+@@ -1214,10 +1214,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
+ Comment cmnt(masm_, "Global variable");
+ // Use inline caching. Variable name is passed in ecx and the global
+ // object on the stack.
+- __ mov(eax, GlobalObjectOperand());
++ __ mov(eax, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ __ mov(ecx, var->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(eax);
+
+ } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
+@@ -1837,11 +1837,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
+ // assignment. Right-hand-side value is passed in eax, variable name in
+ // ecx, and the global object on the stack.
+ __ mov(ecx, var->name());
+- __ mov(edx, GlobalObjectOperand());
++ __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+
+ } else if (op == Token::INIT_CONST) {
+ // Like var declarations, const declarations are hoisted to function
+@@ -2113,9 +2113,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
+ // Push the strict mode flag.
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+
++ // Push the qml mode flag
++ __ push(Immediate(Smi::FromInt(is_qml_mode())));
++
+ __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
+ ? Runtime::kResolvePossiblyDirectEvalNoLookup
+- : Runtime::kResolvePossiblyDirectEval, 4);
++ : Runtime::kResolvePossiblyDirectEval, 5);
+ }
+
+
+@@ -2188,8 +2191,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
+ context()->DropAndPlug(1, eax);
+ } else if (var != NULL && !var->is_this() && var->is_global()) {
+ // Push global object as receiver for the call IC.
+- __ push(GlobalObjectOperand());
+- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
++ __ push(var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand());
++ EmitCallWithIC(expr, var->name(), var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (var != NULL && var->AsSlot() != NULL &&
+ var->AsSlot()->type() == Slot::LOOKUP) {
+ // Call to a lookup slot (dynamically introduced variable).
+diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
+index b986264..f8479ae 100644
+--- a/src/ia32/macro-assembler-ia32.h
++++ b/src/ia32/macro-assembler-ia32.h
+@@ -778,6 +778,11 @@ static inline Operand GlobalObjectOperand() {
+ }
+
+
++static inline Operand QmlGlobalObjectOperand() {
++ return ContextOperand(esi, Context::QML_GLOBAL_INDEX);
++}
++
++
+ // Generates an Operand for saving parameters after PrepareCallApiFunction.
+ Operand ApiParameterOperand(int index);
+
+diff --git a/src/objects-inl.h b/src/objects-inl.h
+index a205f02..8c0c2d0 100644
+--- a/src/objects-inl.h
++++ b/src/objects-inl.h
+@@ -3241,6 +3241,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) {
+ }
+
+
++bool SharedFunctionInfo::qml_mode() {
++ return BooleanBit::get(compiler_hints(), kQmlModeFunction);
++}
++
++
++void SharedFunctionInfo::set_qml_mode(bool value) {
++ set_compiler_hints(BooleanBit::set(compiler_hints(),
++ kQmlModeFunction,
++ value));
++}
++
++
+ ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
+ ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
+
+diff --git a/src/objects.h b/src/objects.h
+index 61685cc..f6549be 100644
+--- a/src/objects.h
++++ b/src/objects.h
+@@ -4331,6 +4331,10 @@ class SharedFunctionInfo: public HeapObject {
+ inline bool strict_mode();
+ inline void set_strict_mode(bool value);
+
++ // Indicates whether the function is a qml mode function
++ inline bool qml_mode();
++ inline void set_qml_mode(bool value);
++
+ // Indicates whether or not the code in the shared function support
+ // deoptimization.
+ inline bool has_deoptimization_support();
+@@ -4511,6 +4515,7 @@ class SharedFunctionInfo: public HeapObject {
+ static const int kCodeAgeMask = 0x7;
+ static const int kOptimizationDisabled = 6;
+ static const int kStrictModeFunction = 7;
++ static const int kQmlModeFunction = 8;
+
+ private:
+ #if V8_HOST_ARCH_32_BIT
+diff --git a/src/parser.cc b/src/parser.cc
+index a84ec6f..7f5c361 100644
+--- a/src/parser.cc
++++ b/src/parser.cc
+@@ -593,7 +593,8 @@ Parser::Parser(Handle<Script> script,
+
+ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
+ bool in_global_context,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool qml_mode) {
+ CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
+
+ HistogramTimerScope timer(isolate()->counters()->parse());
+@@ -609,11 +610,11 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
+ ExternalTwoByteStringUC16CharacterStream stream(
+ Handle<ExternalTwoByteString>::cast(source), 0, source->length());
+ scanner_.Initialize(&stream);
+- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope);
+ } else {
+ GenericStringUC16CharacterStream stream(source, 0, source->length());
+ scanner_.Initialize(&stream);
+- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope);
+ }
+ }
+
+@@ -621,6 +622,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
+ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
+ bool in_global_context,
+ StrictModeFlag strict_mode,
++ bool qml_mode,
+ ZoneScope* zone_scope) {
+ ASSERT(target_stack_ == NULL);
+ if (pre_data_ != NULL) pre_data_->Initialize();
+@@ -641,6 +643,9 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
+ if (strict_mode == kStrictMode) {
+ top_scope_->EnableStrictMode();
+ }
++ if (qml_mode) {
++ scope->EnableQmlMode();
++ }
+ ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
+ bool ok = true;
+ int beg_loc = scanner().location().beg_pos;
+@@ -729,6 +734,9 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
+ if (shared_info->strict_mode()) {
+ top_scope_->EnableStrictMode();
+ }
++ if (shared_info->qml_mode()) {
++ top_scope_->EnableQmlMode();
++ }
+
+ FunctionLiteralType type =
+ shared_info->is_expression() ? EXPRESSION : DECLARATION;
+@@ -1661,6 +1669,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
+ arguments->Add(value);
+ value = NULL; // zap the value to avoid the unnecessary assignment
+
++ int qml_mode = 0;
++ if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name))
++ qml_mode = 1;
++ arguments->Add(NewNumberLiteral(qml_mode));
++
+ // Construct the call to Runtime_InitializeConstGlobal
+ // and add it to the initialization statement block.
+ // Note that the function does different things depending on
+@@ -1676,6 +1689,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN,
+ arguments->Add(NewNumberLiteral(
+ top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode));
+
++ int qml_mode = 0;
++ if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name))
++ qml_mode = 1;
++ arguments->Add(NewNumberLiteral(qml_mode));
++
+ // Be careful not to assign a value to the global variable if
+ // we're in a with. The initialization value should not
+ // necessarily be stored in the global object in that case,
+@@ -5157,7 +5175,8 @@ bool ParserApi::Parse(CompilationInfo* info) {
+ Handle<String> source = Handle<String>(String::cast(script->source()));
+ result = parser.ParseProgram(source,
+ info->is_global(),
+- info->StrictMode());
++ info->StrictMode(),
++ info->is_qml_mode());
+ }
+ }
+
+diff --git a/src/parser.h b/src/parser.h
+index 64f1303..4d45e45 100644
+--- a/src/parser.h
++++ b/src/parser.h
+@@ -431,7 +431,8 @@ class Parser {
+ // Returns NULL if parsing failed.
+ FunctionLiteral* ParseProgram(Handle<String> source,
+ bool in_global_context,
+- StrictModeFlag strict_mode);
++ StrictModeFlag strict_mode,
++ bool qml_mode);
+
+ FunctionLiteral* ParseLazy(CompilationInfo* info);
+
+@@ -464,6 +465,7 @@ class Parser {
+ FunctionLiteral* DoParseProgram(Handle<String> source,
+ bool in_global_context,
+ StrictModeFlag strict_mode,
++ bool qml_mode,
+ ZoneScope* zone_scope);
+
+ // Report syntax error
+diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
+index c777ab4..1964e02 100644
+--- a/src/prettyprinter.cc
++++ b/src/prettyprinter.cc
+@@ -656,6 +656,9 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
+ EmbeddedVector<char, 256> buf;
+ int pos = OS::SNPrintF(buf, "%s (mode = %s", info,
+ Variable::Mode2String(var->mode()));
++ if (var->is_qml_global()) {
++ pos += OS::SNPrintF(buf + pos, ":QML");
++ }
+ OS::SNPrintF(buf + pos, ")");
+ PrintLiteralIndented(buf.start(), value, true);
+ }
+diff --git a/src/runtime.cc b/src/runtime.cc
+index 660352c..827d954 100644
+--- a/src/runtime.cc
++++ b/src/runtime.cc
+@@ -1065,8 +1065,6 @@ static Failure* ThrowRedeclarationError(Isolate* isolate,
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+ ASSERT(args.length() == 4);
+ HandleScope scope(isolate);
+- Handle<GlobalObject> global = Handle<GlobalObject>(
+- isolate->context()->global());
+
+ Handle<Context> context = args.at<Context>(0);
+ CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
+@@ -1075,6 +1073,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+ static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
+ ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
+
++ Handle<JSObject> js_global = Handle<JSObject>(isolate->context()->global());
++ Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global());
++
+ // Compute the property attributes. According to ECMA-262, section
+ // 13, page 71, the property must be read-only and
+ // non-deletable. However, neither SpiderMonkey nor KJS creates the
+@@ -1083,10 +1084,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
+
+ // Traverse the name/value pairs and set the properties.
+ int length = pairs->length();
+- for (int i = 0; i < length; i += 2) {
++ for (int i = 0; i < length; i += 3) {
+ HandleScope scope(isolate);
+ Handle<String> name(String::cast(pairs->get(i)));
+ Handle<Object> value(pairs->get(i + 1), isolate);
++ Handle<Smi> is_qml_global(Smi::cast(pairs->get(i + 2)));
++
++ Handle<JSObject> global = is_qml_global->value()?qml_global:js_global;
+
+ // We have to declare a global const property. To capture we only
+ // assign to it when evaluating the assignment for "const x =
+@@ -1316,20 +1320,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ NoHandleAllocation nha;
+ // args[0] == name
+ // args[1] == strict_mode
+- // args[2] == value (optional)
++ // args[2] == qml_mode
++ // args[3] == value (optional)
+
+ // Determine if we need to assign to the variable if it already
+ // exists (based on the number of arguments).
+- RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
+- bool assign = args.length() == 3;
++ RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
++ bool assign = args.length() == 4;
+
+ CONVERT_ARG_CHECKED(String, name, 0);
+- GlobalObject* global = isolate->context()->global();
+ RUNTIME_ASSERT(args[1]->IsSmi());
+ StrictModeFlag strict_mode =
+ static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
+ ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
+
++ RUNTIME_ASSERT(args[2]->IsSmi());
++ int qml_mode = Smi::cast(args[2])->value();
++
++ JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
++
+ // According to ECMA-262, section 12.2, page 62, the property must
+ // not be deletable.
+ PropertyAttributes attributes = DONT_DELETE;
+@@ -1350,7 +1359,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ if (lookup.IsReadOnly()) {
+ // If we found readonly property on one of hidden prototypes,
+ // just shadow it.
+- if (real_holder != isolate->context()->global()) break;
++ if (real_holder != global) break;
+ return ThrowRedeclarationError(isolate, "const", name);
+ }
+
+@@ -1372,7 +1381,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ // overwrite it with a variable declaration we must throw a
+ // re-declaration error. However if we found readonly property
+ // on one of hidden prototypes, just shadow it.
+- if (real_holder != isolate->context()->global()) break;
++ if (real_holder != global) break;
+ return ThrowRedeclarationError(isolate, "const", name);
+ }
+ }
+@@ -1384,7 +1393,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ }
+
+ // Assign the value (or undefined) to the property.
+- Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
++ Object* value = (assign) ? args[3] : isolate->heap()->undefined_value();
+ return real_holder->SetProperty(
+ &lookup, *name, value, attributes, strict_mode);
+ }
+@@ -1399,9 +1408,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
+ real_holder = JSObject::cast(proto);
+ }
+
+- global = isolate->context()->global();
++ global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
+ if (assign) {
+- return global->SetProperty(*name, args[2], attributes, strict_mode, true);
++ return global->SetProperty(*name, args[3], attributes, strict_mode, true);
+ }
+ return isolate->heap()->undefined_value();
+ }
+@@ -1411,12 +1420,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
+ // All constants are declared with an initial value. The name
+ // of the constant is the first argument and the initial value
+ // is the second.
+- RUNTIME_ASSERT(args.length() == 2);
++ RUNTIME_ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(String, name, 0);
+ Handle<Object> value = args.at<Object>(1);
+
++ RUNTIME_ASSERT(args[2]->IsSmi());
++ int qml_mode = Smi::cast(args[2])->value();
++
+ // Get the current global object from top.
+- GlobalObject* global = isolate->context()->global();
++ JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
+
+ // According to ECMA-262, section 12.2, page 62, the property must
+ // not be deletable. Since it's a const, it must be READ_ONLY too.
+@@ -1456,7 +1468,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
+ // with setting the value because the property is either absent or
+ // read-only. We also have to do redo the lookup.
+ HandleScope handle_scope(isolate);
+- Handle<GlobalObject> global(isolate->context()->global());
++ Handle<JSObject> global(qml_mode?isolate->context()->qml_global():isolate->context()->global());
+
+ // BUG 1213575: Handle the case where we have to set a read-only
+ // property through an interceptor and only do it if it's
+@@ -8160,7 +8172,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
+ Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
+ context,
+ true,
+- kNonStrictMode);
++ kNonStrictMode,
++ false);
+ if (shared.is_null()) return Failure::Exception();
+ Handle<JSFunction> fun =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
+@@ -8173,14 +8186,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
+ static ObjectPair CompileGlobalEval(Isolate* isolate,
+ Handle<String> source,
+ Handle<Object> receiver,
+- StrictModeFlag strict_mode) {
++ StrictModeFlag strict_mode,
++ bool qml_mode) {
+ // Deal with a normal eval call with a string argument. Compile it
+ // and return the compiled function bound in the local context.
+ Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
+ source,
+ Handle<Context>(isolate->context()),
+ isolate->context()->IsGlobalContext(),
+- strict_mode);
++ strict_mode,
++ qml_mode);
+ if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
+ Handle<JSFunction> compiled =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(
+@@ -8190,7 +8205,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate,
+
+
+ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
+- ASSERT(args.length() == 4);
++ ASSERT(args.length() == 5);
+
+ HandleScope scope(isolate);
+ Handle<Object> callee = args.at<Object>(0);
+@@ -8257,16 +8272,18 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
+ }
+
+ ASSERT(args[3]->IsSmi());
++ ASSERT(args[4]->IsSmi());
+ return CompileGlobalEval(isolate,
+ args.at<String>(1),
+ args.at<Object>(2),
+ static_cast<StrictModeFlag>(
+- Smi::cast(args[3])->value()));
++ Smi::cast(args[3])->value()),
++ Smi::cast(args[4])->value());
+ }
+
+
+ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
+- ASSERT(args.length() == 4);
++ ASSERT(args.length() == 5);
+
+ HandleScope scope(isolate);
+ Handle<Object> callee = args.at<Object>(0);
+@@ -8280,11 +8297,13 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
+ }
+
+ ASSERT(args[3]->IsSmi());
++ ASSERT(args[4]->IsSmi());
+ return CompileGlobalEval(isolate,
+ args.at<String>(1),
+ args.at<Object>(2),
+ static_cast<StrictModeFlag>(
+- Smi::cast(args[3])->value()));
++ Smi::cast(args[3])->value()),
++ Smi::cast(args[4])->value());
+ }
+
+
+@@ -10633,7 +10652,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
+ Compiler::CompileEval(function_source,
+ context,
+ context->IsGlobalContext(),
+- kNonStrictMode);
++ kNonStrictMode,
++ false);
+ if (shared.is_null()) return Failure::Exception();
+ Handle<JSFunction> compiled_function =
+ isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
+@@ -10722,7 +10742,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
+ // Currently, the eval code will be executed in non-strict mode,
+ // even in the strict code context.
+ Handle<SharedFunctionInfo> shared =
+- Compiler::CompileEval(source, context, is_global, kNonStrictMode);
++ Compiler::CompileEval(source, context, is_global, kNonStrictMode, false);
+ if (shared.is_null()) return Failure::Exception();
+ Handle<JSFunction> compiled_function =
+ Handle<JSFunction>(
+diff --git a/src/runtime.h b/src/runtime.h
+index bf1ba68..5e97173 100644
+--- a/src/runtime.h
++++ b/src/runtime.h
+@@ -241,8 +241,8 @@ namespace internal {
+ \
+ /* Eval */ \
+ F(GlobalReceiver, 1, 1) \
+- F(ResolvePossiblyDirectEval, 4, 2) \
+- F(ResolvePossiblyDirectEvalNoLookup, 4, 2) \
++ F(ResolvePossiblyDirectEval, 5, 2) \
++ F(ResolvePossiblyDirectEvalNoLookup, 5, 2) \
+ \
+ F(SetProperty, -1 /* 4 or 5 */, 1) \
+ F(DefineOrRedefineDataProperty, 4, 1) \
+@@ -296,8 +296,8 @@ namespace internal {
+ /* Declarations and initialization */ \
+ F(DeclareGlobals, 4, 1) \
+ F(DeclareContextSlot, 4, 1) \
+- F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \
+- F(InitializeConstGlobal, 2, 1) \
++ F(InitializeVarGlobal, -1 /* 3 or 4 */, 1) \
++ F(InitializeConstGlobal, 3, 1) \
+ F(InitializeConstContextSlot, 3, 1) \
+ F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
+ \
+diff --git a/src/scopes.cc b/src/scopes.cc
+index 8df93c5..e34e762 100644
+--- a/src/scopes.cc
++++ b/src/scopes.cc
+@@ -198,6 +198,7 @@ void Scope::SetDefaults(Type type,
+ scope_calls_eval_ = false;
+ // Inherit the strict mode from the parent scope.
+ strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
++ qml_mode_ = (outer_scope != NULL) && outer_scope->qml_mode_;
+ outer_scope_calls_eval_ = false;
+ inner_scope_calls_eval_ = false;
+ outer_scope_is_eval_scope_ = false;
+@@ -516,6 +517,7 @@ bool Scope::HasTrivialContext() const {
+ if (scope->is_eval_scope()) return false;
+ if (scope->scope_inside_with_) return false;
+ if (scope->num_heap_slots_ > 0) return false;
++ if (scope->qml_mode_ && is_global_scope() && inner_scopes_.length()) return false;
+ }
+ return true;
+ }
+@@ -796,6 +798,10 @@ void Scope::ResolveVariable(Scope* global_scope,
+ ASSERT(global_scope != NULL);
+ var = global_scope->DeclareGlobal(proxy->name());
+
++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) {
++ var->set_is_qml_global(true);
++ }
++
+ } else if (scope_inside_with_) {
+ // If we are inside a with statement we give up and look up
+ // the variable at runtime.
+@@ -816,6 +822,8 @@ void Scope::ResolveVariable(Scope* global_scope,
+ // variables.
+ if (context->GlobalIfNotShadowedByEval(proxy->name())) {
+ var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name())))
++ var->set_is_qml_global(true);
+
+ } else {
+ var = NonLocal(proxy->name(), Variable::DYNAMIC);
+@@ -827,6 +835,9 @@ void Scope::ResolveVariable(Scope* global_scope,
+ // variable is global unless it is shadowed by eval-introduced
+ // variables.
+ var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
++
++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name())))
++ var->set_is_qml_global(true);
+ }
+ }
+ }
+@@ -1112,6 +1123,11 @@ void Scope::AllocateVariablesRecursively() {
+ must_have_local_context = is_function_scope();
+ }
+
++ if (qml_mode_ && is_global_scope() && inner_scopes_.length()) {
++ must_have_local_context = true;
++ num_heap_slots_++; // This is a hack to force a context to be allocated to save the QML global
++ }
++
+ // If we didn't allocate any locals in the local context, then we only
+ // need the minimal number of slots if we must have a local context.
+ if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
+diff --git a/src/scopes.h b/src/scopes.h
+index a0e56a4..6dd3f65 100644
+--- a/src/scopes.h
++++ b/src/scopes.h
+@@ -210,6 +210,11 @@ class Scope: public ZoneObject {
+ strict_mode_ = FLAG_strict_mode;
+ }
+
++ // Enable qml mode for this scope
++ void EnableQmlMode() {
++ qml_mode_ = true;
++ }
++
+ // ---------------------------------------------------------------------------
+ // Predicates.
+
+@@ -218,6 +223,7 @@ class Scope: public ZoneObject {
+ bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
+ bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
+ bool is_strict_mode() const { return strict_mode_; }
++ bool is_qml_mode() const { return qml_mode_; }
+
+ // Information about which scopes calls eval.
+ bool calls_eval() const { return scope_calls_eval_; }
+@@ -376,6 +382,7 @@ class Scope: public ZoneObject {
+ bool scope_contains_with_; // this scope contains a 'with' statement
+ bool scope_calls_eval_; // this scope contains an 'eval' call
+ bool strict_mode_; // this scope is a strict mode scope
++ bool qml_mode_; // this scope is a qml mode scope
+
+ // Computed via PropagateScopeInfo.
+ bool outer_scope_calls_eval_;
+diff --git a/src/variables.cc b/src/variables.cc
+index 0502722..190baf6 100644
+--- a/src/variables.cc
++++ b/src/variables.cc
+@@ -99,7 +99,8 @@ Variable::Variable(Scope* scope,
+ rewrite_(NULL),
+ is_valid_LHS_(is_valid_LHS),
+ is_accessed_from_inner_scope_(false),
+- is_used_(false) {
++ is_used_(false),
++ is_qml_global_(false) {
+ // names must be canonicalized for fast equality checks
+ ASSERT(name->IsSymbol());
+ }
+diff --git a/src/variables.h b/src/variables.h
+index b1ff0db..0b31d1a 100644
+--- a/src/variables.h
++++ b/src/variables.h
+@@ -141,6 +141,8 @@ class Variable: public ZoneObject {
+ Expression* rewrite() const { return rewrite_; }
+ void set_rewrite(Expression* expr) { rewrite_ = expr; }
+
++ bool is_qml_global() const { return is_qml_global_; }
++ void set_is_qml_global(bool is_qml_global) { is_qml_global_ = is_qml_global; }
+ private:
+ Scope* scope_;
+ Handle<String> name_;
+@@ -159,6 +161,9 @@ class Variable: public ZoneObject {
+ // Usage info.
+ bool is_accessed_from_inner_scope_; // set by variable resolver
+ bool is_used_;
++
++ // QML info
++ bool is_qml_global_;
+ };
+
+
+diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
+index c365385..d923494 100644
+--- a/src/x64/code-stubs-x64.cc
++++ b/src/x64/code-stubs-x64.cc
+@@ -140,6 +140,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) {
+ __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx);
+
++ // Copy the qml global object from the surrounding context.
++ __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::QML_GLOBAL_INDEX)));
++ __ movq(Operand(rax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), rbx);
++
+ // Initialize the rest of the slots to undefined.
+ __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex);
+ for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
+diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
+index 97168cd..342fe9b 100644
+--- a/src/x64/full-codegen-x64.cc
++++ b/src/x64/full-codegen-x64.cc
+@@ -1119,10 +1119,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
+
+ // All extension objects were empty and it is safe to use a global
+ // load IC call.
+- __ movq(rax, GlobalObjectOperand());
++ __ movq(rax, slot->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ __ Move(rcx, slot->var()->name());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global())
+ ? RelocInfo::CODE_TARGET
+ : RelocInfo::CODE_TARGET_CONTEXT;
+ EmitCallIC(ic, mode);
+@@ -1227,9 +1227,9 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
+ // Use inline caching. Variable name is passed in rcx and the global
+ // object on the stack.
+ __ Move(rcx, var->name());
+- __ movq(rax, GlobalObjectOperand());
++ __ movq(rax, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT);
+ context()->Plug(rax);
+
+ } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
+@@ -1806,11 +1806,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
+ // assignment. Right-hand-side value is passed in rax, variable name in
+ // rcx, and the global object on the stack.
+ __ Move(rcx, var->name());
+- __ movq(rdx, GlobalObjectOperand());
++ __ movq(rdx, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
+ Handle<Code> ic = is_strict_mode()
+ ? isolate()->builtins()->StoreIC_Initialize_Strict()
+ : isolate()->builtins()->StoreIC_Initialize();
+- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT);
+
+ } else if (op == Token::INIT_CONST) {
+ // Like var declarations, const declarations are hoisted to function
+@@ -2085,9 +2085,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
+ // Push the strict mode flag.
+ __ Push(Smi::FromInt(strict_mode_flag()));
+
++ // Push the qml mode flag
++ __ Push(Smi::FromInt(is_qml_mode()));
++
+ __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
+ ? Runtime::kResolvePossiblyDirectEvalNoLookup
+- : Runtime::kResolvePossiblyDirectEval, 4);
++ : Runtime::kResolvePossiblyDirectEval, 5);
+ }
+
+
+@@ -2160,8 +2163,8 @@ void FullCodeGenerator::VisitCall(Call* expr) {
+ } else if (var != NULL && !var->is_this() && var->is_global()) {
+ // Call to a global variable.
+ // Push global object as receiver for the call IC lookup.
+- __ push(GlobalObjectOperand());
+- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
++ __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand());
++ EmitCallWithIC(expr, var->name(), var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT);
+ } else if (var != NULL && var->AsSlot() != NULL &&
+ var->AsSlot()->type() == Slot::LOOKUP) {
+ // Call to a lookup slot (dynamically introduced variable).
+diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
+index 4c17720..aa284ed 100644
+--- a/src/x64/macro-assembler-x64.h
++++ b/src/x64/macro-assembler-x64.h
+@@ -1233,6 +1233,11 @@ static inline Operand GlobalObjectOperand() {
+ }
+
+
++static inline Operand QmlGlobalObjectOperand() {
++ return ContextOperand(rsi, Context::QML_GLOBAL_INDEX);
++}
++
++
+ // Provides access to exit frame stack space (not GCed).
+ static inline Operand StackSpaceOperand(int index) {
+ #ifdef _WIN64
+--
+1.7.2.3
+
--- /dev/null
+From b14d06d5999113a9a546bf045878d6f1a24b9c69 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Wed, 25 May 2011 10:36:13 +1000
+Subject: [PATCH 6/7] Allow access to the calling script data
+
+---
+ include/v8.h | 1 +
+ src/api.cc | 12 ++++++++++++
+ 2 files changed, 13 insertions(+), 0 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 62715ec..42ddbd9 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -3309,6 +3309,7 @@ class V8EXPORT Context {
+ */
+ static Local<Context> GetCalling();
+ static Local<Object> GetCallingQmlGlobal();
++ static Local<Value> GetCallingScriptData();
+
+ /**
+ * Sets the security token for the context. To access an object in
+diff --git a/src/api.cc b/src/api.cc
+index e2efcaa..4c3c013 100644
+--- a/src/api.cc
++++ b/src/api.cc
+@@ -3942,6 +3942,18 @@ v8::Local<v8::Object> Context::GetCallingQmlGlobal() {
+ }
+ }
+
++v8::Local<v8::Value> Context::GetCallingScriptData()
++{
++ i::Isolate* isolate = i::Isolate::Current();
++ if (IsDeadCheck(isolate, "v8::Context::GetCallingScriptData()")) {
++ return Local<Object>();
++ }
++
++ i::JavaScriptFrameIterator it;
++ if (it.done()) return Local<Object>();
++ i::Handle<i::Script> script(i::Script::cast(i::JSFunction::cast(it.frame()->function())->shared()->script()));
++ return Utils::ToLocal(i::Handle<i::Object>(script->data()));
++}
+
+ v8::Local<v8::Object> Context::Global() {
+ if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) {
+--
+1.7.2.3
+
--- /dev/null
+From 15eb9c6a9444307a867a854c742505c15bd8b867 Mon Sep 17 00:00:00 2001
+From: Aaron Kennedy <aaron.kennedy@nokia.com>
+Date: Fri, 27 May 2011 13:04:15 +1000
+Subject: [PATCH 7/7] Fix warnings
+
+---
+ include/v8.h | 16 ++++++++--------
+ 1 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/include/v8.h b/include/v8.h
+index 42ddbd9..bc229f9 100644
+--- a/include/v8.h
++++ b/include/v8.h
+@@ -2388,7 +2388,7 @@ class V8EXPORT Extension { // NOLINT
+ const char** deps = 0);
+ virtual ~Extension() { }
+ virtual v8::Handle<v8::FunctionTemplate>
+- GetNativeFunction(v8::Handle<v8::String> name) {
++ GetNativeFunction(v8::Handle<v8::String>) {
+ return v8::Handle<v8::FunctionTemplate>();
+ }
+
+@@ -3694,13 +3694,13 @@ class Internals {
+ return *reinterpret_cast<T*>(addr);
+ }
+
+- static inline bool CanCastToHeapObject(void* o) { return false; }
+- static inline bool CanCastToHeapObject(Context* o) { return true; }
+- static inline bool CanCastToHeapObject(String* o) { return true; }
+- static inline bool CanCastToHeapObject(Object* o) { return true; }
+- static inline bool CanCastToHeapObject(Message* o) { return true; }
+- static inline bool CanCastToHeapObject(StackTrace* o) { return true; }
+- static inline bool CanCastToHeapObject(StackFrame* o) { return true; }
++ static inline bool CanCastToHeapObject(void*) { return false; }
++ static inline bool CanCastToHeapObject(Context*) { return true; }
++ static inline bool CanCastToHeapObject(String*) { return true; }
++ static inline bool CanCastToHeapObject(Object*) { return true; }
++ static inline bool CanCastToHeapObject(Message*) { return true; }
++ static inline bool CanCastToHeapObject(StackTrace*) { return true; }
++ static inline bool CanCastToHeapObject(StackFrame*) { return true; }
+ };
+
+ } // namespace internal
+--
+1.7.2.3
+
--- /dev/null
+These patches apply cleanly against v8 at 2eaa4b29586fdbd5d41f7b7d9e72ecca6d53dbd2
--- /dev/null
+TEMPLATE = lib
+CONFIG += staticlib
+
+CONFIG += building-libs
+
+QT =
+
+win32|mac:!macx-xcode:CONFIG += debug_and_release
+macx:CONFIG(debug, debug|release) {
+ TARGET = v8_debug
+}
+
+equals(QT_ARCH, "x64")|contains(CONFIG, x86_64):CONFIG += arch_x86_64
+else:equals(QT_ARCH, "i386"):CONFIG += arch_i386
+else:equals(QT_ARCH, "arm"):CONFIG += arch_arm
+
+include($$PWD/v8base.pri)
+
+V8_GENERATED_SOURCES_DIR = generated
+
+# this maybe removed in future
+DEFINES += ENABLE_DEBUGGER_SUPPORT
+
+# this is needed by crankshaft ( http://code.google.com/p/v8/issues/detail?id=1271 )
+DEFINES += ENABLE_VMSTATE_TRACKING ENABLE_LOGGING_AND_PROFILING
+
+CONFIG(debug, debug|release) {
+ DEFINES += DEBUG V8_ENABLE_CHECKS OBJECT_PRINT ENABLE_DISASSEMBLER
+} else {
+ DEFINES += NDEBUG
+}
+
+INCLUDEPATH += \
+ $$V8DIR/src
+
+# $$V8DIR/include
+
+V8SOURCES = \
+ $$V8DIR/src/accessors.cc \
+ $$V8DIR/src/allocation.cc \
+ $$V8DIR/src/api.cc \
+ $$V8DIR/src/assembler.cc \
+ $$V8DIR/src/ast.cc \
+ $$V8DIR/src/atomicops_internals_x86_gcc.cc \
+ $$V8DIR/src/bignum.cc \
+ $$V8DIR/src/bignum-dtoa.cc \
+ $$V8DIR/src/bootstrapper.cc \
+ $$V8DIR/src/builtins.cc \
+ $$V8DIR/src/cached-powers.cc \
+ $$V8DIR/src/checks.cc \
+ $$V8DIR/src/circular-queue.cc \
+ $$V8DIR/src/code-stubs.cc \
+ $$V8DIR/src/codegen.cc \
+ $$V8DIR/src/compilation-cache.cc \
+ $$V8DIR/src/compiler.cc \
+ $$V8DIR/src/contexts.cc \
+ $$V8DIR/src/conversions.cc \
+ $$V8DIR/src/counters.cc \
+ $$V8DIR/src/cpu-profiler.cc \
+ $$V8DIR/src/data-flow.cc \
+ $$V8DIR/src/dateparser.cc \
+ $$V8DIR/src/debug-agent.cc \
+ $$V8DIR/src/debug.cc \
+ $$V8DIR/src/deoptimizer.cc \
+ $$V8DIR/src/disassembler.cc \
+ $$V8DIR/src/diy-fp.cc \
+ $$V8DIR/src/dtoa.cc \
+ $$V8DIR/src/execution.cc \
+ $$V8DIR/src/factory.cc \
+ $$V8DIR/src/flags.cc \
+ $$V8DIR/src/frame-element.cc \
+ $$V8DIR/src/frames.cc \
+ $$V8DIR/src/full-codegen.cc \
+ $$V8DIR/src/func-name-inferrer.cc \
+ $$V8DIR/src/gdb-jit.cc \
+ $$V8DIR/src/global-handles.cc \
+ $$V8DIR/src/fast-dtoa.cc \
+ $$V8DIR/src/fixed-dtoa.cc \
+ $$V8DIR/src/handles.cc \
+ $$V8DIR/src/hashmap.cc \
+ $$V8DIR/src/heap-profiler.cc \
+ $$V8DIR/src/heap.cc \
+ $$V8DIR/src/hydrogen.cc \
+ $$V8DIR/src/hydrogen-instructions.cc \
+ $$V8DIR/src/ic.cc \
+ $$V8DIR/src/inspector.cc \
+ $$V8DIR/src/interpreter-irregexp.cc \
+ $$V8DIR/src/isolate.cc \
+ $$V8DIR/src/jsregexp.cc \
+ $$V8DIR/src/lithium-allocator.cc \
+ $$V8DIR/src/lithium.cc \
+ $$V8DIR/src/liveedit.cc \
+ $$V8DIR/src/liveobjectlist.cc \
+ $$V8DIR/src/log-utils.cc \
+ $$V8DIR/src/log.cc \
+ $$V8DIR/src/mark-compact.cc \
+ $$V8DIR/src/messages.cc \
+ $$V8DIR/src/objects.cc \
+ $$V8DIR/src/objects-printer.cc \
+ $$V8DIR/src/objects-visiting.cc \
+ $$V8DIR/src/parser.cc \
+ $$V8DIR/src/preparser.cc \
+ $$V8DIR/src/preparse-data.cc \
+ $$V8DIR/src/profile-generator.cc \
+ $$V8DIR/src/property.cc \
+ $$V8DIR/src/regexp-macro-assembler-irregexp.cc \
+ $$V8DIR/src/regexp-macro-assembler.cc \
+ $$V8DIR/src/regexp-stack.cc \
+ $$V8DIR/src/rewriter.cc \
+ $$V8DIR/src/runtime.cc \
+ $$V8DIR/src/runtime-profiler.cc \
+ $$V8DIR/src/safepoint-table.cc \
+ $$V8DIR/src/scanner-base.cc \
+ $$V8DIR/src/scanner.cc \
+ $$V8DIR/src/scopeinfo.cc \
+ $$V8DIR/src/scopes.cc \
+ $$V8DIR/src/serialize.cc \
+ $$V8DIR/src/snapshot-common.cc \
+ $$V8DIR/src/spaces.cc \
+ $$V8DIR/src/string-search.cc \
+ $$V8DIR/src/string-stream.cc \
+ $$V8DIR/src/strtod.cc \
+ $$V8DIR/src/stub-cache.cc \
+ $$V8DIR/src/token.cc \
+ $$V8DIR/src/top.cc \
+ $$V8DIR/src/type-info.cc \
+ $$V8DIR/src/unicode.cc \
+ $$V8DIR/src/utils.cc \
+ $$V8DIR/src/v8-counters.cc \
+ $$V8DIR/src/v8.cc \
+ $$V8DIR/src/v8threads.cc \
+ $$V8DIR/src/variables.cc \
+ $$V8DIR/src/version.cc \
+ $$V8DIR/src/zone.cc \
+ $$V8DIR/src/extensions/gc-extension.cc \
+ $$V8DIR/src/extensions/externalize-string-extension.cc
+
+V8SOURCES += \
+ $$V8DIR/src/snapshot-empty.cc \
+
+arch_arm {
+DEFINES += V8_TARGET_ARCH_ARM
+V8SOURCES += \
+ $$V8DIR/src/arm/builtins-arm.cc \
+ $$V8DIR/src/arm/code-stubs-arm.cc \
+ $$V8DIR/src/arm/codegen-arm.cc \
+ $$V8DIR/src/arm/constants-arm.cc \
+ $$V8DIR/src/arm/cpu-arm.cc \
+ $$V8DIR/src/arm/debug-arm.cc \
+ $$V8DIR/src/arm/deoptimizer-arm.cc \
+ $$V8DIR/src/arm/disasm-arm.cc \
+ $$V8DIR/src/arm/frames-arm.cc \
+ $$V8DIR/src/arm/full-codegen-arm.cc \
+ $$V8DIR/src/arm/ic-arm.cc \
+ $$V8DIR/src/arm/lithium-arm.cc \
+ $$V8DIR/src/arm/lithium-codegen-arm.cc \
+ $$V8DIR/src/arm/lithium-gap-resolver-arm.cc \
+ $$V8DIR/src/arm/macro-assembler-arm.cc \
+ $$V8DIR/src/arm/regexp-macro-assembler-arm.cc \
+ $$V8DIR/src/arm/stub-cache-arm.cc \
+ $$V8DIR/src/arm/assembler-arm.cc
+}
+
+arch_i386 {
+DEFINES += V8_TARGET_ARCH_IA32
+V8SOURCES += \
+ $$V8DIR/src/ia32/assembler-ia32.cc \
+ $$V8DIR/src/ia32/builtins-ia32.cc \
+ $$V8DIR/src/ia32/code-stubs-ia32.cc \
+ $$V8DIR/src/ia32/codegen-ia32.cc \
+ $$V8DIR/src/ia32/cpu-ia32.cc \
+ $$V8DIR/src/ia32/debug-ia32.cc \
+ $$V8DIR/src/ia32/deoptimizer-ia32.cc \
+ $$V8DIR/src/ia32/disasm-ia32.cc \
+ $$V8DIR/src/ia32/frames-ia32.cc \
+ $$V8DIR/src/ia32/full-codegen-ia32.cc \
+ $$V8DIR/src/ia32/ic-ia32.cc \
+ $$V8DIR/src/ia32/lithium-codegen-ia32.cc \
+ $$V8DIR/src/ia32/lithium-gap-resolver-ia32.cc \
+ $$V8DIR/src/ia32/lithium-ia32.cc \
+ $$V8DIR/src/ia32/macro-assembler-ia32.cc \
+ $$V8DIR/src/ia32/regexp-macro-assembler-ia32.cc \
+ $$V8DIR/src/ia32/stub-cache-ia32.cc
+}
+
+# FIXME Should we use QT_CONFIG instead? What about 32 bit Macs?
+arch_x86_64 {
+DEFINES += V8_TARGET_ARCH_X64
+V8SOURCES += \
+ $$V8DIR/src/x64/assembler-x64.cc \
+ $$V8DIR/src/x64/builtins-x64.cc \
+ $$V8DIR/src/x64/code-stubs-x64.cc \
+ $$V8DIR/src/x64/codegen-x64.cc \
+ $$V8DIR/src/x64/cpu-x64.cc \
+ $$V8DIR/src/x64/debug-x64.cc \
+ $$V8DIR/src/x64/deoptimizer-x64.cc \
+ $$V8DIR/src/x64/disasm-x64.cc \
+ $$V8DIR/src/x64/frames-x64.cc \
+ $$V8DIR/src/x64/full-codegen-x64.cc \
+ $$V8DIR/src/x64/ic-x64.cc \
+ $$V8DIR/src/x64/lithium-codegen-x64.cc \
+ $$V8DIR/src/x64/lithium-gap-resolver-x64.cc \
+ $$V8DIR/src/x64/lithium-x64.cc \
+ $$V8DIR/src/x64/macro-assembler-x64.cc \
+ $$V8DIR/src/x64/regexp-macro-assembler-x64.cc \
+ $$V8DIR/src/x64/stub-cache-x64.cc
+}
+
+unix:!symbian:!macx {
+V8SOURCES += \
+ $$V8DIR/src/platform-linux.cc \
+ $$V8DIR/src/platform-posix.cc
+}
+
+#os:macos
+macx {
+V8SOURCES += \
+ $$V8DIR/src/platform-macos.cc \
+ $$V8DIR/src/platform-posix.cc
+}
+
+win32 {
+V8SOURCES += \
+ $$V8DIR/src/platform-win32.cc
+}
+
+#mode:debug
+CONFIG(debug) {
+ V8SOURCES += \
+ $$V8DIR/src/objects-debug.cc \
+ $$V8DIR/src/prettyprinter.cc \
+ $$V8DIR/src/regexp-macro-assembler-tracer.cc
+}
+
+V8_LIBRARY_FILES = \
+ $$V8DIR/src/runtime.js \
+ $$V8DIR/src/v8natives.js \
+ $$V8DIR/src/array.js \
+ $$V8DIR/src/string.js \
+ $$V8DIR/src/uri.js \
+ $$V8DIR/src/math.js \
+ $$V8DIR/src/messages.js \
+ $$V8DIR/src/apinatives.js \
+ $$V8DIR/src/date.js \
+ $$V8DIR/src/regexp.js \
+ $$V8DIR/src/json.js \
+ $$V8DIR/src/liveedit-debugger.js \
+ $$V8DIR/src/mirror-debugger.js \
+ $$V8DIR/src/debug-debugger.js
+
+SOURCES += $$V8SOURCES
+
+v8_js2c.commands = python $$V8DIR/tools/js2c.py $$V8_GENERATED_SOURCES_DIR/libraries.cpp $$V8_GENERATED_SOURCES_DIR/libraries-empty.cpp CORE
+v8_js2c.commands += $$V8DIR/src/macros.py ${QMAKE_FILE_IN}
+v8_js2c.output = $$V8_GENERATED_SOURCES_DIR/libraries.cpp
+v8_js2c.input = V8_LIBRARY_FILES
+v8_js2c.variable_out = SOURCES
+v8_js2c.dependency_type = TYPE_C
+v8_js2c.depends = $$V8DIR/tools/js2c.py $$V8DIR/src/macros.py
+v8_js2c.CONFIG += combine
+v8_js2c.name = generating[v8] ${QMAKE_FILE_IN}
+silent:v8_js2c.commands = @echo generating[v8] ${QMAKE_FILE_IN} && $$v8_js2c.commands
+QMAKE_EXTRA_COMPILERS += v8_js2c
--- /dev/null
+V8DIR = $$(V8DIR)
+isEmpty(V8DIR) {
+ V8DIR = $$PWD/../3rdparty/v8
+} else {
+ message(using external V8 from $$V8DIR)
+}
+
+*-g++*: {
+ QMAKE_CFLAGS_WARN_ON += -Wno-unused-parameter
+ QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
+
+ # mksnapshot hangs if gcc 4.5 is used
+ # for reference look at http://code.google.com/p/v8/issues/detail?id=884
+ # FIXME how to find 4.5 series?
+ message(because of a bug in gcc / v8 we need to add -fno-strict-aliasing)
+ QMAKE_CFLAGS += -fno-strict-aliasing
+ QMAKE_CXXFLAGS += -fno-strict-aliasing
+}
--- /dev/null
+#!/usr/bin/perl
+#############################################################################
+##
+## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+## All rights reserved.
+## Contact: Nokia Corporation (qt-info@nokia.com)
+##
+## This file is part of the translations module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## No Commercial Usage
+## This file contains pre-release code and may not be distributed.
+## You may use this file in accordance with the terms and conditions
+## contained in the Technology Preview License Agreement accompanying
+## this package.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## In addition, as a special exception, Nokia gives you certain additional
+## rights. These rights are described in the Nokia Qt LGPL Exception
+## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+##
+## If you have questions regarding the use of this file, please contact
+## Nokia at qt-info@nokia.com.
+##
+##
+##
+##
+##
+##
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+scalar(@ARGV) == 2 or die "Usage: $0 INFILE OUTFILE";
+my $inFile = $ARGV[0];
+my $outFile = $ARGV[1];
+open FILE, ">", $outFile or die "Error: could not open $outFile for writing";
+print FILE "#include \"$inFile\"\n";
+close FILE;
qsgtext \
qsgtextedit \
qsgtextinput \
- qsgvisualdatamodel
+ qsgvisualdatamodel \
+ v8
}
QDeclarativeContext ctxt(engine.rootContext());
ctxt.setContextProperty("ctxtProp", QVariant());
- QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Result of expression 'ctxtProp' [undefined] is not an object.");
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Cannot read property 'a' of undefined");
QObject *obj = component.create(&ctxt);
QVariant v = obj->property("obj");
property int a
property variant b
+ property bool test1: false;
+ property bool test2: false;
+
Component.onCompleted: {
try {
root.a = undefined;
} catch(e) {
- console.log (e.fileName + ":" + e.lineNumber + ":" + e);
+ if (e.message == "Cannot assign [undefined] to int" &&
+ e.stack.indexOf("propertyAssignmentErrors.qml:14") != -1)
+ root.test1 = true;
}
try {
root.a = "Hello";
} catch(e) {
- console.log (e.fileName + ":" + e.lineNumber + ":" + e);
+ if (e.message == "Cannot assign QString to int" &&
+ e.stack.indexOf("propertyAssignmentErrors.qml:22") != -1)
+ root.test2 = true;
}
}
}
QtObject {
id: goo
- property bool test: undefined == goo.Test.foo
+ property bool test: undefined == goo.Test
}
id: root
property MyScarceResourceObject a: MyScarceResourceObject { id: scarceResourceProvider }
property variant scarceResourceCopy;
+ property string srp_name: a.toString();
function retrieveScarceResource() {
root.scarceResourceCopy = scarceResourceProvider.scarceResource(); // common syntax error, should throw exception
#include <QtCore/qdir.h>
#include <QtCore/qnumeric.h>
#include <private/qdeclarativeengine_p.h>
-#include <private/qdeclarativeglobalscriptclass_p.h>
#include <private/qscriptdeclarativeclass_p.h>
#include "testtypes.h"
#include "testhttpserver.h"
url = componentTwo.url().toString();
object = componentTwo.create();
QVERIFY(object != 0);
- warning = url + QLatin1String(":16: TypeError: Result of expression 'scarceResourceProvider.scarceResource' [[object Object]] is not a function.");
+
+ QString srpname = object->property("srp_name").toString();
+
+ warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
+ QLatin1String(" is not a function");
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
QMetaObject::invokeMethod(object, "retrieveScarceResource");
delete object;
QString url = component.url().toString();
- QString warning1 = url + ":11:Error: Cannot assign [undefined] to int";
- QString warning2 = url + ":17:Error: Cannot assign QString to int";
-
- QTest::ignoreMessage(QtDebugMsg, warning1.toLatin1().constData());
- QTest::ignoreMessage(QtDebugMsg, warning2.toLatin1().constData());
-
QObject *object = component.create();
QVERIFY(object != 0);
+ QCOMPARE(object->property("test1").toBool(), true);
+ QCOMPARE(object->property("test2").toBool(), true);
+
delete object;
}
QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
QString url = component.url().toString();
- QString warning = url + ":4: TypeError: Result of expression 'objectProperty' [null] is not an object.";
+ QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
delete object;
}
+static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
+{
+ QString functionSource = QLatin1String("(function(object) { return ") +
+ QLatin1String(source) + QLatin1String(" })");
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
+ if (tc.HasCaught())
+ return false;
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
+ if (function.IsEmpty())
+ return false;
+ v8::Handle<v8::Value> args[] = { o };
+ function->Call(engine->global(), 1, args);
+ return tc.HasCaught();
+}
+
+static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
+ const char *source, v8::Handle<v8::Value> result)
+{
+ QString functionSource = QLatin1String("(function(object) { return ") +
+ QLatin1String(source) + QLatin1String(" })");
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
+ if (tc.HasCaught())
+ return false;
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
+ if (function.IsEmpty())
+ return false;
+ v8::Handle<v8::Value> args[] = { o };
+
+ v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
+
+ if (tc.HasCaught())
+ return false;
+
+ return value->StrictEquals(result);
+}
+
+static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
+ const char *source)
+{
+ QString functionSource = QLatin1String("(function(object) { return ") +
+ QLatin1String(source) + QLatin1String(" })");
+ v8::TryCatch tc;
+ v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
+ if (tc.HasCaught())
+ return v8::Handle<v8::Value>();
+ v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
+ if (function.IsEmpty())
+ return v8::Handle<v8::Value>();
+ v8::Handle<v8::Value> args[] = { o };
+
+ v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
+
+ if (tc.HasCaught())
+ return v8::Handle<v8::Value>();
+ return value;
+}
+
+#define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
+#define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
+#define EVALUATE(source) evaluate(engine, object, source)
+
void tst_qdeclarativeecmascript::callQtInvokables()
{
MyInvokableObject o;
QDeclarativeEngine qmlengine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
- QScriptEngine *engine = &ep->scriptEngine;
+
+ QV8Engine *engine = &ep->v8engine;
- QStringList names; QList<QScriptValue> values;
- names << QLatin1String("object"); values << ep->objectClass->newQObject(&o);
- names << QLatin1String("undefined"); values << engine->undefinedValue();
+ v8::HandleScope handle_scope;
+ v8::Context::Scope scope(engine->context());
- ep->globalClass->explicitSetProperty(names, values);
+ v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
// Non-existent methods
o.reset();
- QCOMPARE(engine->evaluate("object.method_nonexistent()").isError(), true);
+ QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), -1);
QCOMPARE(o.actuals().count(), 0);
o.reset();
- QCOMPARE(engine->evaluate("object.method_nonexistent(10, 11)").isError(), true);
+ QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), -1);
QCOMPARE(o.actuals().count(), 0);
// Insufficient arguments
o.reset();
- QCOMPARE(engine->evaluate("object.method_int()").isError(), true);
+ QVERIFY(EVALUATE_ERROR("object.method_int()"));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), -1);
QCOMPARE(o.actuals().count(), 0);
o.reset();
- QCOMPARE(engine->evaluate("object.method_intint(10)").isError(), true);
+ QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), -1);
QCOMPARE(o.actuals().count(), 0);
// Excessive arguments
o.reset();
- QCOMPARE(engine->evaluate("object.method_int(10, 11)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 8);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(10));
o.reset();
- QCOMPARE(engine->evaluate("object.method_intint(10, 11, 12)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 9);
QCOMPARE(o.actuals().count(), 2);
// Test return types
o.reset();
- QCOMPARE(engine->evaluate("object.method_NoArgs()").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 0);
QCOMPARE(o.actuals().count(), 0);
o.reset();
- QVERIFY(engine->evaluate("object.method_NoArgs_int()").strictlyEquals(QScriptValue(engine, 6)));
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 1);
QCOMPARE(o.actuals().count(), 0);
o.reset();
- QVERIFY(engine->evaluate("object.method_NoArgs_real()").strictlyEquals(QScriptValue(engine, 19.75)));
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 2);
QCOMPARE(o.actuals().count(), 0);
o.reset();
{
- QScriptValue ret = engine->evaluate("object.method_NoArgs_QPointF()");
- QCOMPARE(ret.toVariant(), QVariant(QPointF(123, 4.5)));
+ v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
+ QVERIFY(!ret.IsEmpty());
+ QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 3);
QCOMPARE(o.actuals().count(), 0);
o.reset();
{
- QScriptValue ret = engine->evaluate("object.method_NoArgs_QObject()");
- QVERIFY(ret.isQObject());
- QCOMPARE(ret.toQObject(), (QObject *)&o);
+ v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
+ QCOMPARE(engine->toQObject(ret), (QObject *)&o);
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 4);
QCOMPARE(o.actuals().count(), 0);
}
o.reset();
- QCOMPARE(engine->evaluate("object.method_NoArgs_unknown()").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 5);
QCOMPARE(o.actuals().count(), 0);
+ // XXX enable once qml/qtscript integration is implemented
+#if 0
o.reset();
{
- QScriptValue ret = engine->evaluate("object.method_NoArgs_QScriptValue()");
- QVERIFY(ret.isString());
- QCOMPARE(ret.toString(), QString("Hello world"));
+ v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
+ QVERIFY(ret->IsString());
+ QCOMPARE(engine->toString(ret), QString("Hello world"));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 6);
QCOMPARE(o.actuals().count(), 0);
}
+#endif
o.reset();
- QVERIFY(engine->evaluate("object.method_NoArgs_QVariant()").strictlyEquals(QScriptValue(engine, "QML rocks")));
+ QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 7);
QCOMPARE(o.actuals().count(), 0);
// Test arg types
o.reset();
- QCOMPARE(engine->evaluate("object.method_int(94)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 8);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(94));
o.reset();
- QCOMPARE(engine->evaluate("object.method_int(\"94\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 8);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(94));
o.reset();
- QCOMPARE(engine->evaluate("object.method_int(\"not a number\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 8);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_int(null)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 8);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_int(undefined)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 8);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_int(object)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 8);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_intint(122, 9)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 9);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(1), QVariant(9));
o.reset();
- QCOMPARE(engine->evaluate("object.method_real(94.3)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 10);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(94.3));
o.reset();
- QCOMPARE(engine->evaluate("object.method_real(\"94.3\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 10);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(94.3));
o.reset();
- QCOMPARE(engine->evaluate("object.method_real(\"not a number\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 10);
QCOMPARE(o.actuals().count(), 1);
QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_real(null)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 10);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_real(undefined)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 10);
QCOMPARE(o.actuals().count(), 1);
QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_real(object)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 10);
QCOMPARE(o.actuals().count(), 1);
QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QString(\"Hello world\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 11);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QString(19)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 11);
QCOMPARE(o.actuals().count(), 1);
o.reset();
{
QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
- QCOMPARE(engine->evaluate("object.method_QString(object)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 11);
QCOMPARE(o.actuals().count(), 1);
}
o.reset();
- QCOMPARE(engine->evaluate("object.method_QString(null)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 11);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QString()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QString(undefined)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 11);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QString()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QPointF(0)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 12);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QPointF(null)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 12);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QPointF(undefined)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 12);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QPointF(object)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 12);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QPointF(object.method_get_QPointF())").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 12);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QPointF(object.method_get_QPoint())").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 12);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QObject(0)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 13);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QObject(\"Hello world\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 13);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QObject(null)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 13);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QObject(undefined)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 13);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QObject(object)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 13);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
+ // XXX enable once qml/qtscript integration is implemented
+#if 0
o.reset();
- QCOMPARE(engine->evaluate("object.method_QScriptValue(null)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
o.reset();
- QCOMPARE(engine->evaluate("object.method_QScriptValue(undefined)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
o.reset();
- QCOMPARE(engine->evaluate("object.method_QScriptValue(19)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QScriptValue([19, 20])").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 14);
QCOMPARE(o.actuals().count(), 1);
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
o.reset();
- QCOMPARE(engine->evaluate("object.method_intQScriptValue(4, null)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
o.reset();
- QCOMPARE(engine->evaluate("object.method_intQScriptValue(8, undefined)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
o.reset();
- QCOMPARE(engine->evaluate("object.method_intQScriptValue(3, 19)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
o.reset();
- QCOMPARE(engine->evaluate("object.method_intQScriptValue(44, [19, 20])").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 15);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(0), QVariant(44));
QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
+#endif
o.reset();
- QCOMPARE(engine->evaluate("object.method_overload()").isError(), true);
+ QVERIFY(EVALUATE_ERROR("object.method_overload()"));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), -1);
QCOMPARE(o.actuals().count(), 0);
o.reset();
- QCOMPARE(engine->evaluate("object.method_overload(10)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 16);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(10));
o.reset();
- QCOMPARE(engine->evaluate("object.method_overload(10, 11)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 17);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(1), QVariant(11));
o.reset();
- QCOMPARE(engine->evaluate("object.method_overload(\"Hello\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 18);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
o.reset();
- QCOMPARE(engine->evaluate("object.method_with_enum(9)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 19);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(9));
o.reset();
- QVERIFY(engine->evaluate("object.method_default(10)").strictlyEquals(QScriptValue(19)));
+ QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 20);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(1), QVariant(19));
o.reset();
- QVERIFY(engine->evaluate("object.method_default(10, 13)").strictlyEquals(QScriptValue(13)));
+ QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 20);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(1), QVariant(13));
o.reset();
- QCOMPARE(engine->evaluate("object.method_inherited(9)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), -3);
QCOMPARE(o.actuals().count(), 1);
QCOMPARE(o.actuals().at(0), QVariant(9));
o.reset();
- QCOMPARE(engine->evaluate("object.method_QVariant(9)").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 21);
QCOMPARE(o.actuals().count(), 2);
QCOMPARE(o.actuals().at(1), QVariant());
o.reset();
- QCOMPARE(engine->evaluate("object.method_QVariant(\"Hello\", \"World\")").isUndefined(), true);
+ QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
QCOMPARE(o.error(), false);
QCOMPARE(o.invoked(), 21);
QCOMPARE(o.actuals().count(), 2);
QVERIFY(own.object != 0);
QObject *object = component.create(context);
- QDeclarativeEnginePrivate::getScriptEngine(&engine)->collectGarbage();
+
+ engine.collectGarbage();
QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
QVERIFY(own.object != 0);
QObject *object = component.create(context);
- QDeclarativeEnginePrivate::getScriptEngine(&engine)->collectGarbage();
+
+ engine.collectGarbage();
QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
delete object;
}
+ engine.collectGarbage();
QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
QVERIFY(source.value == 0);
QVERIFY(object != 0);
QVERIFY(object->property("scarceResourceCopy").isValid());
QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
delete object;
QVERIFY(object != 0);
QVERIFY(object->property("scarceResourceCopy").isValid());
QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
delete object;
object = componentThree.create();
QVERIFY(object != 0);
QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
delete object;
QVERIFY(object != 0);
QVERIFY(object->property("scarceResourceTest").isValid());
QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
delete object;
QVERIFY(object != 0);
QVERIFY(object->property("scarceResourceTest").isValid());
QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
delete object;
QVERIFY(object != 0);
QVERIFY(object->property("scarceResourceTest").isValid());
QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
delete object;
QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
object = componentSeven.create();
QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
- QVERIFY(ep->scarceResources == 0); // but they should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
delete object;
QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
object = componentEight.create();
QVERIFY(object != 0);
QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
delete object;
QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
- QVERIFY(ep->scarceResources == 0); // this will still be zero, because "preserve()" REMOVES it from this list.
+ QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
delete object;
// test that scarce resources are handled properly in signal invocation
QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
delete object;
// test that scarce resources are handled properly from js functions in qml files
QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
delete object;
// test that if an exception occurs while invoking js function from cpp, that the resources are released.
QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QString expectedWarning = QLatin1String("file://") + TEST_FILE("scarceresources/scarceResourceFunctionFail.qml").toLocalFile() + QLatin1String(":16: TypeError: Result of expression 'scarceResourceProvider.scarceResource' [[object Object]] is not a function.");
- QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData()); // we expect a meaningful warning to be printed.
+ QString srp_name = object->property("srp_name").toString();
+ QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
QMetaObject::invokeMethod(object, "retrieveScarceResource");
QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QVERIFY(ep->scarceResources == 0); // should have been released by this point.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
delete object;
}
QVERIFY(!o->property("a").isValid());
QString url = component.url().toString();
- QString warning = url + ":63: Unable to assign QString to int";
+ QString warning = url + ":67: Unable to assign QString to int";
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
o->setProperty("assignWrongType", true);
- warning = url + ":70: Unable to assign QString to int";
+ warning = url + ":71: Unable to assign QString to int";
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
o->setProperty("assignWrongTypeToValueType", true);
function checkMapAToInvalid(x, y) {
var pos = itemA.mapToItem(1122, x, y)
- return pos.x == undefined && pos.y == undefined
+ return pos == undefined;
}
function checkMapAFromInvalid(x, y) {
var pos = itemA.mapFromItem(1122, x, y)
- return pos.x == undefined && pos.y == undefined
+ return pos == undefined;
}
}
--- /dev/null
+import QtQuick 1.0
+
+QtObject {
+ // months are 0-based - so January = 0, December = 11.
+ property variant qtime: new Date(0,0,0,14,15,38,200) // yyyy/MM/dd 14:15:38.200
+ property variant qdate: new Date(2008,11,24) // 2008/12/24 hh:mm:ss.zzz
+ property variant qdatetime: new Date(2008,11,24,14,15,38,200) // 2008/12/24 14:15:38.200
+
+ property variant qdatetime2: new Date(2852,11,31,23,59,59,500) // 2852/12/31 23:59:59.500
+ property variant qdatetime3: new Date(1970,0,1,0,0,0,0) // 1970/01/01 00:00:00.000
+ property variant qdatetime4: new Date(1586,1,2) // 1586/02/02 hh:mm:ss.zzz
+ property variant qdatetime5: new Date(955,0,1,0,0,0,0) // 955/01/01 00:00:00.000
+ property variant qdatetime6: new Date(113,1,24,14,15,38,200) // 113/02/24 14:15:38.200
+}
void createComponent_pragmaLibrary();
void createQmlObject();
void consoleLog();
+ void dateTimeConversion();
void dateTimeFormatting();
void dateTimeFormatting_data();
+ void dateTimeFormattingVariants();
+ void dateTimeFormattingVariants_data();
void isQtObject();
void btoa();
void atob();
QDeclarativeComponent component(&engine, TEST_FILE("createQmlObject.qml"));
QString warning1 = component.url().toString() + ":7: Error: Qt.createQmlObject(): Invalid arguments";
- QString warning2 = component.url().toString()+ ":10: Error: Qt.createQmlObject() failed to create object: \n " + TEST_FILE("inline").toString() + ":2:10: Blah is not a type";
- QString warning3 = component.url().toString()+ ":11: Error: Qt.createQmlObject() failed to create object: \n " + TEST_FILE("main.qml").toString() + ":4:1: Duplicate property name";
+ QString warning2 = component.url().toString()+ ":10: Error: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("inline").toString() + ":2:10: Blah is not a type";
+ QString warning3 = component.url().toString()+ ":11: Error: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("main.qml").toString() + ":4:1: Duplicate property name";
QString warning4 = component.url().toString()+ ":9: Error: Qt.createQmlObject(): Missing parent object";
QString warning5 = component.url().toString()+ ":8: Error: Qt.createQmlObject(): Invalid arguments";
- QString warning6 = "RunTimeError: Qt.createQmlObject() failed to create object: \n " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method";
+ QString warning6 = "RunTimeError: Qt.createQmlObject(): failed to create object: \n " + TEST_FILE("inline").toString() + ":3: Cannot assign object type QObject with no default method";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
delete object;
}
+void tst_qdeclarativeqt::dateTimeConversion()
+{
+ QDate date(2008,12,24);
+ QTime time(14,15,38,200);
+ QDateTime dateTime(date, time);
+ QDateTime dateTime2(QDate(2852,12,31), QTime(23,59,59,500));
+ QDateTime dateTime3(QDate(1970,1,1), QTime(0,0,0,0));
+ QDateTime dateTime4(QDate(1586,2,2), QTime(0,0,0,0));
+ QDateTime dateTime5(QDate(955,1,1), QTime(0,0,0,0));
+ QDateTime dateTime6(QDate(113,2,24), QTime(14,15,38,200));
+
+ QDeclarativeEngine eng;
+ QDeclarativeComponent component(&eng, TEST_FILE("dateTimeConversion.qml"));
+ QObject *obj = component.create();
+
+ QCOMPARE(obj->property("qdate").toDate(), date);
+ QCOMPARE(obj->property("qtime").toTime(), time);
+ QCOMPARE(obj->property("qdatetime").toDateTime(), dateTime);
+ QCOMPARE(obj->property("qdatetime2").toDateTime(), dateTime2);
+ QCOMPARE(obj->property("qdatetime3").toDateTime(), dateTime3);
+ QCOMPARE(obj->property("qdatetime4").toDateTime(), dateTime4);
+ QCOMPARE(obj->property("qdatetime5").toDateTime(), dateTime5);
+ QCOMPARE(obj->property("qdatetime6").toDateTime(), dateTime6);
+}
+
void tst_qdeclarativeqt::dateTimeFormatting()
{
QFETCH(QString, method);
QVERIFY(object != 0);
QVERIFY(inputProperties.count() > 0);
-
QVariant result;
foreach(const QString &prop, inputProperties) {
QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(),
Q_RETURN_ARG(QVariant, result),
Q_ARG(QVariant, prop)));
-
QStringList output = result.toStringList();
+ QCOMPARE(output.size(), expectedResults.size());
for (int i=0; i<output.count(); i++)
QCOMPARE(output[i], expectedResults[i]);
}
<< dateTime.toString("M/d/yy H:m:s a"));
}
+void tst_qdeclarativeqt::dateTimeFormattingVariants()
+{
+ QFETCH(QString, method);
+ QFETCH(QVariant, variant);
+ QFETCH(QStringList, expectedResults);
+
+ QDeclarativeEngine eng;
+ eng.rootContext()->setContextProperty("qvariant", variant);
+ QDeclarativeComponent component(&eng, TEST_FILE("formatting.qml"));
+
+ QStringList warnings;
+ warnings << component.url().toString() + ":37: Error: Qt.formatDate(): Invalid date format"
+ << component.url().toString() + ":36: Error: Qt.formatDate(): Invalid arguments"
+ << component.url().toString() + ":40: Error: Qt.formatTime(): Invalid time format"
+ << component.url().toString() + ":39: Error: Qt.formatTime(): Invalid arguments"
+ << component.url().toString() + ":43: Error: Qt.formatDateTime(): Invalid datetime format"
+ << component.url().toString() + ":42: Error: Qt.formatDateTime(): Invalid arguments";
+
+ foreach (const QString &warning, warnings)
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ QObject *object = component.create();
+ QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
+ QVERIFY(object != 0);
+
+ QVariant result;
+ QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(),
+ Q_RETURN_ARG(QVariant, result),
+ Q_ARG(QVariant, QString(QLatin1String("qvariant")))));
+ QStringList output = result.toStringList();
+ QCOMPARE(output, expectedResults);
+
+ delete object;
+}
+
+void tst_qdeclarativeqt::dateTimeFormattingVariants_data()
+{
+ QTest::addColumn<QString>("method");
+ QTest::addColumn<QVariant>("variant");
+ QTest::addColumn<QStringList>("expectedResults");
+
+ QDateTime temporary;
+
+ QTime time(11, 16, 39, 755);
+ temporary = QDateTime(QDate(1970,1,1), time);
+ QTest::newRow("formatDate, qtime") << "formatDate" << QVariant::fromValue(time) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
+ QTest::newRow("formatDateTime, qtime") << "formatDateTime" << QVariant::fromValue(time) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
+ QTest::newRow("formatTime, qtime") << "formatTime" << QVariant::fromValue(time) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
+
+ QDate date(2011,5,31);
+ temporary = QDateTime(date);
+ QTest::newRow("formatDate, qdate") << "formatDate" << QVariant::fromValue(date) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
+ QTest::newRow("formatDateTime, qdate") << "formatDateTime" << QVariant::fromValue(date) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
+ QTest::newRow("formatTime, qdate") << "formatTime" << QVariant::fromValue(date) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
+
+ QDateTime dateTime(date, time);
+ temporary = dateTime;
+ QTest::newRow("formatDate, qdatetime") << "formatDate" << QVariant::fromValue(dateTime) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
+ QTest::newRow("formatDateTime, qdatetime") << "formatDateTime" << QVariant::fromValue(dateTime) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
+ QTest::newRow("formatTime, qdatetime") << "formatTime" << QVariant::fromValue(dateTime) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
+
+ QString string(QLatin1String("2011/05/31 11:16:39.755"));
+ temporary = QDateTime::fromString(string, "yyyy/MM/dd HH:mm:ss.zzz");
+ QTest::newRow("formatDate, qstring") << "formatDate" << QVariant::fromValue(string) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
+ QTest::newRow("formatDateTime, qstring") << "formatDateTime" << QVariant::fromValue(string) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
+ QTest::newRow("formatTime, qstring") << "formatTime" << QVariant::fromValue(string) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
+
+ QColor color(Qt::red);
+ temporary = QVariant::fromValue(color).toDateTime();
+ QTest::newRow("formatDate, qcolor") << "formatDate" << QVariant::fromValue(color) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
+ QTest::newRow("formatDateTime, qcolor") << "formatDateTime" << QVariant::fromValue(color) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
+ QTest::newRow("formatTime, qcolor") << "formatTime" << QVariant::fromValue(color) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
+
+ int integer(4);
+ temporary = QVariant::fromValue(integer).toDateTime();
+ QTest::newRow("formatDate, int") << "formatDate" << QVariant::fromValue(integer) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy"));
+ QTest::newRow("formatDateTime, int") << "formatDateTime" << QVariant::fromValue(integer) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a"));
+ QTest::newRow("formatTime, int") << "formatTime" << QVariant::fromValue(integer) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz"));
+}
+
void tst_qdeclarativeqt::isQtObject()
{
QDeclarativeComponent component(&engine, TEST_FILE("isQtObject.qml"));
// making it more like the tests are running in new processes.
testQml();
- QDeclarativeEnginePrivate::getScriptEngine(engine)->collectGarbage(); // close databases
+ engine->collectGarbage();
+
foreach (QString dbname, QSqlDatabase::connectionNames()) {
QSqlDatabase::removeDatabase(dbname);
}
#include <private/qdeclarativeengine_p.h>
#include "../../../shared/util.h"
-Q_DECLARE_METATYPE(QScriptValue)
-
#ifdef Q_OS_SYMBIAN
// In Symbian OS test data is located in applications private dir
#define SRCDIR "."
// QVariant roundtrip, since the properties will be stored in a QVariantMap.
QString jsObject = "{'haste': 1125, 'name': 'zyz', 'spell power': 3101}";
- QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(worker));
- QScriptValue sv = engine->newObject();
- sv.setProperty("haste", 1125);
- sv.setProperty("name", "zyz");
- sv.setProperty("spell power", 3101);
+ QVariantMap map;
+ map.insert("haste", 1125);
+ map.insert("name", "zyz");
+ map.insert("spell power", 3101);
- QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, qVariantFromValue(sv))));
+ QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, qVariantFromValue(map))));
waitForEchoMessage(worker);
QVariant result = qVariantFromValue(false);
QVERIFY(worker != 0);
QTRY_COMPARE(qdeclarativeworkerscript_lastWarning,
- TEST_FILE("data/script_error_onLoad.js").toString() + QLatin1String(":3: SyntaxError: Parse error"));
+ TEST_FILE("data/script_error_onLoad.js").toString() + QLatin1String(":3: SyntaxError: Unexpected identifier"));
qInstallMsgHandler(previousMsgHandler);
qApp->processEvents();
import QtQuick 1.0
QtObject {
- property bool onreadystatechange: false
property bool readyState: false
property bool status: false
property bool statusText: false
var o = 10;
try {
- XMLHttpRequest.prototype.onreadystatechange
- } catch (e) {
- if (!(e instanceof ReferenceError))
- return;
-
- if (e.message != "Not an XMLHttpRequest object")
- return;
-
- onreadystatechange = true;
- }
- try {
XMLHttpRequest.prototype.readyState
} catch (e) {
if (!(e instanceof ReferenceError))
QObject *object = component.create();
QVERIFY(object != 0);
- QCOMPARE(object->property("onreadystatechange").toBool(), true);
QCOMPARE(object->property("readyState").toBool(), true);
QCOMPARE(object->property("status").toBool(), true);
QCOMPARE(object->property("statusText").toBool(), true);
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qtest.h>
+#include "../../../../src/3rdparty/v8/include/v8.h"
+
+using namespace v8;
+
+class tst_v8 : public QObject
+{
+ Q_OBJECT
+public:
+ tst_v8() {}
+
+private slots:
+ void initTestCase() {}
+ void cleanupTestCase();
+
+ void eval();
+
+private:
+ Persistent<Context> context;
+};
+
+void tst_v8::eval()
+{
+ HandleScope handle_scope;
+ context = Context::New();
+ Context::Scope context_scope(context);
+
+ Local<Object> qmlglobal = Object::New();
+ qmlglobal->Set(String::New("a"), v8::Integer::New(1922));
+
+ Local<Script> script = Script::Compile(String::New("eval(\"a\")"), NULL, NULL,
+ Handle<String>(), Script::QmlMode);
+
+ TryCatch tc;
+ Local<Value> result = script->Run(qmlglobal);
+
+ QVERIFY(!tc.HasCaught());
+ QCOMPARE(result->Int32Value(), 1922);
+}
+
+void tst_v8::cleanupTestCase()
+{
+ context.Dispose();
+ context = Persistent<Context>();
+}
+
+int main(int argc, char *argv[])
+{
+ V8::SetFlagsFromCommandLine(&argc, argv, true);
+
+ QCoreApplication app(argc, argv);
+ tst_v8 tc;
+ return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_v8.moc"
--- /dev/null
+load(qttest_p4)
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_v8.cpp
+
+CONFIG += parallel_test
+
+LIBS += -L../../../../src/v8/
+macx:CONFIG(debug, debug|release) {
+ LIBS += -lv8_debug
+} else {
+ LIBS += -lv8
+}
+