aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2012-04-11 14:56:22 +0200
committerLars Knoll <lars.knoll@nokia.com>2012-04-11 16:05:03 +0200
commita896d4b39ec3d45ba708d9b36ea9c864b1df2136 (patch)
tree45cfe153cce6114c2c76c48dc0bdabde2a8cf3e3 /src
parent24fb8dc27eddfdd62bd2c3a6e863cbf433762cd6 (diff)
parent65bfc35429e845cf6b76d58107360a1360a654fc (diff)
Merge remote-tracking branch 'origin/master' into api_changes
Conflicts: src/qml/debugger/qqmlprofilerservice_p.h src/qml/qml/qqmlboundsignal.cpp src/qml/qml/v4/qv4bindings.cpp src/quick/items/qquickshadereffect.cpp src/quick/particles/qquickcustomparticle.cpp src/quick/qtquick2.cpp Change-Id: Ia9c6517035ae912fa75e77473a452bd3383def56
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/javascriptcore/COPYING.LIB488
-rw-r--r--src/3rdparty/javascriptcore/DateMath.cpp393
-rw-r--r--src/3rdparty/javascriptcore/DateMath.h190
-rw-r--r--src/3rdparty/javascriptcore/VERSION15
-rw-r--r--src/imports/imports.pro2
-rw-r--r--src/imports/particles/particles.pro19
-rw-r--r--src/imports/particles/plugin.cpp (renamed from src/plugins/qmltooling/qmldbg_qtquick2/selectiontool.h)53
-rw-r--r--src/imports/particles/qmldir1
-rw-r--r--src/imports/testlib/TestCase.qml14
-rw-r--r--src/imports/testlib/testcase.qdoc25
-rw-r--r--src/imports/window/plugin.cpp (renamed from src/plugins/qmltooling/qmldbg_qtquick2/selectiontool.cpp)63
-rw-r--r--src/imports/window/qmldir1
-rw-r--r--src/imports/window/window.pro19
-rw-r--r--src/plugins/accessible/quick/main.cpp6
-rw-r--r--src/plugins/accessible/quick/qaccessiblequickview.cpp7
-rw-r--r--src/plugins/plugins.pro4
-rw-r--r--src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.cpp (renamed from src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.cpp)243
-rw-r--r--src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.h (renamed from src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.h)56
-rw-r--r--src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro6
-rw-r--r--src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp24
-rw-r--r--src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h6
-rw-r--r--src/plugins/qmltooling/shared/abstracttool.h2
-rw-r--r--src/plugins/qmltooling/shared/abstractviewinspector.cpp38
-rw-r--r--src/plugins/qmltooling/shared/abstractviewinspector.h12
-rw-r--r--src/plugins/qmltooling/shared/qmlinspectorconstants.h5
-rw-r--r--src/plugins/qmltooling/shared/qqmlinspectorprotocol.h7
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp16
-rw-r--r--src/qml/debugger/qqmldebug.h4
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp7
-rw-r--r--src/qml/debugger/qqmlenginedebugservice.cpp16
-rw-r--r--src/qml/debugger/qqmlenginedebugservice_p.h1
-rw-r--r--src/qml/debugger/qqmlprofilerservice.cpp4
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h37
-rw-r--r--src/qml/qml/qqmlabstractexpression_p.h2
-rw-r--r--src/qml/qml/qqmlaccessors_p.h2
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp184
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h88
-rw-r--r--src/qml/qml/qqmlcompiler.cpp31
-rw-r--r--src/qml/qml/qqmlcomponent.cpp3
-rw-r--r--src/qml/qml/qqmldata_p.h14
-rw-r--r--src/qml/qml/qqmldirparser.cpp12
-rw-r--r--src/qml/qml/qqmlengine.cpp14
-rw-r--r--src/qml/qml/qqmlexpression.cpp33
-rw-r--r--src/qml/qml/qqmlexpression_p.h7
-rw-r--r--src/qml/qml/qqmlimport.cpp36
-rw-r--r--src/qml/qml/qqmlinstruction.cpp3
-rw-r--r--src/qml/qml/qqmlinstruction_p.h2
-rw-r--r--src/qml/qml/qqmlproperty.cpp37
-rw-r--r--src/qml/qml/qqmlproperty_p.h8
-rw-r--r--src/qml/qml/qqmlrewrite.cpp17
-rw-r--r--src/qml/qml/qqmlrewrite_p.h29
-rw-r--r--src/qml/qml/qqmlscript.cpp5
-rw-r--r--src/qml/qml/qqmlvme.cpp86
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp456
-rw-r--r--src/qml/qml/v4/qv4bindings_p.h6
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp267
-rw-r--r--src/qml/qml/v4/qv4compiler_p_p.h16
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp130
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h85
-rw-r--r--src/qml/qml/v4/qv4ir.cpp37
-rw-r--r--src/qml/qml/v4/qv4ir_p.h6
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp30
-rw-r--r--src/qml/qml/v4/qv4irbuilder_p.h4
-rw-r--r--src/qml/qml/v4/qv4program_p.h4
-rw-r--r--src/qml/qml/v8/qjsvalue_p.h2
-rw-r--r--src/qml/qml/v8/qv8bindings.cpp23
-rw-r--r--src/qml/qml/v8/qv8bindings_p.h20
-rw-r--r--src/qml/qml/v8/qv8contextwrapper.cpp2
-rw-r--r--src/qml/qml/v8/qv8engine.cpp43
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp29
-rw-r--r--src/qml/qml/v8/v8.pri6
-rw-r--r--src/qmltest/qmltest.pro4
-rw-r--r--src/qmltest/quicktest.cpp34
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp682
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h22
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp30
-rw-r--r--src/quick/items/qquickcanvas.cpp17
-rw-r--r--src/quick/items/qquickcanvas.h2
-rw-r--r--src/quick/items/qquickflickable.cpp3
-rw-r--r--src/quick/items/qquickimplicitsizeitem.cpp12
-rw-r--r--src/quick/items/qquickitem.cpp53
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickitemchangelistener_p.h2
-rw-r--r--src/quick/items/qquicklistview.cpp11
-rw-r--r--src/quick/items/qquickloader.cpp81
-rw-r--r--src/quick/items/qquickloader_p_p.h7
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp2
-rw-r--r--src/quick/items/qquickpathview.cpp143
-rw-r--r--src/quick/items/qquickpathview_p.h7
-rw-r--r--src/quick/items/qquickpathview_p_p.h9
-rw-r--r--src/quick/items/qquickshadereffect.cpp960
-rw-r--r--src/quick/items/qquickshadereffect_p.h69
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp210
-rw-r--r--src/quick/items/qquickshadereffectnode_p.h52
-rw-r--r--src/quick/items/qquickspriteengine.cpp3
-rw-r--r--src/quick/items/qquicktext.cpp9
-rw-r--r--src/quick/items/qquicktextcontrol.cpp74
-rw-r--r--src/quick/items/qquicktextcontrol_p.h4
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h4
-rw-r--r--src/quick/items/qquicktextedit.cpp12
-rw-r--r--src/quick/items/qquicktextinput.cpp82
-rw-r--r--src/quick/items/qquicktextinput_p_p.h9
-rw-r--r--src/quick/items/qquicktextnode.cpp22
-rw-r--r--src/quick/items/qquickvisualdatamodel.cpp2
-rw-r--r--src/quick/items/qquickwindowmanager.cpp2
-rw-r--r--src/quick/items/qquickwindowmodule_p.h4
-rw-r--r--src/quick/particles/qquickcustomparticle.cpp387
-rw-r--r--src/quick/particles/qquickcustomparticle_p.h48
-rw-r--r--src/quick/particles/qquickparticleemitter_p.h3
-rw-r--r--src/quick/particles/qquickparticlesmodule_p.h10
-rw-r--r--src/quick/qtquick2.cpp6
-rw-r--r--src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp25
-rw-r--r--src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h11
-rw-r--r--src/quick/scenegraph/util/qsgpainternode.cpp5
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp4
-rw-r--r--src/quick/util/qquickconnections.cpp5
-rw-r--r--src/quick/util/qquickpropertychanges.cpp124
118 files changed, 3217 insertions, 3619 deletions
diff --git a/src/3rdparty/javascriptcore/COPYING.LIB b/src/3rdparty/javascriptcore/COPYING.LIB
deleted file mode 100644
index 87c4a33dd8..0000000000
--- a/src/3rdparty/javascriptcore/COPYING.LIB
+++ /dev/null
@@ -1,488 +0,0 @@
-
-
-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!
diff --git a/src/3rdparty/javascriptcore/DateMath.cpp b/src/3rdparty/javascriptcore/DateMath.cpp
deleted file mode 100644
index be99d2ca25..0000000000
--- a/src/3rdparty/javascriptcore/DateMath.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * 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 <time.h>
-#include <cmath>
-
-//#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 defined(_MSC_VER)
- if (!_finite(t) || fabs(t) > maxECMAScriptTime)
- return NaN;
- return t >= 0 ? floor(t) : ceil(t);
-#else
-
-#if defined(__QNXNTO__)
- if (!isfinite(t) || fabs(t) > maxECMAScriptTime)
- return NaN;
-#else
- if (!std::isfinite(t) || fabs(t) > maxECMAScriptTime)
- return NaN;
-#endif
-
- return trunc(t);
-#endif
-}
-} // 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
-
diff --git a/src/3rdparty/javascriptcore/DateMath.h b/src/3rdparty/javascriptcore/DateMath.h
deleted file mode 100644
index 5adb0d358c..0000000000
--- a/src/3rdparty/javascriptcore/DateMath.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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
diff --git a/src/3rdparty/javascriptcore/VERSION b/src/3rdparty/javascriptcore/VERSION
deleted file mode 100644
index af6229afcb..0000000000
--- a/src/3rdparty/javascriptcore/VERSION
+++ /dev/null
@@ -1,15 +0,0 @@
-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).
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index b62275b009..f7861ac009 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,5 +1,5 @@
TEMPLATE = subdirs
-SUBDIRS += qtquick2 folderlistmodel localstorage
+SUBDIRS += qtquick2 particles window folderlistmodel localstorage
contains(QT_CONFIG, qmltest): SUBDIRS += testlib
contains(QT_CONFIG, xmlpatterns) : SUBDIRS += xmllistmodel
diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro
new file mode 100644
index 0000000000..dc3198d124
--- /dev/null
+++ b/src/imports/particles/particles.pro
@@ -0,0 +1,19 @@
+TARGET = particlesplugin
+TARGETPATH = QtQuick/Particles.2
+include(../qimportbase.pri)
+
+SOURCES += \
+ plugin.cpp
+
+QT += quick-private qml-private
+
+OTHER_FILES += \
+ qmldir
+
+DESTDIR = $$QT.qml.imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+INSTALLS += target qmldir
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/selectiontool.h b/src/imports/particles/plugin.cpp
index c2aa26a1a7..b5680b5ed1 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/selectiontool.h
+++ b/src/imports/particles/plugin.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@@ -39,48 +39,27 @@
**
****************************************************************************/
-#ifndef SELECTIONTOOL_H
-#define SELECTIONTOOL_H
+#include <QtQml/qqmlextensionplugin.h>
-#include "abstracttool.h"
+#include <private/qquickparticlesmodule_p.h>
-#include <QtCore/QList>
-#include <QtCore/QPoint>
+QT_BEGIN_NAMESPACE
-QT_FORWARD_DECLARE_CLASS(QQuickItem)
-
-namespace QmlJSDebugger {
-namespace QtQuick2 {
-
-class QQuickViewInspector;
-class HoverHighlight;
-
-class SelectionTool : public AbstractTool
+//![class decl]
+class QtQuick2ParticlesPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
public:
- explicit SelectionTool(QQuickViewInspector *inspector);
-
- void leaveEvent(QEvent *);
-
- void mousePressEvent(QMouseEvent *);
- void mouseMoveEvent(QMouseEvent *) {}
- void mouseReleaseEvent(QMouseEvent *) {}
- void mouseDoubleClickEvent(QMouseEvent *) {}
-
- void hoverMoveEvent(QMouseEvent *);
- void wheelEvent(QWheelEvent *) {}
-
- void keyPressEvent(QKeyEvent *) {}
- void keyReleaseEvent(QKeyEvent *) {}
-
-private:
- QQuickViewInspector *inspector() const;
-
- HoverHighlight *m_hoverHighlight;
+ virtual void registerTypes(const char *uri)
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Particles"));
+ Q_UNUSED(uri);
+ QQuickParticlesModule::defineModule();
+ }
};
+//![class decl]
-} // namespace QtQuick2
-} // namespace QmlJSDebugger
+QT_END_NAMESPACE
-#endif // SELECTIONTOOL_H
+#include "plugin.moc"
diff --git a/src/imports/particles/qmldir b/src/imports/particles/qmldir
new file mode 100644
index 0000000000..593915f83f
--- /dev/null
+++ b/src/imports/particles/qmldir
@@ -0,0 +1 @@
+plugin particlesplugin
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index 1f9de5e998..371bba9fde 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -607,6 +607,10 @@ Item {
functionsToRun.splice(index, 1)
}
qtest_results.functionName = prop
+
+ if (!(datafunc in testCase))
+ datafunc = "init_data";
+
if (datafunc in testCase) {
if (qtest_runInternal(datafunc)) {
var table = qtest_testCaseResult
@@ -624,9 +628,13 @@ Item {
qtest_runFunction(prop, row)
qtest_results.dataTag = ""
}
- if (!haveData)
- qtest_results.warn("no data supplied for " + prop + "() by " + datafunc + "()"
- , util.callerFile(), util.callerLine());
+ if (!haveData) {
+ if (datafunc === "init_data")
+ qtest_runFunction(prop, null, isBenchmark)
+ else
+ qtest_results.warn("no data supplied for " + prop + "() by " + datafunc + "()"
+ , util.callerFile(), util.callerLine());
+ }
qtest_results.clearTestTable()
}
} else if (isBenchmark) {
diff --git a/src/imports/testlib/testcase.qdoc b/src/imports/testlib/testcase.qdoc
index f928cdaa44..29f7a2d287 100644
--- a/src/imports/testlib/testcase.qdoc
+++ b/src/imports/testlib/testcase.qdoc
@@ -51,8 +51,8 @@
element:
\code
- import QtQuick 1.0
- import QtQuickTest 1.0
+ import QtQuick 2.0
+ import QtTest 1.0
TestCase {
name: "MathTests"
@@ -97,15 +97,24 @@
\section1 Data-driven tests
Table data can be provided to a test using a function name that ends
- with "_data":
+ with "_data". Alternatively, the \c init_data() function can be used
+ to provide default test data for all test functions in a TestCase element:
+
\code
- import QtQuick 1.0
- import QtQuickTest 1.0
+ import QtQuick 2.0
+ import QtTest 1.0
TestCase {
name: "DataTests"
+ function init_data() {
+ return [
+ {tag:"init_data_1", a:1, b:2, answer: 3},
+ {tag:"init_data_2", a:2, b:4, answer: 6}
+ ];
+ }
+
function test_table_data() {
return [
{tag: "2 + 2 = 4", a: 2, b: 2, answer: 4 },
@@ -114,6 +123,12 @@
}
function test_table(data) {
+ //data comes from test_table_data
+ compare(data.a + data.b, data.answer)
+ }
+
+ function test__default_table(data) {
+ //data comes from init_data
compare(data.a + data.b, data.answer)
}
}
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/selectiontool.cpp b/src/imports/window/plugin.cpp
index 5ad102a92d..b0c8c90890 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/selectiontool.cpp
+++ b/src/imports/window/plugin.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@@ -39,54 +39,27 @@
**
****************************************************************************/
-#include "selectiontool.h"
+#include <QtQml/qqmlextensionplugin.h>
-#include "highlight.h"
-#include "qquickviewinspector.h"
+#include <private/qquickwindowmodule_p.h>
-#include <QtGui/QMouseEvent>
-#include <QtQuick/QQuickView>
-#include <QtQuick/QQuickItem>
+QT_BEGIN_NAMESPACE
-namespace QmlJSDebugger {
-namespace QtQuick2 {
-
-SelectionTool::SelectionTool(QQuickViewInspector *inspector) :
- AbstractTool(inspector),
- m_hoverHighlight(new HoverHighlight(inspector->overlay()))
-{
-}
-
-void SelectionTool::leaveEvent(QEvent *)
-{
- m_hoverHighlight->setVisible(false);
-}
-
-void SelectionTool::mousePressEvent(QMouseEvent *event)
+//![class decl]
+class QtQuick2WindowPlugin : public QQmlExtensionPlugin
{
- if (event->button() == Qt::LeftButton) {
- if (QQuickItem *item = inspector()->topVisibleItemAt(event->pos()))
- inspector()->setSelectedItems(QList<QQuickItem*>() << item);
- } else if (event->button() == Qt::RightButton) {
- // todo: Show context menu
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
+public:
+ virtual void registerTypes(const char *uri)
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Window"));
+ Q_UNUSED(uri);
+ QQuickWindowModule::defineModule();
}
-}
+};
+//![class decl]
-void SelectionTool::hoverMoveEvent(QMouseEvent *event)
-{
- QQuickItem *item = inspector()->topVisibleItemAt(event->pos());
- if (!item) {
- m_hoverHighlight->setVisible(false);
- } else {
- m_hoverHighlight->setItem(item);
- m_hoverHighlight->setVisible(true);
- }
-}
-
-QQuickViewInspector *SelectionTool::inspector() const
-{
- return static_cast<QQuickViewInspector*>(AbstractTool::inspector());
-}
+QT_END_NAMESPACE
-} // namespace QtQuick2
-} // namespace QmlJSDebugger
+#include "plugin.moc"
diff --git a/src/imports/window/qmldir b/src/imports/window/qmldir
new file mode 100644
index 0000000000..32844a6ed6
--- /dev/null
+++ b/src/imports/window/qmldir
@@ -0,0 +1 @@
+plugin windowplugin
diff --git a/src/imports/window/window.pro b/src/imports/window/window.pro
new file mode 100644
index 0000000000..42b6f5911d
--- /dev/null
+++ b/src/imports/window/window.pro
@@ -0,0 +1,19 @@
+TARGET = windowplugin
+TARGETPATH = QtQuick/Window.2
+include(../qimportbase.pri)
+
+SOURCES += \
+ plugin.cpp
+
+QT += quick-private qml-private
+
+OTHER_FILES += \
+ qmldir
+
+DESTDIR = $$QT.qml.imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+INSTALLS += target qmldir
diff --git a/src/plugins/accessible/quick/main.cpp b/src/plugins/accessible/quick/main.cpp
index 2c75e594c2..6592c59e0f 100644
--- a/src/plugins/accessible/quick/main.cpp
+++ b/src/plugins/accessible/quick/main.cpp
@@ -46,6 +46,7 @@
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>
+#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
#include <qaccessibleplugin.h>
@@ -86,8 +87,11 @@ QAccessibleInterface *AccessibleQuickFactory::create(const QString &classname, Q
if (classname == QLatin1String("QQuickView")) {
return new QAccessibleQuickView(qobject_cast<QQuickView *>(object)); // FIXME
} else if (classname == QLatin1String("QQuickItem")) {
- QQuickItem * item = qobject_cast<QQuickItem *>(object);
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
Q_ASSERT(item);
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ if (!itemPrivate->isAccessible)
+ return 0;
QVariant v = QQuickAccessibleAttached::property(item, "role");
bool ok;
diff --git a/src/plugins/accessible/quick/qaccessiblequickview.cpp b/src/plugins/accessible/quick/qaccessiblequickview.cpp
index 2df1f243b8..ed8167f4d1 100644
--- a/src/plugins/accessible/quick/qaccessiblequickview.cpp
+++ b/src/plugins/accessible/quick/qaccessiblequickview.cpp
@@ -127,7 +127,11 @@ static QQuickItem *childAt_helper(QQuickItem *item, int x, int y)
}
QScopedPointer<QAccessibleInterface> accessibleInterface(QAccessible::queryAccessibleInterface(item));
- if (accessibleInterface && accessibleInterface->childCount() == 0) {
+ // this item has no Accessible attached property
+ if (!accessibleInterface)
+ return 0;
+
+ if (accessibleInterface->childCount() == 0) {
return (itemScreenRect(item).contains(x, y)) ? item : 0;
}
@@ -155,6 +159,7 @@ QAccessibleInterface *QAccessibleQuickView::childAt(int x, int y) const
if (root) {
if (QQuickItem *item = childAt_helper(root, x, y))
return QAccessible::queryAccessibleInterface(item);
+ return QAccessible::queryAccessibleInterface(root);
}
return 0;
}
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index ae42ba1ba4..9ef8c7ab72 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -1,3 +1,5 @@
TEMPLATE = subdirs
SUBDIRS += qmltooling
-SUBDIRS += accessible
+contains(QT_CONFIG, accessibility) {
+ SUBDIRS += accessible
+}
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp
index bb4048ee92..da959933f7 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp
+++ b/src/plugins/qmltooling/qmldbg_qtquick2/highlight.cpp
@@ -81,14 +81,14 @@ void Highlight::adjust()
}
-void SelectionHighlight::paint(QPainter *painter)
+void HoverHighlight::paint(QPainter *painter)
{
painter->setPen(QColor(108, 141, 221));
painter->drawRect(QRect(0, 0, width() - 1, height() - 1));
}
-void HoverHighlight::paint(QPainter *painter)
+void SelectionHighlight::paint(QPainter *painter)
{
painter->setPen(QPen(QColor(0, 22, 159)));
painter->drawRect(QRect(1, 1, width() - 3, height() - 3));
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.cpp
index 171f1a52e9..67b12822be 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.cpp
+++ b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.cpp
@@ -39,14 +39,19 @@
**
****************************************************************************/
-#include "zoomtool.h"
+#include "inspecttool.h"
+
+#include "highlight.h"
#include "qquickviewinspector.h"
#include <QtCore/QLineF>
+
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtGui/QTouchEvent>
#include <QtGui/QKeyEvent>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QStyleHints>
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>
@@ -54,67 +59,107 @@
namespace QmlJSDebugger {
namespace QtQuick2 {
-ZoomTool::ZoomTool(QQuickViewInspector *inspector, QQuickView *view) :
+InspectTool::InspectTool(QQuickViewInspector *inspector, QQuickView *view) :
AbstractTool(inspector),
+ m_originalSmooth(view->rootItem()->smooth()),
m_dragStarted(false),
m_pinchStarted(false),
+ m_didPressAndHold(false),
+ m_tapEvent(false),
+ m_rootItem(view->rootItem()),
+ m_originalPosition(view->rootItem()->pos()),
m_currentScale(1.0f),
- m_smoothScaleFactor(0.05f),
+ m_smoothScaleFactor(Constants::ZoomSnapDelta),
m_minScale(0.125f),
m_maxScale(48.0f),
- m_tapScaleCounter(0)
+ m_originalScale(view->rootItem()->scale()),
+ m_touchTimestamp(0),
+ m_hoverHighlight(new HoverHighlight(inspector->overlay())),
+ m_lastItem(0),
+ m_lastClickedItem(0)
{
- m_rootItem = view->rootItem();
- m_originalSmooth = m_rootItem->smooth();
- if (!m_originalSmooth)
- m_rootItem->setSmooth(true);
- m_originalPosition = m_rootItem->pos();
- m_originalScale = m_rootItem->scale();
+ //Press and Hold Timer
+ m_pressAndHoldTimer.setSingleShot(true);
+ m_pressAndHoldTimer.setInterval(Constants::PressAndHoldTimeout);
+ connect(&m_pressAndHoldTimer, SIGNAL(timeout()), SLOT(zoomTo100()));
+ enable(true);
}
-ZoomTool::~ZoomTool()
+InspectTool::~InspectTool()
{
- // restoring the original states.
- m_rootItem->setScale(m_originalScale);
- m_rootItem->setPos(m_originalPosition);
- if (!m_originalSmooth)
- m_rootItem->setSmooth(m_originalSmooth);
+ enable(false);
}
-void ZoomTool::mousePressEvent(QMouseEvent *event)
+void InspectTool::enable(bool enable)
{
- m_mousePosition = event->posF();
- if (event->buttons() & Qt::LeftButton) {
- m_dragStartPosition = event->posF();
- m_dragStarted = false;
+ if (!enable) {
+ inspector()->setSelectedItems(QList<QQuickItem*>());
+ // restoring the original states.
+ if (m_rootItem) {
+ m_rootItem->setScale(m_originalScale);
+ m_rootItem->setPos(m_originalPosition);
+ m_rootItem->setSmooth(m_originalSmooth);
+ }
+ } else {
+ if (m_rootItem) {
+ m_originalSmooth = m_rootItem->smooth();
+ m_originalScale = m_rootItem->scale();
+ m_originalPosition = m_rootItem->pos();
+ m_rootItem->setSmooth(true);
+ }
}
}
-void ZoomTool::mouseMoveEvent(QMouseEvent *event)
+void InspectTool::leaveEvent(QEvent *)
{
- if (m_pinchStarted)
- return;
+ m_hoverHighlight->setVisible(false);
+}
+void InspectTool::mousePressEvent(QMouseEvent *event)
+{
m_mousePosition = event->posF();
- if (!m_dragStarted
- && event->buttons() & Qt::LeftButton
- && ((m_dragStartPosition - event->posF()).manhattanLength()
- > Constants::DragStartDistance)) {
- m_dragStarted = true;
- }
- if (m_dragStarted) {
- m_adjustedOrigin += event->posF() - m_dragStartPosition;
- m_dragStartPosition = event->posF();
- m_rootItem->setPos(m_adjustedOrigin);
+ if (event->button() == Qt::LeftButton) {
+ m_pressAndHoldTimer.start();
+ initializeDrag(event->posF());
}
}
-void ZoomTool::hoverMoveEvent(QMouseEvent *event)
+void InspectTool::mouseReleaseEvent(QMouseEvent *event)
+{
+ m_mousePosition = event->posF();
+ m_pressAndHoldTimer.stop();
+ if (event->button() == Qt::LeftButton)
+ selectItem();
+}
+
+void InspectTool::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ m_mousePosition = event->posF();
+ m_pressAndHoldTimer.stop();
+ if (event->button() == Qt::LeftButton)
+ selectNextItem();
+}
+
+void InspectTool::mouseMoveEvent(QMouseEvent *event)
+{
+ m_mousePosition = event->posF();
+ moveItem(event->buttons() & Qt::LeftButton);
+}
+
+void InspectTool::hoverMoveEvent(QMouseEvent *event)
{
m_mousePosition = event->posF();
+ m_pressAndHoldTimer.stop();
+ QQuickItem *item = inspector()->topVisibleItemAt(event->pos());
+ if (!item || item == m_lastClickedItem) {
+ m_hoverHighlight->setVisible(false);
+ } else {
+ m_hoverHighlight->setItem(item);
+ m_hoverHighlight->setVisible(true);
+ }
}
-void ZoomTool::wheelEvent(QWheelEvent *event)
+void InspectTool::wheelEvent(QWheelEvent *event)
{
if (event->orientation() != Qt::Vertical)
return;
@@ -133,13 +178,7 @@ void ZoomTool::wheelEvent(QWheelEvent *event)
}
}
-void ZoomTool::mouseDoubleClickEvent(QMouseEvent *event)
-{
- m_mousePosition = event->posF();
- zoomTo100();
-}
-
-void ZoomTool::keyReleaseEvent(QKeyEvent *event)
+void InspectTool::keyReleaseEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Plus:
@@ -166,16 +205,31 @@ void ZoomTool::keyReleaseEvent(QKeyEvent *event)
}
}
-void ZoomTool::touchEvent(QTouchEvent *event)
+void InspectTool::touchEvent(QTouchEvent *event)
{
QList<QTouchEvent::TouchPoint> touchPoints = event->touchPoints();
switch (event->type()) {
case QEvent::TouchBegin:
- // fall through..
+ if (touchPoints.count() == 1 && (event->touchPointStates() & Qt::TouchPointPressed)) {
+ if (!m_pressAndHoldTimer.isActive())
+ m_pressAndHoldTimer.start();
+ m_mousePosition = touchPoints.first().pos();
+ initializeDrag(touchPoints.first().pos());
+ m_tapEvent = true;
+ } else {
+ m_tapEvent = false;
+ }
+ break;
case QEvent::TouchUpdate: {
- if ((touchPoints.count() == 2)
- && (!(event->touchPointStates() & Qt::TouchPointReleased))) {
+ if (touchPoints.count() > 1)
+ m_tapEvent = false;
+ if ((touchPoints.count() == 1)
+ && (event->touchPointStates() & Qt::TouchPointMoved)) {
+ m_mousePosition = touchPoints.first().pos();
+ moveItem(true);
+ } else if ((touchPoints.count() == 2)
+ && (!(event->touchPointStates() & Qt::TouchPointReleased))) {
// determine scale factor
const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
@@ -188,21 +242,27 @@ void ZoomTool::touchEvent(QTouchEvent *event)
QPointF newcenter = (touchPoint0.pos() + touchPoint1.pos()) / 2;
m_pinchStarted = true;
- m_tapScaleCounter = 0;
scaleView(touchScaleFactor, newcenter, oldcenter);
}
break;
}
case QEvent::TouchEnd: {
+ m_pressAndHoldTimer.stop();
if (m_pinchStarted) {
m_pinchStarted = false;
- } else if ((touchPoints.count() == 1)
- &&(!m_dragStarted)) {
- ++m_tapScaleCounter;
- qreal factor = 1.0f + (1.0f / (m_tapScaleCounter + 1));
- scaleView(factor, touchPoints.first().pos(),
- touchPoints.first().pos());
}
+ if (touchPoints.count() == 1 && !m_dragStarted &&
+ !m_didPressAndHold && m_tapEvent) {
+ m_tapEvent = false;
+ bool doubleTap = event->timestamp() - m_touchTimestamp
+ < static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval());
+ if (doubleTap)
+ selectNextItem();
+ else
+ selectItem();
+ m_touchTimestamp = event->timestamp();
+ }
+ m_didPressAndHold = false;
break;
}
default:
@@ -210,8 +270,9 @@ void ZoomTool::touchEvent(QTouchEvent *event)
}
}
-void ZoomTool::scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter)
+void InspectTool::scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter)
{
+ m_pressAndHoldTimer.stop();
if (((m_currentScale * factor) > m_maxScale)
|| ((m_currentScale * factor) < m_minScale)) {
return;
@@ -224,29 +285,29 @@ void ZoomTool::scaleView(const qreal &factor, const QPointF &newcenter, const QP
m_rootItem->setPos(m_adjustedOrigin);
}
-void ZoomTool::zoomIn()
+void InspectTool::zoomIn()
{
qreal newScale = nextZoomScale(ZoomIn);
scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition);
}
-void ZoomTool::zoomOut()
+void InspectTool::zoomOut()
{
qreal newScale = nextZoomScale(ZoomOut);
scaleView(newScale / m_currentScale, m_mousePosition, m_mousePosition);
}
-void ZoomTool::zoomTo100()
+void InspectTool::zoomTo100()
{
+ m_didPressAndHold = true;
m_currentScale = 1.0;
m_adjustedOrigin = QPointF(0, 0);
- m_tapScaleCounter = 0;
m_rootItem->setPos(m_adjustedOrigin);
m_rootItem->setScale(m_currentScale);
}
-qreal ZoomTool::nextZoomScale(ZoomDirection direction)
+qreal InspectTool::nextZoomScale(ZoomDirection direction)
{
static QList<qreal> zoomScales =
QList<qreal>()
@@ -286,5 +347,67 @@ qreal ZoomTool::nextZoomScale(ZoomDirection direction)
return 1.0f;
}
+void InspectTool::initializeDrag(const QPointF &pos)
+{
+ m_dragStartPosition = pos;
+ m_dragStarted = false;
+}
+
+void InspectTool::dragItemToPosition()
+{
+ m_adjustedOrigin += m_mousePosition - m_dragStartPosition;
+ m_dragStartPosition = m_mousePosition;
+ m_rootItem->setPos(m_adjustedOrigin);
+}
+
+void InspectTool::moveItem(bool valid)
+{
+ if (m_pinchStarted)
+ return;
+
+ if (!m_dragStarted
+ && valid
+ && ((m_dragStartPosition - m_mousePosition).manhattanLength()
+ > qApp->styleHints()->startDragDistance())) {
+ m_pressAndHoldTimer.stop();
+ m_dragStarted = true;
+ }
+ if (m_dragStarted)
+ dragItemToPosition();
+}
+
+void InspectTool::selectNextItem()
+{
+ if (m_lastClickedItem != inspector()->topVisibleItemAt(m_mousePosition))
+ return;
+ QList<QQuickItem*> items = inspector()->itemsAt(m_mousePosition);
+ for (int i = 0; i < items.count(); i++) {
+ if (m_lastItem == items[i]) {
+ if (i + 1 < items.count())
+ m_lastItem = items[i+1];
+ else
+ m_lastItem = items[0];
+ inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastItem);
+ break;
+ }
+ }
+}
+
+void InspectTool::selectItem()
+{
+ if (!inspector()->topVisibleItemAt(m_mousePosition))
+ return;
+ if (m_lastClickedItem == inspector()->topVisibleItemAt(m_mousePosition))
+ return;
+ m_lastClickedItem = inspector()->topVisibleItemAt(m_mousePosition);
+ m_lastItem = m_lastClickedItem;
+ inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastClickedItem);
+}
+
+QQuickViewInspector *InspectTool::inspector() const
+{
+ return static_cast<QQuickViewInspector*>(AbstractTool::inspector());
+}
+
} // namespace QtQuick2
} // namespace QmlJSDebugger
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.h b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.h
index 02ed8e09df..25d0c634b2 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/zoomtool.h
+++ b/src/plugins/qmltooling/qmldbg_qtquick2/inspecttool.h
@@ -39,12 +39,14 @@
**
****************************************************************************/
-#ifndef ZOOMTOOL_H
-#define ZOOMTOOL_H
+#ifndef INSPECTTOOL_H
+#define INSPECTTOOL_H
#include "abstracttool.h"
#include <QtCore/QPointF>
+#include <QtCore/QPointer>
+#include <QtCore/QTimer>
QT_FORWARD_DECLARE_CLASS(QQuickView)
QT_FORWARD_DECLARE_CLASS(QQuickItem)
@@ -53,46 +55,59 @@ namespace QmlJSDebugger {
namespace QtQuick2 {
class QQuickViewInspector;
+class HoverHighlight;
-class ZoomTool : public AbstractTool
+class InspectTool : public AbstractTool
{
Q_OBJECT
-
public:
enum ZoomDirection {
ZoomIn,
ZoomOut
};
- explicit ZoomTool(QQuickViewInspector *inspector, QQuickView *view);
- virtual ~ZoomTool();
- void leaveEvent(QEvent *) {}
+ InspectTool(QQuickViewInspector *inspector, QQuickView *view);
+ ~InspectTool();
+
+ void enable(bool enable);
- void mousePressEvent(QMouseEvent *event);
- void mouseMoveEvent(QMouseEvent *event);
- void mouseReleaseEvent(QMouseEvent *) {}
- void mouseDoubleClickEvent(QMouseEvent *event);
+ void leaveEvent(QEvent *);
- void hoverMoveEvent(QMouseEvent *event);
- void wheelEvent(QWheelEvent *event);
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void mouseDoubleClickEvent(QMouseEvent *);
+
+ void hoverMoveEvent(QMouseEvent *);
+ void wheelEvent(QWheelEvent *);
void keyPressEvent(QKeyEvent *) {}
- void keyReleaseEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *);
void touchEvent(QTouchEvent *event);
private:
+ QQuickViewInspector *inspector() const;
qreal nextZoomScale(ZoomDirection direction);
void scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter);
- void zoomTo100();
void zoomIn();
void zoomOut();
+ void initializeDrag(const QPointF &pos);
+ void dragItemToPosition();
+ void moveItem(bool valid);
+ void selectNextItem();
+ void selectItem();
+
+private slots:
+ void zoomTo100();
private:
bool m_originalSmooth;
bool m_dragStarted;
bool m_pinchStarted;
- QQuickItem *m_rootItem;
+ bool m_didPressAndHold;
+ bool m_tapEvent;
+ QPointer<QQuickItem> m_rootItem;
QPointF m_adjustedOrigin;
QPointF m_dragStartPosition;
QPointF m_mousePosition;
@@ -101,11 +116,16 @@ private:
qreal m_smoothScaleFactor;
qreal m_minScale;
qreal m_maxScale;
- qreal m_tapScaleCounter;
qreal m_originalScale;
+ ulong m_touchTimestamp;
+ QTimer m_pressAndHoldTimer;
+
+ HoverHighlight *m_hoverHighlight;
+ QQuickItem *m_lastItem;
+ QQuickItem *m_lastClickedItem;
};
} // namespace QtQuick2
} // namespace QmlJSDebugger
-#endif // ZOOMTOOL_H
+#endif // INSPECTTOOL_H
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro b/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro
index 33bda11dcc..f40e3f0b04 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro
+++ b/src/plugins/qmltooling/qmldbg_qtquick2/qmldbg_qtquick2.pro
@@ -12,22 +12,20 @@ INCLUDEPATH *= $$PWD $$PWD/../shared
SOURCES += \
qtquick2plugin.cpp \
highlight.cpp \
- selectiontool.cpp \
qquickviewinspector.cpp \
../shared/abstracttool.cpp \
../shared/abstractviewinspector.cpp \
- zoomtool.cpp
+ inspecttool.cpp
HEADERS += \
qtquick2plugin.h \
highlight.h \
- selectiontool.h \
qquickviewinspector.h \
../shared/abstracttool.h \
../shared/abstractviewinspector.h \
../shared/qqmlinspectorprotocol.h \
../shared/qmlinspectorconstants.h \
- zoomtool.h
+ inspecttool.h
OTHER_FILES += qtquick2plugin.json
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp
index 0a73540b40..95ce86678c 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp
+++ b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.cpp
@@ -43,8 +43,7 @@
#include "qqmlinspectorprotocol.h"
#include "highlight.h"
-#include "selectiontool.h"
-#include "zoomtool.h"
+#include "inspecttool.h"
#include <QtQuick/private/qquickitem_p.h>
@@ -120,8 +119,7 @@ QQuickViewInspector::QQuickViewInspector(QQuickView *view, QObject *parent) :
AbstractViewInspector(parent),
m_view(view),
m_overlay(new QQuickItem),
- m_selectionTool(new SelectionTool(this)),
- m_zoomTool(0),
+ m_inspectTool(new InspectTool(this, view)),
m_designMode(true)
{
// Try to make sure the overlay is always on top
@@ -131,7 +129,7 @@ QQuickViewInspector::QQuickViewInspector(QQuickView *view, QObject *parent) :
m_overlay->setParentItem(root);
view->installEventFilter(this);
- setCurrentTool(m_selectionTool);
+ setCurrentTool(m_inspectTool);
}
void QQuickViewInspector::changeCurrentObjects(const QList<QObject*> &objects)
@@ -165,23 +163,13 @@ void QQuickViewInspector::reparentQmlObject(QObject *object, QObject *newParent)
void QQuickViewInspector::changeTool(InspectorProtocol::Tool tool)
{
switch (tool) {
- case InspectorProtocol::ColorPickerTool:
- // TODO
- emit colorPickerActivated();
- break;
case InspectorProtocol::SelectMarqueeTool:
// TODO
emit marqueeSelectToolActivated();
break;
- case InspectorProtocol::SelectTool:
- setCurrentTool(m_selectionTool);
- emit selectToolActivated();
- break;
- case InspectorProtocol::ZoomTool:
- if (!m_zoomTool)
- m_zoomTool = new ZoomTool(this, m_view);
- setCurrentTool(m_zoomTool);
- emit zoomToolActivated();
+ case InspectorProtocol::InspectTool:
+ setCurrentTool(m_inspectTool);
+ emit inspectToolActivated();
break;
}
}
diff --git a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h
index e8fdf351de..0fd2948279 100644
--- a/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h
+++ b/src/plugins/qmltooling/qmldbg_qtquick2/qquickviewinspector.h
@@ -55,9 +55,8 @@ QT_END_NAMESPACE
namespace QmlJSDebugger {
namespace QtQuick2 {
-class SelectionTool;
+class InspectTool;
class SelectionHighlight;
-class ZoomTool;
class QQuickViewInspector : public AbstractViewInspector
{
@@ -99,8 +98,7 @@ private:
QQuickView *m_view;
QQuickItem *m_overlay;
- SelectionTool *m_selectionTool;
- ZoomTool *m_zoomTool;
+ InspectTool *m_inspectTool;
QList<QWeakPointer<QQuickItem> > m_selectedItems;
QHash<QQuickItem*, SelectionHighlight*> m_highlightItems;
diff --git a/src/plugins/qmltooling/shared/abstracttool.h b/src/plugins/qmltooling/shared/abstracttool.h
index 7e5ba65fd4..ef9894a852 100644
--- a/src/plugins/qmltooling/shared/abstracttool.h
+++ b/src/plugins/qmltooling/shared/abstracttool.h
@@ -64,6 +64,8 @@ public:
AbstractViewInspector *inspector() const { return m_inspector; }
+ virtual void enable(bool enable) = 0;
+
virtual void leaveEvent(QEvent *event) = 0;
virtual void mousePressEvent(QMouseEvent *event) = 0;
diff --git a/src/plugins/qmltooling/shared/abstractviewinspector.cpp b/src/plugins/qmltooling/shared/abstractviewinspector.cpp
index 135da1b8b7..60a95986b0 100644
--- a/src/plugins/qmltooling/shared/abstractviewinspector.cpp
+++ b/src/plugins/qmltooling/shared/abstractviewinspector.cpp
@@ -100,6 +100,7 @@ void AbstractViewInspector::setDesignModeBehavior(bool value)
return;
m_designModeBehavior = value;
+ m_currentTool->enable(m_designModeBehavior);
emit designModeBehaviorChanged(value);
sendDesignModeBehavior(value);
}
@@ -163,19 +164,9 @@ void AbstractViewInspector::setShowAppOnTop(bool appOnTop)
emit showAppOnTopChanged(appOnTop);
}
-void AbstractViewInspector::changeToColorPickerTool()
+void AbstractViewInspector::changeToInspectTool()
{
- changeTool(InspectorProtocol::ColorPickerTool);
-}
-
-void AbstractViewInspector::changeToZoomTool()
-{
- changeTool(InspectorProtocol::ZoomTool);
-}
-
-void AbstractViewInspector::changeToSingleSelectTool()
-{
- changeTool(InspectorProtocol::SelectTool);
+ changeTool(InspectorProtocol::InspectTool);
}
void AbstractViewInspector::changeToMarqueeSelectTool()
@@ -272,18 +263,12 @@ bool AbstractViewInspector::keyReleaseEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_V:
- changeTool(InspectorProtocol::SelectTool);
+ changeTool(InspectorProtocol::InspectTool);
break;
// disabled because multiselection does not do anything useful without design mode
// case Qt::Key_M:
// changeTool(InspectorProtocol::SelectMarqueeTool);
// break;
- case Qt::Key_I:
- changeTool(InspectorProtocol::ColorPickerTool);
- break;
- case Qt::Key_Z:
- changeTool(InspectorProtocol::ZoomTool);
- break;
case Qt::Key_Space:
setAnimationPaused(!animationPaused());
break;
@@ -332,8 +317,8 @@ void AbstractViewInspector::handleMessage(const QByteArray &message)
if (QObject *obj = QQmlDebugService::objectForId(debugId))
selectedObjects << obj;
}
-
- changeCurrentObjects(selectedObjects);
+ if (m_designModeBehavior)
+ changeCurrentObjects(selectedObjects);
break;
}
case InspectorProtocol::Reload: {
@@ -497,17 +482,6 @@ void AbstractViewInspector::sendShowAppOnTop(bool showAppOnTop)
m_debugService->sendMessage(message);
}
-void AbstractViewInspector::sendColorChanged(const QColor &color)
-{
- QByteArray message;
- QDataStream ds(&message, QIODevice::WriteOnly);
-
- ds << InspectorProtocol::ColorChanged
- << color;
-
- m_debugService->sendMessage(message);
-}
-
QString AbstractViewInspector::idStringForObject(QObject *obj) const
{
const int id = QQmlDebugService::idForObject(obj);
diff --git a/src/plugins/qmltooling/shared/abstractviewinspector.h b/src/plugins/qmltooling/shared/abstractviewinspector.h
index 04ca02917e..17f9e26660 100644
--- a/src/plugins/qmltooling/shared/abstractviewinspector.h
+++ b/src/plugins/qmltooling/shared/abstractviewinspector.h
@@ -45,7 +45,6 @@
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QStringList>
-#include <QtGui/QColor>
#include "qqmlinspectorprotocol.h"
#include "qmlinspectorconstants.h"
@@ -109,10 +108,7 @@ signals:
void showAppOnTopChanged(bool showAppOnTop);
void reloadRequested();
void marqueeSelectToolActivated();
- void selectToolActivated();
- void zoomToolActivated();
- void colorPickerActivated();
- void selectedColorChanged(const QColor &color);
+ void inspectToolActivated();
void animationSpeedChanged(qreal factor);
void animationPausedChanged(bool paused);
@@ -132,15 +128,11 @@ protected:
virtual bool wheelEvent(QWheelEvent *event);
virtual bool touchEvent(QTouchEvent *event);
-private slots:
- void sendColorChanged(const QColor &color);
-
private:
void sendDesignModeBehavior(bool inDesignMode);
- void changeToColorPickerTool();
void changeToZoomTool();
- void changeToSingleSelectTool();
+ void changeToInspectTool();
void changeToMarqueeSelectTool();
virtual void setDesignModeBehavior(bool value);
diff --git a/src/plugins/qmltooling/shared/qmlinspectorconstants.h b/src/plugins/qmltooling/shared/qmlinspectorconstants.h
index e5a0ee5450..4463283d9f 100644
--- a/src/plugins/qmltooling/shared/qmlinspectorconstants.h
+++ b/src/plugins/qmltooling/shared/qmlinspectorconstants.h
@@ -53,13 +53,10 @@ enum DesignTool {
MarqueeSelectionToolMode = 2,
MoveToolMode = 3,
ResizeToolMode = 4,
- ColorPickerMode = 5,
ZoomMode = 6
};
-static const int DragStartTime = 50;
-
-static const int DragStartDistance = 20;
+static const int PressAndHoldTimeout = 800;
static const double ZoomSnapDelta = 0.04;
diff --git a/src/plugins/qmltooling/shared/qqmlinspectorprotocol.h b/src/plugins/qmltooling/shared/qqmlinspectorprotocol.h
index 63772aa8e4..8527bf6394 100644
--- a/src/plugins/qmltooling/shared/qqmlinspectorprotocol.h
+++ b/src/plugins/qmltooling/shared/qqmlinspectorprotocol.h
@@ -60,7 +60,6 @@ public:
AnimationPausedChanged = 19, // highest value
ChangeTool = 1,
ClearComponentCache = 2,
- ColorChanged = 3,
CreateObject = 5,
CurrentObjectsChanged = 6,
DestroyObject = 7,
@@ -77,10 +76,8 @@ public:
};
enum Tool {
- ColorPickerTool,
- SelectMarqueeTool,
- SelectTool,
- ZoomTool
+ SelectMarqueeTool = 1,
+ InspectTool
};
static inline QString toString(Message message)
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
index 83b2192313..59bceaaf4e 100644
--- a/src/qml/animations/qanimationgroupjob.cpp
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -51,8 +51,7 @@ QAnimationGroupJob::QAnimationGroupJob()
QAnimationGroupJob::~QAnimationGroupJob()
{
- while (firstChild() != 0)
- delete firstChild();
+ clear();
}
void QAnimationGroupJob::topLevelAnimationLoopChanged()
@@ -123,9 +122,16 @@ void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation)
void QAnimationGroupJob::clear()
{
- //### should this remove and delete, or just remove?
- while (firstChild() != 0)
- delete firstChild(); //removeAnimation(firstChild());
+ QAbstractAnimationJob *child = firstChild();
+ QAbstractAnimationJob *nextSibling = 0;
+ while (child != 0) {
+ child->m_group = 0;
+ nextSibling = child->nextSibling();
+ delete child;
+ child = nextSibling;
+ }
+ m_firstChild = 0;
+ m_lastChild = 0;
}
void QAnimationGroupJob::resetUncontrolledAnimationsFinishTime()
diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h
index 318e0bd71f..115f3cbc3a 100644
--- a/src/qml/debugger/qqmldebug.h
+++ b/src/qml/debugger/qqmldebug.h
@@ -55,9 +55,9 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler
};
// Execute code in constructor before first QQmlEngine is instantiated
-#if defined(QT_DECLARATIVE_DEBUG_NO_WARNING)
+#if defined(QT_QML_DEBUG_NO_WARNING)
static QQmlDebuggingEnabler qmlEnableDebuggingHelper(false);
-#elif defined(QT_DECLARATIVE_DEBUG)
+#elif defined(QT_QML_DEBUG) || defined(QT_DECLARATIVE_DEBUG)
static QQmlDebuggingEnabler qmlEnableDebuggingHelper(true);
#endif
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
index dcf93b400e..468b653a1f 100644
--- a/src/qml/debugger/qqmldebugserver.cpp
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -255,7 +255,7 @@ QQmlDebugServer *QQmlDebugServer::instance()
commandLineTested = true;
QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp));
-#ifndef QQML_NO_DEBUG_PROTOCOL
+#ifndef QT_QML_NO_DEBUGGER
// ### remove port definition when protocol is changed
int port = 0;
bool block = false;
@@ -398,7 +398,6 @@ void QQmlDebugServer::receiveMessage(const QByteArray &message)
iter.value()->stateChanged(newState);
}
- qDebug("QML Debugger: Connection established.");
d->messageArrivedCondition.wakeAll();
} else if (op == 1) {
@@ -458,14 +457,14 @@ void QQmlDebugServerPrivate::_q_sendMessages(const QList<QByteArray> &messages)
QList<QQmlDebugService*> QQmlDebugServer::services() const
{
- const Q_D(QQmlDebugServer);
+ Q_D(const QQmlDebugServer);
QReadLocker(&d->pluginsLock);
return d->plugins.values();
}
QStringList QQmlDebugServer::serviceNames() const
{
- const Q_D(QQmlDebugServer);
+ Q_D(const QQmlDebugServer);
QReadLocker(&d->pluginsLock);
return d->plugins.keys();
}
diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp
index cd09b69e48..d8997fd587 100644
--- a/src/qml/debugger/qqmlenginedebugservice.cpp
+++ b/src/qml/debugger/qqmlenginedebugservice.cpp
@@ -67,7 +67,7 @@ QQmlEngineDebugService *QQmlEngineDebugService::instance()
}
QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent)
- : QQmlDebugService(QStringLiteral("QmlDebugger"), 1, parent),
+ : QQmlDebugService(QStringLiteral("QmlDebugger"), 2, parent),
m_watch(new QQmlWatcher(this)),
m_statesDelegate(0)
{
@@ -86,7 +86,8 @@ QDataStream &operator<<(QDataStream &ds,
const QQmlEngineDebugService::QQmlObjectData &data)
{
ds << data.url << data.lineNumber << data.columnNumber << data.idString
- << data.objectName << data.objectType << data.objectId << data.contextId;
+ << data.objectName << data.objectType << data.objectId << data.contextId
+ << data.parentId;
return ds;
}
@@ -94,7 +95,8 @@ QDataStream &operator>>(QDataStream &ds,
QQmlEngineDebugService::QQmlObjectData &data)
{
ds >> data.url >> data.lineNumber >> data.columnNumber >> data.idString
- >> data.objectName >> data.objectType >> data.objectId >> data.contextId;
+ >> data.objectName >> data.objectType >> data.objectId >> data.contextId
+ >> data.parentId;
return ds;
}
@@ -264,7 +266,7 @@ void QQmlEngineDebugService::buildObjectDump(QDataStream &message,
QQmlObjectProperty prop;
prop.type = QQmlObjectProperty::SignalProperty;
prop.hasNotifySignal = false;
- QQmlExpression *expr = signalHandler->expression();
+ QQmlBoundSignalExpression *expr = signalHandler->expression();
if (expr) {
prop.value = expr->expression();
QObject *scope = expr->scopeObject();
@@ -376,7 +378,7 @@ QQmlEngineDebugService::objectData(QObject *object)
rv.objectName = object->objectName();
rv.objectId = QQmlDebugService::idForObject(object);
rv.contextId = QQmlDebugService::idForObject(qmlContext(object));
-
+ rv.parentId = QQmlDebugService::idForObject(object->parent());
QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
if (type) {
QString typeName = type->qmlTypeName();
@@ -603,9 +605,9 @@ bool QQmlEngineDebugService::setBinding(int objectId,
if (isLiteralValue) {
property.write(expression);
} else if (hasValidSignal(object, propertyName)) {
- QQmlExpression *qmlExpression = new QQmlExpression(context, object, expression.toString());
+ QQmlBoundSignalExpression *qmlExpression = new QQmlBoundSignalExpression(QQmlContextData::get(context), object, expression.toString(),
+ false, filename, line, column);
QQmlPropertyPrivate::setSignalExpression(property, qmlExpression);
- qmlExpression->setSourceLocation(filename, line, column);
} else if (property.isProperty()) {
QQmlBinding *binding = new QQmlBinding(expression.toString(), false, object, QQmlContextData::get(context), filename, line, column);;
binding->setTarget(property);
diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h
index 19a5776e27..3b855cb602 100644
--- a/src/qml/debugger/qqmlenginedebugservice_p.h
+++ b/src/qml/debugger/qqmlenginedebugservice_p.h
@@ -83,6 +83,7 @@ public:
QString objectType;
int objectId;
int contextId;
+ int parentId;
};
struct QQmlObjectProperty {
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp
index c643073308..7109286197 100644
--- a/src/qml/debugger/qqmlprofilerservice.cpp
+++ b/src/qml/debugger/qqmlprofilerservice.cpp
@@ -195,7 +195,7 @@ void QQmlProfilerService::rangeData(RangeType range, const QUrl &rData)
if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
return;
- QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(QUrl::FormattingOption(0x100)), -1, -1, 0, 0};
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeData, (int)range, rData.toString(), -1, -1, 0, 0};
processMessage(rd);
}
@@ -213,7 +213,7 @@ void QQmlProfilerService::rangeLocation(RangeType range, const QUrl &fileName, i
if (!QQmlDebugService::isDebuggingEnabled() || !m_enabled)
return;
- QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(QUrl::FormattingOption(0x100)), line, column, 0, 0};
+ QQmlProfilerData rd = {m_timer.nsecsElapsed(), (int)RangeLocation, (int)range, fileName.toString(), line, column, 0, 0};
processMessage(rd);
}
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
index 2e351792cc..8662abb52e 100644
--- a/src/qml/debugger/qqmlprofilerservice_p.h
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -54,7 +54,7 @@
//
#include <private/qqmldebugservice_p.h>
-#include "qqmlexpression.h"
+#include <private/qqmlboundsignal_p.h>
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qmetaobject.h>
@@ -201,20 +201,20 @@ struct QQmlBindingProfiler {
};
struct QQmlHandlingSignalProfiler {
- QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlExpression *expression)
+ QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlBoundSignalExpression *expression)
{
enabled = QQmlProfilerService::instance
? QQmlProfilerService::instance->profilingEnabled() : false;
- if (enabled)
- init(signal, expression);
- }
-
- QQmlHandlingSignalProfiler(QObject *object, int index, QQmlExpression *expression)
- {
- enabled = QQmlProfilerService::instance
- ? QQmlProfilerService::instance->profilingEnabled() : false;
- if (enabled)
- init(object->metaObject()->method(index), expression);
+ if (enabled) {
+ QQmlProfilerService *service = QQmlProfilerService::instance;
+ service->startRange(QQmlProfilerService::HandlingSignal);
+ service->rangeData(QQmlProfilerService::HandlingSignal,
+ QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ")
+ + expression->expression());
+ service->rangeLocation(QQmlProfilerService::HandlingSignal,
+ expression->sourceFile(), expression->lineNumber(),
+ expression->columnNumber());
+ }
}
~QQmlHandlingSignalProfiler()
@@ -224,19 +224,6 @@ struct QQmlHandlingSignalProfiler {
}
bool enabled;
-
-private:
- void init(const QMetaMethod &signal, QQmlExpression *expression)
- {
- QQmlProfilerService *service = QQmlProfilerService::instance;
- service->startRange(QQmlProfilerService::HandlingSignal);
- service->rangeData(QQmlProfilerService::HandlingSignal,
- QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ")
- + expression->expression());
- service->rangeLocation(QQmlProfilerService::HandlingSignal,
- expression->sourceFile(), expression->lineNumber(),
- expression->columnNumber());
- }
};
struct QQmlObjectCreatingProfiler {
diff --git a/src/qml/qml/qqmlabstractexpression_p.h b/src/qml/qml/qqmlabstractexpression_p.h
index fe2ee1762b..1d5ecac08e 100644
--- a/src/qml/qml/qqmlabstractexpression_p.h
+++ b/src/qml/qml/qqmlabstractexpression_p.h
@@ -59,7 +59,7 @@
QT_BEGIN_NAMESPACE
-class QQmlAbstractExpression
+class Q_QML_PRIVATE_EXPORT QQmlAbstractExpression
{
public:
QQmlAbstractExpression();
diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h
index 8e67a58511..7558ab3e35 100644
--- a/src/qml/qml/qqmlaccessors_p.h
+++ b/src/qml/qml/qqmlaccessors_p.h
@@ -47,7 +47,7 @@
#include <QtCore/qhash.h>
#include <QtCore/QReadWriteLock>
-#ifdef Q_OS_QNX
+#if defined(Q_OS_QNX) || defined(Q_OS_LINUX)
#include <stdint.h>
#endif
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 3a3bf403e6..b77484c7e5 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -49,6 +49,7 @@
#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlglobal_p.h"
+#include "qqmlrewrite_p.h"
#include <private/qqmlprofilerservice_p.h>
#include <private/qv8debugservice_p.h>
@@ -59,6 +60,105 @@ Q_DECLARE_METATYPE(QJSValue)
QT_BEGIN_NAMESPACE
+static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = {
+ QQmlBoundSignalExpression::expressionIdentifier,
+ QQmlBoundSignalExpression::expressionChanged
+};
+
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QByteArray &expression,
+ bool isRewritten, const QString &fileName, int line, int column)
+ : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable)
+{
+ setNotifyOnValueChanged(false);
+ setContext(ctxt);
+ setScopeObject(scope);
+ m_expression = QString::fromUtf8(expression);
+ m_expressionFunctionValid = false;
+ m_expressionFunctionRewritten = isRewritten;
+ m_fileName = fileName;
+ m_line = line;
+ m_column = column;
+}
+
+QQmlBoundSignalExpression::QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QString &expression,
+ bool isRewritten, const QString &fileName, int line, int column)
+ : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable)
+{
+ setNotifyOnValueChanged(false);
+ setContext(ctxt);
+ setScopeObject(scope);
+ m_expression = expression;
+ m_expressionFunctionValid = false;
+ m_expressionFunctionRewritten = isRewritten;
+ m_fileName = fileName;
+ m_line = line;
+ m_column = column;
+}
+
+QQmlBoundSignalExpression::~QQmlBoundSignalExpression()
+{
+ qPersistentDispose(m_v8function);
+ qPersistentDispose(m_v8qmlscope);
+}
+
+QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e)
+{
+ QQmlBoundSignalExpression *This = static_cast<QQmlBoundSignalExpression *>(e);
+ return QLatin1String("\"") + This->m_expression + QLatin1String("\"");
+}
+
+void QQmlBoundSignalExpression::expressionChanged(QQmlJavaScriptExpression *)
+{
+ // bound signals do not notify on change.
+}
+
+// This mirrors code in QQmlExpressionPrivate::value() and v8value().
+// Any change made here should be made there and vice versa.
+void QQmlBoundSignalExpression::evaluate(QObject *secondaryScope)
+{
+ Q_ASSERT (context() && engine());
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine());
+
+ ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
+ {
+ v8::HandleScope handle_scope;
+ v8::Context::Scope context_scope(ep->v8engine()->context());
+ if (!m_expressionFunctionValid) {
+ bool ok = true;
+ QString code;
+ if (m_expressionFunctionRewritten) {
+ code = m_expression;
+ } else {
+ QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
+ code = rewriteSignalHandler(m_expression, m_functionName, &ok);
+ }
+
+ if (ok)
+ m_v8function = evalFunction(context(), scopeObject(), code, m_fileName, m_line, &m_v8qmlscope);
+
+ if (m_v8function.IsEmpty() || m_v8function->IsNull()) {
+ ep->dereferenceScarceResources();
+ return; // could not evaluate function. Not valid.
+ }
+
+ setUseSharedContext(false);
+ m_expressionFunctionValid = true;
+ }
+
+ if (secondaryScope) {
+ QObject *restoreSecondaryScope = 0;
+ restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, secondaryScope);
+ QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
+ ep->v8engine()->contextWrapper()->setSecondaryScope(m_v8qmlscope, restoreSecondaryScope);
+ } else {
+ QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
+ }
+ }
+ ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
+}
+
+////////////////////////////////////////////////////////////////////////
+
class QQmlBoundSignalParameters : public QObject
{
Q_OBJECT
@@ -104,10 +204,9 @@ QQmlAbstractBoundSignal::~QQmlAbstractBoundSignal()
}
}
-void QQmlAbstractBoundSignal::addToObject()
+void QQmlAbstractBoundSignal::addToObject(QObject *obj)
{
Q_ASSERT(!m_prevSignal);
- QObject *obj = object();
Q_ASSERT(obj);
QQmlData *data = QQmlData::get(obj, true);
@@ -120,13 +219,15 @@ void QQmlAbstractBoundSignal::addToObject()
QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal,
QObject *owner)
-: m_expression(0), m_signal(signal), m_paramsValid(false), m_isEvaluating(false), m_params(0), m_owner(owner)
+: m_expression(0), m_params(0), m_scope(scope), m_signal(signal), m_paramsValid(false), m_isEvaluating(false)
{
// This is thread safe. Although it may be updated by two threads, they
// will both set it to the same value - so the worst thing that can happen
// is that they both do the work to figure it out. Boo hoo.
if (evaluateIdx == -1) evaluateIdx = metaObject()->methodCount();
+ addToObject(owner);
+
QQmlPropertyPrivate::connect(scope, m_signal.methodIndex(), this, evaluateIdx);
}
@@ -144,7 +245,7 @@ int QQmlBoundSignal::index() const
/*!
Returns the signal expression.
*/
-QQmlExpression *QQmlBoundSignal::expression() const
+QQmlBoundSignalExpression *QQmlBoundSignal::expression() const
{
return m_expression;
}
@@ -156,9 +257,9 @@ QQmlExpression *QQmlBoundSignal::expression() const
The QQmlBoundSignal instance takes ownership of \a e. The caller is
assumes ownership of the returned QQmlExpression.
*/
-QQmlExpression *QQmlBoundSignal::setExpression(QQmlExpression *e)
+QQmlBoundSignalExpression *QQmlBoundSignal::setExpression(QQmlBoundSignalExpression *e)
{
- QQmlExpression *rv = m_expression;
+ QQmlBoundSignalExpression *rv = m_expression;
m_expression = e;
if (m_expression) m_expression->setNotifyOnValueChanged(false);
return rv;
@@ -183,8 +284,8 @@ int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a)
}
if (m_params) m_params->setValues(a);
- if (m_expression && m_expression->engine()) {
- QQmlExpressionPrivate::get(m_expression)->value(m_params);
+ if (m_expression && m_expression->context() && m_expression->engine()) {
+ m_expression->evaluate(m_params);
if (m_expression && m_expression->hasError())
QQmlEnginePrivate::warning(m_expression->engine(), m_expression->error());
}
@@ -247,7 +348,7 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method,
if (scope == "Qt")
meta = &QObject::staticQtMetaObject;
else
- meta = static_cast<QQmlBoundSignal*>(parent)->object()->metaObject();
+ meta = static_cast<QQmlBoundSignal*>(parent)->scope()->metaObject();
for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
QMetaEnum m = meta->enumerator(i);
if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) {
@@ -300,71 +401,6 @@ int QQmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a)
}
}
-////////////////////////////////////////////////////////////////////////
-
-QQmlBoundSignalNoParams::QQmlBoundSignalNoParams(QObject *scope, const QMetaMethod &signal,
- QObject *owner)
-: m_expression(0), m_owner(owner), m_index(signal.methodIndex()), m_isEvaluating(false)
-{
- callback = &subscriptionCallback;
- QQmlNotifierEndpoint::connect(scope, m_index);
-}
-
-QQmlBoundSignalNoParams::~QQmlBoundSignalNoParams()
-{
- delete m_expression;
- m_expression = 0;
-}
-
-int QQmlBoundSignalNoParams::index() const
-{
- return m_index;
-}
-
-/*!
- Returns the signal expression.
-*/
-QQmlExpression *QQmlBoundSignalNoParams::expression() const
-{
- return m_expression;
-}
-
-/*!
- Sets the signal expression to \a e. Returns the current signal expression,
- or null if there is no signal expression.
-
- The QQmlBoundSignalNoParams instance takes ownership of \a e. The caller is
- assumes ownership of the returned QQmlExpression.
-*/
-QQmlExpression *QQmlBoundSignalNoParams::setExpression(QQmlExpression *e)
-{
- QQmlExpression *rv = m_expression;
- m_expression = e;
- if (m_expression) m_expression->setNotifyOnValueChanged(false);
- return rv;
-}
-
-void QQmlBoundSignalNoParams::subscriptionCallback(QQmlNotifierEndpoint *e)
-{
- QQmlBoundSignalNoParams *s = static_cast<QQmlBoundSignalNoParams*>(e);
- if (!s->m_expression)
- return;
-
- if (QQmlDebugService::isDebuggingEnabled())
- QV8DebugService::instance()->signalEmitted(QString::fromAscii(s->m_owner->metaObject()->method(s->m_index).methodSignature()));
-
- QQmlHandlingSignalProfiler prof(s->m_owner, s->m_index, s->m_expression);
-
- s->m_isEvaluating = true;
-
- if (s->m_expression && s->m_expression->engine()) {
- QQmlExpressionPrivate::get(s->m_expression)->value();
- if (s->m_expression && s->m_expression->hasError())
- QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error());
- }
- s->m_isEvaluating = false;
-}
-
QT_END_NAMESPACE
#include <qqmlboundsignal.moc>
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index 5fc8c3522f..c6ce875d07 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -53,15 +53,51 @@
// We mean it.
//
-#include "qqmlexpression.h"
-
#include <QtCore/qmetaobject.h>
-#include <private/qqmlnotifier_p.h>
+#include <private/qqmlabstractexpression_p.h>
+#include <private/qqmljavascriptexpression_p.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
+class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlAbstractExpression, public QQmlJavaScriptExpression
+{
+public:
+ QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QByteArray &expression,
+ bool isRewritten, const QString &fileName, int line, int column);
+ QQmlBoundSignalExpression(QQmlContextData *ctxt, QObject *scope, const QString &expression,
+ bool isRewritten, const QString &fileName, int line, int column);
+ ~QQmlBoundSignalExpression();
+
+ // "inherited" from QQmlJavaScriptExpression.
+ static QString expressionIdentifier(QQmlJavaScriptExpression *);
+ static void expressionChanged(QQmlJavaScriptExpression *);
+
+ // evaluation of a bound signal expression doesn't return any value
+ void evaluate(QObject *secondaryScope = 0);
+
+ QString sourceFile() const { return m_fileName; }
+ int lineNumber() const { return m_line; }
+ int columnNumber() const { return m_column; }
+ QString expression() const { return m_expression; }
+
+ QQmlEngine *engine() const { return context() ? context()->engine : 0; }
+
+private:
+ v8::Persistent<v8::Object> m_v8qmlscope;
+ v8::Persistent<v8::Function> m_v8function;
+
+ QString m_expression;
+ QString m_functionName; // hint for debugger
+ QString m_fileName;
+ int m_line;
+ int m_column;
+
+ bool m_expressionFunctionValid:1;
+ bool m_expressionFunctionRewritten:1;
+};
+
class Q_QML_EXPORT QQmlAbstractBoundSignal
{
public:
@@ -69,11 +105,12 @@ public:
virtual ~QQmlAbstractBoundSignal();
virtual int index() const = 0;
- virtual QQmlExpression *expression() const = 0;
- virtual QQmlExpression *setExpression(QQmlExpression *) = 0;
- virtual QObject *object() = 0;
+ virtual QQmlBoundSignalExpression *expression() const = 0;
+ virtual QQmlBoundSignalExpression *setExpression(QQmlBoundSignalExpression *) = 0;
+ virtual QObject *scope() = 0;
- void addToObject();
+protected:
+ void addToObject(QObject *owner);
private:
friend class QQmlData;
@@ -93,9 +130,9 @@ public:
int index() const;
- QQmlExpression *expression() const;
- QQmlExpression *setExpression(QQmlExpression *);
- QObject *object() { return m_owner; }
+ QQmlBoundSignalExpression *expression() const;
+ QQmlBoundSignalExpression *setExpression(QQmlBoundSignalExpression *);
+ QObject *scope() { return m_scope; }
bool isEvaluating() const { return m_isEvaluating; }
@@ -103,39 +140,14 @@ protected:
virtual int qt_metacall(QMetaObject::Call c, int id, void **a);
private:
- QQmlExpression *m_expression;
+ QQmlBoundSignalExpression *m_expression;
+ QQmlBoundSignalParameters *m_params;
+ QObject *m_scope;
QMetaMethod m_signal;
bool m_paramsValid : 1;
bool m_isEvaluating : 1;
- QQmlBoundSignalParameters *m_params;
- QObject *m_owner;
-};
-
-class Q_QML_EXPORT QQmlBoundSignalNoParams : public QQmlAbstractBoundSignal,
- public QQmlNotifierEndpoint
-{
-public:
- QQmlBoundSignalNoParams(QObject *scope, const QMetaMethod &signal, QObject *owner);
- virtual ~QQmlBoundSignalNoParams();
-
- int index() const;
-
- QQmlExpression *expression() const;
- QQmlExpression *setExpression(QQmlExpression *);
- QObject *object() { return m_owner; }
-
- static void subscriptionCallback(QQmlNotifierEndpoint *e);
-
- bool isEvaluating() const { return m_isEvaluating; }
-
-private:
- QQmlExpression *m_expression;
- QObject *m_owner;
- int m_index;
- bool m_isEvaluating;
};
-
QT_END_NAMESPACE
#endif // QQMLBOUNDSIGNAL_P_H
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index dec9911481..54577f9b92 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -3468,6 +3468,7 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
store.value = js.compiledIndex;
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
+ store.isAlias = prop->isAlias;
if (valueTypeProperty) {
store.isRoot = (compileState->root == valueTypeProperty->parent);
} else {
@@ -3488,30 +3489,29 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
} else if (ref.dataType == BindingReference::QtScript) {
const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
- QQmlInstruction store;
- store.assignBinding.value = output->indexForString(js.rewrittenExpression);
- store.assignBinding.context = js.bindingContext.stack;
- store.assignBinding.owner = js.bindingContext.owner;
- store.assignBinding.line = binding->location.start.line;
- store.assignBinding.column = binding->location.start.column;
+ Instruction::StoreBinding store;
+ store.value = output->indexForString(js.rewrittenExpression);
+ store.context = js.bindingContext.stack;
+ store.owner = js.bindingContext.owner;
+ store.line = binding->location.start.line;
+ store.column = binding->location.start.column;
+ store.isAlias = prop->isAlias;
if (valueTypeProperty) {
- store.assignBinding.isRoot = (compileState->root == valueTypeProperty->parent);
+ store.isRoot = (compileState->root == valueTypeProperty->parent);
} else {
- store.assignBinding.isRoot = (compileState->root == obj);
+ store.isRoot = (compileState->root == obj);
}
Q_ASSERT(js.bindingContext.owner == 0 ||
(js.bindingContext.owner != 0 && valueTypeProperty));
if (js.bindingContext.owner) {
- store.assignBinding.property = genValueTypeData(prop, valueTypeProperty);
+ store.property = genValueTypeData(prop, valueTypeProperty);
} else {
- store.assignBinding.property = prop->core;
+ store.property = prop->core;
}
- output->addInstructionHelper(
- !prop->isAlias ? QQmlInstruction::StoreBinding
- : QQmlInstruction::StoreBindingOnAlias
- , store);
+
+ output->addInstruction(store);
} else {
Q_ASSERT(!"Unhandled BindingReference::DataType type");
}
@@ -3588,8 +3588,7 @@ bool QQmlCompiler::completeComponentBuild()
bool isSharable = false;
binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable);
- if (isSharable && !binding.property->isAlias /* See above re alias */ &&
- binding.property->type != qMetaTypeId<QQmlBinding*>()) {
+ if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
binding.dataType = BindingReference::V8;
sharedBindings.append(b);
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 7bddaadcd0..2e46192246 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1396,7 +1396,8 @@ void QV8IncubatorResource::statusChanged(Status s)
{
if (s == Ready) {
Q_ASSERT(QQmlData::get(object()));
- QQmlData::get(object())->setImplicitDestructible();
+ QQmlData::get(object())->explicitIndestructibleSet = false;
+ QQmlData::get(object())->indestructible = false;
}
if (!me.IsEmpty()) { // Will be false in synchronous mode
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index e7e001c4f2..3dd1c3ccba 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -181,11 +181,25 @@ public:
QQmlNotifier *objectNameNotifier() const;
QHash<int, QObject *> *attachedProperties() const;
+ static inline bool wasDeleted(QObject *);
private:
// For objectNameNotifier and attachedProperties
mutable QQmlDataExtended *extendedData;
};
+bool QQmlData::wasDeleted(QObject *object)
+{
+ if (!object)
+ return true;
+
+ QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object));
+ if (priv->wasDeleted)
+ return true;
+
+ return priv->declarativeData &&
+ static_cast<QQmlData *>(priv->declarativeData)->isQueuedForDeletion;
+}
+
QQmlNotifierEndpoint *QQmlData::notify(int index)
{
Q_ASSERT(index <= 0xFFFF);
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index df5f7f8ee9..82289311c9 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -297,16 +297,16 @@ QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const
QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component)
{
- return debug << qPrintable(QString("{%1 %2.%3}").arg(component.typeName)
- .arg(component.majorVersion)
- .arg(component.minorVersion));
+ const QString output = QString::fromLatin1("{%1 %2.%3}").
+ arg(component.typeName).arg(component.majorVersion).arg(component.minorVersion);
+ return debug << qPrintable(output);
}
QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script)
{
- return debug << qPrintable(QString("{%1 %2.%3}").arg(script.nameSpace)
- .arg(script.majorVersion)
- .arg(script.minorVersion));
+ const QString output = QString::fromLatin1("{%1 %2.%3}").
+ arg(script.nameSpace).arg(script.majorVersion).arg(script.minorVersion);
+ return debug << qPrintable(output);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 955c8ce414..153d6b325a 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -598,9 +598,17 @@ QQmlEngine::~QQmlEngine()
/*!
Clears the engine's internal component cache.
- Normally the QQmlEngine caches components loaded from qml
- files. This method clears this cache and forces the component to be
- reloaded.
+ This function causes the property metadata of all components previously
+ loaded by the engine to be destroyed. All previously loaded components and
+ the property bindings for all extant objects created from those components will
+ cease to function.
+
+ This function returns the engine to a state where it does not contain any loaded
+ component data. This may be useful in order to reload a smaller subset of the
+ previous component set, or to load a new version of a previously loaded component.
+
+ Once the component cache has been cleared, components must be loaded before
+ any new objects can be created.
*/
void QQmlEngine::clearComponentCache()
{
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index d760486605..940b3c8354 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -60,7 +60,7 @@ static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = {
QQmlExpressionPrivate::QQmlExpressionPrivate()
: QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable),
expressionFunctionValid(true), expressionFunctionRewritten(false),
- extractExpressionFromFunction(false), line(-1), dataRef(0)
+ line(-1)
{
}
@@ -68,8 +68,6 @@ QQmlExpressionPrivate::~QQmlExpressionPrivate()
{
qPersistentDispose(v8qmlscope);
qPersistentDispose(v8function);
- if (dataRef) dataRef->release();
- dataRef = 0;
}
void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QObject *me)
@@ -321,13 +319,7 @@ QQmlContext *QQmlExpression::context() const
QString QQmlExpression::expression() const
{
Q_D(const QQmlExpression);
- if (d->extractExpressionFromFunction && context()->engine()) {
- QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(context()->engine());
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(v8engine->context());
-
- return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
- } else if (!d->expressionUtf8.isEmpty()) {
+ if (!d->expressionUtf8.isEmpty()) {
return QString::fromUtf8(d->expressionUtf8);
} else {
return d->expression;
@@ -351,7 +343,7 @@ void QQmlExpression::setExpression(const QString &expression)
}
// Must be called with a valid handle scope
-v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QQmlExpressionPrivate::v8value(bool *isUndefined)
{
if (!expressionFunctionValid) {
bool ok = true;
@@ -369,21 +361,10 @@ v8::Local<v8::Value> QQmlExpressionPrivate::v8value(QObject *secondaryScope, boo
expressionFunctionValid = true;
}
-
- if (secondaryScope) {
- v8::Local<v8::Value> result;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine);
- QObject *restoreSecondaryScope = 0;
- restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
- result = evaluate(context(), v8function, isUndefined);
- ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
- return result;
- } else {
- return evaluate(context(), v8function, isUndefined);
- }
+ return evaluate(context(), v8function, isUndefined);
}
-QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
+QVariant QQmlExpressionPrivate::value(bool *isUndefined)
{
Q_Q(QQmlExpression);
@@ -400,7 +381,7 @@ QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined
{
v8::HandleScope handle_scope;
v8::Context::Scope context_scope(ep->v8engine()->context());
- v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
+ v8::Local<v8::Value> result = v8value(isUndefined);
rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
}
@@ -421,7 +402,7 @@ QVariant QQmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined
QVariant QQmlExpression::evaluate(bool *valueIsUndefined)
{
Q_D(QQmlExpression);
- return d->value(0, valueIsUndefined);
+ return d->value(valueIsUndefined);
}
/*!
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index 186e3aebf9..d32e2d314c 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -82,9 +82,9 @@ public:
void init(QQmlContextData *, const QString &, bool, QObject *, const QString &, int, int);
void init(QQmlContextData *, const QByteArray &, bool, QObject *, const QString &, int, int);
- QVariant value(QObject *secondaryScope = 0, bool *isUndefined = 0);
+ QVariant value(bool *isUndefined = 0);
- v8::Local<v8::Value> v8value(QObject *secondaryScope = 0, bool *isUndefined = 0);
+ v8::Local<v8::Value> v8value(bool *isUndefined = 0);
static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
@@ -96,7 +96,6 @@ public:
bool expressionFunctionValid:1;
bool expressionFunctionRewritten:1;
- bool extractExpressionFromFunction:1;
// "Inherited" from QQmlJavaScriptExpression
static QString expressionIdentifier(QQmlJavaScriptExpression *);
@@ -113,8 +112,6 @@ public:
int line;
int column;
QString name; //function name, hint for the debugger
-
- QQmlRefCount *dataRef;
};
QQmlExpressionPrivate *QQmlExpressionPrivate::get(QQmlExpression *expr)
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 1224efdaac..be870cad4c 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -545,27 +545,27 @@ QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork
}
}
- // TODO: Should this search be omitted if found == true?
-
- // step 2: search for extension with encoded version major
- foreach (const QString &p, database->fileImportPath) {
- dir = p+Slash+url;
+ if (!found) {
+ // step 2: search for extension with encoded version major
+ foreach (const QString &p, database->fileImportPath) {
+ dir = p+Slash+url;
- QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"));
- const QString absoluteFilePath = fi.absoluteFilePath();
+ QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"));
+ const QString absoluteFilePath = fi.absoluteFilePath();
- if (fi.isFile()) {
- found = true;
+ if (fi.isFile()) {
+ found = true;
- const QString absolutePath = fi.absolutePath();
- if (absolutePath.at(0) == QLatin1Char(':'))
- url = QLatin1String("qrc://") + absolutePath.mid(1);
- else
- url = QUrl::fromLocalFile(fi.absolutePath()).toString();
- uri = resolvedUri(dir, database);
- if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
- return QString();
- break;
+ const QString absolutePath = fi.absolutePath();
+ if (absolutePath.at(0) == QLatin1Char(':'))
+ url = QLatin1String("qrc://") + absolutePath.mid(1);
+ else
+ url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+ uri = resolvedUri(dir, database);
+ if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
+ return QString();
+ break;
+ }
}
}
diff --git a/src/qml/qml/qqmlinstruction.cpp b/src/qml/qml/qqmlinstruction.cpp
index b37117e69b..82cf235712 100644
--- a/src/qml/qml/qqmlinstruction.cpp
+++ b/src/qml/qml/qqmlinstruction.cpp
@@ -210,9 +210,6 @@ void QQmlCompiledData::dump(QQmlInstruction *instr, int idx)
case QQmlInstruction::StoreBinding:
qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
break;
- case QQmlInstruction::StoreBindingOnAlias:
- qWarning().nospace() << idx << "\t\t" << "STORE_BINDING_ALIAS\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
- break;
case QQmlInstruction::StoreV4Binding:
qWarning().nospace() << idx << "\t\t" << "STORE_COMPILED_BINDING\t" << instr->assignV4Binding.property << "\t" << instr->assignV4Binding.value << "\t" << instr->assignV4Binding.context;
break;
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index b7533aca68..cfc530df04 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -114,7 +114,6 @@ QT_BEGIN_NAMESPACE
F(BeginObject, begin) \
F(InitV8Bindings, initV8Bindings) \
F(StoreBinding, assignBinding) \
- F(StoreBindingOnAlias, assignBinding) \
F(StoreV8Binding, assignBinding) \
F(StoreV4Binding, assignV4Binding) \
F(StoreValueSource, assignValueSource) \
@@ -251,6 +250,7 @@ union QQmlInstruction
short context;
short owner;
bool isRoot;
+ bool isAlias;
ushort line;
ushort column;
};
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index f68c345f3a..075c1f6c4f 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -920,7 +920,7 @@ QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valu
Returns the expression associated with this signal property, or 0 if no
signal expression exists.
*/
-QQmlExpression *
+QQmlBoundSignalExpression *
QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
{
if (!(that.type() & QQmlProperty::SignalProperty))
@@ -948,9 +948,9 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
Ownership of \a expr transfers to QML. Ownership of the return value is
assumed by the caller.
*/
-QQmlExpression *
+QQmlBoundSignalExpression *
QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
- QQmlExpression *expr)
+ QQmlBoundSignalExpression *expr)
{
if (!(that.type() & QQmlProperty::SignalProperty)) {
delete expr;
@@ -970,13 +970,8 @@ QQmlPropertyPrivate::setSignalExpression(const QQmlProperty &that,
return signalHandler->setExpression(expr);
if (expr) {
- QQmlAbstractBoundSignal *signal = 0;
- if (that.method().parameterTypes().count())
- signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object);
- else
- signal = new QQmlBoundSignalNoParams(that.d->object, that.method(), that.d->object);
- QQmlExpression *oldExpr = signal->setExpression(expr);
- signal->addToObject();
+ QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object);
+ QQmlBoundSignalExpression *oldExpr = signal->setExpression(expr);
return oldExpr;
} else {
return 0;
@@ -1531,13 +1526,29 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
return true;
const char *valueType = 0;
- if (value.userType() == QVariant::Invalid) valueType = "null";
- else valueType = QMetaType::typeName(value.userType());
+ const char *propertyType = 0;
+
+ if (value.userType() == QMetaType::QObjectStar) {
+ if (QObject *o = *(QObject **)value.constData()) {
+ valueType = o->metaObject()->className();
+
+ if (const QMetaObject *propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type)) {
+ propertyType = propertyMetaObject->className();
+ }
+ }
+ } else if (value.userType() != QVariant::Invalid) {
+ valueType = QMetaType::typeName(value.userType());
+ }
+
+ if (!valueType)
+ valueType = "null";
+ if (!propertyType)
+ propertyType = QMetaType::typeName(type);
expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
QLatin1String(valueType) +
QLatin1String(" to ") +
- QLatin1String(QMetaType::typeName(type)));
+ QLatin1String(propertyType));
return false;
}
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index f4a9ced53b..e33c95ae41 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -64,7 +64,7 @@
QT_BEGIN_NAMESPACE
class QQmlContext;
-class QQmlExpression;
+class QQmlBoundSignalExpression;
class QQmlEnginePrivate;
class QQmlJavaScriptExpression;
class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount
@@ -140,9 +140,9 @@ public:
static QQmlAbstractBinding *setBinding(const QQmlProperty &that,
QQmlAbstractBinding *,
WriteFlags flags = DontRemoveBinding);
- static QQmlExpression *signalExpression(const QQmlProperty &that);
- static QQmlExpression *setSignalExpression(const QQmlProperty &that,
- QQmlExpression *) ;
+ static QQmlBoundSignalExpression *signalExpression(const QQmlProperty &that);
+ static QQmlBoundSignalExpression *setSignalExpression(const QQmlProperty &that,
+ QQmlBoundSignalExpression *) ;
static bool write(const QQmlProperty &that, const QVariant &, WriteFlags);
static bool writeBinding(QObject *, const QQmlPropertyData &,
QQmlContextData *context,
diff --git a/src/qml/qml/qqmlrewrite.cpp b/src/qml/qml/qqmlrewrite.cpp
index 72bd23955b..bbb17b631d 100644
--- a/src/qml/qml/qqmlrewrite.cpp
+++ b/src/qml/qml/qqmlrewrite.cpp
@@ -51,6 +51,8 @@ DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP);
namespace QQmlRewrite {
+QString SharedBindingTester::evalString("eval");
+
static void rewriteStringLiteral(AST::StringLiteral *ast, const QString *code, int startPosition, TextWriter *writer)
{
const unsigned position = ast->firstSourceLocation().begin() - startPosition + 1;
@@ -419,6 +421,21 @@ QString RewriteSignalHandler::operator()(QQmlJS::AST::Node *node, const QString
return rewritten;
}
+QString RewriteSignalHandler::operator()(const QString &code, const QString &name, bool *ok)
+{
+ Engine engine;
+ Lexer lexer(&engine);
+ Parser parser(&engine);
+ lexer.setCode(code, 0);
+ parser.parseStatement();
+ if (!parser.statement()) {
+ if (ok) *ok = false;
+ return QString();
+ }
+ if (ok) *ok = true;
+ return operator()(parser.statement(), code, name);
+}
+
} // namespace QQmlRewrite
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlrewrite_p.h b/src/qml/qml/qqmlrewrite_p.h
index 1d69839878..efa10ce316 100644
--- a/src/qml/qml/qqmlrewrite_p.h
+++ b/src/qml/qml/qqmlrewrite_p.h
@@ -70,9 +70,11 @@ public:
bool isSharable(const QString &code);
bool isSharable(AST::Node *Node);
- virtual bool visit(AST::FunctionDeclaration *) { _sharable = false; return false; }
- virtual bool visit(AST::FunctionExpression *) { _sharable = false; return false; }
- virtual bool visit(AST::CallExpression *) { _sharable = false; return false; }
+ inline virtual bool visit(AST::FunctionDeclaration *);
+ inline virtual bool visit(AST::FunctionExpression *);
+ inline virtual bool visit(AST::IdentifierExpression *);
+
+ static QString evalString;
};
class RewriteBinding: protected AST::Visitor
@@ -133,6 +135,7 @@ class RewriteSignalHandler: protected AST::Visitor
public:
RewriteSignalHandler();
QString operator()(QQmlJS::AST::Node *node, const QString &code, const QString &name);
+ QString operator()(const QString &code, const QString &name, bool *ok = 0);
protected:
void rewriteMultilineStrings(QString &code);
@@ -142,6 +145,26 @@ protected:
virtual bool visit(AST::StringLiteral *ast);
};
+bool SharedBindingTester::visit(AST::FunctionDeclaration *)
+{
+ _sharable = false;
+ return false;
+}
+
+bool SharedBindingTester::visit(AST::FunctionExpression *)
+{
+ _sharable = false;
+ return false;
+}
+
+bool SharedBindingTester::visit(AST::IdentifierExpression *e)
+{
+ if (e->name == evalString)
+ _sharable = false;
+
+ return false; // IdentifierExpression is a leaf node anyway
+}
+
} // namespace QQmlRewrite
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
index e1925eb238..37c0fb44a4 100644
--- a/src/qml/qml/qqmlscript.cpp
+++ b/src/qml/qml/qqmlscript.cpp
@@ -66,6 +66,11 @@ QQmlScript::Object::Object()
: type(-1), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), parserStatusCast(-1),
componentCompileState(0), nextAliasingObject(0), nextIdObject(0)
{
+ // initialize the members in the meta object
+ extObject.d.superdata = 0;
+ extObject.d.stringdata = 0;
+ extObject.d.data = 0;
+ extObject.d.extradata = 0;
}
QQmlScript::Object::~Object()
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 5412315d31..985d291a8e 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -204,13 +204,19 @@ inline bool fastHasBinding(QObject *o, int index)
{
QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(o)->declarativeData);
+ index &= 0xFFFFFF; // To handle value types
+
return ddata && (ddata->bindingBitsSize > index) &&
(ddata->bindingBits[index / 32] & (1 << (index % 32)));
}
static void removeBindingOnProperty(QObject *o, int index)
{
- QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, index, -1, 0);
+ int coreIndex = index & 0xFFFFFF;
+ int valueTypeIndex = index & 0xFF000000;
+ if (!valueTypeIndex) valueTypeIndex = -1;
+
+ QQmlAbstractBinding *binding = QQmlPropertyPrivate::setBinding(o, coreIndex, valueTypeIndex, 0);
if (binding) binding->destroy();
}
@@ -724,15 +730,10 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QMetaMethod signal = target->metaObject()->method(instr.signalIndex);
- QQmlAbstractBoundSignal *bs = 0;
- if (signal.parameterTypes().count())
- bs = new QQmlBoundSignal(target, signal, target);
- else
- bs = new QQmlBoundSignalNoParams(target, signal, target);
- QQmlExpression *expr =
- new QQmlExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column, *new QQmlExpressionPrivate);
+ QQmlBoundSignal *bs = new QQmlBoundSignal(target, signal, target);
+ QQmlBoundSignalExpression *expr =
+ new QQmlBoundSignalExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column);
bs->setExpression(expr);
- bs->addToObject();
QML_END_INSTR(StoreSignal)
QML_BEGIN_INSTR(StoreImportedScript)
@@ -788,35 +789,23 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
bind->m_mePtr = &bindValues.top();
bind->setTarget(target, instr.property, CTXT);
- typedef QQmlPropertyPrivate QDPP;
- Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property));
- Q_ASSERT(bind->object() == target);
-
- bind->addToObject();
- QML_END_INSTR(StoreBinding)
-
- QML_BEGIN_INSTR(StoreBindingOnAlias)
- QObject *target =
- objects.at(objects.count() - 1 - instr.owner);
- QObject *context =
- objects.at(objects.count() - 1 - instr.context);
+ if (instr.isAlias) {
+ QQmlAbstractBinding *old =
+ QQmlPropertyPrivate::setBindingNoEnable(target,
+ instr.property.coreIndex,
+ instr.property.getValueTypeCoreIndex(),
+ bind);
+ if (old) { old->destroy(); }
+ } else {
+ typedef QQmlPropertyPrivate QDPP;
+ Q_ASSERT(bind->propertyIndex() == QDPP::bindingIndex(instr.property));
+ Q_ASSERT(bind->object() == target);
- if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
- QML_NEXT_INSTR(StoreBindingOnAlias);
+ CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property));
- QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
- context, CTXT, COMP->name, instr.line,
- instr.column);
- bindValues.push(bind);
- bind->m_mePtr = &bindValues.top();
- bind->setTarget(target, instr.property, CTXT);
-
- QQmlAbstractBinding *old =
- QQmlPropertyPrivate::setBindingNoEnable(target, instr.property.coreIndex,
- instr.property.getValueTypeCoreIndex(),
- bind);
- if (old) { old->destroy(); }
- QML_END_INSTR(StoreBindingOnAlias)
+ bind->addToObject();
+ }
+ QML_END_INSTR(StoreBinding)
QML_BEGIN_INSTR(StoreV4Binding)
QObject *target =
@@ -837,6 +826,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
Q_ASSERT(binding->propertyIndex() == (property & 0xFF00FFFF));
Q_ASSERT(binding->object() == target);
+ CLEAN_PROPERTY(target, property & 0xFF00FFFF);
+
binding->addToObject();
QML_END_INSTR(StoreV4Binding)
@@ -855,11 +846,22 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
bindValues.push(binding);
binding->m_mePtr = &bindValues.top();
- typedef QQmlPropertyPrivate QDPP;
- Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property));
- Q_ASSERT(binding->object() == target);
+ if (instr.isAlias) {
+ QQmlAbstractBinding *old =
+ QQmlPropertyPrivate::setBindingNoEnable(target,
+ instr.property.coreIndex,
+ instr.property.getValueTypeCoreIndex(),
+ binding);
+ if (old) { old->destroy(); }
+ } else {
+ typedef QQmlPropertyPrivate QDPP;
+ Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property));
+ Q_ASSERT(binding->object() == target);
+
+ CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property));
- binding->addToObject();
+ binding->addToObject();
+ }
}
QML_END_INSTR(StoreV8Binding)
@@ -1242,9 +1244,9 @@ QQmlContextData *QQmlVME::complete(const Interrupt &interrupt)
while (!bindValues.isEmpty()) {
QQmlAbstractBinding *b = bindValues.pop();
- if(b) {
+ if (b) {
b->m_mePtr = 0;
- b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
+ b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
QQmlPropertyPrivate::DontRemoveBinding);
}
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
index 0cd6ffd082..4c92598c32 100644
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ b/src/qml/qml/v4/qv4bindings.cpp
@@ -52,6 +52,7 @@
#include <private/qqmlmetatype_p.h>
#include <private/qqmltrace_p.h>
#include <private/qqmlstringconverters_p.h>
+#include <private/qqmlproperty_p.h>
#include <QtQml/qqmlinfo.h>
#include <QtCore/qnumeric.h>
@@ -66,46 +67,53 @@ namespace {
struct Register {
typedef QQmlRegisterType Type;
- void setUndefined() { dataType = UndefinedType; }
- void setNull() { dataType = NullType; }
- void setNaN() { setqreal(qSNaN()); }
- bool isUndefined() const { return dataType == UndefinedType; }
+ inline void setUndefined() { dataType = UndefinedType; }
+ inline void setNull() { dataType = NullType; }
+ inline void setNaN() { setnumber(qSNaN()); }
+ inline bool isUndefined() const { return dataType == UndefinedType; }
- void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
- QObject *getQObject() const { return qobjectValue; }
+ inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
+ inline QObject *getQObject() const { return qobjectValue; }
- void setqreal(qreal v) { qrealValue = v; dataType = QRealType; }
- qreal getqreal() const { return qrealValue; }
- qreal &getqrealref() { return qrealValue; }
+ inline void setnumber(double v) { numberValue = v; dataType = NumberType; }
+ inline double getnumber() const { return numberValue; }
+ inline double &getnumberref() { return numberValue; }
- void setint(int v) { intValue = v; dataType = IntType; }
- int getint() const { return intValue; }
- int &getintref() { return intValue; }
+ inline void setfloat(float v) { floatValue = v; dataType = FloatType; }
+ inline float getfloat() const { return floatValue; }
+ inline float &getfloatref() { return floatValue; }
- void setbool(bool v) { boolValue = v; dataType = BoolType; }
- bool getbool() const { return boolValue; }
- bool &getboolref() { return boolValue; }
+ inline void setint(int v) { intValue = v; dataType = IntType; }
+ inline int getint() const { return intValue; }
+ inline int &getintref() { return intValue; }
- QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
- QString *getstringptr() { return (QString *)typeDataPtr(); }
- QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
- const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
- const QString *getstringptr() const { return (QString *)typeDataPtr(); }
- const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
+ inline void setbool(bool v) { boolValue = v; dataType = BoolType; }
+ inline bool getbool() const { return boolValue; }
+ inline bool &getboolref() { return boolValue; }
+
+ inline QVariant *getvariantptr() { return (QVariant *)typeDataPtr(); }
+ inline QString *getstringptr() { return (QString *)typeDataPtr(); }
+ inline QUrl *geturlptr() { return (QUrl *)typeDataPtr(); }
+ inline QColor *getcolorptr() { return (QColor *)typeDataPtr(); }
+ inline const QVariant *getvariantptr() const { return (QVariant *)typeDataPtr(); }
+ inline const QString *getstringptr() const { return (QString *)typeDataPtr(); }
+ inline const QUrl *geturlptr() const { return (QUrl *)typeDataPtr(); }
+ inline const QColor *getcolorptr() const { return (QColor *)typeDataPtr(); }
size_t dataSize() { return sizeof(data); }
- void *typeDataPtr() { return (void *)&data; }
- void *typeMemory() { return (void *)data; }
- const void *typeDataPtr() const { return (void *)&data; }
- const void *typeMemory() const { return (void *)data; }
+ inline void *typeDataPtr() { return (void *)&data; }
+ inline void *typeMemory() { return (void *)data; }
+ inline const void *typeDataPtr() const { return (void *)&data; }
+ inline const void *typeMemory() const { return (void *)data; }
- Type gettype() const { return dataType; }
- void settype(Type t) { dataType = t; }
+ inline Type gettype() const { return dataType; }
+ inline void settype(Type t) { dataType = t; }
Type dataType; // Type of data
union {
QObject *qobjectValue;
- qreal qrealValue;
+ double numberValue;
+ float floatValue;
int intValue;
bool boolValue;
void *data[sizeof(QVariant)];
@@ -387,85 +395,6 @@ void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex)
sub->disconnect();
}
-// Conversion functions - these MUST match the QtScript expression path
-inline static qreal toReal(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::QReal) {
- return reg->getqreal();
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toReal();
- } else {
- if (ok) *ok = false;
- return 0;
- }
-}
-
-inline static QString toString(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::QReal) {
- return QString::number(reg->getqreal());
- } else if (type == QMetaType::Int) {
- return QString::number(reg->getint());
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toString();
- } else if (type == QMetaType::QString) {
- return *reg->getstringptr();
- } else {
- if (ok) *ok = false;
- return QString();
- }
-}
-
-inline static bool toBool(Register *reg, int type, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- if (type == QMetaType::Bool) {
- return reg->getbool();
- } else if (type == qMetaTypeId<QVariant>()) {
- return reg->getvariantptr()->toBool();
- } else {
- if (ok) *ok = false;
- return false;
- }
-}
-
-inline static QUrl toUrl(Register *reg, int type, QQmlContextData *context, bool *ok = 0)
-{
- if (ok) *ok = true;
-
- QUrl base;
- if (type == qMetaTypeId<QVariant>()) {
- QVariant *var = reg->getvariantptr();
- int vt = var->type();
- if (vt == QVariant::Url) {
- base = var->toUrl();
- } else if (vt == QVariant::ByteArray) {
- // Preserve any valid percent-encoded octets supplied by the source
- base.setEncodedUrl(var->toByteArray(), QUrl::TolerantMode);
- } else if (vt == QVariant::String) {
- base.setEncodedUrl(var->toString().toUtf8(), QUrl::TolerantMode);
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
- } else if (type == QMetaType::QString) {
- base.setEncodedUrl(reg->getstringptr()->toUtf8(), QUrl::TolerantMode);
- } else {
- if (ok) *ok = false;
- return QUrl();
- }
-
- if (!base.isEmpty() && base.isRelative())
- return context->url.resolved(base);
- else
- return base;
-}
-
static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
{
QVariant qtscript = qtscriptRaw;
@@ -529,10 +458,29 @@ static void testBindingResult(const QString &binding, int line, int column,
if (expression.hasError()) {
iserror = true;
qtscriptResult = "exception";
- } else {
- qtscriptResult = testResultToString(value, isUndefined);
+ } else if (value.userType() != resultType) {
+ // Override the QMetaType conversions to make them more JS friendly.
+ if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString ||
+ resultType == QMetaType::QUrl)) {
+ // number to string-like conversion.
+ value = QVariant::fromValue<QString>(QString::number(value.toDouble(), 'g', 16));
+ } else if (value.userType() == QMetaType::QUrl && resultType == QMetaType::Bool) {
+ // url to bool conversion
+ value = QVariant::fromValue<bool>(!value.toUrl().isEmpty());
+ }
+
+ if (!value.isNull() && !value.convert(resultType)) {
+ iserror = true;
+ qtscriptResult = "exception";
+ } else if (resultType == QMetaType::QUrl) {
+ // a V8 value was converted to QUrl.
+ value = QVariant::fromValue<QUrl>(context->resolvedUrl(value.toUrl()));
+ }
}
+ if (! iserror)
+ qtscriptResult = testResultToString(value, isUndefined);
+
if (isUndefined && result.isUndefined()) {
return;
} else if(isUndefined != result.isUndefined()) {
@@ -557,8 +505,8 @@ static void testBindingResult(const QString &binding, int line, int column,
case QMetaType::Int:
v4value = result.getint();
break;
- case QMetaType::QReal:
- v4value = result.getqreal();
+ case QMetaType::Double:
+ v4value = result.getnumber();
break;
default:
if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
@@ -621,15 +569,15 @@ static void throwException(int id, QQmlDelayedError *error,
QQmlEnginePrivate::warning(context->engine, error->error);
}
-const qreal QV4Bindings::D32 = 4294967296.0;
+const double QV4Bindings::D32 = 4294967296.0;
-qint32 QV4Bindings::toInt32(qreal n)
+qint32 QV4Bindings::toInt32(double n)
{
if (qIsNaN(n) || qIsInf(n) || (n == 0))
return 0;
double sign = (n < 0) ? -1.0 : 1.0;
- qreal abs_n = fabs(n);
+ double abs_n = fabs(n);
n = ::fmod(sign * ::floor(abs_n), D32);
const double D31 = D32 / 2.0;
@@ -643,13 +591,13 @@ qint32 QV4Bindings::toInt32(qreal n)
return qint32 (n);
}
-inline quint32 QV4Bindings::toUint32(qreal n)
+inline quint32 QV4Bindings::toUint32(double n)
{
if (qIsNaN(n) || qIsInf(n) || (n == 0))
return 0;
double sign = (n < 0) ? -1.0 : 1.0;
- qreal abs_n = fabs(n);
+ double abs_n = fabs(n);
n = ::fmod(sign * ::floor(abs_n), D32);
@@ -665,6 +613,11 @@ inline quint32 QV4Bindings::toUint32(qreal n)
goto exceptionExit; \
}
+#define THROW_VALUE_EXCEPTION_STR(id, str) { \
+ throwException((id), error, program, context, (str)); \
+ goto exceptionExit; \
+}
+
#define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
#define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
@@ -791,13 +744,21 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
sub->bindings = this;
sub->method = subIdx;
}
- reg.init((Register::Type)instr->fetchAndSubscribe.valueType);
+
+ const Register::Type valueType = (Register::Type)instr->fetchAndSubscribe.valueType;
+ reg.init(valueType);
if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
MARK_REGISTER(instr->fetchAndSubscribe.reg);
QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
reg.typeDataPtr());
+ if (valueType == FloatType) {
+ // promote floats
+ const double v = reg.getfloat();
+ reg.setnumber(v);
+ }
+
if (accessors->notifier) {
QQmlNotifier *notifier = 0;
accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, &notifier);
@@ -868,11 +829,11 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(UnaryNot, unaryop)
- QML_V4_BEGIN_INSTR(UnaryMinusReal, unaryop)
+ QML_V4_BEGIN_INSTR(UnaryMinusNumber, unaryop)
{
- registers[instr->unaryop.output].setqreal(-registers[instr->unaryop.src].getqreal());
+ registers[instr->unaryop.output].setnumber(-registers[instr->unaryop.src].getnumber());
}
- QML_V4_END_INSTR(UnaryMinusReal, unaryop)
+ QML_V4_END_INSTR(UnaryMinusNumber, unaryop)
QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
{
@@ -880,11 +841,11 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(UnaryMinusInt, unaryop)
- QML_V4_BEGIN_INSTR(UnaryPlusReal, unaryop)
+ QML_V4_BEGIN_INSTR(UnaryPlusNumber, unaryop)
{
- registers[instr->unaryop.output].setqreal(+registers[instr->unaryop.src].getqreal());
+ registers[instr->unaryop.output].setnumber(+registers[instr->unaryop.src].getnumber());
}
- QML_V4_END_INSTR(UnaryPlusReal, unaryop)
+ QML_V4_END_INSTR(UnaryPlusNumber, unaryop)
QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
{
@@ -901,14 +862,14 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
- QML_V4_BEGIN_INSTR(ConvertBoolToReal, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setqreal(src.getbool());
+ else output.setnumber(src.getbool());
}
- QML_V4_END_INSTR(ConvertBoolToReal, unaryop)
+ QML_V4_END_INSTR(ConvertBoolToNumber, unaryop)
QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
{
@@ -932,14 +893,14 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertIntToBool, unaryop)
- QML_V4_BEGIN_INSTR(ConvertIntToReal, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setqreal(qreal(src.getint()));
+ else output.setnumber(double(src.getint()));
}
- QML_V4_END_INSTR(ConvertIntToReal, unaryop)
+ QML_V4_END_INSTR(ConvertIntToNumber, unaryop)
QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
{
@@ -954,25 +915,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertIntToString, unaryop)
- QML_V4_BEGIN_INSTR(ConvertRealToBool, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setbool(src.getqreal() != 0);
+ else output.setbool(src.getnumber() != 0);
}
- QML_V4_END_INSTR(ConvertRealToBool, unaryop)
+ QML_V4_END_INSTR(ConvertNumberToBool, unaryop)
- QML_V4_BEGIN_INSTR(ConvertRealToInt, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertNumberToInt, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setint(toInt32(src.getqreal()));
+ else output.setint(toInt32(src.getnumber()));
}
- QML_V4_END_INSTR(ConvertRealToInt, unaryop)
+ QML_V4_END_INSTR(ConvertNumberToInt, unaryop)
- QML_V4_BEGIN_INSTR(ConvertRealToString, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
@@ -980,11 +941,11 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
if (src.isUndefined()) {
output.setUndefined();
} else {
- new (output.getstringptr()) QString(QString::number(src.getqreal()));
+ new (output.getstringptr()) QString(QString::number(src.getnumber(), 'g', 16));
STRING_REGISTER(instr->unaryop.output);
}
}
- QML_V4_END_INSTR(ConvertRealToString, unaryop)
+ QML_V4_END_INSTR(ConvertNumberToString, unaryop)
QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
{
@@ -1026,7 +987,7 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ConvertStringToInt, unaryop)
- QML_V4_BEGIN_INSTR(ConvertStringToReal, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
@@ -1041,10 +1002,10 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
output.cleanupString();
MARK_CLEAN_REGISTER(instr->unaryop.output);
}
- output.setqreal(tmp.toNumber());
+ output.setnumber(tmp.toNumber());
}
}
- QML_V4_END_INSTR(ConvertStringToReal, unaryop)
+ QML_V4_END_INSTR(ConvertStringToNumber, unaryop)
QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
{
@@ -1190,75 +1151,75 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(ResolveUrl, unaryop)
- QML_V4_BEGIN_INSTR(MathSinReal, unaryop)
+ QML_V4_BEGIN_INSTR(MathSinNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setqreal(qSin(src.getqreal()));
+ else output.setnumber(qSin(src.getnumber()));
}
- QML_V4_END_INSTR(MathSinReal, unaryop)
+ QML_V4_END_INSTR(MathSinNumber, unaryop)
- QML_V4_BEGIN_INSTR(MathCosReal, unaryop)
+ QML_V4_BEGIN_INSTR(MathCosNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setqreal(qCos(src.getqreal()));
+ else output.setnumber(qCos(src.getnumber()));
}
- QML_V4_END_INSTR(MathCosReal, unaryop)
+ QML_V4_END_INSTR(MathCosNumber, unaryop)
- QML_V4_BEGIN_INSTR(MathAbsReal, unaryop)
+ QML_V4_BEGIN_INSTR(MathAbsNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setqreal(qAbs(src.getqreal()));
+ else output.setnumber(qAbs(src.getnumber()));
}
- QML_V4_END_INSTR(MathAbsReal, unaryop)
+ QML_V4_END_INSTR(MathAbsNumber, unaryop)
- QML_V4_BEGIN_INSTR(MathRoundReal, unaryop)
+ QML_V4_BEGIN_INSTR(MathRoundNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setint(qRound(src.getqreal()));
+ else output.setint(qRound(src.getnumber()));
}
- QML_V4_END_INSTR(MathRoundReal, unaryop)
+ QML_V4_END_INSTR(MathRoundNumber, unaryop)
- QML_V4_BEGIN_INSTR(MathFloorReal, unaryop)
+ QML_V4_BEGIN_INSTR(MathFloorNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setint(qFloor(src.getqreal()));
+ else output.setint(qFloor(src.getnumber()));
}
- QML_V4_END_INSTR(MathFloorReal, unaryop)
+ QML_V4_END_INSTR(MathFloorNumber, unaryop)
- QML_V4_BEGIN_INSTR(MathCeilReal, unaryop)
+ QML_V4_BEGIN_INSTR(MathCeilNumber, unaryop)
{
const Register &src = registers[instr->unaryop.src];
Register &output = registers[instr->unaryop.output];
if (src.isUndefined()) output.setUndefined();
- else output.setint(qCeil(src.getqreal()));
+ else output.setint(qCeil(src.getnumber()));
}
- QML_V4_END_INSTR(MathCeilReal, unaryop)
+ QML_V4_END_INSTR(MathCeilNumber, unaryop)
- QML_V4_BEGIN_INSTR(MathPIReal, unaryop)
+ QML_V4_BEGIN_INSTR(MathPINumber, unaryop)
{
- static const qreal qmlPI = 2.0 * qAsin(1.0);
+ static const double qmlPI = 2.0 * qAsin(1.0);
Register &output = registers[instr->unaryop.output];
- output.setqreal(qmlPI);
+ output.setnumber(qmlPI);
}
- QML_V4_END_INSTR(MathPIReal, unaryop)
+ QML_V4_END_INSTR(MathPINumber, unaryop)
QML_V4_BEGIN_INSTR(LoadNull, null_value)
registers[instr->null_value.reg].setNull();
QML_V4_END_INSTR(LoadNull, null_value)
- QML_V4_BEGIN_INSTR(LoadReal, real_value)
- registers[instr->real_value.reg].setqreal(instr->real_value.value);
- QML_V4_END_INSTR(LoadReal, real_value)
+ QML_V4_BEGIN_INSTR(LoadNumber, number_value)
+ registers[instr->number_value.reg].setnumber(instr->number_value.value);
+ QML_V4_END_INSTR(LoadNumber, number_value)
QML_V4_BEGIN_INSTR(LoadInt, int_value)
registers[instr->int_value.reg].setint(instr->int_value.value);
@@ -1305,12 +1266,12 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(BitXorInt, binaryop)
- QML_V4_BEGIN_INSTR(AddReal, binaryop)
+ QML_V4_BEGIN_INSTR(AddNumber, binaryop)
{
- registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() +
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() +
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(AddReal, binaryop)
+ QML_V4_END_INSTR(AddNumber, binaryop)
QML_V4_BEGIN_INSTR(AddString, binaryop)
{
@@ -1324,36 +1285,33 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(AddString, binaryop)
- QML_V4_BEGIN_INSTR(SubReal, binaryop)
+ QML_V4_BEGIN_INSTR(SubNumber, binaryop)
{
- registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() -
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() -
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(SubReal, binaryop)
+ QML_V4_END_INSTR(SubNumber, binaryop)
- QML_V4_BEGIN_INSTR(MulReal, binaryop)
+ QML_V4_BEGIN_INSTR(MulNumber, binaryop)
{
- registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() *
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() *
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(MulReal, binaryop)
+ QML_V4_END_INSTR(MulNumber, binaryop)
- QML_V4_BEGIN_INSTR(DivReal, binaryop)
+ QML_V4_BEGIN_INSTR(DivNumber, binaryop)
{
- registers[instr->binaryop.output].setqreal(registers[instr->binaryop.left].getqreal() /
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() /
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(DivReal, binaryop)
+ QML_V4_END_INSTR(DivNumber, binaryop)
- QML_V4_BEGIN_INSTR(ModReal, binaryop)
+ QML_V4_BEGIN_INSTR(ModNumber, binaryop)
{
Register &target = registers[instr->binaryop.output];
const Register &left = registers[instr->binaryop.left];
const Register &right = registers[instr->binaryop.right];
- if (QMetaType::QReal == QMetaType::Float)
- target.setqreal(::fmodf(left.getqreal(), right.getqreal()));
- else
- target.setqreal(::fmod(left.getqreal(), right.getqreal()));
+ target.setnumber(::fmod(left.getnumber(), right.getnumber()));
}
QML_V4_END_INSTR(ModInt, binaryop)
@@ -1378,61 +1336,61 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(URShiftInt, binaryop)
- QML_V4_BEGIN_INSTR(GtReal, binaryop)
+ QML_V4_BEGIN_INSTR(GtNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(GtReal, binaryop)
+ QML_V4_END_INSTR(GtNumber, binaryop)
- QML_V4_BEGIN_INSTR(LtReal, binaryop)
+ QML_V4_BEGIN_INSTR(LtNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(LtReal, binaryop)
+ QML_V4_END_INSTR(LtNumber, binaryop)
- QML_V4_BEGIN_INSTR(GeReal, binaryop)
+ QML_V4_BEGIN_INSTR(GeNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() >=
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >=
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(GeReal, binaryop)
+ QML_V4_END_INSTR(GeNumber, binaryop)
- QML_V4_BEGIN_INSTR(LeReal, binaryop)
+ QML_V4_BEGIN_INSTR(LeNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() <=
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <=
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(LeReal, binaryop)
+ QML_V4_END_INSTR(LeNumber, binaryop)
- QML_V4_BEGIN_INSTR(EqualReal, binaryop)
+ QML_V4_BEGIN_INSTR(EqualNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(EqualReal, binaryop)
+ QML_V4_END_INSTR(EqualNumber, binaryop)
- QML_V4_BEGIN_INSTR(NotEqualReal, binaryop)
+ QML_V4_BEGIN_INSTR(NotEqualNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(NotEqualReal, binaryop)
+ QML_V4_END_INSTR(NotEqualNumber, binaryop)
- QML_V4_BEGIN_INSTR(StrictEqualReal, binaryop)
+ QML_V4_BEGIN_INSTR(StrictEqualNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() ==
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(StrictEqualReal, binaryop)
+ QML_V4_END_INSTR(StrictEqualNumber, binaryop)
- QML_V4_BEGIN_INSTR(StrictNotEqualReal, binaryop)
+ QML_V4_BEGIN_INSTR(StrictNotEqualNumber, binaryop)
{
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getqreal() !=
- registers[instr->binaryop.right].getqreal());
+ registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
+ registers[instr->binaryop.right].getnumber());
}
- QML_V4_END_INSTR(StrictNotEqualReal, binaryop)
+ QML_V4_END_INSTR(StrictNotEqualNumber, binaryop)
QML_V4_BEGIN_INSTR(GtString, binaryop)
{
@@ -1578,25 +1536,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
}
QML_V4_END_INSTR(StrictNotEqualObject, binaryop)
- QML_V4_BEGIN_INSTR(MathMaxReal, binaryop)
+ QML_V4_BEGIN_INSTR(MathMaxNumber, binaryop)
{
const Register &left = registers[instr->binaryop.left];
const Register &right = registers[instr->binaryop.right];
Register &output = registers[instr->binaryop.output];
if (left.isUndefined() || right.isUndefined()) output.setUndefined();
- else output.setqreal(qMax(left.getqreal(), right.getqreal()));
+ else output.setnumber(qMax(left.getnumber(), right.getnumber()));
}
- QML_V4_END_INSTR(MathMaxReal, binaryop)
+ QML_V4_END_INSTR(MathMaxNumber, binaryop)
- QML_V4_BEGIN_INSTR(MathMinReal, binaryop)
+ QML_V4_BEGIN_INSTR(MathMinNumber, binaryop)
{
const Register &left = registers[instr->binaryop.left];
const Register &right = registers[instr->binaryop.right];
Register &output = registers[instr->binaryop.output];
if (left.isUndefined() || right.isUndefined()) output.setUndefined();
- else output.setqreal(qMin(left.getqreal(), right.getqreal()));
+ else output.setnumber(qMin(left.getnumber(), right.getnumber()));
}
- QML_V4_END_INSTR(MathMinReal, binaryop)
+ QML_V4_END_INSTR(MathMinNumber, binaryop)
QML_V4_BEGIN_INSTR(NewString, construct)
{
@@ -1625,11 +1583,17 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
if (!object) {
THROW_EXCEPTION(instr->fetch.exceptionId);
} else {
- reg.init((Register::Type)instr->fetch.valueType);
+ const Register::Type valueType = (Register::Type)instr->fetch.valueType;
+ reg.init(valueType);
if (instr->fetch.valueType >= FirstCleanupType)
MARK_REGISTER(instr->fetch.reg);
void *argv[] = { reg.typeDataPtr(), 0 };
QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
+ if (valueType == FloatType) {
+ // promote floats
+ const double v = reg.getfloat();
+ reg.setnumber(v);
+ }
}
}
QML_V4_END_INSTR(Fetch, fetch)
@@ -1649,6 +1613,30 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
if (data.isUndefined())
THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
+ if (data.gettype() == QObjectStarType) {
+ if (QObject *dataObject = data.getQObject()) {
+ const QMetaObject *dataMo = dataObject->metaObject();
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
+ QMetaProperty receiver = output->metaObject()->property(instr->store.index);
+ const QMetaObject *receiverMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, receiver.userType());
+
+ // Verify that these types are compatible
+ if (!QQmlPropertyPrivate::canConvert(dataMo, receiverMo)) {
+ THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") +
+ QLatin1String(dataMo->className()) +
+ QLatin1String(" to ") +
+ QLatin1String(receiverMo->className()));
+ }
+ }
+ }
+
+ if (instr->store.valueType == FloatType) {
+ // cast numbers to floats
+ const float v = (float) data.getnumber();
+ data.setfloat(v);
+ }
+
int status = -1;
void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
QMetaObject::metacall(output, QMetaObject::WriteProperty,
@@ -1687,22 +1675,14 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
executedBlocks |= instr->blockop.block;
QML_V4_END_INSTR(Block, blockop)
- // XXX not applicable in v8
- QML_V4_BEGIN_INSTR(InitString, initstring)
-// if (!identifiers[instr->initstring.offset].identifier) {
-// quint32 len = *(quint32 *)(data + instr->initstring.dataIdx);
-// QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32));
-
-// QString str = QString::fromRawData(strdata, len);
-
-// // identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str);
-// }
- QML_V4_END_INSTR(InitString, initstring)
-
QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
registers[instr->cleanup.reg].cleanup();
QML_V4_END_INSTR(CleanupRegister, cleanup)
+ QML_V4_BEGIN_INSTR(Throw, throwop)
+ THROW_VALUE_EXCEPTION_STR(instr->throwop.exceptionId, *registers[instr->throwop.message].getstringptr());
+ QML_V4_END_INSTR(Throw, throwop)
+
#ifdef QML_THREADED_INTERPRETER
// nothing to do
#else
diff --git a/src/qml/qml/v4/qv4bindings_p.h b/src/qml/qml/v4/qv4bindings_p.h
index 1824fa4ee9..3a7d175d7b 100644
--- a/src/qml/qml/v4/qv4bindings_p.h
+++ b/src/qml/qml/v4/qv4bindings_p.h
@@ -141,9 +141,9 @@ private:
inline void subscribeId(QQmlContextData *p, int idIndex, int subIndex);
inline void subscribe(QObject *o, int notifyIndex, int subIndex);
- inline static qint32 toInt32(qreal n);
- static const qreal D32;
- static quint32 toUint32(qreal n);
+ inline static qint32 toInt32(double n);
+ static const double D32;
+ static quint32 toUint32(double n);
};
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
index c9495e8987..045a14fbb5 100644
--- a/src/qml/qml/v4/qv4compiler.cpp
+++ b/src/qml/qml/v4/qv4compiler.cpp
@@ -62,7 +62,9 @@ static bool qmlEnableV4 = true;
using namespace QQmlJS;
QV4CompilerPrivate::QV4CompilerPrivate()
- : _function(0) , _block(0) , _discarded(false), registerCount(0)
+ : subscriptionOffset(0)
+ , _function(0) , _block(0) , _discarded(false), registerCount(0)
+ , bindingLine(0), bindingColumn(0)
{
}
@@ -73,6 +75,8 @@ void QV4CompilerPrivate::trace(int line, int column)
{
bytecode.clear();
+ this->bindingLine = line;
+ this->bindingColumn = column;
this->currentReg = _function->tempCount;
this->registerCount = qMax(this->registerCount, this->currentReg);
@@ -226,8 +230,9 @@ void QV4CompilerPrivate::visitConst(IR::Const *e)
gen(i);
} break;
- case IR::RealType: {
- Instr::LoadReal i;
+ case IR::FloatType:
+ case IR::NumberType: {
+ Instr::LoadNumber i;
i.reg = currentReg;
i.value = e->value;
gen(i);
@@ -316,7 +321,7 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
Instr::LoadAttached attached;
attached.output = currentReg;
attached.reg = currentReg;
- attached.exceptionId = exceptionId(e->line, e->column);
+ attached.exceptionId = exceptionId(bindingLine, bindingColumn);
if (e->declarativeType->attachedPropertiesId() == -1)
discard();
attached.id = e->declarativeType->attachedPropertiesId();
@@ -351,8 +356,11 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
QQmlRegisterType regType;
switch (propTy) {
- case QMetaType::QReal:
- regType = QRealType;
+ case QMetaType::Float:
+ regType = FloatType;
+ break;
+ case QMetaType::Double:
+ regType = NumberType;
break;
case QMetaType::Bool:
regType = BoolType;
@@ -373,7 +381,7 @@ void QV4CompilerPrivate::visitName(IR::Name *e)
default:
if (propTy == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
regType = PODValueType;
- } else if (QQmlMetaType::isQObject(propTy)) {
+ } else if (engine->metaObjectForType(propTy)) {
regType = QObjectStarType;
} else {
if (qmlVerboseCompiler())
@@ -458,14 +466,14 @@ void QV4CompilerPrivate::visitUnop(IR::Unop *e)
} break;
case IR::OpUMinus:
- if (e->expr->type == IR::RealType) {
- Instr::UnaryMinusReal i;
+ if (IR::isRealType(e->expr->type)) {
+ Instr::UnaryMinusNumber i;
i.output = currentReg;
i.src = src;
gen(i);
} else if (e->expr->type == IR::IntType) {
- convertToReal(e->expr, currentReg);
- Instr::UnaryMinusReal i;
+ convertToNumber(e->expr, currentReg);
+ Instr::UnaryMinusNumber i;
i.output = currentReg;
i.src = src;
gen(i);
@@ -475,14 +483,14 @@ void QV4CompilerPrivate::visitUnop(IR::Unop *e)
break;
case IR::OpUPlus:
- if (e->expr->type == IR::RealType) {
- Instr::UnaryPlusReal i;
+ if (IR::isRealType(e->expr->type)) {
+ Instr::UnaryPlusNumber i;
i.output = currentReg;
i.src = src;
gen(i);
} else if (e->expr->type == IR::IntType) {
- convertToReal(e->expr, currentReg);
- Instr::UnaryPlusReal i;
+ convertToNumber(e->expr, currentReg);
+ Instr::UnaryPlusNumber i;
i.output = currentReg;
i.src = src;
gen(i);
@@ -522,25 +530,26 @@ void QV4CompilerPrivate::visitUnop(IR::Unop *e)
} // switch
}
-void QV4CompilerPrivate::convertToReal(IR::Expr *expr, int reg)
+void QV4CompilerPrivate::convertToNumber(IR::Expr *expr, int reg)
{
- if (expr->type == IR::RealType)
+ if (expr->type == IR::NumberType)
return;
switch (expr->type) {
case IR::BoolType: {
- Instr::ConvertBoolToReal i;
+ Instr::ConvertBoolToNumber i;
i.output = i.src = reg;
gen(i);
} break;
case IR::IntType: {
- Instr::ConvertIntToReal i;
+ Instr::ConvertIntToNumber i;
i.output = i.src = reg;
gen(i);
} break;
- case IR::RealType:
+ case IR::FloatType:
+ case IR::NumberType:
// nothing to do
return;
@@ -566,8 +575,9 @@ void QV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
// nothing to do
return;
- case IR::RealType: {
- Instr::ConvertRealToInt i;
+ case IR::FloatType:
+ case IR::NumberType: {
+ Instr::ConvertNumberToInt i;
i.output = i.src = reg;
gen(i);
} break;
@@ -594,8 +604,9 @@ void QV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
gen(i);
} break;
- case IR::RealType: {
- Instr::ConvertRealToBool i;
+ case IR::FloatType:
+ case IR::NumberType: {
+ Instr::ConvertNumberToBool i;
i.output = i.src = reg;
gen(i);
} return;
@@ -643,19 +654,19 @@ quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
case IR::OpAdd:
if (e->type == IR::StringType)
return V4Instr::AddString;
- return V4Instr::AddReal;
+ return V4Instr::AddNumber;
case IR::OpSub:
- return V4Instr::SubReal;
+ return V4Instr::SubNumber;
case IR::OpMul:
- return V4Instr::MulReal;
+ return V4Instr::MulNumber;
case IR::OpDiv:
- return V4Instr::DivReal;
+ return V4Instr::DivNumber;
case IR::OpMod:
- return V4Instr::ModReal;
+ return V4Instr::ModNumber;
case IR::OpLShift:
return V4Instr::LShiftInt;
@@ -669,50 +680,50 @@ quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
case IR::OpGt:
if (e->left->type == IR::StringType)
return V4Instr::GtString;
- return V4Instr::GtReal;
+ return V4Instr::GtNumber;
case IR::OpLt:
if (e->left->type == IR::StringType)
return V4Instr::LtString;
- return V4Instr::LtReal;
+ return V4Instr::LtNumber;
case IR::OpGe:
if (e->left->type == IR::StringType)
return V4Instr::GeString;
- return V4Instr::GeReal;
+ return V4Instr::GeNumber;
case IR::OpLe:
if (e->left->type == IR::StringType)
return V4Instr::LeString;
- return V4Instr::LeReal;
+ return V4Instr::LeNumber;
case IR::OpEqual:
if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
return V4Instr::EqualObject;
if (e->left->type == IR::StringType)
return V4Instr::EqualString;
- return V4Instr::EqualReal;
+ return V4Instr::EqualNumber;
case IR::OpNotEqual:
if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
return V4Instr::NotEqualObject;
if (e->left->type == IR::StringType)
return V4Instr::NotEqualString;
- return V4Instr::NotEqualReal;
+ return V4Instr::NotEqualNumber;
case IR::OpStrictEqual:
if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
return V4Instr::StrictEqualObject;
if (e->left->type == IR::StringType)
return V4Instr::StrictEqualString;
- return V4Instr::StrictEqualReal;
+ return V4Instr::StrictEqualNumber;
case IR::OpStrictNotEqual:
if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
return V4Instr::StrictNotEqualObject;
if (e->left->type == IR::StringType)
return V4Instr::StrictNotEqualString;
- return V4Instr::StrictNotEqualReal;
+ return V4Instr::StrictNotEqualNumber;
case IR::OpAnd:
case IR::OpOr:
@@ -733,12 +744,26 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e)
int left = currentReg;
int right = currentReg + 1;
- traceExpression(e->left, left);
- traceExpression(e->right, right);
+ if (e->left->asTemp() && e->type != IR::StringType)
+ left = e->left->asTemp()->index;
+ else
+ traceExpression(e->left, left);
- // At this point it is possible that the type of the
- // subexpressions is different. This can happen because
- // we keep BINOP expressions in HIR.
+ if (IR::Temp *t = e->right->asTemp())
+ right = t->index;
+ else
+ traceExpression(e->right, right);
+
+ if (e->left->type != e->right->type) {
+ if (qmlVerboseCompiler())
+ qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
+ << "(`" << IR::binaryOperator(e->left->type)
+ << "' and `"
+ << IR::binaryOperator(e->right->type)
+ << "'";
+ discard();
+ return;
+ }
switch (e->op) {
case IR::OpInvalid:
@@ -766,8 +791,8 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e)
case IR::OpAdd:
if (e->type != IR::StringType) {
- convertToReal(e->left, left);
- convertToReal(e->right, right);
+ convertToNumber(e->left, left);
+ convertToNumber(e->right, right);
}
break;
@@ -775,8 +800,8 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e)
case IR::OpMul:
case IR::OpDiv:
case IR::OpMod:
- convertToReal(e->left, left);
- convertToReal(e->right, right);
+ convertToNumber(e->left, left);
+ convertToNumber(e->right, right);
break;
case IR::OpGt:
@@ -788,8 +813,8 @@ void QV4CompilerPrivate::visitBinop(IR::Binop *e)
case IR::OpStrictEqual:
case IR::OpStrictNotEqual:
if (e->left->type >= IR::FirstNumberType) {
- convertToReal(e->left, left);
- convertToReal(e->right, right);
+ convertToNumber(e->left, left);
+ convertToNumber(e->right, right);
}
break;
@@ -813,7 +838,7 @@ void QV4CompilerPrivate::visitCall(IR::Call *call)
{
if (IR::Name *name = call->base->asName()) {
IR::Expr *arg = call->onlyArgument();
- if (arg != 0 && arg->type == IR::RealType) {
+ if (arg != 0 && IR::isRealType(arg->type)) {
traceExpression(arg, currentReg);
switch (name->builtin) {
@@ -821,37 +846,37 @@ void QV4CompilerPrivate::visitCall(IR::Call *call)
break;
case IR::MathSinBultinFunction: {
- Instr::MathSinReal i;
+ Instr::MathSinNumber i;
i.output = i.src = currentReg;
gen(i);
} return;
case IR::MathCosBultinFunction: {
- Instr::MathCosReal i;
+ Instr::MathCosNumber i;
i.output = i.src = currentReg;
gen(i);
} return;
case IR::MathAbsBuiltinFunction: {
- Instr::MathAbsReal i;
+ Instr::MathAbsNumber i;
i.output = i.src = currentReg;
gen(i);
} return;
case IR::MathRoundBultinFunction: {
- Instr::MathRoundReal i;
+ Instr::MathRoundNumber i;
i.output = i.src = currentReg;
gen(i);
} return;
case IR::MathFloorBultinFunction: {
- Instr::MathFloorReal i;
+ Instr::MathFloorNumber i;
i.output = i.src = currentReg;
gen(i);
} return;
case IR::MathCeilBuiltinFunction: {
- Instr::MathCeilReal i;
+ Instr::MathCeilNumber i;
i.output = i.src = currentReg;
gen(i);
} return;
@@ -869,21 +894,21 @@ void QV4CompilerPrivate::visitCall(IR::Call *call)
IR::Expr *arg1 = call->args->expr;
IR::Expr *arg2 = call->args->next->expr;
- if (arg1 != 0 && arg1->type == IR::RealType &&
- arg2 != 0 && arg2->type == IR::RealType) {
+ if (arg1 != 0 && IR::isRealType(arg1->type) &&
+ arg2 != 0 && IR::isRealType(arg2->type)) {
traceExpression(arg1, currentReg);
traceExpression(arg2, currentReg + 1);
if (name->builtin == IR::MathMaxBuiltinFunction) {
- Instr::MathMaxReal i;
+ Instr::MathMaxNumber i;
i.left = currentReg;
i.right = currentReg + 1;
i.output = currentReg;
gen(i);
return;
} else if (name->builtin == IR::MathMinBuiltinFunction) {
- Instr::MathMinReal i;
+ Instr::MathMinNumber i;
i.left = currentReg;
i.right = currentReg + 1;
i.output = currentReg;
@@ -917,7 +942,17 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
quint8 dest = target->index;
- if (target->type != s->source->type) {
+ IR::Type targetTy = s->target->type;
+ IR::Type sourceTy = s->source->type;
+
+ // promote the floats
+ if (sourceTy == IR::FloatType)
+ sourceTy = IR::NumberType;
+
+ if (targetTy == IR::FloatType)
+ targetTy = IR::NumberType;
+
+ if (sourceTy != targetTy) {
quint8 src = dest;
if (IR::Temp *t = s->source->asTemp())
@@ -926,8 +961,6 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
traceExpression(s->source, dest);
V4Instr::Type opcode = V4Instr::Noop;
- IR::Type targetTy = s->target->type;
- IR::Type sourceTy = s->source->type;
if (sourceTy == IR::UrlType) {
switch (targetTy) {
@@ -937,13 +970,22 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
// url-to-xxx conversions.
break;
default: {
+ if (s->isMoveForReturn) {
+ V4Instr instr;
+ instr.throwop.exceptionId = exceptionId(bindingLine, bindingColumn);
+ registerLiteralString(dest, _function->newString(QString::fromUtf8("Unable to assign %1 to %2")
+ .arg(QLatin1String(IR::typeName(sourceTy)))
+ .arg(QLatin1String(IR::typeName(targetTy)))));
+ instr.throwop.message = dest;
+ gen(V4Instr::Throw, instr);
+ return;
+ }
// generate a UrlToString conversion and fix
// the type of the source expression.
V4Instr conv;
- conv.unaryop.output = V4Instr::ConvertUrlToString;
+ conv.unaryop.output = src;
conv.unaryop.src = src;
- gen(opcode, conv);
-
+ gen(V4Instr::ConvertUrlToString, conv);
sourceTy = IR::StringType;
break;
}
@@ -953,7 +995,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
if (targetTy == IR::BoolType) {
switch (sourceTy) {
case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
- case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
+ case IR::NumberType: opcode = V4Instr::ConvertNumberToBool; break;
case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
case IR::ColorType: opcode = V4Instr::ConvertColorToBool; break;
@@ -963,33 +1005,44 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
} else if (targetTy == IR::IntType) {
switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
- case IR::RealType: {
+ case IR::NumberType: {
if (s->isMoveForReturn)
- opcode = V4Instr::MathRoundReal;
+ opcode = V4Instr::MathRoundNumber;
else
- opcode = V4Instr::ConvertRealToInt;
+ opcode = V4Instr::ConvertNumberToInt;
break;
}
case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
default: break;
} // switch
- } else if (targetTy == IR::RealType) {
+ } else if (IR::isRealType(targetTy)) {
switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToReal; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToReal; break;
+ case IR::BoolType: opcode = V4Instr::ConvertBoolToNumber; break;
+ case IR::IntType: opcode = V4Instr::ConvertIntToNumber; break;
+ case IR::StringType: opcode = V4Instr::ConvertStringToNumber; break;
default: break;
} // switch
} else if (targetTy == IR::StringType) {
switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
case IR::IntType: opcode = V4Instr::ConvertIntToString; break;
- case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
+ case IR::NumberType: opcode = V4Instr::ConvertNumberToString; break;
case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break;
case IR::ColorType: opcode = V4Instr::ConvertColorToString; break;
default: break;
} // switch
} else if (targetTy == IR::UrlType) {
+ if (s->isMoveForReturn && sourceTy != IR::StringType) {
+ V4Instr instr;
+ instr.throwop.exceptionId = exceptionId(bindingLine, bindingColumn);
+ registerLiteralString(dest, _function->newString(QString::fromUtf8("Unable to assign %1 to %2")
+ .arg(QLatin1String(IR::typeName(sourceTy)))
+ .arg(QLatin1String(IR::typeName(targetTy)))));
+ instr.throwop.message = dest;
+ gen(V4Instr::Throw, instr);
+ return;
+ }
+
V4Instr convToString;
convToString.unaryop.output = dest;
convToString.unaryop.src = src;
@@ -998,7 +1051,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s)
switch (sourceTy) {
case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break;
case IR::IntType: gen(V4Instr::ConvertIntToString, convToString); sourceTy = IR::StringType; break;
- case IR::RealType: gen(V4Instr::ConvertRealToString, convToString); sourceTy = IR::StringType; break;
+ case IR::NumberType: gen(V4Instr::ConvertNumberToString, convToString); sourceTy = IR::StringType; break;
case IR::ColorType: gen(V4Instr::ConvertColorToString, convToString); sourceTy = IR::StringType; break;
default: break;
} // switch
@@ -1094,8 +1147,9 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s)
case IR::IntType:
test.regType = QMetaType::Int;
break;
- case IR::RealType:
- test.regType = QMetaType::QReal;
+ case IR::FloatType:
+ case IR::NumberType:
+ test.regType = QMetaType::Double;
break;
default:
discard();
@@ -1108,6 +1162,7 @@ void QV4CompilerPrivate::visitRet(IR::Ret *s)
store.output = 0;
store.index = expression->property->index;
store.reg = storeReg;
+ store.valueType = s->type == IR::FloatType ? FloatType : 0;
store.exceptionId = exceptionId(s->line, s->column);
gen(store);
}
@@ -1119,7 +1174,6 @@ void QV4Compiler::dump(const QByteArray &programData)
qWarning() << "Program.bindings:" << program->bindings;
qWarning() << "Program.dataLength:" << program->dataLength;
qWarning() << "Program.subscriptions:" << program->subscriptions;
- qWarning() << "Program.indentifiers:" << program->identifiers;
const int programSize = program->instructionCount;
const char *start = program->instructions();
@@ -1137,8 +1191,8 @@ void QV4CompilerPrivate::resetInstanceState()
data = committed.data;
exceptions = committed.exceptions;
usedSubscriptionIds.clear();
- subscriptionIds = committed.subscriptionIds;
- registeredStrings = committed.registeredStrings;
+ subscriptionIds.clear();
+ subscriptionOffset = committed.subscriptionCount;
bytecode.clear();
patches.clear();
pool.clear();
@@ -1159,8 +1213,9 @@ int QV4CompilerPrivate::commitCompile()
committed.bytecode.append(bytecode.constData(), bytecode.size());
committed.data = data;
committed.exceptions = exceptions;
- committed.subscriptionIds = subscriptionIds;
- committed.registeredStrings = registeredStrings;
+ committed.subscriptionCount = subscriptionOffset + subscriptionIds.count();
+ if (bindingsDump())
+ committed.subscriptions.append(subscriptionIds);
return rv;
}
@@ -1212,7 +1267,7 @@ bool QV4CompilerPrivate::compile(QQmlJS::AST::Node *node)
qerr << endl;
}
- if (discarded || subscriptionIds.count() > 0xFFFF || registeredStrings.count() > 0xFFFF || registerCount > 31)
+ if (discarded || subscriptionIds.count() > 0xFFFF || registerCount > 31)
return false;
return true;
@@ -1236,32 +1291,6 @@ int QV4CompilerPrivate::registerLiteralString(quint8 reg, const QStringRef &str)
return reg;
}
-// Returns an identifier offset
-int QV4CompilerPrivate::registerString(const QString &string)
-{
- Q_ASSERT(!string.isEmpty());
-
- QPair<int, int> *iter = registeredStrings.value(string);
-
- if (!iter) {
- quint32 len = string.length();
- QByteArray lendata((const char *)&len, sizeof(quint32));
- QByteArray strdata((const char *)string.constData(), string.length() * sizeof(QChar));
- strdata.prepend(lendata);
- int rv = data.count();
- data += strdata;
-
- iter = &registeredStrings[string];
- *iter = qMakePair(registeredStrings.count(), rv);
- }
-
- Instr::InitString reg;
- reg.offset = iter->first;
- reg.dataIdx = iter->second;
- gen(reg);
- return reg.offset;
-}
-
/*!
Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
*/
@@ -1285,7 +1314,7 @@ int QV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
QString str = sub.join(QLatin1String("."));
int *iter = subscriptionIds.value(str);
if (!iter) {
- int count = subscriptionIds.count();
+ int count = subscriptionOffset + subscriptionIds.count();
iter = &subscriptionIds[str];
*iter = count;
}
@@ -1384,8 +1413,8 @@ QByteArray QV4CompilerPrivate::buildSignalTable() const
QVector<quint32> header;
QVector<quint32> data;
- for (int ii = 0; ii < committed.subscriptionIds.count(); ++ii) {
- header.append(committed.subscriptionIds.count() + data.count());
+ for (int ii = 0; ii < committed.subscriptionCount; ++ii) {
+ header.append(committed.subscriptionCount + data.count());
const QList<QPair<int, quint32> > &bindings = table[ii];
data.append(bindings.count());
for (int jj = 0; jj < bindings.count(); ++jj) {
@@ -1443,8 +1472,7 @@ QByteArray QV4Compiler::program() const
data += d->buildExceptionData();
prog.dataLength = 4 * ((data.size() + 3) / 4);
- prog.subscriptions = d->committed.subscriptionIds.count();
- prog.identifiers = d->committed.registeredStrings.count();
+ prog.subscriptions = d->committed.subscriptionCount;
prog.instructionCount = bytecode.count();
int size = sizeof(QV4Program) + bytecode.count();
size += prog.dataLength;
@@ -1461,12 +1489,13 @@ QByteArray QV4Compiler::program() const
if (bindingsDump()) {
qWarning().nospace() << "Subscription slots:";
- for (QQmlAssociationList<QString, int>::ConstIterator iter = d->committed.subscriptionIds.begin();
- iter != d->committed.subscriptionIds.end();
- ++iter) {
- qWarning().nospace() << " " << iter->first << "\t-> " << iter->second;
+ QQmlAssociationList<QString, int> subscriptionIds;
+ foreach (subscriptionIds, d->committed.subscriptions) {
+ for (QQmlAssociationList<QString, int>::ConstIterator iter = subscriptionIds.begin();
+ iter != subscriptionIds.end(); ++iter) {
+ qWarning().nospace() << " " << iter->first << "\t-> " << iter->second;
+ }
}
-
QV4Compiler::dump(programData);
}
diff --git a/src/qml/qml/v4/qv4compiler_p_p.h b/src/qml/qml/v4/qv4compiler_p_p.h
index a9209d978f..0c06ade87f 100644
--- a/src/qml/qml/v4/qv4compiler_p_p.h
+++ b/src/qml/qml/v4/qv4compiler_p_p.h
@@ -128,8 +128,6 @@ public:
bool compile(QQmlJS::AST::Node *);
int registerLiteralString(quint8 reg, const QStringRef &);
- int registerString(const QString &);
- QQmlAssociationList<QString, QPair<int, int> > registeredStrings;
QByteArray data;
bool blockNeedsSubscription(const QStringList &);
@@ -141,7 +139,7 @@ public:
QVector<quint64> exceptions;
QQmlAssociationList<int, quint32> usedSubscriptionIds;
-
+ int subscriptionOffset;
QQmlAssociationList<QString, int> subscriptionIds;
QQmlJS::Bytecode bytecode;
@@ -156,17 +154,17 @@ public:
QQmlPool pool;
// Committed binding data
- struct {
+ struct Committed {
+ Committed(): subscriptionCount(0) {}
QList<int> offsets;
QList<QQmlAssociationList<int, quint32> > dependencies;
//QQmlJS::Bytecode bytecode;
QByteArray bytecode;
QByteArray data;
- QQmlAssociationList<QString, int> subscriptionIds;
QVector<quint64> exceptions;
-
- QQmlAssociationList<QString, QPair<int, int> > registeredStrings;
+ int subscriptionCount;
+ QList<QQmlAssociationList<QString, int> > subscriptions;
int count() const { return offsets.count(); }
} committed;
@@ -174,7 +172,7 @@ public:
QByteArray buildSignalTable() const;
QByteArray buildExceptionData() const;
- void convertToReal(QQmlJS::IR::Expr *expr, int reg);
+ void convertToNumber(QQmlJS::IR::Expr *expr, int reg);
void convertToInt(QQmlJS::IR::Expr *expr, int reg);
void convertToBool(QQmlJS::IR::Expr *expr, int reg);
quint8 instructionOpcode(QQmlJS::IR::Binop *e);
@@ -235,6 +233,8 @@ private:
bool usedSubscriptionIdsChanged;
quint32 currentBlockMask;
+ int bindingLine;
+ int bindingColumn;
};
diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp
index cb6ff40589..ecd4f01ef3 100644
--- a/src/qml/qml/v4/qv4instruction.cpp
+++ b/src/qml/qml/v4/qv4instruction.cpp
@@ -123,14 +123,14 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::UnaryNot:
INSTR_DUMP << "\t" << "UnaryNot" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::UnaryMinusReal:
- INSTR_DUMP << "\t" << "UnaryMinusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::UnaryMinusNumber:
+ INSTR_DUMP << "\t" << "UnaryMinusNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
case V4Instr::UnaryMinusInt:
INSTR_DUMP << "\t" << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::UnaryPlusReal:
- INSTR_DUMP << "\t" << "UnaryPlusReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::UnaryPlusNumber:
+ INSTR_DUMP << "\t" << "UnaryPlusNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
case V4Instr::UnaryPlusInt:
INSTR_DUMP << "\t" << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
@@ -138,8 +138,8 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertBoolToInt:
INSTR_DUMP << "\t" << "ConvertBoolToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::ConvertBoolToReal:
- INSTR_DUMP << "\t" << "ConvertBoolToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::ConvertBoolToNumber:
+ INSTR_DUMP << "\t" << "ConvertBoolToNumber" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
case V4Instr::ConvertBoolToString:
INSTR_DUMP << "\t" << "ConvertBoolToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
@@ -147,20 +147,20 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertIntToBool:
INSTR_DUMP << "\t" << "ConvertIntToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::ConvertIntToReal:
- INSTR_DUMP << "\t" << "ConvertIntToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::ConvertIntToNumber:
+ INSTR_DUMP << "\t" << "ConvertIntToNumber" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
case V4Instr::ConvertIntToString:
INSTR_DUMP << "\t" << "ConvertIntToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::ConvertRealToBool:
- INSTR_DUMP << "\t" << "ConvertRealToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::ConvertNumberToBool:
+ INSTR_DUMP << "\t" << "ConvertNumberToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::ConvertRealToInt:
- INSTR_DUMP << "\t" << "ConvertRealToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::ConvertNumberToInt:
+ INSTR_DUMP << "\t" << "ConvertNumberToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::ConvertRealToString:
- INSTR_DUMP << "\t" << "ConvertRealToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::ConvertNumberToString:
+ INSTR_DUMP << "\t" << "ConvertNumberToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
case V4Instr::ConvertStringToBool:
INSTR_DUMP << "\t" << "ConvertStringToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
@@ -168,8 +168,8 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ConvertStringToInt:
INSTR_DUMP << "\t" << "ConvertStringToInt" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::ConvertStringToReal:
- INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::ConvertStringToNumber:
+ INSTR_DUMP << "\t" << "ConvertStringToNumber" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
case V4Instr::ConvertStringToUrl:
INSTR_DUMP << "\t" << "ConvertStringToUrl" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
@@ -198,32 +198,32 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::ResolveUrl:
INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::MathSinReal:
- INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::MathSinNumber:
+ INSTR_DUMP << "\t" << "MathSinNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::MathCosReal:
- INSTR_DUMP << "\t" << "MathCosReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::MathCosNumber:
+ INSTR_DUMP << "\t" << "MathCosNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::MathAbsReal:
- INSTR_DUMP << "\t" << "MathAbsReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::MathAbsNumber:
+ INSTR_DUMP << "\t" << "MathAbsNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::MathRoundReal:
- INSTR_DUMP << "\t" << "MathRoundReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::MathRoundNumber:
+ INSTR_DUMP << "\t" << "MathRoundNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::MathFloorReal:
- INSTR_DUMP << "\t" << "MathFloorReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::MathFloorNumber:
+ INSTR_DUMP << "\t" << "MathFloorNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::MathCeilReal:
- INSTR_DUMP << "\t" << "MathCeilReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::MathCeilNumber:
+ INSTR_DUMP << "\t" << "MathCeilNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
- case V4Instr::MathPIReal:
- INSTR_DUMP << "\t" << "MathPIReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ case V4Instr::MathPINumber:
+ INSTR_DUMP << "\t" << "MathPINumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
case V4Instr::LoadNull:
INSTR_DUMP << "\t" << "LoadNull" << "\t\t" << "Constant(null) -> Output_Reg(" << i->null_value.reg << ")";
break;
- case V4Instr::LoadReal:
- INSTR_DUMP << "\t" << "LoadReal" << "\t\t" << "Constant(" << i->real_value.value << ") -> Output_Reg(" << i->real_value.reg << ")";
+ case V4Instr::LoadNumber:
+ INSTR_DUMP << "\t" << "LoadNumber" << "\t\t" << "Constant(" << i->number_value.value << ") -> Output_Reg(" << i->number_value.reg << ")";
break;
case V4Instr::LoadInt:
INSTR_DUMP << "\t" << "LoadInt" << "\t\t\t" << "Constant(" << i->int_value.value << ") -> Output_Reg(" << i->int_value.reg << ")";
@@ -249,23 +249,23 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::BitXorInt:
INSTR_DUMP << "\t" << "BitXorInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::AddReal:
- INSTR_DUMP << "\t" << "AddReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::AddNumber:
+ INSTR_DUMP << "\t" << "AddNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
case V4Instr::AddString:
INSTR_DUMP << "\t" << "AddString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::SubReal:
- INSTR_DUMP << "\t" << "SubReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::SubNumber:
+ INSTR_DUMP << "\t" << "SubNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::MulReal:
- INSTR_DUMP << "\t" << "MulReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::MulNumber:
+ INSTR_DUMP << "\t" << "MulNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::DivReal:
- INSTR_DUMP << "\t" << "DivReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::DivNumber:
+ INSTR_DUMP << "\t" << "DivNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::ModReal:
- INSTR_DUMP << "\t" << "ModReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::ModNumber:
+ INSTR_DUMP << "\t" << "ModNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
case V4Instr::LShiftInt:
INSTR_DUMP << "\t" << "LShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
@@ -276,29 +276,29 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::URShiftInt:
INSTR_DUMP << "\t" << "URShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::GtReal:
- INSTR_DUMP << "\t" << "GtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::GtNumber:
+ INSTR_DUMP << "\t" << "GtNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::LtReal:
- INSTR_DUMP << "\t" << "LtReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::LtNumber:
+ INSTR_DUMP << "\t" << "LtNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::GeReal:
- INSTR_DUMP << "\t" << "GeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::GeNumber:
+ INSTR_DUMP << "\t" << "GeNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::LeReal:
- INSTR_DUMP << "\t" << "LeReal" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::LeNumber:
+ INSTR_DUMP << "\t" << "LeNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::EqualReal:
- INSTR_DUMP << "\t" << "EqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::EqualNumber:
+ INSTR_DUMP << "\t" << "EqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::NotEqualReal:
- INSTR_DUMP << "\t" << "NotEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::NotEqualNumber:
+ INSTR_DUMP << "\t" << "NotEqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::StrictEqualReal:
- INSTR_DUMP << "\t" << "StrictEqualReal" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::StrictEqualNumber:
+ INSTR_DUMP << "\t" << "StrictEqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::StrictNotEqualReal:
- INSTR_DUMP << "\t" << "StrictNotEqualReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::StrictNotEqualNumber:
+ INSTR_DUMP << "\t" << "StrictNotEqualNumber" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
case V4Instr::GtString:
INSTR_DUMP << "\t" << "GtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
@@ -336,11 +336,11 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::StrictNotEqualObject:
INSTR_DUMP << "\t" << "StrictNotEqualObject" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::MathMaxReal:
- INSTR_DUMP << "\t" << "MathMaxReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::MathMaxNumber:
+ INSTR_DUMP << "\t" << "MathMaxNumber" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
- case V4Instr::MathMinReal:
- INSTR_DUMP << "\t" << "MathMinReal" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
+ case V4Instr::MathMinNumber:
+ INSTR_DUMP << "\t" << "MathMinNumber" << "\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ")";
break;
case V4Instr::NewString:
INSTR_DUMP << "\t" << "NewString" << "\t\t" << "Register(" << i->construct.reg << ")";
@@ -376,12 +376,12 @@ void Bytecode::dump(const V4Instr *i, int address) const
case V4Instr::Branch:
INSTR_DUMP << "\t" << "Branch" << "\t\t\t" << "Address(" << (address + size() + i->branchop.offset) << ")";
break;
- case V4Instr::InitString:
- INSTR_DUMP << "\t" << "InitString" << "\t\t" << "String_DataIndex(" << i->initstring.dataIdx << ") -> String_Slot(" << i->initstring.offset << ")";
- break;
case V4Instr::Block:
INSTR_DUMP << "\t" << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(i->blockop.block, 16).constData() << ")";
break;
+ case V4Instr::Throw:
+ INSTR_DUMP << "\t" << "Throw" << "\t\t\t" << "InputReg(" << i->throwop.message << ")";
+ break;
default:
INSTR_DUMP << "\t" << "Unknown";
break;
diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h
index 239cb362cc..310bfbaff5 100644
--- a/src/qml/qml/v4/qv4instruction_p.h
+++ b/src/qml/qml/v4/qv4instruction_p.h
@@ -76,22 +76,22 @@ QT_BEGIN_NAMESPACE
F(LoadModuleObject, load) \
F(LoadAttached, attached) \
F(UnaryNot, unaryop) \
- F(UnaryMinusReal, unaryop) \
+ F(UnaryMinusNumber, unaryop) \
F(UnaryMinusInt, unaryop) \
- F(UnaryPlusReal, unaryop) \
+ F(UnaryPlusNumber, unaryop) \
F(UnaryPlusInt, unaryop) \
F(ConvertBoolToInt, unaryop) \
- F(ConvertBoolToReal, unaryop) \
+ F(ConvertBoolToNumber, unaryop) \
F(ConvertBoolToString, unaryop) \
F(ConvertIntToBool, unaryop) \
- F(ConvertIntToReal, unaryop) \
+ F(ConvertIntToNumber, unaryop) \
F(ConvertIntToString, unaryop) \
- F(ConvertRealToBool, unaryop) \
- F(ConvertRealToInt, unaryop) \
- F(ConvertRealToString, unaryop) \
+ F(ConvertNumberToBool, unaryop) \
+ F(ConvertNumberToInt, unaryop) \
+ F(ConvertNumberToString, unaryop) \
F(ConvertStringToBool, unaryop) \
F(ConvertStringToInt, unaryop) \
- F(ConvertStringToReal, unaryop) \
+ F(ConvertStringToNumber, unaryop) \
F(ConvertStringToUrl, unaryop) \
F(ConvertStringToColor, unaryop) \
F(ConvertUrlToBool, unaryop) \
@@ -101,15 +101,15 @@ QT_BEGIN_NAMESPACE
F(ConvertObjectToBool, unaryop) \
F(ConvertNullToObject, unaryop) \
F(ResolveUrl, unaryop) \
- F(MathSinReal, unaryop) \
- F(MathCosReal, unaryop) \
- F(MathAbsReal, unaryop) \
- F(MathRoundReal, unaryop) \
- F(MathFloorReal, unaryop) \
- F(MathCeilReal, unaryop) \
- F(MathPIReal, unaryop) \
+ F(MathSinNumber, unaryop) \
+ F(MathCosNumber, unaryop) \
+ F(MathAbsNumber, unaryop) \
+ F(MathRoundNumber, unaryop) \
+ F(MathFloorNumber, unaryop) \
+ F(MathCeilNumber, unaryop) \
+ F(MathPINumber, unaryop) \
F(LoadNull, null_value) \
- F(LoadReal, real_value) \
+ F(LoadNumber, number_value) \
F(LoadInt, int_value) \
F(LoadBool, bool_value) \
F(LoadString, string_value) \
@@ -118,23 +118,23 @@ QT_BEGIN_NAMESPACE
F(BitAndInt, binaryop) \
F(BitOrInt, binaryop) \
F(BitXorInt, binaryop) \
- F(AddReal, binaryop) \
+ F(AddNumber, binaryop) \
F(AddString, binaryop) \
- F(SubReal, binaryop) \
- F(MulReal, binaryop) \
- F(DivReal, binaryop) \
- F(ModReal, binaryop) \
+ F(SubNumber, binaryop) \
+ F(MulNumber, binaryop) \
+ F(DivNumber, binaryop) \
+ F(ModNumber, binaryop) \
F(LShiftInt, binaryop) \
F(RShiftInt, binaryop) \
F(URShiftInt, binaryop) \
- F(GtReal, binaryop) \
- F(LtReal, binaryop) \
- F(GeReal, binaryop) \
- F(LeReal, binaryop) \
- F(EqualReal, binaryop) \
- F(NotEqualReal, binaryop) \
- F(StrictEqualReal, binaryop) \
- F(StrictNotEqualReal, binaryop) \
+ F(GtNumber, binaryop) \
+ F(LtNumber, binaryop) \
+ F(GeNumber, binaryop) \
+ F(LeNumber, binaryop) \
+ F(EqualNumber, binaryop) \
+ F(NotEqualNumber, binaryop) \
+ F(StrictEqualNumber, binaryop) \
+ F(StrictNotEqualNumber, binaryop) \
F(GtString, binaryop) \
F(LtString, binaryop) \
F(GeString, binaryop) \
@@ -147,8 +147,8 @@ QT_BEGIN_NAMESPACE
F(NotEqualObject, binaryop) \
F(StrictEqualObject, binaryop) \
F(StrictNotEqualObject, binaryop) \
- F(MathMaxReal, binaryop) \
- F(MathMinReal, binaryop) \
+ F(MathMaxNumber, binaryop) \
+ F(MathMinNumber, binaryop) \
F(NewString, construct) \
F(NewUrl, construct) \
F(CleanupRegister, cleanup) \
@@ -160,8 +160,7 @@ QT_BEGIN_NAMESPACE
F(BranchFalse, branchop) \
F(Branch, branchop) \
F(Block, blockop) \
- /* Speculative property resolution */ \
- F(InitString, initstring)
+ F(Throw, throwop)
#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
# define QML_THREADED_INTERPRETER
@@ -192,7 +191,7 @@ class QQmlNotifier;
namespace QQmlJS {
-union V4Instr {
+union Q_AUTOTEST_EXPORT V4Instr {
enum Type {
FOR_EACH_V4_INSTR(QML_V4_INSTR_ENUM)
};
@@ -241,6 +240,7 @@ union V4Instr {
qint8 output;
qint8 reg;
quint8 exceptionId;
+ quint8 valueType;
quint32 index;
};
@@ -283,10 +283,10 @@ union V4Instr {
qint8 reg;
};
- struct instr_real_value {
+ struct instr_number_value {
QML_V4_INSTR_HEADER
qint8 reg;
- qreal value; // XXX Makes the instruction 12 bytes
+ double value; // XXX Makes the instruction 12 bytes
};
struct instr_int_value {
@@ -358,6 +358,12 @@ union V4Instr {
quint32 block;
};
+ struct instr_throwop {
+ QML_V4_INSTR_HEADER
+ quint8 exceptionId;
+ quint32 message;
+ };
+
instr_common common;
instr_id id;
instr_init init;
@@ -371,7 +377,7 @@ union V4Instr {
instr_copy copy;
instr_construct construct;
instr_null_value null_value;
- instr_real_value real_value;
+ instr_number_value number_value;
instr_int_value int_value;
instr_bool_value bool_value;
instr_string_value string_value;
@@ -383,6 +389,7 @@ union V4Instr {
instr_initstring initstring;
instr_branchop branchop;
instr_blockop blockop;
+ instr_throwop throwop;
};
template<int N>
@@ -400,11 +407,11 @@ FOR_EACH_V4_INSTR(QML_V4_INSTR_META_TEMPLATE);
#undef QML_V4_INSTR_META_TEMPLATE
template<int Instr>
-class V4InstrData : public V4InstrMeta<Instr>::DataType
+class Q_AUTOTEST_EXPORT V4InstrData : public V4InstrMeta<Instr>::DataType
{
};
-class Bytecode
+class Q_AUTOTEST_EXPORT Bytecode
{
Q_DISABLE_COPY(Bytecode)
diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp
index 34245f5bf4..ba0faec80e 100644
--- a/src/qml/qml/v4/qv4ir.cpp
+++ b/src/qml/qml/v4/qv4ir.cpp
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
namespace QQmlJS {
namespace IR {
-inline const char *typeName(Type t)
+const char *typeName(Type t)
{
switch (t) {
case InvalidType: return "invalid";
@@ -58,15 +58,15 @@ inline const char *typeName(Type t)
case NullType: return "null";
case VoidType: return "void";
case StringType: return "string";
- case UrlType: return "url";
- case ColorType: return "color";
+ case UrlType: return "QUrl";
+ case ColorType: return "QColor";
case SGAnchorLineType: return "SGAnchorLine";
case AttachType: return "AttachType";
case ObjectType: return "object";
case BoolType: return "bool";
case IntType: return "int";
- case RealType: return "qreal";
- case RealNaNType: return "NaN";
+ case FloatType: return "float";
+ case NumberType: return "number";
default: return "invalid";
}
}
@@ -91,15 +91,20 @@ IR::Type maxType(IR::Type left, IR::Type right)
return IR::StringType;
} else if (left == right)
return left;
- else if (isNumberType(left) && isNumberType(right))
- return qMax(left, right);
- else if ((isNumberType(left) && isStringType(right)) ||
+ else if (isNumberType(left) && isNumberType(right)) {
+ IR::Type ty = qMax(left, right);
+ return ty == FloatType ? NumberType : ty; // promote floats
+ } else if ((isNumberType(left) && isStringType(right)) ||
(isNumberType(right) && isStringType(left)))
return IR::StringType;
else
return IR::InvalidType;
}
+bool isRealType(IR::Type type)
+{
+ return type == IR::NumberType || type == IR::FloatType;
+}
const char *opname(AluOp op)
{
@@ -233,7 +238,7 @@ void Name::init(Name *base, Type type, const QString *id, Symbol symbol, quint32
builtin = MathMinBuiltinFunction;
} else if (id->length() == 7 && *id == QLatin1String("Math.PI")) {
builtin = MathPIBuiltinConstant;
- this->type = RealType;
+ this->type = NumberType;
}
}
@@ -267,7 +272,7 @@ Type Unop::typeForOp(AluOp op, Expr *expr)
case OpUMinus:
case OpUPlus:
case OpCompl:
- return maxType(expr->type, RealType);
+ return maxType(expr->type, NumberType);
default:
break;
@@ -309,13 +314,13 @@ Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
case OpAdd:
if (left->type == StringType)
return StringType;
- return RealType;
+ return NumberType;
case OpSub:
case OpMul:
case OpDiv:
case OpMod:
- return RealType;
+ return NumberType;
case OpLShift:
case OpRShift:
@@ -364,7 +369,7 @@ Type Call::typeForFunction(Expr *base)
case MathAbsBuiltinFunction: //### type could also be Int if input was Int
case MathMaxBuiltinFunction:
case MathMinBuiltinFunction:
- return RealType;
+ return NumberType;
case MathRoundBultinFunction:
case MathFloorBultinFunction:
@@ -601,6 +606,12 @@ Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
break;
}
}
+ } else if (op == OpAdd) {
+ if (String *s1 = left->asString()) {
+ if (String *s2 = right->asString()) {
+ return STRING(function->newString(s1->value.toString() + s2->value));
+ }
+ }
}
}
diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h
index 4e9f9faacd..26bd43c406 100644
--- a/src/qml/qml/v4/qv4ir_p.h
+++ b/src/qml/qml/v4/qv4ir_p.h
@@ -150,10 +150,12 @@ enum Type {
FirstNumberType,
BoolType = FirstNumberType,
IntType,
- RealType,
- RealNaNType
+ FloatType,
+ NumberType
};
Type maxType(IR::Type left, IR::Type right);
+bool isRealType(IR::Type type);
+const char *typeName(IR::Type t);
struct ExprVisitor {
virtual ~ExprVisitor() {}
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
index 453120c6c7..31ed9a5a6a 100644
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ b/src/qml/qml/v4/qv4irbuilder.cpp
@@ -61,8 +61,11 @@ static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine, const QM
case QMetaType::Int:
return IR::IntType;
- case QMetaType::QReal:
- return IR::RealType;
+ case QMetaType::Float:
+ return IR::FloatType;
+
+ case QMetaType::Double:
+ return IR::NumberType;
case QMetaType::QString:
return IR::StringType;
@@ -542,7 +545,7 @@ bool QV4IRBuilder::visit(AST::NumericLiteral *ast)
_expr.format = ExprResult::cx;
_block->JUMP(ast->value ? _expr.iftrue : _expr.iffalse);
} else {
- _expr.code = _block->CONST(IR::RealType, ast->value);
+ _expr.code = _block->CONST(IR::NumberType, ast->value);
}
return false;
}
@@ -889,7 +892,14 @@ void QV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult
_expr.format = ExprResult::cx;
_block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
} else {
- _expr.code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ IR::Expr *e = _block->BINOP(IR::binaryOperator(ast->op), left, right);
+ if (e->asConst() != 0 || e->asString() != 0)
+ _expr.code = e;
+ else {
+ IR::Temp *t = _block->TEMP(e->type);
+ _block->MOVE(t, e);
+ _expr.code = t;
+ }
}
}
@@ -977,8 +987,8 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
if (left.type() == IR::StringType && right.type() == IR::StringType) {
binop(ast, left, right);
} else if (left.isValid() && right.isValid()) {
- implicitCvt(left, IR::RealType);
- implicitCvt(right, IR::RealType);
+ implicitCvt(left, IR::NumberType);
+ implicitCvt(right, IR::NumberType);
binop(ast, left, right);
}
} break;
@@ -998,8 +1008,8 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
}
} else if ((left.type() == IR::StringType && right.type() >= IR::FirstNumberType) ||
(left.type() >= IR::FirstNumberType && right.type() == IR::StringType)) {
- implicitCvt(left, IR::RealType);
- implicitCvt(right, IR::RealType);
+ implicitCvt(left, IR::NumberType);
+ implicitCvt(right, IR::NumberType);
binop(ast, left, right);
} else if (left.isValid() && right.isValid()) {
binop(ast, left, right);
@@ -1086,8 +1096,8 @@ bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
IR::Type t = maxType(left.type(), right.type());
if (t >= IR::FirstNumberType) {
- implicitCvt(left, IR::RealType);
- implicitCvt(right, IR::RealType);
+ implicitCvt(left, IR::NumberType);
+ implicitCvt(right, IR::NumberType);
IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
_expr.code = _block->TEMP(code->type);
diff --git a/src/qml/qml/v4/qv4irbuilder_p.h b/src/qml/qml/v4/qv4irbuilder_p.h
index 2b338c0778..e73ec22750 100644
--- a/src/qml/qml/v4/qv4irbuilder_p.h
+++ b/src/qml/qml/v4/qv4irbuilder_p.h
@@ -95,8 +95,8 @@ protected:
case QQmlJS::IR::StringType:
case QQmlJS::IR::BoolType:
case QQmlJS::IR::IntType:
- case QQmlJS::IR::RealType:
- case QQmlJS::IR::RealNaNType:
+ case QQmlJS::IR::FloatType:
+ case QQmlJS::IR::NumberType:
return true;
default:
diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4program_p.h
index 60e7403786..c1dc39279d 100644
--- a/src/qml/qml/v4/qv4program_p.h
+++ b/src/qml/qml/v4/qv4program_p.h
@@ -65,7 +65,6 @@ struct QV4Program {
quint32 signalTableOffset;
quint32 exceptionDataOffset;
quint16 subscriptions;
- quint16 identifiers;
quint16 instructionCount;
struct BindingReference {
@@ -87,7 +86,8 @@ enum QQmlRegisterType {
UndefinedType,
NullType,
QObjectStarType,
- QRealType,
+ NumberType,
+ FloatType,
IntType,
BoolType,
diff --git a/src/qml/qml/v8/qjsvalue_p.h b/src/qml/qml/v8/qjsvalue_p.h
index acfe958cb6..099d53ee7a 100644
--- a/src/qml/qml/v8/qjsvalue_p.h
+++ b/src/qml/qml/v8/qjsvalue_p.h
@@ -177,7 +177,7 @@ private:
CBool,
CNull,
CUndefined,
- JSValue = 0x2000, // V8 values are equal or higher then this value.
+ JSValue = 0x2000 // V8 values are equal or higher then this value.
// JSPrimitive,
// JSObject
} m_state;
diff --git a/src/qml/qml/v8/qv8bindings.cpp b/src/qml/qml/v8/qv8bindings.cpp
index 4b96679cf3..025854f1ac 100644
--- a/src/qml/qml/v8/qv8bindings.cpp
+++ b/src/qml/qml/v8/qv8bindings.cpp
@@ -58,7 +58,7 @@ static QQmlJavaScriptExpression::VTable QV8Bindings_Binding_jsvtable = {
};
QV8Bindings::Binding::Binding()
-: QQmlJavaScriptExpression(&QV8Bindings_Binding_jsvtable), target(0), parent(0)
+: QQmlJavaScriptExpression(&QV8Bindings_Binding_jsvtable), parent(0)
{
}
@@ -85,12 +85,20 @@ void QV8Bindings::Binding::refresh()
int QV8Bindings::Binding::propertyIndex() const
{
- return instruction->property.encodedIndex();
+ if (target.hasValue()) return target.constValue()->targetProperty;
+ else return instruction->property.encodedIndex();
}
QObject *QV8Bindings::Binding::object() const
{
- return target;
+ if (target.hasValue()) return target.constValue()->target;
+ else return *target;
+}
+
+void QV8Bindings::Binding::retargetBinding(QObject *t, int i)
+{
+ target.value().target = t;
+ target.value().targetProperty = i;
}
void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
@@ -127,13 +135,13 @@ void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
trace.event("writing V8 result");
bool needsErrorData = false;
- if (!watcher.wasDeleted() && !hasError()) {
+ if (!watcher.wasDeleted() && !destroyedFlag() && !hasError()) {
typedef QQmlPropertyPrivate PP;
- needsErrorData = !PP::writeBinding(target, instruction->property, context, this, result,
+ needsErrorData = !PP::writeBinding(*target, instruction->property, context, this, result,
isUndefined, flags);
}
- if (!watcher.wasDeleted()) {
+ if (!watcher.wasDeleted() && !destroyedFlag()) {
if (needsErrorData) {
QUrl url = parent->url();
@@ -156,7 +164,7 @@ void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
ep->dereferenceScarceResources();
} else {
- QQmlProperty p = QQmlPropertyPrivate::restore(target, instruction->property, context);
+ QQmlProperty p = QQmlPropertyPrivate::restore(*target, instruction->property, context);
QQmlAbstractBinding::printBindingLoopError(p);
}
}
@@ -177,6 +185,7 @@ void QV8Bindings::Binding::expressionChanged(QQmlJavaScriptExpression *e)
void QV8Bindings::Binding::destroy()
{
setEnabledFlag(false);
+ setDestroyedFlag(true);
removeFromObject();
clear();
clearError();
diff --git a/src/qml/qml/v8/qv8bindings_p.h b/src/qml/qml/v8/qv8bindings_p.h
index ad5b2cb8b0..7cc1cc9c21 100644
--- a/src/qml/qml/v8/qv8bindings_p.h
+++ b/src/qml/qml/v8/qv8bindings_p.h
@@ -53,12 +53,13 @@
// We mean it.
//
+#include <private/qpointervaluepair_p.h>
#include <private/qqmlpropertycache_p.h>
#include <private/qqmlinstruction_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlcompiler_p.h>
-#include <private/qqmlbinding_p.h>
#include <private/qflagpointer_p.h>
+#include <private/qqmlbinding_p.h>
QT_BEGIN_HEADER
@@ -96,17 +97,26 @@ public:
virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags);
virtual void update(QQmlPropertyPrivate::WriteFlags flags);
virtual void destroy();
- virtual int propertyIndex() const;
virtual QObject *object() const;
+ virtual int propertyIndex() const;
+ virtual void retargetBinding(QObject *, int);
- QObject *target;
QV8Bindings *parent;
+ struct Retarget {
+ QObject *target;
+ int targetProperty;
+ };
+
// To save memory, we store flags inside the instruction pointer.
- // flag1: enabled
- // flag2: updating
+ // target.flag1: destroyed
+ // instruction.flag1: enabled
+ // instruction.flag2: updating
+ QPointerValuePair<QObject, Retarget> target;
QFlagPointer<const QQmlInstruction::instr_assignBinding> instruction;
+ inline bool destroyedFlag() const { return target.flag(); }
+ inline void setDestroyedFlag(bool v) { return target.setFlagValue(v); }
inline bool enabledFlag() const { return instruction.flag(); }
inline void setEnabledFlag(bool v) { instruction.setFlagValue(v); }
inline bool updatingFlag() const { return instruction.flag2(); }
diff --git a/src/qml/qml/v8/qv8contextwrapper.cpp b/src/qml/qml/v8/qv8contextwrapper.cpp
index 39392b8984..8a98727205 100644
--- a/src/qml/qml/v8/qv8contextwrapper.cpp
+++ b/src/qml/qml/v8/qv8contextwrapper.cpp
@@ -327,7 +327,7 @@ v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
const QVariant &value = cp->propertyValues.at(propertyIdx);
if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
- QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*)propertyIdx,
+ QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx),
0,
QQmlContextPrivate::context_count,
QQmlContextPrivate::context_at);
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 678f9aa3ee..2302d0e369 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -46,7 +46,6 @@
#include "qv8sequencewrapper_p.h"
#include "qv8include_p.h"
#include "qjsengine_p.h"
-#include "../../../3rdparty/javascriptcore/DateMath.h"
#include <private/qqmlbuiltinfunctions_p.h>
#include <private/qqmllist_p.h>
@@ -765,23 +764,19 @@ void QV8Engine::setExtensionData(int index, Deletable *data)
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());
+
+ return dt.toMSecsSinceEpoch();
+}
+
+QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate)
+{
+ if (qIsNaN(jsDate))
+ return QDateTime();
+
+ return QDateTime::fromMSecsSinceEpoch(jsDate);
}
v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, bool *shouldBeStrong)
@@ -815,24 +810,6 @@ v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, boo
}
}
-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();
-}
-
void QV8Engine::addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle)
{
if (handle.IsEmpty())
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index 2350b9dc2c..ce85725642 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -63,7 +63,7 @@ Q_DECLARE_METATYPE(QQmlV8Handle);
QT_BEGIN_NAMESPACE
-#if defined(__GNUC__)
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
# 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
@@ -269,7 +269,7 @@ static v8::Handle<v8::Value> GenericValueGetter(v8::Local<v8::String>, const v8:
QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(This);
QObject *object = resource->object;
- if (!object) return v8::Undefined();
+ if (QQmlData::wasDeleted(object)) return v8::Undefined();
QQmlPropertyData *property =
(QQmlPropertyData *)v8::External::Unwrap(info.Data());
@@ -476,6 +476,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
objectHandle?*objectHandle:engine->newQObject(object),
v8::Integer::New(index)
};
+ Q_ASSERT(argv[0]->IsObject());
return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 2, argv);
}
static v8::Handle<v8::Value> createWithGlobal(QV8Engine *engine, QObject *object,
@@ -486,10 +487,14 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject
v8::Integer::New(index),
v8::Context::GetCallingQmlGlobal()
};
+ Q_ASSERT(argv[0]->IsObject());
return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 3, argv);
}
};
+ if (QQmlData::wasDeleted(object))
+ return v8::Handle<v8::Value>();
+
{
// Comparing the hash first actually makes a measurable difference here, at least on x86
quint32 hash = property.hash();
@@ -705,6 +710,9 @@ bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QH
engine->qobjectWrapper()->m_destroyString == property)
return true;
+ if (QQmlData::wasDeleted(object))
+ return false;
+
QQmlPropertyData local;
QQmlPropertyData *result = 0;
result = QQmlPropertyCache::property(engine->engine(), object, property, local);
@@ -735,7 +743,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property,
{
QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
- if (resource->object.isNull())
+ if (QQmlData::wasDeleted(resource->object))
return v8::Handle<v8::Value>();
QObject *object = resource->object;
@@ -779,7 +787,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
{
QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
- if (resource->object.isNull())
+ if (QQmlData::wasDeleted(resource->object))
return value;
QObject *object = resource->object;
@@ -873,7 +881,7 @@ static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
{
QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
- if (resource->object.isNull())
+ if (QQmlData::wasDeleted(resource->object))
return;
QObject *object = resource->object;
@@ -900,7 +908,7 @@ static void FastValueSetterReadOnly(v8::Local<v8::String> property, v8::Local<v8
{
QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
- if (resource->object.isNull())
+ if (QQmlData::wasDeleted(resource->object))
return;
QV8Engine *v8engine = resource->engine;
@@ -1080,20 +1088,13 @@ released the handle.
*/
v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
{
- if (!object)
+ if (QQmlData::wasDeleted(object))
return v8::Null();
- if (QObjectPrivate::get(object)->wasDeleted)
- return v8::Null();
-
QQmlData *ddata = QQmlData::get(object, true);
-
if (!ddata)
return v8::Undefined();
- if (ddata->isQueuedForDeletion)
- return v8::Null();
-
if (ddata->v8objectid == m_id && !ddata->v8object.IsEmpty()) {
// We own the v8object
return v8::Local<v8::Object>::New(ddata->v8object);
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
index de492a8ce5..7816c84b79 100644
--- a/src/qml/qml/v8/v8.pri
+++ b/src/qml/qml/v8/v8.pri
@@ -1,5 +1,3 @@
-INCLUDEPATH += $$PWD/../../../3rdparty/javascriptcore
-
include(script.pri)
HEADERS += \
@@ -20,7 +18,6 @@ HEADERS += \
$$PWD/qv8include_p.h \
$$PWD/qv8worker_p.h \
$$PWD/qv8bindings_p.h \
- $$PWD/../../../3rdparty/javascriptcore/DateMath.h \
$$PWD/qv8engine_impl_p.h \
$$PWD/qv8domerrors_p.h \
$$PWD/qv8sqlerrors_p.h \
@@ -39,7 +36,6 @@ SOURCES += \
$$PWD/qv8include.cpp \
$$PWD/qv8worker.cpp \
$$PWD/qv8bindings.cpp \
- $$PWD/../../../3rdparty/javascriptcore/DateMath.cpp \
$$PWD/qv8domerrors.cpp \
$$PWD/qv8sqlerrors.cpp \
- $$PWD/qqmlbuiltinfunctions.cpp \ No newline at end of file
+ $$PWD/qqmlbuiltinfunctions.cpp
diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro
index 6df36d20cb..157cfe97c0 100644
--- a/src/qmltest/qmltest.pro
+++ b/src/qmltest/qmltest.pro
@@ -4,7 +4,7 @@ TARGET = QtQuickTest
QPRO_PWD = $$PWD
CONFIG += module
-CONFIG += dll warn_on
+CONFIG += dll warn_on declarative_debug
MODULE_PRI += ../../modules/qt_qmltest.pri
QT += testlib testlib-private qml quick gui
@@ -33,4 +33,4 @@ HEADERS += \
$$PWD/qtestoptions_p.h
-DEFINES += QT_BUILD_QUICK_TEST_LIB
+DEFINES += QT_BUILD_QUICK_TEST_LIB \ No newline at end of file
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index 1c69cee456..3a2103afb6 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -100,10 +100,10 @@ static inline QString stripQuotes(const QString &s)
return s;
}
-template <class View> void handleCompileErrors(const QFileInfo &fi, const View &view)
+void handleCompileErrors(const QFileInfo &fi, QQuickView *view)
{
// Error compiling the test - flag failure in the log and continue.
- const QList<QQmlError> errors = view.errors();
+ const QList<QQmlError> errors = view->errors();
QuickTestResult results;
results.setTestCaseName(fi.baseName());
results.startLogging();
@@ -125,8 +125,8 @@ template <class View> void handleCompileErrors(const QFileInfo &fi, const View &
str << ": " << e.description() << '\n';
}
str << " Working directory: " << QDir::toNativeSeparators(QDir::current().absolutePath()) << '\n';
- if (QQmlEngine *engine = view.engine()) {
- str << " View: " << view.metaObject()->className() << ", import paths:\n";
+ if (QQmlEngine *engine = view->engine()) {
+ str << " View: " << view->metaObject()->className() << ", import paths:\n";
foreach (const QString &i, engine->importPathList())
str << " '" << QDir::toNativeSeparators(i) << "'\n";
const QStringList pluginPaths = engine->pluginPathList();
@@ -249,17 +249,17 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport
// Scan through all of the "tst_*.qml" files and run each of them
// in turn with a QQuickView.
- QQuickView view;
+ QQuickView *view = new QQuickView;
QTestRootObject rootobj;
QEventLoop eventLoop;
- QObject::connect(view.engine(), SIGNAL(quit()),
+ QObject::connect(view->engine(), SIGNAL(quit()),
&rootobj, SLOT(quit()));
- QObject::connect(view.engine(), SIGNAL(quit()),
+ QObject::connect(view->engine(), SIGNAL(quit()),
&eventLoop, SLOT(quit()));
- view.rootContext()->setContextProperty
+ view->rootContext()->setContextProperty
(QLatin1String("qtest"), &rootobj);
foreach (const QString &path, imports)
- view.engine()->addImportPath(path);
+ view->engine()->addImportPath(path);
foreach (QString file, files) {
QFileInfo fi(file);
@@ -271,13 +271,13 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport
rootobj.hasQuit = false;
QString path = fi.absoluteFilePath();
if (path.startsWith(QLatin1String(":/")))
- view.setSource(QUrl(QLatin1String("qrc:") + path.mid(2)));
+ view->setSource(QUrl(QLatin1String("qrc:") + path.mid(2)));
else
- view.setSource(QUrl::fromLocalFile(path));
+ view->setSource(QUrl::fromLocalFile(path));
if (QTest::printAvailableFunctions)
continue;
- if (view.status() == QQuickView::Error) {
+ if (view->status() == QQuickView::Error) {
handleCompileErrors(fi, view);
continue;
}
@@ -286,8 +286,8 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport
// synchronously during setSource(). Otherwise it is
// an asynchronous test and we need to show the window
// and wait for the quit indication.
- view.show();
- QTest::qWaitForWindowShown(&view);
+ view->show();
+ QTest::qWaitForWindowShown(view);
rootobj.setWindowShown(true);
if (!rootobj.hasQuit && rootobj.hasTestCase())
eventLoop.exec();
@@ -296,10 +296,8 @@ int quick_test_main(int argc, char **argv, const char *name, quick_test_viewport
// Flush the current logging stream.
QuickTestResult::setProgramName(0);
-
- //Sometimes delete app cause crash here with some qpa plugins,
- //so we comment the follow line out to make them happy.
- //delete app;
+ delete view;
+ delete app;
// Return the number of failures as the exit code.
return QuickTestResult::exitCode();
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index a605b9ce6d..6d8d9b852b 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -47,7 +47,6 @@
#include <QtQuick/private/qquickshadereffectsource_p.h>
#include <QtGui/qopenglframebufferobject.h>
-#include <QtCore/qdebug.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquicksvgparser_p.h>
#include <private/qquickpath_p.h>
@@ -185,7 +184,7 @@ QColor qt_color_from_string(v8::Local<v8::Value> name)
if (*p != ')') return QColor();
if (isRgb)
return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
- else
+ else if (isHsl)
return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
}
return QColor();
@@ -484,8 +483,6 @@ static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
CHECK_CONTEXT(r)
r->context->reset();
- r->context->m_path = QPainterPath();
- r->context->m_path.setFillRule(Qt::WindingFill);
return args.This();
}
@@ -551,15 +548,8 @@ static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
- if (args.Length() == 1) {
- qreal angle = args[0]->NumberValue();
- if (!qIsFinite(angle))
- return args.This();
-
- r->context->state.matrix.rotate(DEGREES(angle));
- r->context->buffer()->updateMatrix(r->context->state.matrix);
- }
-
+ if (args.Length() == 1)
+ r->context->rotate(args[0]->NumberValue());
return args.This();
}
@@ -583,17 +573,8 @@ static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
CHECK_CONTEXT(r)
- if (args.Length() == 2) {
- qreal x, y;
- x = args[0]->NumberValue();
- y = args[1]->NumberValue();
- if (!qIsFinite(x) || !qIsFinite(y))
- return args.This();
-
- r->context->state.matrix.scale(x, y);
- r->context->buffer()->updateMatrix(r->context->state.matrix);
- }
-
+ if (args.Length() == 2)
+ r->context->scale(args[0]->NumberValue(), args[1]->NumberValue());
return args.This();
}
@@ -636,25 +617,13 @@ static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
CHECK_CONTEXT(r)
- if (args.Length() == 6) {
- qreal a = args[0]->NumberValue();
- qreal b = args[1]->NumberValue();
- qreal c = args[2]->NumberValue();
- qreal d = args[3]->NumberValue();
- qreal e = args[4]->NumberValue();
- qreal f = args[5]->NumberValue();
-
- if (!qIsFinite(a)
- || !qIsFinite(b)
- || !qIsFinite(c)
- || !qIsFinite(d)
- || !qIsFinite(e)
- || !qIsFinite(f))
- return args.This();
-
- r->context->state.matrix = QTransform(a, b, c, d, e, f);
- r->context->buffer()->updateMatrix(r->context->state.matrix);
- }
+ if (args.Length() == 6)
+ r->context->setTransform( args[0]->NumberValue()
+ , args[1]->NumberValue()
+ , args[2]->NumberValue()
+ , args[3]->NumberValue()
+ , args[4]->NumberValue()
+ , args[5]->NumberValue());
return args.This();
}
@@ -675,25 +644,13 @@ static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
CHECK_CONTEXT(r)
- if (args.Length() == 6) {
- qreal a = args[0]->NumberValue();
- qreal b = args[1]->NumberValue();
- qreal c = args[2]->NumberValue();
- qreal d = args[3]->NumberValue();
- qreal e = args[4]->NumberValue();
- qreal f = args[5]->NumberValue();
-
- if (!qIsFinite(a)
- || !qIsFinite(b)
- || !qIsFinite(c)
- || !qIsFinite(d)
- || !qIsFinite(e)
- || !qIsFinite(f))
- return args.This();
-
- r->context->state.matrix *= QTransform(a, b, c, d, e, f);
- r->context->buffer()->updateMatrix(r->context->state.matrix);
- }
+ if (args.Length() == 6)
+ r->context->transform( args[0]->NumberValue()
+ , args[1]->NumberValue()
+ , args[2]->NumberValue()
+ , args[3]->NumberValue()
+ , args[4]->NumberValue()
+ , args[5]->NumberValue());
return args.This();
}
@@ -713,17 +670,8 @@ static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
CHECK_CONTEXT(r)
- if (args.Length() == 2) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y))
- return args.This();
-
- r->context->state.matrix.translate(x, y);
- r->context->buffer()->updateMatrix(r->context->state.matrix);
- }
-
+ if (args.Length() == 2)
+ r->context->translate(args[0]->NumberValue(), args[1]->NumberValue());
return args.This();
}
@@ -739,8 +687,7 @@ static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
- r->context->state.matrix = QTransform();
- r->context->buffer()->updateMatrix(r->context->state.matrix);
+ r->context->setTransform(1, 0, 0, 1, 0, 0);
return args.This();
}
@@ -755,16 +702,9 @@ static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
- if (args.Length() == 2) {
- qreal sh = args[0]->NumberValue();
- qreal sv = args[1]->NumberValue();
+ if (args.Length() == 2)
+ r->context->shear(args[0]->NumberValue(), args[1]->NumberValue());
- if (!qIsFinite(sh) || !qIsFinite(sv))
- return args.This();
-
- r->context->state.matrix.shear(sh, sv);
- r->context->buffer()->updateMatrix(r->context->state.matrix);
- }
return args.This();
}
// compositing
@@ -1596,17 +1536,11 @@ static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
CHECK_CONTEXT(r)
- if (args.Length() == 4) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- qreal w = args[2]->NumberValue();
- qreal h = args[3]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
- return args.This();
-
- r->context->buffer()->clearRect(x, y, w, h);
- }
+ if (args.Length() == 4)
+ r->context->clearRect(args[0]->NumberValue(),
+ args[1]->NumberValue(),
+ args[2]->NumberValue(),
+ args[3]->NumberValue());
return args.This();
}
@@ -1621,18 +1555,8 @@ static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
- if (args.Length() == 4) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- qreal w = args[2]->NumberValue();
- qreal h = args[3]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
- return args.This();
-
- r->context->buffer()->fillRect(x, y, w, h);
- }
-
+ if (args.Length() == 4)
+ r->context->fillRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
return args.This();
}
@@ -1651,18 +1575,8 @@ static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
-
- if (args.Length() == 4) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- qreal w = args[2]->NumberValue();
- qreal h = args[3]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
- return args.This();
-
- r->context->buffer()->strokeRect(x, y, w, h);
- }
+ if (args.Length() == 4)
+ r->context->strokeRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
return args.This();
}
@@ -1687,15 +1601,8 @@ static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
antiClockwise = args[5]->BooleanValue();
qreal radius = args[2]->NumberValue();
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- qreal sa = args[3]->NumberValue();
- qreal ea = args[4]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(sa) || !qIsFinite(ea))
- return args.This();
- if (radius < 0)
+ if (qIsFinite(radius) && radius < 0)
V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
r->context->arc(args[0]->NumberValue(),
@@ -1734,25 +1641,17 @@ static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
-
-
if (args.Length() == 5) {
- qreal x1 = args[0]->NumberValue();
- qreal y1 = args[1]->NumberValue();
- qreal x2 = args[2]->NumberValue();
- qreal y2 = args[3]->NumberValue();
-
- if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
- return args.This();
-
qreal radius = args[4]->NumberValue();
- if (radius < 0)
+
+ if (qIsFinite(radius) && radius < 0)
V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
+
r->context->arcTo(args[0]->NumberValue(),
args[1]->NumberValue(),
args[2]->NumberValue(),
args[3]->NumberValue(),
- args[4]->NumberValue());
+ radius);
}
return args.This();
@@ -1845,14 +1744,7 @@ static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
- QPainterPath clipPath = r->context->m_path;
- clipPath.closeSubpath();
- if (!r->context->state.clipPath.isEmpty())
- r->context->state.clipPath = clipPath.intersected(r->context->state.clipPath);
- else
- r->context->state.clipPath = clipPath;
- r->context->buffer()->clip(r->context->state.clipPath);
-
+ r->context->clip();
return args.This();
}
@@ -1887,9 +1779,7 @@ static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
{
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r);
-
- r->context->buffer()->fill(r->context->m_path);
-
+ r->context->fill();
return args.This();
}
@@ -1975,19 +1865,8 @@ static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
-
- if (args.Length() == 4) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- qreal w = args[2]->NumberValue();
- qreal h = args[3]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
- return args.This();
-
- r->context->rect(x, y, w, h);
- }
-
+ if (args.Length() == 4)
+ r->context->rect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
return args.This();
}
@@ -2002,23 +1881,13 @@ static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
- if (args.Length() == 6) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- qreal w = args[2]->NumberValue();
- qreal h = args[3]->NumberValue();
- qreal xr = args[4]->NumberValue();
- qreal yr = args[5]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
- return args.This();
-
- if (!qIsFinite(xr) || !qIsFinite(yr))
- V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "roundedRect(): Invalid arguments");
-
- r->context->roundedRect(x, y, w, h, xr, yr);
- }
-
+ if (args.Length() == 6)
+ r->context->roundedRect(args[0]->NumberValue()
+ , args[1]->NumberValue()
+ , args[2]->NumberValue()
+ , args[3]->NumberValue()
+ , args[4]->NumberValue()
+ , args[5]->NumberValue());
return args.This();
}
@@ -2036,18 +1905,8 @@ static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
CHECK_CONTEXT(r)
- if (args.Length() == 4) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- qreal w = args[2]->NumberValue();
- qreal h = args[3]->NumberValue();
-
- if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
- return args.This();
-
-
- r->context->ellipse(x, y, w, h);
- }
+ if (args.Length() == 4)
+ r->context->ellipse(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
return args.This();
}
@@ -2089,9 +1948,7 @@ static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
CHECK_CONTEXT(r)
-
- r->context->buffer()->stroke(r->context->m_path);
-
+ r->context->stroke();
return args.This();
}
@@ -2108,13 +1965,8 @@ static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
CHECK_CONTEXT(r)
bool pointInPath = false;
- if (args.Length() == 2) {
- qreal x = args[0]->NumberValue();
- qreal y = args[1]->NumberValue();
- if (!qIsFinite(x) || !qIsFinite(y))
- return v8::Boolean::New(false);
- pointInPath = r->context->isPointInPath(x, y);
- }
+ if (args.Length() == 2)
+ pointInPath = r->context->isPointInPath(args[0]->NumberValue(), args[1]->NumberValue());
return v8::Boolean::New(pointInPath);
}
@@ -2331,14 +2183,8 @@ static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
CHECK_CONTEXT(r)
QV8Engine *engine = V8ENGINE();
- if (args.Length() == 3) {
- qreal x = args[1]->NumberValue();
- qreal y = args[2]->NumberValue();
- if (!qIsFinite(x) || !qIsFinite(y))
- return args.This();
- QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
- r->context->buffer()->stroke(textPath);
- }
+ if (args.Length() == 3)
+ r->context->drawText(engine->toString(args[0]), args[1]->NumberValue(), args[2]->NumberValue(), false);
return args.This();
}
/*!
@@ -2450,6 +2296,10 @@ static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
if (!args.Length())
return args.This();
+ //FIXME:This function should be moved to QQuickContext2D::drawImage(...)
+ if (!r->context->state.invertibleCTM)
+ return args.This();
+
QImage image;
if (args[0]->IsString()) {
QUrl url(engine->toString(args[0]->ToString()));
@@ -2868,16 +2718,221 @@ static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &ar
return args.This();
}
+void QQuickContext2D::scale(qreal x, qreal y)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y))
+ return;
+
+ QTransform newTransform = state.matrix;
+ newTransform.scale(x, y);
+
+ if (!newTransform.isInvertible()) {
+ state.invertibleCTM = false;
+ return;
+ }
+
+ state.matrix = newTransform;
+ buffer()->updateMatrix(state.matrix);
+ m_path = QTransform().scale(1.0 / x, 1.0 / y).map(m_path);
+}
+
+void QQuickContext2D::rotate(qreal angle)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(angle))
+ return;
+
+ QTransform newTransform =state.matrix;
+ newTransform.rotate(DEGREES(angle));
+
+ if (!newTransform.isInvertible()) {
+ state.invertibleCTM = false;
+ return;
+ }
+
+ state.matrix = newTransform;
+ buffer()->updateMatrix(state.matrix);
+ m_path = QTransform().rotate(-DEGREES(angle)).map(m_path);
+}
+
+void QQuickContext2D::shear(qreal h, qreal v)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(h) || !qIsFinite(v))
+ return ;
+
+ QTransform newTransform = state.matrix;
+ newTransform.shear(h, v);
+
+ if (!newTransform.isInvertible()) {
+ state.invertibleCTM = false;
+ return;
+ }
+
+ state.matrix = newTransform;
+ buffer()->updateMatrix(state.matrix);
+ m_path = QTransform().shear(-h, -v).map(m_path);
+}
+
+void QQuickContext2D::translate(qreal x, qreal y)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y))
+ return ;
+
+ QTransform newTransform = state.matrix;
+ newTransform.translate(x, y);
+
+ if (!newTransform.isInvertible()) {
+ state.invertibleCTM = false;
+ return;
+ }
+
+ state.matrix = newTransform;
+ buffer()->updateMatrix(state.matrix);
+ m_path = QTransform().translate(-x, -y).map(m_path);
+}
+
+void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
+ return;
+
+ QTransform transform(a, b, c, d, e, f);
+ QTransform newTransform = state.matrix * transform;
+
+ if (!newTransform.isInvertible()) {
+ state.invertibleCTM = false;
+ return;
+ }
+ state.matrix = newTransform;
+ buffer()->updateMatrix(state.matrix);
+ m_path = transform.inverted().map(m_path);
+}
+
+void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
+{
+ if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
+ return;
+
+ QTransform ctm = state.matrix;
+ if (!ctm.isInvertible())
+ return;
+
+ state.matrix = ctm.inverted() * state.matrix;
+ m_path = ctm.map(m_path);
+ state.invertibleCTM = true;
+ transform(a, b, c, d, e, f);
+}
+
+void QQuickContext2D::fill()
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!m_path.elementCount())
+ return;
+
+ m_path.setFillRule(state.fillRule);
+ buffer()->fill(m_path);
+}
+
+void QQuickContext2D::clip()
+{
+ if (!state.invertibleCTM)
+ return;
+
+ QPainterPath clipPath = m_path;
+ clipPath.closeSubpath();
+ if (!state.clipPath.isEmpty())
+ state.clipPath = clipPath.intersected(state.clipPath);
+ else
+ state.clipPath = clipPath;
+ buffer()->clip(state.clipPath);
+}
+
+void QQuickContext2D::stroke()
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!m_path.elementCount())
+ return;
+
+ buffer()->stroke(m_path);
+}
+
+void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+ return;
+
+ buffer()->fillRect(x, y, w, h);
+}
+
+void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+ return;
+
+ buffer()->strokeRect(x, y, w, h);
+}
+
+void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+ return;
+
+ buffer()->clearRect(x, y, w, h);
+}
+
+void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
+{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y))
+ return;
+
+ QPainterPath textPath = createTextGlyphs(x, y, text);
+ if (fill)
+ buffer()->fill(textPath);
+ else
+ buffer()->stroke(textPath);
+}
+
void QQuickContext2D::beginPath()
{
+ if (!m_path.elementCount())
+ return;
m_path = QPainterPath();
- m_path.setFillRule(state.fillRule);
}
void QQuickContext2D::closePath()
{
- if (m_path.isEmpty())
+ if (!m_path.elementCount())
return;
QRectF boundRect = m_path.boundingRect();
@@ -2889,29 +2944,53 @@ void QQuickContext2D::closePath()
void QQuickContext2D::moveTo( qreal x, qreal y)
{
+ if (!state.invertibleCTM)
+ return;
+
//FIXME: moveTo should not close the previous subpath
- m_path.moveTo(state.matrix.map(QPointF(x, y)));
+ m_path.moveTo(QPointF(x, y));
}
void QQuickContext2D::lineTo( qreal x, qreal y)
{
- m_path.lineTo(state.matrix.map(QPointF(x, y)));
+ if (!state.invertibleCTM)
+ return;
+
+ QPointF pt(x, y);
+
+ if (!m_path.elementCount())
+ m_path.moveTo(pt);
+ else if (m_path.currentPosition() != pt)
+ m_path.lineTo(pt);
}
void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
qreal x, qreal y)
{
- m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
- state.matrix.map(QPointF(x, y)));
+ if (!state.invertibleCTM)
+ return;
+
+ if (!m_path.elementCount())
+ m_path.moveTo(QPointF(cpx, cpy));
+
+ QPointF pt(x, y);
+ if (m_path.currentPosition() != pt)
+ m_path.quadTo(QPointF(cpx, cpy), pt);
}
void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
qreal cp2x, qreal cp2y,
qreal x, qreal y)
{
- m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
- state.matrix.map(QPointF(cp2x, cp2y)),
- state.matrix.map(QPointF(x, y)));
+ if (!state.invertibleCTM)
+ return;
+
+ if (!m_path.elementCount())
+ m_path.moveTo(QPointF(cp1x, cp1y));
+
+ QPointF pt(x, y);
+ if (m_path.currentPosition() != pt)
+ m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt);
}
void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
@@ -2969,69 +3048,100 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
if ((sa < ea) && ((ea - sa) > Q_PI))
anticlockwise = true;
- arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
+ arc(p.x(), p.y(), radius, sa, ea, anticlockwise);
}
void QQuickContext2D::arcTo(qreal x1, qreal y1,
qreal x2, qreal y2,
qreal radius)
{
- QPointF st = state.matrix.map(QPointF(x1, y1));
- QPointF end = state.matrix.map(QPointF(x2, y2));
+ if (!state.invertibleCTM)
+ return;
- if (!m_path.elementCount()) {
+ if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
+ return;
+
+ QPointF st(x1, y1);
+ QPointF end(x2, y2);
+
+ if (!m_path.elementCount())
m_path.moveTo(st);
- } else if (st == m_path.currentPosition() || st == end || !radius) {
- m_path.lineTo(st);
- } else {
+ else if (st == m_path.currentPosition() || st == end || !radius)
+ lineTo(x1, y1);
+ else
addArcTo(st, end, radius);
- }
-}
+ }
-void QQuickContext2D::rect(qreal x, qreal y,
- qreal w, qreal h)
+void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h)
{
- m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
+ if (!state.invertibleCTM)
+ return;
+ if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+ return;
+
+ if (!w && !h) {
+ m_path.moveTo(x, y);
+ return;
+ }
+ m_path.addRect(x, y, w, h);
}
void QQuickContext2D::roundedRect(qreal x, qreal y,
qreal w, qreal h,
qreal xr, qreal yr)
{
- QPainterPath path;
- path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
- m_path.addPath(state.matrix.map(path));
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr))
+ return;
+
+ if (!w && !h) {
+ m_path.moveTo(x, y);
+ return;
+ }
+ m_path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
}
void QQuickContext2D::ellipse(qreal x, qreal y,
qreal w, qreal h)
{
- QPainterPath path;
- path.addEllipse(x, y, w, h);
- m_path.addPath(state.matrix.map(path));
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+ return;
+
+ if (!w && !h) {
+ m_path.moveTo(x, y);
+ return;
+ }
+
+ m_path.addEllipse(x, y, w, h);
}
void QQuickContext2D::text(const QString& str, qreal x, qreal y)
{
+ if (!state.invertibleCTM)
+ return;
+
QPainterPath path;
path.addText(x, y, state.font, str);
- m_path.addPath(state.matrix.map(path));
+ m_path.addPath(path);
}
-void QQuickContext2D::arc(qreal xc,
- qreal yc,
- qreal radius,
- qreal sar,
- qreal ear,
- bool antiClockWise,
- bool transform)
+void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear, bool antiClockWise)
{
+ if (!state.invertibleCTM)
+ return;
+
+ if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius))
+ return;
+
+ if (sar == ear)
+ return;
+
- if (transform) {
- QPointF point = state.matrix.map(QPointF(xc, yc));
- xc = point.x();
- yc = point.y();
- }
//### HACK
// In Qt we don't switch the coordinate system for degrees
@@ -3068,17 +3178,14 @@ void QQuickContext2D::arc(qreal xc,
qFuzzyCompare(qAbs(span), 360))) {
span += ea - sa;
}
- if (!m_path.elementCount())
- m_path.moveTo(xs, ys);
}
-
- if (transform) {
- QPointF currentPos = m_path.currentPosition();
- QPointF startPos = QPointF(xc + radius * qCos(sar),
- yc - radius * qSin(sar));
- if (currentPos != startPos)
- m_path.lineTo(startPos);
+ // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
+ if (!m_path.elementCount())
+ m_path.arcMoveTo(xs, ys, width, height, sa);
+ else if (!radius) {
+ m_path.lineTo(xc, yc);
+ return;
}
m_path.arcTo(xs, ys, width, height, sa, span);
@@ -3142,9 +3249,59 @@ QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString&
}
+static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
+{
+ // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
+ return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
+}
+
+static inline bool withinRange(qreal p, qreal a, qreal b)
+{
+ return (p >= a && p <= b) || (p >= b && p <= a);
+}
+
bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
{
- return m_path.contains(QPointF(x, y));
+ if (!state.invertibleCTM)
+ return false;
+
+ if (!m_path.elementCount())
+ return false;
+
+ if (!qIsFinite(x) || !qIsFinite(y))
+ return false;
+
+ QPointF point(x, y);
+ QTransform ctm = state.matrix;
+ QPointF p = ctm.inverted().map(point);
+ if (!qIsFinite(p.x()) || !qIsFinite(p.y()))
+ return false;
+
+ const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule);
+
+ bool contains = m_path.contains(p);
+
+ if (!contains) {
+ // check whether the point is on the border
+ QPolygonF border = m_path.toFillPolygon();
+
+ QPointF p1 = border.at(0);
+ QPointF p2;
+
+ for (int i = 1; i < border.size(); ++i) {
+ p2 = border.at(i);
+ if (areCollinear(p, p1, p2)
+ // Once we know that the points are collinear we
+ // only need to check one of the coordinates
+ && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
+ withinRange(p.x(), p1.x(), p2.x()) :
+ withinRange(p.y(), p1.y(), p2.y()))) {
+ return true;
+ }
+ p1 = p2;
+ }
+ }
+ return contains;
}
QQuickContext2D::QQuickContext2D(QObject *parent)
@@ -3405,7 +3562,9 @@ void QQuickContext2D::popState()
if (newState.shadowOffsetY != state.shadowOffsetY)
buffer()->setShadowOffsetY(newState.shadowOffsetY);
+ m_path = state.matrix.map(m_path);
state = newState;
+ m_path = state.matrix.inverted().map(m_path);
}
void QQuickContext2D::pushState()
{
@@ -3417,6 +3576,8 @@ void QQuickContext2D::reset()
QQuickContext2D::State newState;
newState.matrix = QTransform();
+ m_path = QPainterPath();
+
QPainterPath defaultClipPath;
QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
@@ -3431,6 +3592,7 @@ void QQuickContext2D::reset()
newState.fillPatternRepeatY = false;
newState.strokePatternRepeatX = false;
newState.strokePatternRepeatY = false;
+ newState.invertibleCTM = true;
newState.fillRule = Qt::WindingFill;
newState.globalAlpha = 1.0;
newState.lineWidth = 1;
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 3230881134..4112d4ebf0 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -116,6 +116,7 @@ public:
, fillPatternRepeatY(false)
, strokePatternRepeatX(false)
, strokePatternRepeatY(false)
+ , invertibleCTM(true)
, fillRule(Qt::WindingFill)
, globalAlpha(1.0)
, lineWidth(1)
@@ -141,6 +142,7 @@ public:
bool fillPatternRepeatY:1;
bool strokePatternRepeatX:1;
bool strokePatternRepeatY:1;
+ bool invertibleCTM:1;
Qt::FillRule fillRule;
qreal globalAlpha;
qreal lineWidth;
@@ -180,7 +182,23 @@ public:
void pushState();
void reset();
- // path API
+ void fill();
+ void clip();
+ void stroke();
+ void fillRect(qreal x, qreal y, qreal w, qreal h);
+ void strokeRect(qreal x, qreal y, qreal w, qreal h);
+ void clearRect(qreal x, qreal y, qreal w, qreal h);
+ void drawText(const QString& text, qreal x, qreal y, bool fill);
+
+ //Transform APIs
+ void scale(qreal x, qreal y);
+ void rotate(qreal angle);
+ void shear(qreal h, qreal v);
+ void translate(qreal x, qreal y);
+ void transform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f);
+ void setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f);
+
+ // Path APIs
void beginPath();
void closePath();
void moveTo(qreal x, qreal y);
@@ -195,7 +213,7 @@ public:
void text(const QString& str, qreal x, qreal y);
void arc(qreal x, qreal y, qreal radius,
qreal startAngle, qreal endAngle,
- bool anticlockwise, bool transform=true);
+ bool anticlockwise);
void addArcTo(const QPointF& p1, const QPointF& p2, float radius);
bool isPointInPath(qreal x, qreal y) const;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 591fc216a4..f6b9a1afeb 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -236,7 +236,7 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
reset();
- QTransform originMatrix = p->transform();
+ QTransform originMatrix = p->worldTransform();
QPen pen = makePen(state);
setPainterState(p, state, pen);
@@ -247,7 +247,7 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
case QQuickContext2D::UpdateMatrix:
{
state.matrix = takeMatrix();
- p->setTransform(state.matrix * originMatrix);
+ p->setWorldTransform(state.matrix * originMatrix);
break;
}
case QQuickContext2D::ClearRect:
@@ -303,36 +303,42 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
state.strokeStyle = takeStrokeStyle();
state.strokePatternRepeatX = takeBool();
state.strokePatternRepeatY = takeBool();
- pen.setBrush(state.strokeStyle);
- p->setPen(pen);
+ QPen nPen = p->pen();
+ nPen.setBrush(state.strokeStyle);
+ p->setPen(nPen);
break;
}
case QQuickContext2D::LineWidth:
{
state.lineWidth = takeLineWidth();
- pen.setWidth(state.lineWidth);
- p->setPen(pen);
+ QPen nPen = p->pen();
+
+ nPen.setWidthF(state.lineWidth);
+ p->setPen(nPen);
break;
}
case QQuickContext2D::LineCap:
{
state.lineCap = takeLineCap();
- pen.setCapStyle(state.lineCap);
- p->setPen(pen);
+ QPen nPen = p->pen();
+ nPen.setCapStyle(state.lineCap);
+ p->setPen(nPen);
break;
}
case QQuickContext2D::LineJoin:
{
state.lineJoin = takeLineJoin();
- pen.setJoinStyle(state.lineJoin);
- p->setPen(pen);
+ QPen nPen = p->pen();
+ nPen.setJoinStyle(state.lineJoin);
+ p->setPen(nPen);
break;
}
case QQuickContext2D::MiterLimit:
{
state.miterLimit = takeMiterLimit();
- pen.setMiterLimit(state.miterLimit);
- p->setPen(pen);
+ QPen nPen = p->pen();
+ nPen.setMiterLimit(state.miterLimit);
+ p->setPen(nPen);
break;
}
case QQuickContext2D::TextAlign:
diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp
index 2e2c8725aa..3f08c8f056 100644
--- a/src/quick/items/qquickcanvas.cpp
+++ b/src/quick/items/qquickcanvas.cpp
@@ -55,7 +55,6 @@
#include <private/qguiapplication_p.h>
#include <QtGui/QInputMethod>
-#include <QtGui/QCursor>
#include <private/qabstractanimation_p.h>
@@ -123,10 +122,12 @@ private:
bool m_eventSent;
};
+#ifndef QT_NO_ACCESSIBILITY
QAccessibleInterface *QQuickCanvas::accessibleRoot() const
{
return QAccessible::queryAccessibleInterface(const_cast<QQuickCanvas*>(this));
}
+#endif
/*
@@ -154,6 +155,10 @@ have a scope focused item), and the other items will have their focus cleared.
// #define TOUCH_DEBUG
// #define DIRTY_DEBUG
+#ifdef FOCUS_DEBUG
+void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
+#endif
+
QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
: transformNode(0)
{
@@ -952,7 +957,7 @@ bool QQuickCanvasPrivate::clearHover()
if (hoverItems.isEmpty())
return false;
- QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
+ QPointF pos = QGuiApplicationPrivate::lastCursorPosition;; // ### refactor: q->mapFromGlobal(QCursor::pos());
bool accepted = false;
foreach (QQuickItem* item, hoverItems)
@@ -1087,8 +1092,12 @@ bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
QQuickMouseEventEx me(event->type(), transform.map(event->windowPos()),
event->windowPos(), event->screenPos(),
event->button(), event->buttons(), event->modifiers());
- if (QQuickMouseEventEx::extended(event))
- me.setVelocity(QQuickMouseEventEx::extended(event)->velocity());
+ QQuickMouseEventEx *eventEx = QQuickMouseEventEx::extended(event);
+ if (eventEx) {
+ me.setVelocity(eventEx->velocity());
+ me.setCapabilities(eventEx->capabilities());
+ }
+ me.setTimestamp(event->timestamp());
me.accept();
q->sendEvent(mouseGrabberItem, &me);
event->setAccepted(me.isAccepted());
diff --git a/src/quick/items/qquickcanvas.h b/src/quick/items/qquickcanvas.h
index 787bb7e3c7..396bc2b8ff 100644
--- a/src/quick/items/qquickcanvas.h
+++ b/src/quick/items/qquickcanvas.h
@@ -102,7 +102,9 @@ public:
QQmlIncubationController *incubationController() const;
+#ifndef QT_NO_ACCESSIBILITY
virtual QAccessibleInterface *accessibleRoot() const;
+#endif
// Scene graph specific functions
QSGTexture *createTextureFromImage(const QImage &image) const;
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 62d0e4aa41..75c9919e34 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -1108,7 +1108,8 @@ void QQuickFlickable::mouseReleaseEvent(QMouseEvent *event)
d->clearDelayedPress();
d->handleMouseReleaseEvent(event);
event->accept();
- ungrabMouse();
+ if (canvas() && canvas()->mouseGrabberItem() == this)
+ ungrabMouse();
} else {
QQuickItem::mouseReleaseEvent(event);
}
diff --git a/src/quick/items/qquickimplicitsizeitem.cpp b/src/quick/items/qquickimplicitsizeitem.cpp
index 427be42312..1de8e0ab73 100644
--- a/src/quick/items/qquickimplicitsizeitem.cpp
+++ b/src/quick/items/qquickimplicitsizeitem.cpp
@@ -47,12 +47,24 @@ QT_BEGIN_NAMESPACE
void QQuickImplicitSizeItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickImplicitSizeItem);
+ for (int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QQuickItemPrivate::ImplicitWidth) {
+ change.listener->itemImplicitWidthChanged(q);
+ }
+ }
emit q->implicitWidthChanged();
}
void QQuickImplicitSizeItemPrivate::implicitHeightChanged()
{
Q_Q(QQuickImplicitSizeItem);
+ for (int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QQuickItemPrivate::ImplicitHeight) {
+ change.listener->itemImplicitHeightChanged(q);
+ }
+ }
emit q->implicitHeightChanged();
}
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 1cf10df2f7..ffaec540a2 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -52,8 +52,8 @@
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlinfo.h>
#include <QtGui/qpen.h>
-#include <QtGui/qcursor.h>
#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qinputmethod.h>
#include <QtCore/qdebug.h>
#include <QtCore/qcoreevent.h>
@@ -75,6 +75,26 @@
QT_BEGIN_NAMESPACE
+#ifdef FOCUS_DEBUG
+void printFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1);
+void printFocusTree(QQuickItem *item, QQuickItem *scope, int depth)
+{
+ qWarning()
+ << QByteArray(depth, '\t').constData()
+ << (scope && QQuickItemPrivate::get(scope)->subFocusItem == item ? '*' : ' ')
+ << item->hasFocus()
+ << item->hasActiveFocus()
+ << item->isFocusScope()
+ << item;
+ foreach (QQuickItem *child, item->childItems()) {
+ printFocusTree(
+ child,
+ item->isFocusScope() || !scope ? item : scope,
+ item->isFocusScope() || !scope ? depth + 1 : depth);
+ }
+}
+#endif
+
static void QQuickItem_parentNotifier(QObject *o, intptr_t, QQmlNotifier **n)
{
QQuickItemPrivate *d = QQuickItemPrivate::get(static_cast<QQuickItem *>(o));
@@ -1613,9 +1633,6 @@ void QQuickItemPrivate::setAccessibleFlagAndListener()
if (item->d_func()->isAccessible)
break; // already set - grandparents should have the flag set as well.
- if (item->canvas() && item->canvas()->rootItem() == item)
- break; // don't add a listener to the canvas root item
-
item->d_func()->isAccessible = true;
item = item->d_func()->parentItem;
}
@@ -1939,6 +1956,8 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
if (d->canvas) {
QQuickCanvasPrivate::get(d->canvas)->clearFocusInScope(scopeItem, scopeFocusedItem,
QQuickCanvasPrivate::DontChangeFocusProperty);
+ if (scopeFocusedItem != this)
+ QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(this, true);
} else {
QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(scopeItem, false);
}
@@ -1990,7 +2009,10 @@ void QQuickItem::setParentItem(QQuickItem *parentItem)
while (!scopeItem->isFocusScope() && scopeItem->parentItem())
scopeItem = scopeItem->parentItem();
- if (scopeItem->scopedFocusItem()) {
+ if (QQuickItemPrivate::get(scopeItem)->subFocusItem
+ || (!scopeItem->isFocusScope() && scopeItem->hasFocus())) {
+ if (scopeFocusedItem != this)
+ QQuickItemPrivate::get(scopeFocusedItem)->updateSubFocusItem(this, false);
QQuickItemPrivate::get(scopeFocusedItem)->focus = false;
emit scopeFocusedItem->focusChanged(false);
} else {
@@ -4145,7 +4167,7 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
for (int ii = 0; ii < childItems.count(); ++ii) {
QQuickItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur(
- flags & QQuickItem::ItemIsFocusScope ? q : scope, newEffectiveEnable);
+ (flags & QQuickItem::ItemIsFocusScope) && scope ? q : scope, newEffectiveEnable);
}
if (canvas && scope && effectiveEnable && focus) {
@@ -4509,6 +4531,12 @@ void QQuickItem::resetWidth()
void QQuickItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickItem);
+ for (int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QQuickItemPrivate::ImplicitWidth) {
+ change.listener->itemImplicitWidthChanged(q);
+ }
+ }
emit q->implicitWidthChanged();
}
@@ -4631,6 +4659,12 @@ void QQuickItem::resetHeight()
void QQuickItemPrivate::implicitHeightChanged()
{
Q_Q(QQuickItem);
+ for (int ii = 0; ii < changeListeners.count(); ++ii) {
+ const QQuickItemPrivate::ChangeListener &change = changeListeners.at(ii);
+ if (change.types & QQuickItemPrivate::ImplicitHeight) {
+ change.listener->itemImplicitHeightChanged(q);
+ }
+ }
emit q->implicitHeightChanged();
}
@@ -4781,6 +4815,7 @@ void QQuickItem::setFocus(bool focus)
QVarLengthArray<QQuickItem *, 20> changed;
QQuickItem *oldSubFocusItem = QQuickItemPrivate::get(scope)->subFocusItem;
if (oldSubFocusItem) {
+ QQuickItemPrivate::get(oldSubFocusItem)->updateSubFocusItem(scope, false);
QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
changed << oldSubFocusItem;
}
@@ -4850,7 +4885,7 @@ bool QQuickItem::isUnderMouse() const
if (!d->canvas)
return false;
- QPoint cursorPos = QCursor::pos();
+ QPointF cursorPos = QGuiApplicationPrivate::lastCursorPosition;
if (QRectF(0, 0, width(), height()).contains(mapFromScene(cursorPos))) // ### refactor: d->canvas->mapFromGlobal(cursorPos))))
return true;
return false;
@@ -5669,10 +5704,11 @@ void QQuickItemLayer::activateEffect()
Q_ASSERT(m_effectComponent);
Q_ASSERT(!m_effect);
- QObject *created = m_effectComponent->create();
+ QObject *created = m_effectComponent->beginCreate(m_effectComponent->creationContext());
m_effect = qobject_cast<QQuickItem *>(created);
if (!m_effect) {
qWarning("Item: layer.effect is not a QML Item.");
+ m_effectComponent->completeCreate();
delete created;
return;
}
@@ -5683,6 +5719,7 @@ void QQuickItemLayer::activateEffect()
}
m_effect->setVisible(m_item->isVisible());
m_effect->setProperty(m_name, qVariantFromValue<QObject *>(m_effectSource));
+ m_effectComponent->completeCreate();
}
void QQuickItemLayer::deactivateEffect()
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 01e8b4d335..89c09ed015 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -302,6 +302,8 @@ public:
Parent = 0x20,
Children = 0x40,
Rotation = 0x80,
+ ImplicitWidth = 0x100,
+ ImplicitHeight = 0x200
};
Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
diff --git a/src/quick/items/qquickitemchangelistener_p.h b/src/quick/items/qquickitemchangelistener_p.h
index 3a5c25f5f5..cbdfb2b18b 100644
--- a/src/quick/items/qquickitemchangelistener_p.h
+++ b/src/quick/items/qquickitemchangelistener_p.h
@@ -74,6 +74,8 @@ public:
virtual void itemChildRemoved(QQuickItem *, QQuickItem *) {}
virtual void itemParentChanged(QQuickItem *, QQuickItem *) {}
virtual void itemRotationChanged(QQuickItem *) {}
+ virtual void itemImplicitWidthChanged(QQuickItem *) {}
+ virtual void itemImplicitHeightChanged(QQuickItem *) {}
virtual QQuickAnchorsPrivate *anchorPrivate() { return 0; }
};
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 6f33545185..1cc2637fe6 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -577,7 +577,7 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
if (sectionCriteria && sectionCriteria->delegate()) {
- if (item->attached->m_prevSection != item->attached->m_section)
+ if (QString::compare(item->attached->m_prevSection, item->attached->m_section, Qt::CaseInsensitive))
updateInlineSection(static_cast<FxListItemSG*>(item));
}
}
@@ -962,7 +962,7 @@ void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
{
if (!sectionCriteria || !sectionCriteria->delegate())
return;
- if (listItem->attached->m_prevSection != listItem->attached->m_section
+ if (QString::compare(listItem->attached->m_prevSection, listItem->attached->m_section, Qt::CaseInsensitive)
&& (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels
|| (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) {
if (!listItem->section()) {
@@ -1022,7 +1022,7 @@ void QQuickListViewPrivate::updateStickySections()
if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.count()) {
if (!currentSectionItem) {
currentSectionItem = getSectionItem(currentSection);
- } else if (currentStickySection != currentSection) {
+ } else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
context->setContextProperty(QLatin1String("section"), currentSection);
}
@@ -1055,7 +1055,7 @@ void QQuickListViewPrivate::updateStickySections()
if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.count()) {
if (!nextSectionItem) {
nextSectionItem = getSectionItem(nextSection);
- } else if (nextStickySection != nextSection) {
+ } else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
context->setContextProperty(QLatin1String("section"), nextSection);
}
@@ -2040,6 +2040,9 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
sections, etc. for an address book)
\endlist
+ A case insensitive comparison is used when determining section
+ boundaries.
+
\c section.delegate holds the delegate component for each section.
\c section.labelPositioning determines whether the current and/or
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index f41ba44943..864e03bf43 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -52,9 +52,11 @@
QT_BEGIN_NAMESPACE
+static const QQuickItemPrivate::ChangeTypes watchedChanges
+ = QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+
QQuickLoaderPrivate::QQuickLoaderPrivate()
: item(0), component(0), itemContext(0), incubator(0), updatingSize(false),
- itemWidthValid(false), itemHeightValid(false),
active(true), loadingFromSource(false), asynchronous(false)
{
}
@@ -69,16 +71,23 @@ QQuickLoaderPrivate::~QQuickLoaderPrivate()
void QQuickLoaderPrivate::itemGeometryChanged(QQuickItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry)
{
- if (resizeItem == item) {
- if (!updatingSize && newGeometry.width() != oldGeometry.width())
- itemWidthValid = true;
- if (!updatingSize && newGeometry.height() != oldGeometry.height())
- itemHeightValid = true;
+ if (resizeItem == item)
_q_updateSize(false);
- }
QQuickItemChangeListener::itemGeometryChanged(resizeItem, newGeometry, oldGeometry);
}
+void QQuickLoaderPrivate::itemImplicitWidthChanged(QQuickItem *)
+{
+ Q_Q(QQuickLoader);
+ q->setImplicitWidth(getImplicitWidth());
+}
+
+void QQuickLoaderPrivate::itemImplicitHeightChanged(QQuickItem *)
+{
+ Q_Q(QQuickLoader);
+ q->setImplicitHeight(getImplicitHeight());
+}
+
void QQuickLoaderPrivate::clear()
{
Q_Q(QQuickLoader);
@@ -103,7 +112,7 @@ void QQuickLoaderPrivate::clear()
if (item) {
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ p->removeItemChangeListener(this, watchedChanges);
// We can't delete immediately because our item may have triggered
// the Loader to load a different item.
@@ -117,14 +126,32 @@ void QQuickLoaderPrivate::clear()
void QQuickLoaderPrivate::initResize()
{
QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->addItemChangeListener(this, QQuickItemPrivate::Geometry);
- // We may override the item's size, so we need to remember
- // whether the item provided its own valid size.
- itemWidthValid = p->widthValid;
- itemHeightValid = p->heightValid;
+ p->addItemChangeListener(this, watchedChanges);
_q_updateSize();
}
+qreal QQuickLoaderPrivate::getImplicitWidth() const
+{
+ Q_Q(const QQuickLoader);
+ // If the Loader has a valid width then Loader has set an explicit width on the
+ // item, and we want the item's implicitWidth. If the Loader's width has
+ // not been set then its implicitWidth is the width of the item.
+ if (item)
+ return q->widthValid() ? item->implicitWidth() : item->width();
+ return QQuickImplicitSizeItemPrivate::getImplicitWidth();
+}
+
+qreal QQuickLoaderPrivate::getImplicitHeight() const
+{
+ Q_Q(const QQuickLoader);
+ // If the Loader has a valid height then Loader has set an explicit height on the
+ // item, and we want the item's implicitHeight. If the Loader's height has
+ // not been set then its implicitHeight is the height of the item.
+ if (item)
+ return q->heightValid() ? item->implicitHeight() : item->height();
+ return QQuickImplicitSizeItemPrivate::getImplicitHeight();
+}
+
/*!
\qmlclass Loader QQuickLoader
\inqmlmodule QtQuick 2
@@ -245,7 +272,7 @@ QQuickLoader::~QQuickLoader()
Q_D(QQuickLoader);
if (d->item) {
QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
- p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
+ p->removeItemChangeListener(d, watchedChanges);
}
}
@@ -282,9 +309,16 @@ void QQuickLoader::setActive(bool newVal)
loadFromSourceComponent();
}
} else {
+ // cancel any current incubation
+ if (d->incubator) {
+ d->incubator->clear();
+ delete d->itemContext;
+ d->itemContext = 0;
+ }
+
if (d->item) {
QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
- p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
+ p->removeItemChangeListener(d, watchedChanges);
// We can't delete immediately because our item may have triggered
// the Loader to load a different item.
@@ -553,6 +587,14 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj)
QQuickItem *item = qobject_cast<QQuickItem*>(obj);
if (item) {
+ // If the item doesn't have an explicit size, but the Loader
+ // does, then set the item's size now before bindings are
+ // evaluated, otherwise we will end up resizing the item
+ // later and triggering any affected bindings/anchors.
+ if (widthValid && !QQuickItemPrivate::get(item)->widthValid)
+ item->setWidth(q->width());
+ if (heightValid && !QQuickItemPrivate::get(item)->heightValid)
+ item->setHeight(q->height());
QQml_setParent_noEvent(itemContext, obj);
QQml_setParent_noEvent(item, q);
item->setParentItem(q);
@@ -607,7 +649,8 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status)
emit q->sourceComponentChanged();
emit q->statusChanged();
emit q->progressChanged();
- emit q->loaded();
+ if (status == QQmlIncubator::Ready)
+ emit q->loaded();
disposeInitialPropertyValues(); // cleanup
}
@@ -812,15 +855,13 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
updatingSize = true;
- qreal iWidth = !itemWidthValid ? item->implicitWidth() : item->width();
- qreal iHeight = !itemHeightValid ? item->implicitHeight() : item->height();
- q->setImplicitSize(iWidth, iHeight);
-
if (loaderGeometryChanged && q->widthValid())
item->setWidth(q->width());
if (loaderGeometryChanged && q->heightValid())
item->setHeight(q->height());
+ q->setImplicitSize(getImplicitWidth(), getImplicitHeight());
+
updatingSize = false;
}
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 1ad7756ed8..0978911315 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -87,6 +87,8 @@ public:
~QQuickLoaderPrivate();
void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
+ void itemImplicitWidthChanged(QQuickItem *);
+ void itemImplicitHeightChanged(QQuickItem *);
void clear();
void initResize();
void load();
@@ -97,6 +99,9 @@ public:
QUrl resolveSourceUrl(QQmlV8Function *args);
v8::Handle<v8::Object> extractInitialPropertyValues(QQmlV8Function *args, QObject *loader, bool *error);
+ virtual qreal getImplicitWidth() const;
+ virtual qreal getImplicitHeight() const;
+
QUrl source;
QQuickItem *item;
QQmlComponent *component;
@@ -105,8 +110,6 @@ public:
v8::Persistent<v8::Object> initialPropertyValues;
v8::Persistent<v8::Object> qmlGlobalForIpv;
bool updatingSize: 1;
- bool itemWidthValid : 1;
- bool itemHeightValid : 1;
bool active : 1;
bool loadingFromSource : 1;
bool asynchronous : 1;
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 110cc6ad7a..2ba7b80748 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -236,7 +236,7 @@ void QQuickTouchPoint::setSceneY(qreal sceneY)
\list
\li setting \c touchPoints to provide touch point objects with properties that can be bound to
- \li using the onTouchUpdated or onTouchPointsPressed, onTouchPointsUpdated and onTouchPointsReleased handlers
+ \li using the onTouchUpdated or onPressed, onUpdated and onReleased handlers
\endlist
While a MultiPointTouchArea \e can take exclusive ownership of certain touch points, it is also possible to have
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 962dddafc9..836943c478 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -58,13 +58,13 @@
// The number of samples to use in calculating the velocity of a flick
#ifndef QML_FLICK_SAMPLEBUFFER
-#define QML_FLICK_SAMPLEBUFFER 3
+#define QML_FLICK_SAMPLEBUFFER 1
#endif
// The number of samples to discard when calculating the flick velocity.
// Touch panels often produce inaccurate results as the finger is lifted.
#ifndef QML_FLICK_DISCARDSAMPLES
-#define QML_FLICK_DISCARDSAMPLES 1
+#define QML_FLICK_DISCARDSAMPLES 0
#endif
// The default maximum velocity of a flick.
@@ -114,8 +114,8 @@ void QQuickPathViewAttached::setValue(const QByteArray &name, const QVariant &va
}
QQuickPathViewPrivate::QQuickPathViewPrivate()
- : path(0), currentIndex(0), currentItemOffset(0.0), startPc(0), lastDist(0)
- , lastElapsed(0), offset(0.0), offsetAdj(0.0), mappedRange(1.0)
+ : path(0), currentIndex(0), currentItemOffset(0.0), startPc(0)
+ , offset(0.0), offsetAdj(0.0), mappedRange(1.0)
, stealMouse(false), ownModel(false), interactive(true), haveHighlightRange(true)
, autoHighlight(true), highlightUp(false), layoutScheduled(false)
, moving(false), flicking(false), requestedOnPath(false), inRequest(false)
@@ -127,7 +127,7 @@ QQuickPathViewPrivate::QQuickPathViewPrivate()
, highlightPosition(0)
, highlightRangeStart(0), highlightRangeEnd(0)
, highlightRangeMode(QQuickPathView::StrictlyEnforceRange)
- , highlightMoveDuration(300), modelCount(0)
+ , highlightMoveDuration(300), modelCount(0), snapMode(QQuickPathView::NoSnap)
{
}
@@ -139,7 +139,7 @@ void QQuickPathViewPrivate::init()
q->setFlag(QQuickItem::ItemIsFocusScope);
q->setFiltersChildMouseEvents(true);
FAST_CONNECT(&tl, SIGNAL(updated()), q, SLOT(ticked()))
- lastPosTime.invalidate();
+ timer.invalidate();
FAST_CONNECT(&tl, SIGNAL(completed()), q, SLOT(movementEnding()))
}
@@ -266,7 +266,8 @@ qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const
if (model && index >= 0 && index < modelCount) {
qreal start = 0.0;
- if (haveHighlightRange && highlightRangeMode != QQuickPathView::NoHighlightRange)
+ if (haveHighlightRange && (highlightRangeMode != QQuickPathView::NoHighlightRange
+ || snapMode != QQuickPathView::NoSnap))
start = highlightRangeStart;
qreal globalPos = index + offset;
globalPos = qmlMod(globalPos, qreal(modelCount)) / modelCount;
@@ -698,7 +699,7 @@ void QQuickPathView::setCurrentIndex(int idx)
if (d->modelCount) {
d->createCurrentItem();
if (d->haveHighlightRange && d->highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
- d->snapToCurrent();
+ d->snapToIndex(d->currentIndex);
d->currentItemOffset = d->positionOfIndex(d->currentIndex);
d->updateHighlight();
}
@@ -889,7 +890,7 @@ void QQuickPathView::setPreferredHighlightBegin(qreal start)
if (d->highlightRangeStart == start || start < 0 || start > 1.0)
return;
d->highlightRangeStart = start;
- d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
refill();
emit preferredHighlightBeginChanged();
}
@@ -906,7 +907,7 @@ void QQuickPathView::setPreferredHighlightEnd(qreal end)
if (d->highlightRangeEnd == end || end < 0 || end > 1.0)
return;
d->highlightRangeEnd = end;
- d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
refill();
emit preferredHighlightEndChanged();
}
@@ -923,10 +924,12 @@ void QQuickPathView::setHighlightRangeMode(HighlightRangeMode mode)
if (d->highlightRangeMode == mode)
return;
d->highlightRangeMode = mode;
- d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ d->haveHighlightRange = d->highlightRangeStart <= d->highlightRangeEnd;
if (d->haveHighlightRange) {
d->regenerate();
- d->snapToCurrent();
+ int index = d->highlightRangeMode != NoHighlightRange ? d->currentIndex : d->calcCurrentIndex();
+ if (index >= 0)
+ d->snapToIndex(index);
}
emit highlightRangeModeChanged();
}
@@ -1175,6 +1178,41 @@ void QQuickPathView::setPathItemCount(int i)
emit pathItemCountChanged();
}
+/*!
+ \qmlproperty enumeration QtQuick2::PathView::snapMode
+
+ This property determines how the items will settle following a drag or flick.
+ The possible values are:
+
+ \list
+ \li PathView.NoSnap (default) - the items stop anywhere along the path.
+ \li PathView.SnapToItem - the items settle with an item aligned with the \l preferredHighlightBegin.
+ \li PathView.SnapOneItem - the items settle no more than one item away from the item nearest
+ \l preferredHighlightBegin at the time the press is released. This mode is particularly
+ useful for moving one page at a time.
+ \endlist
+
+ \c snapMode does not affect the \l currentIndex. To update the
+ \l currentIndex as the view is moved, set \l highlightRangeMode
+ to \c PathView.StrictlyEnforceRange (default for PathView).
+
+ \sa highlightRangeMode
+*/
+QQuickPathView::SnapMode QQuickPathView::snapMode() const
+{
+ Q_D(const QQuickPathView);
+ return d->snapMode;
+}
+
+void QQuickPathView::setSnapMode(SnapMode mode)
+{
+ Q_D(QQuickPathView);
+ if (mode == d->snapMode)
+ return;
+ d->snapMode = mode;
+ emit snapModeChanged();
+}
+
QPointF QQuickPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
{
qreal samples = qMin(path->path().length()/5, qreal(500.0));
@@ -1236,6 +1274,15 @@ qreal QQuickPathViewPrivate::calcVelocity() const
return velocity;
}
+qint64 QQuickPathViewPrivate::computeCurrentTime(QInputEvent *event)
+{
+ if (0 != event->timestamp() && QQuickItemPrivate::consistentTime == -1) {
+ return event->timestamp();
+ }
+
+ return QQuickItemPrivate::elapsed(timer);
+}
+
void QQuickPathView::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickPathView);
@@ -1277,9 +1324,8 @@ void QQuickPathViewPrivate::handleMousePressEvent(QMouseEvent *event)
else
stealMouse = false;
- lastElapsed = 0;
- lastDist = 0;
- QQuickItemPrivate::start(lastPosTime);
+ QQuickItemPrivate::start(timer);
+ lastPosTime = computeCurrentTime(event);
tl.clear();
}
@@ -1299,7 +1345,7 @@ void QQuickPathView::mouseMoveEvent(QMouseEvent *event)
void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event)
{
Q_Q(QQuickPathView);
- if (!interactive || !lastPosTime.isValid() || !model || !modelCount)
+ if (!interactive || !timer.isValid() || !model || !modelCount)
return;
qreal newPc;
@@ -1308,10 +1354,10 @@ void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event)
QPointF delta = pathPoint - startPoint;
if (qAbs(delta.x()) > qApp->styleHints()->startDragDistance() || qAbs(delta.y()) > qApp->styleHints()->startDragDistance()) {
stealMouse = true;
- startPc = newPc;
}
}
+ qint64 currentTimestamp = computeCurrentTime(event);
if (stealMouse) {
moveReason = QQuickPathViewPrivate::Mouse;
qreal diff = (newPc - startPc)*modelCount*mappedRange;
@@ -1323,10 +1369,9 @@ void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event)
else if (diff < -modelCount/2)
diff += modelCount;
- lastElapsed = QQuickItemPrivate::restart(lastPosTime);
- lastDist = diff;
- startPc = newPc;
- addVelocitySample(diff / (qreal(lastElapsed) / 1000.));
+ qint64 elapsed = currentTimestamp - lastPosTime;
+ if (elapsed > 0)
+ addVelocitySample(diff / (qreal(elapsed) / 1000.));
}
if (!moving) {
moving = true;
@@ -1334,6 +1379,8 @@ void QQuickPathViewPrivate::handleMouseMoveEvent(QMouseEvent *event)
emit q->movementStarted();
}
}
+ startPc = newPc;
+ lastPosTime = currentTimestamp;
}
void QQuickPathView::mouseReleaseEvent(QMouseEvent *event)
@@ -1353,8 +1400,8 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
Q_Q(QQuickPathView);
stealMouse = false;
q->setKeepMouseGrab(false);
- if (!interactive || !lastPosTime.isValid() || !model || !modelCount) {
- lastPosTime.invalidate();
+ if (!interactive || !timer.isValid() || !model || !modelCount) {
+ timer.invalidate();
if (!tl.isActive())
q->movementEnding();
return;
@@ -1364,7 +1411,7 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
qreal count = modelCount*mappedRange;
qreal pixelVelocity = (path->path().length()/count) * velocity;
if (qAbs(pixelVelocity) > MinimumFlickVelocity) {
- if (qAbs(pixelVelocity) > maximumFlickVelocity) {
+ if (qAbs(pixelVelocity) > maximumFlickVelocity || snapMode == QQuickPathView::SnapOneItem) {
// limit velocity
qreal maxVel = velocity < 0 ? -maximumFlickVelocity : maximumFlickVelocity;
velocity = maxVel / (path->path().length()/count);
@@ -1373,14 +1420,24 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
qreal v2 = velocity*velocity;
qreal accel = deceleration/10;
qreal dist = 0;
- if (haveHighlightRange && highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
- // + 0.25 to encourage moving at least one item in the flick direction
- dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
- // round to nearest item.
- if (velocity > 0.)
- dist = qRound(dist + offset) - offset;
- else
- dist = qRound(dist - offset) + offset;
+ if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
+ || snapMode != QQuickPathView::NoSnap)) {
+ if (snapMode == QQuickPathView::SnapOneItem) {
+ // encourage snapping one item in direction of motion
+ if (velocity > 0.)
+ dist = qRound(0.5 + offset) - offset;
+ else
+ dist = qRound(0.5 - offset) + offset;
+ } else {
+ // + 0.25 to encourage moving at least one item in the flick direction
+ dist = qMin(qreal(modelCount-1), qreal(v2 / (accel * 2.0) + 0.25));
+
+ // round to nearest item.
+ if (velocity > 0.)
+ dist = qRound(dist + offset) - offset;
+ else
+ dist = qRound(dist - offset) + offset;
+ }
// Calculate accel required to stop on item boundary
if (dist <= 0.) {
dist = 0.;
@@ -1405,7 +1462,7 @@ void QQuickPathViewPrivate::handleMouseReleaseEvent(QMouseEvent *)
fixOffset();
}
- lastPosTime.invalidate();
+ timer.invalidate();
if (!tl.isActive())
q->movementEnding();
}
@@ -1441,8 +1498,8 @@ bool QQuickPathView::sendMouseEvent(QMouseEvent *event)
grabMouse();
return d->stealMouse;
- } else if (d->lastPosTime.isValid()) {
- d->lastPosTime.invalidate();
+ } else if (d->timer.isValid()) {
+ d->timer.invalidate();
d->fixOffset();
}
if (event->type() == QEvent::MouseButtonRelease)
@@ -1476,7 +1533,7 @@ void QQuickPathView::mouseUngrabEvent()
// fix our state
d->stealMouse = false;
setKeepMouseGrab(false);
- d->lastPosTime.invalidate();
+ d->timer.invalidate();
d->fixOffset();
if (!d->tl.isActive())
movementEnding();
@@ -1557,7 +1614,8 @@ void QQuickPathView::refill()
if (d->items.count() < count) {
int idx = qRound(d->modelCount - d->offset) % d->modelCount;
qreal startPos = 0.0;
- if (d->haveHighlightRange && d->highlightRangeMode != QQuickPathView::NoHighlightRange)
+ if (d->haveHighlightRange && (d->highlightRangeMode != QQuickPathView::NoHighlightRange
+ || d->snapMode != QQuickPathView::NoSnap))
startPos = d->highlightRangeStart;
if (d->firstIndex >= 0) {
startPos = d->positionOfIndex(d->firstIndex);
@@ -1833,22 +1891,23 @@ void QQuickPathViewPrivate::fixOffset()
{
Q_Q(QQuickPathView);
if (model && items.count()) {
- if (haveHighlightRange && highlightRangeMode == QQuickPathView::StrictlyEnforceRange) {
+ if (haveHighlightRange && (highlightRangeMode == QQuickPathView::StrictlyEnforceRange
+ || snapMode != QQuickPathView::NoSnap)) {
int curr = calcCurrentIndex();
- if (curr != currentIndex)
+ if (curr != currentIndex && highlightRangeMode == QQuickPathView::StrictlyEnforceRange)
q->setCurrentIndex(curr);
else
- snapToCurrent();
+ snapToIndex(curr);
}
}
}
-void QQuickPathViewPrivate::snapToCurrent()
+void QQuickPathViewPrivate::snapToIndex(int index)
{
if (!model || modelCount <= 0)
return;
- qreal targetOffset = qmlMod(modelCount - currentIndex, modelCount);
+ qreal targetOffset = qmlMod(modelCount - index, modelCount);
if (offset == targetOffset)
return;
diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h
index 8b15e85b8a..2c0c106113 100644
--- a/src/quick/items/qquickpathview_p.h
+++ b/src/quick/items/qquickpathview_p.h
@@ -83,8 +83,10 @@ class Q_AUTOTEST_EXPORT QQuickPathView : public QQuickItem
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
Q_PROPERTY(int pathItemCount READ pathItemCount WRITE setPathItemCount NOTIFY pathItemCountChanged)
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
Q_ENUMS(HighlightRangeMode)
+ Q_ENUMS(SnapMode)
public:
QQuickPathView(QQuickItem *parent=0);
@@ -144,6 +146,10 @@ public:
int pathItemCount() const;
void setPathItemCount(int);
+ enum SnapMode { NoSnap, SnapToItem, SnapOneItem };
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
static QQuickPathViewAttached *qmlAttachedProperties(QObject *);
public Q_SLOTS:
@@ -176,6 +182,7 @@ Q_SIGNALS:
void movementEnded();
void flickStarted();
void flickEnded();
+ void snapModeChanged();
protected:
virtual void updatePolish();
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index ac74e9a568..3285b40036 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -122,10 +122,11 @@ public:
void setAdjustedOffset(qreal offset);
void regenerate();
void updateItem(QQuickItem *, qreal);
- void snapToCurrent();
+ void snapToIndex(int index);
QPointF pointNear(const QPointF &point, qreal *nearPercent=0) const;
void addVelocitySample(qreal v);
qreal calcVelocity() const;
+ qint64 computeCurrentTime(QInputEvent *event);
QQuickPath *path;
int currentIndex;
@@ -133,8 +134,6 @@ public:
qreal currentItemOffset;
qreal startPc;
QPointF startPoint;
- qreal lastDist;
- int lastElapsed;
qreal offset;
qreal offsetAdj;
qreal mappedRange;
@@ -149,7 +148,8 @@ public:
bool flicking : 1;
bool requestedOnPath : 1;
bool inRequest : 1;
- QElapsedTimer lastPosTime;
+ QElapsedTimer timer;
+ qint64 lastPosTime;
QPointF lastPos;
qreal dragMargin;
qreal deceleration;
@@ -180,6 +180,7 @@ public:
int highlightMoveDuration;
int modelCount;
QPODVector<qreal,10> velocityBuffer;
+ QQuickPathView::SnapMode snapMode;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index e232746417..1549057ef8 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -88,6 +88,446 @@ const char *qtTexCoordAttributeName()
return qt_texcoord_attribute_name;
}
+namespace {
+
+ enum VariableQualifier {
+ AttributeQualifier,
+ UniformQualifier
+ };
+
+ inline bool qt_isalpha(char c)
+ {
+ char ch = c | 0x20;
+ return (ch >= 'a' && ch <= 'z') || c == '_';
+ }
+
+ inline bool qt_isalnum(char c)
+ {
+ return qt_isalpha(c) || (c >= '0' && c <= '9');
+ }
+
+ inline bool qt_isspace(char c)
+ {
+ return c == ' ' || (c >= 0x09 && c <= 0x0d);
+ }
+
+ // Returns -1 if not found, returns index to first character after the name if found.
+ int qt_search_for_variable(const char *s, int length, int index, VariableQualifier &decl,
+ int &typeIndex, int &typeLength,
+ int &nameIndex, int &nameLength)
+ {
+ enum Identifier {
+ QualifierIdentifier, // Base state
+ PrecisionIdentifier,
+ TypeIdentifier,
+ NameIdentifier
+ };
+ Identifier expected = QualifierIdentifier;
+ bool compilerDirectiveExpected = index == 0;
+
+ while (index < length) {
+ // Skip whitespace.
+ while (qt_isspace(s[index])) {
+ compilerDirectiveExpected |= s[index] == '\n';
+ ++index;
+ }
+
+ if (qt_isalpha(s[index])) {
+ // Read identifier.
+ int idIndex = index;
+ ++index;
+ while (qt_isalnum(s[index]))
+ ++index;
+ int idLength = index - idIndex;
+
+ const int attrLen = sizeof("attribute") - 1;
+ const int uniLen = sizeof("uniform") - 1;
+ const int loLen = sizeof("lowp") - 1;
+ const int medLen = sizeof("mediump") - 1;
+ const int hiLen = sizeof("highp") - 1;
+
+ switch (expected) {
+ case QualifierIdentifier:
+ if (idLength == attrLen && qstrncmp("attribute", s + idIndex, attrLen) == 0) {
+ decl = AttributeQualifier;
+ expected = PrecisionIdentifier;
+ } else if (idLength == uniLen && qstrncmp("uniform", s + idIndex, uniLen) == 0) {
+ decl = UniformQualifier;
+ expected = PrecisionIdentifier;
+ }
+ break;
+ case PrecisionIdentifier:
+ if ((idLength == loLen && qstrncmp("lowp", s + idIndex, loLen) == 0)
+ || (idLength == medLen && qstrncmp("mediump", s + idIndex, medLen) == 0)
+ || (idLength == hiLen && qstrncmp("highp", s + idIndex, hiLen) == 0))
+ {
+ expected = TypeIdentifier;
+ break;
+ }
+ // Fall through.
+ case TypeIdentifier:
+ typeIndex = idIndex;
+ typeLength = idLength;
+ expected = NameIdentifier;
+ break;
+ case NameIdentifier:
+ nameIndex = idIndex;
+ nameLength = idLength;
+ return index; // Attribute or uniform declaration found. Return result.
+ default:
+ break;
+ }
+ } else if (s[index] == '#' && compilerDirectiveExpected) {
+ // Skip compiler directives.
+ ++index;
+ while (index < length && (s[index] != '\n' || s[index - 1] == '\\'))
+ ++index;
+ } else if (s[index] == '/' && s[index + 1] == '/') {
+ // Skip comments.
+ index += 2;
+ while (index < length && s[index] != '\n')
+ ++index;
+ } else if (s[index] == '/' && s[index + 1] == '*') {
+ // Skip comments.
+ index += 2;
+ while (index < length && (s[index] != '*' || s[index + 1] != '/'))
+ ++index;
+ if (index < length)
+ index += 2; // Skip star-slash.
+ } else {
+ expected = QualifierIdentifier;
+ ++index;
+ }
+ compilerDirectiveExpected = false;
+ }
+ return -1;
+ }
+}
+
+
+
+QQuickShaderEffectCommon::~QQuickShaderEffectCommon()
+{
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
+ qDeleteAll(signalMappers[shaderType]);
+}
+
+void QQuickShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
+{
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ if (signalMappers[shaderType].at(i) == 0)
+ continue;
+ const UniformData &d = uniformData[shaderType].at(i);
+ QSignalMapper *mapper = signalMappers[shaderType].at(i);
+ QObject::disconnect(item, 0, mapper, SLOT(map()));
+ QObject::disconnect(mapper, SIGNAL(mapped(int)), item, SLOT(propertyChanged(int)));
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qVariantValue<QObject *>(d.value));
+ if (source) {
+ if (item->canvas())
+ QQuickItemPrivate::get(source)->derefCanvas();
+ QObject::disconnect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
+ }
+ }
+ }
+}
+
+void QQuickShaderEffectCommon::connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
+{
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ if (signalMappers[shaderType].at(i) == 0)
+ continue;
+ const UniformData &d = uniformData[shaderType].at(i);
+ int pi = item->metaObject()->indexOfProperty(d.name.constData());
+ if (pi >= 0) {
+ QMetaProperty mp = item->metaObject()->property(pi);
+ if (!mp.hasNotifySignal())
+ qWarning("QQuickShaderEffect: property '%s' does not have notification method!", d.name.constData());
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().methodSignature());
+ QSignalMapper *mapper = signalMappers[shaderType].at(i);
+ QObject::connect(item, signalName, mapper, SLOT(map()));
+ QObject::connect(mapper, SIGNAL(mapped(int)), item, SLOT(propertyChanged(int)));
+ } else {
+ // If the source is set via a dynamic property, like the layer is, then we need this
+ // check to disable the warning.
+ if (!item->property(d.name.constData()).isValid())
+ qWarning("QQuickShaderEffect: '%s' does not have a matching property!", d.name.constData());
+ }
+
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qVariantValue<QObject *>(d.value));
+ if (source) {
+ if (item->canvas())
+ QQuickItemPrivate::get(source)->refCanvas(item->canvas());
+ QObject::connect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
+ }
+ }
+ }
+}
+
+void QQuickShaderEffectCommon::updateParseLog(bool ignoreAttributes)
+{
+ parseLog.clear();
+ if (!ignoreAttributes) {
+ if (!attributes.contains(qt_position_attribute_name)) {
+ parseLog += QLatin1String("Warning: Missing reference to \'");
+ parseLog += QLatin1String(qt_position_attribute_name);
+ parseLog += QLatin1String("\'.\n");
+ }
+ if (!attributes.contains(qt_texcoord_attribute_name)) {
+ parseLog += QLatin1String("Warning: Missing reference to \'");
+ parseLog += QLatin1String(qt_texcoord_attribute_name);
+ parseLog += QLatin1String("\'.\n");
+ }
+ }
+ bool respectsMatrix = false;
+ bool respectsOpacity = false;
+ for (int i = 0; i < uniformData[Key::VertexShader].size(); ++i)
+ respectsMatrix |= uniformData[Key::VertexShader].at(i).specialType == UniformData::Matrix;
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i)
+ respectsOpacity |= uniformData[shaderType].at(i).specialType == UniformData::Opacity;
+ }
+ if (!respectsMatrix)
+ parseLog += QLatin1String("Warning: Vertex shader is missing reference to \'qt_Matrix\'.\n");
+ if (!respectsOpacity)
+ parseLog += QLatin1String("Warning: Shaders are missing reference to \'qt_Opacity\'.\n");
+}
+
+void QQuickShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code)
+{
+ int index = 0;
+ int typeIndex, typeLength, nameIndex, nameLength;
+ const char *s = code.constData();
+ VariableQualifier decl;
+ while ((index = qt_search_for_variable(s, code.size(), index, decl, typeIndex, typeLength,
+ nameIndex, nameLength)) != -1)
+ {
+ if (decl == AttributeQualifier) {
+ if (shaderType == Key::VertexShader)
+ attributes.append(QByteArray(s + nameIndex, nameLength));
+ } else {
+ Q_ASSERT(decl == UniformQualifier);
+
+ const int sampLen = sizeof("sampler2D") - 1;
+ const int opLen = sizeof("qt_Opacity") - 1;
+ const int matLen = sizeof("qt_Matrix") - 1;
+
+ UniformData d;
+ QSignalMapper *mapper = 0;
+ d.name = QByteArray(s + nameIndex, nameLength);
+ if (nameLength == opLen && qstrncmp("qt_Opacity", s + nameIndex, opLen) == 0) {
+ d.specialType = UniformData::Opacity;
+ } else if (nameLength == matLen && qstrncmp("qt_Matrix", s + nameIndex, matLen) == 0) {
+ d.specialType = UniformData::Matrix;
+ } else {
+ mapper = new QSignalMapper;
+ mapper->setMapping(item, uniformData[shaderType].size() | (shaderType << 16));
+ d.value = item->property(d.name.constData());
+ bool sampler = typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0;
+ d.specialType = sampler ? UniformData::Sampler : UniformData::None;
+ }
+ uniformData[shaderType].append(d);
+ signalMappers[shaderType].append(mapper);
+ }
+ }
+}
+
+void QQuickShaderEffectCommon::updateShader(QQuickItem *item, Key::ShaderType shaderType)
+{
+ disconnectPropertySignals(item, shaderType);
+ qDeleteAll(signalMappers[shaderType]);
+ uniformData[shaderType].clear();
+ signalMappers[shaderType].clear();
+ if (shaderType == Key::VertexShader)
+ attributes.clear();
+
+ const QByteArray &code = source.sourceCode[shaderType];
+ if (code.isEmpty()) {
+ // Optimize for default code.
+ if (shaderType == Key::VertexShader) {
+ attributes.append(QByteArray(qt_position_attribute_name));
+ attributes.append(QByteArray(qt_texcoord_attribute_name));
+ UniformData d;
+ d.name = "qt_Matrix";
+ d.specialType = UniformData::Matrix;
+ uniformData[Key::VertexShader].append(d);
+ signalMappers[Key::VertexShader].append(0);
+ } else if (shaderType == Key::FragmentShader) {
+ UniformData d;
+ d.name = "qt_Opacity";
+ d.specialType = UniformData::Opacity;
+ uniformData[Key::FragmentShader].append(d);
+ signalMappers[Key::FragmentShader].append(0);
+ QSignalMapper *mapper = new QSignalMapper;
+ mapper->setMapping(item, 1 | (Key::FragmentShader << 16));
+ const char *sourceName = "source";
+ d.name = sourceName;
+ d.value = item->property(sourceName);
+ d.specialType = UniformData::Sampler;
+ uniformData[Key::FragmentShader].append(d);
+ signalMappers[Key::FragmentShader].append(mapper);
+ }
+ } else {
+ lookThroughShaderCode(item, shaderType, code);
+ }
+
+ connectPropertySignals(item, shaderType);
+}
+
+void QQuickShaderEffectCommon::updateMaterial(QQuickShaderEffectNode *node,
+ QQuickShaderEffectMaterial *material,
+ bool updateUniforms, bool updateUniformValues,
+ bool updateTextureProviders)
+{
+ if (updateUniforms) {
+ for (int i = 0; i < material->textureProviders.size(); ++i) {
+ QSGTextureProvider *t = material->textureProviders.at(i).second;
+ if (t) {
+ QObject::disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ QObject::disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
+ }
+ material->textureProviders.clear();
+
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ const UniformData &d = uniformData[shaderType].at(i);
+ // First make room in the textureProviders array. Set to proper value further down.
+ if (d.specialType == UniformData::Sampler)
+ material->textureProviders.append(qMakePair(d.name, (QSGTextureProvider *)0));
+ }
+ material->uniforms[shaderType] = uniformData[shaderType];
+ }
+ updateUniformValues = false;
+ updateTextureProviders = true;
+ }
+
+ if (updateUniformValues) {
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ Q_ASSERT(uniformData[shaderType].size() == material->uniforms[shaderType].size());
+ for (int i = 0; i < uniformData[shaderType].size(); ++i)
+ material->uniforms[shaderType][i].value = uniformData[shaderType].at(i).value;
+ }
+ }
+
+ if (updateTextureProviders) {
+ int index = 0;
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ const UniformData &d = uniformData[shaderType].at(i);
+ if (d.specialType != UniformData::Sampler)
+ continue;
+ Q_ASSERT(material->textureProviders.at(index).first == d.name);
+ QSGTextureProvider *oldProvider = material->textureProviders.at(index).second;
+ QSGTextureProvider *newProvider = 0;
+ QQuickItem *source = qobject_cast<QQuickItem *>(qVariantValue<QObject *>(d.value));
+ if (source && source->isTextureProvider())
+ newProvider = source->textureProvider();
+ if (newProvider != oldProvider) {
+ if (oldProvider) {
+ QObject::disconnect(oldProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ QObject::disconnect(oldProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
+ if (newProvider) {
+ Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
+ "QQuickShaderEffect::updatePaintNode",
+ "Texture provider must belong to the rendering thread");
+ QObject::connect(newProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ } else {
+ const char *typeName = source ? source->metaObject()->className() : d.value.typeName();
+ qWarning("ShaderEffect: Property '%s' is not assigned a valid texture provider (%s).",
+ d.name.constData(), typeName);
+ }
+ material->textureProviders[index].second = newProvider;
+ }
+ ++index;
+ }
+ }
+ Q_ASSERT(index == material->textureProviders.size());
+ }
+}
+
+void QQuickShaderEffectCommon::updateCanvas(QQuickCanvas *canvas)
+{
+ // See comment in QQuickShaderEffectCommon::propertyChanged().
+ if (canvas) {
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ const UniformData &d = uniformData[shaderType].at(i);
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qVariantValue<QObject *>(d.value));
+ if (source)
+ QQuickItemPrivate::get(source)->refCanvas(canvas);
+ }
+ }
+ }
+ } else {
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ const UniformData &d = uniformData[shaderType].at(i);
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qVariantValue<QObject *>(d.value));
+ if (source)
+ QQuickItemPrivate::get(source)->derefCanvas();
+ }
+ }
+ }
+ }
+}
+
+void QQuickShaderEffectCommon::sourceDestroyed(QObject *object)
+{
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ UniformData &d = uniformData[shaderType][i];
+ if (d.specialType == UniformData::Sampler && qVariantCanConvert<QObject *>(d.value)) {
+ if (qVariantValue<QObject *>(d.value) == object)
+ d.value = QVariant();
+ }
+ }
+ }
+}
+
+
+void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
+ bool *textureProviderChanged)
+{
+ Key::ShaderType shaderType = Key::ShaderType(mappedId >> 16);
+ int index = mappedId & 0xffff;
+ UniformData &d = uniformData[shaderType][index];
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qVariantValue<QObject *>(d.value));
+ if (source) {
+ if (item->canvas())
+ QQuickItemPrivate::get(source)->derefCanvas();
+ QObject::disconnect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
+ }
+
+ d.value = item->property(d.name.constData());
+
+ source = qobject_cast<QQuickItem *>(qVariantValue<QObject *>(d.value));
+ if (source) {
+ // 'source' needs a canvas to get a scene graph node. It usually gets one through its
+ // parent, but if the source item is "inline" rather than a reference -- i.e.
+ // "property variant source: Image { }" instead of "property variant source: foo" -- it
+ // will not get a parent. In those cases, 'source' should get the canvas from 'item'.
+ if (item->canvas())
+ QQuickItemPrivate::get(source)->refCanvas(item->canvas());
+ QObject::connect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
+ }
+ if (textureProviderChanged)
+ *textureProviderChanged = true;
+ } else {
+ d.value = item->property(d.name.constData());
+ if (textureProviderChanged)
+ *textureProviderChanged = false;
+ }
+}
+
+
/*!
\qmlclass ShaderEffect QQuickShaderEffect
\inqmlmodule QtQuick 2
@@ -187,18 +627,21 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
, m_cullMode(NoCulling)
, m_status(Uncompiled)
, m_blending(true)
- , m_dirtyData(true)
- , m_programDirty(true)
+ , m_dirtyUniforms(true)
+ , m_dirtyUniformValues(true)
+ , m_dirtyTextureProviders(true)
+ , m_dirtyProgram(true)
+ , m_dirtyParseLog(true)
, m_dirtyMesh(true)
, m_dirtyGeometry(true)
- , m_complete(false)
{
setFlag(QQuickItem::ItemHasContents);
}
QQuickShaderEffect::~QQuickShaderEffect()
{
- reset();
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
+ m_common.disconnectPropertySignals(this, Key::ShaderType(shaderType));
}
/*!
@@ -211,11 +654,16 @@ QQuickShaderEffect::~QQuickShaderEffect()
void QQuickShaderEffect::setFragmentShader(const QByteArray &code)
{
- if (m_source.fragmentCode.constData() == code.constData())
+ if (m_common.source.sourceCode[Key::FragmentShader].constData() == code.constData())
return;
- m_source.fragmentCode = code;
+ m_common.source.sourceCode[Key::FragmentShader] = code;
+ m_dirtyProgram = true;
+ m_dirtyParseLog = true;
+
+ if (isComponentComplete())
+ m_common.updateShader(this, Key::FragmentShader);
+
update();
- m_complete = false;
if (m_status != Uncompiled) {
m_status = Uncompiled;
emit statusChanged();
@@ -234,11 +682,16 @@ void QQuickShaderEffect::setFragmentShader(const QByteArray &code)
void QQuickShaderEffect::setVertexShader(const QByteArray &code)
{
- if (m_source.vertexCode.constData() == code.constData())
+ if (m_common.source.sourceCode[Key::VertexShader].constData() == code.constData())
return;
- m_source.vertexCode = code;
+ m_common.source.sourceCode[Key::VertexShader] = code;
+ m_dirtyProgram = true;
+ m_dirtyParseLog = true;
+
+ if (isComponentComplete())
+ m_common.updateShader(this, Key::VertexShader);
+
update();
- m_complete = false;
if (m_status != Uncompiled) {
m_status = Uncompiled;
emit statusChanged();
@@ -316,6 +769,7 @@ void QQuickShaderEffect::setMesh(const QVariant &mesh)
}
m_dirtyMesh = true;
+ m_dirtyParseLog = true;
update();
emit meshChanged();
}
@@ -343,6 +797,34 @@ void QQuickShaderEffect::setCullMode(CullMode face)
emit cullModeChanged();
}
+QString QQuickShaderEffect::parseLog()
+{
+ if (m_dirtyParseLog) {
+ m_common.updateParseLog(m_mesh != 0);
+ m_dirtyParseLog = false;
+ }
+ return m_common.parseLog;
+}
+
+bool QQuickShaderEffect::event(QEvent *event)
+{
+ if (event->type() == QEvent::DynamicPropertyChange) {
+ QDynamicPropertyChangeEvent *e = static_cast<QDynamicPropertyChangeEvent *>(event);
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < m_common.uniformData[shaderType].size(); ++i) {
+ if (m_common.uniformData[shaderType].at(i).name == e->propertyName()) {
+ bool textureProviderChanged;
+ m_common.propertyChanged(this, (shaderType << 16) | i, &textureProviderChanged);
+ m_dirtyTextureProviders |= textureProviderChanged;
+ m_dirtyUniformValues = true;
+ update();
+ }
+ }
+ }
+ }
+ return QQuickItem::event(event);
+}
+
/*!
\qmlproperty enumeration QtQuick2::ShaderEffect::status
@@ -371,19 +853,6 @@ void QQuickShaderEffect::setCullMode(CullMode face)
\sa status
*/
-void QQuickShaderEffect::changeSource(int index)
-{
- Q_ASSERT(index >= 0 && index < m_sources.size());
- QVariant v = property(m_sources.at(index).name.constData());
- setSource(v, index);
-}
-
-void QQuickShaderEffect::updateData()
-{
- m_dirtyData = true;
- update();
-}
-
void QQuickShaderEffect::updateGeometry()
{
m_dirtyGeometry = true;
@@ -392,7 +861,7 @@ void QQuickShaderEffect::updateGeometry()
void QQuickShaderEffect::updateLogAndStatus(const QString &log, int status)
{
- m_log = m_parseLog + log;
+ m_log = parseLog() + log;
m_status = Status(status);
emit logChanged();
emit statusChanged();
@@ -400,341 +869,17 @@ void QQuickShaderEffect::updateLogAndStatus(const QString &log, int status)
void QQuickShaderEffect::sourceDestroyed(QObject *object)
{
- for (int i = 0; i < m_sources.size(); ++i) {
- SourceData &source = m_sources[i];
- if (object == source.sourceObject)
- source.sourceObject = 0;
- }
-}
-
-void QQuickShaderEffect::setSource(const QVariant &var, int index)
-{
- Q_ASSERT(index >= 0 && index < m_sources.size());
-
- SourceData &source = m_sources[index];
-
- if (source.sourceObject) {
- if (canvas())
- QQuickItemPrivate::get(source.sourceObject)->derefCanvas();
- disconnect(source.sourceObject, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
- }
-
- source.sourceObject = 0;
- if (var.isNull()) {
- return;
- } else if (!qVariantCanConvert<QObject *>(var)) {
- qWarning("Could not assign source of type '%s' to property '%s'.", var.typeName(), source.name.constData());
- return;
- }
-
- QObject *obj = qVariantValue<QObject *>(var);
- if (!obj)
- return;
- QQuickItem *item = qobject_cast<QQuickItem *>(obj);
- if (!item || !item->isTextureProvider()) {
- qWarning("ShaderEffect: source uniform [%s] is not assigned a valid texture provider: %s [%s]",
- source.name.constData(), qPrintable(obj->objectName()), obj->metaObject()->className());
- return;
- }
-
- source.sourceObject = item;
-
- if (item) {
- // 'item' needs a canvas to get a scene graph node. It usually gets one through its
- // parent, but if the source item is "inline" rather than a reference -- i.e.
- // "property variant source: Image { }" instead of "property variant source: foo" -- it
- // will not get a parent. In those cases, 'item' should get the canvas from 'this'.
- if (canvas())
- QQuickItemPrivate::get(item)->refCanvas(canvas());
- connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
- }
-}
-
-void QQuickShaderEffect::disconnectPropertySignals()
-{
- disconnect(this, 0, this, SLOT(updateData()));
- for (int i = 0; i < m_sources.size(); ++i) {
- SourceData &source = m_sources[i];
- disconnect(this, 0, source.mapper, 0);
- disconnect(source.mapper, 0, this, 0);
- }
-}
-
-void QQuickShaderEffect::connectPropertySignals()
-{
- QSet<QByteArray>::const_iterator it;
- for (it = m_source.uniformNames.begin(); it != m_source.uniformNames.end(); ++it) {
- int pi = metaObject()->indexOfProperty(it->constData());
- if (pi >= 0) {
- QMetaProperty mp = metaObject()->property(pi);
- if (!mp.hasNotifySignal())
- qWarning("QQuickShaderEffect: property '%s' does not have notification method!", it->constData());
- QByteArray signalName("2");
- signalName.append(mp.notifySignal().methodSignature());
- connect(this, signalName, this, SLOT(updateData()));
- } else {
- // If the source is set via a dynamic property, like the layer is, then we need this check
- // to disable the warning.
- if (property(it->constData()).isValid())
- continue;
- qWarning("QQuickShaderEffect: '%s' does not have a matching property!", it->constData());
- }
- }
- for (int i = 0; i < m_sources.size(); ++i) {
- SourceData &source = m_sources[i];
- int pi = metaObject()->indexOfProperty(source.name.constData());
- if (pi >= 0) {
- QMetaProperty mp = metaObject()->property(pi);
- QByteArray signalName("2");
- signalName.append(mp.notifySignal().methodSignature());
- connect(this, signalName, source.mapper, SLOT(map()));
- source.mapper->setMapping(this, i);
- connect(source.mapper, SIGNAL(mapped(int)), this, SLOT(changeSource(int)));
- } else {
- // If the source is set via a dynamic property, like the layer is, then we need this check
- // to disable the warning.
- if (property(source.name.constData()).isValid())
- continue;
- qWarning("QQuickShaderEffect: '%s' does not have a matching source!", source.name.constData());
- }
- }
-}
-
-
-void QQuickShaderEffect::ensureCompleted()
-{
- if (!m_complete) {
- reset();
- updateProperties();
- m_complete = true;
- }
-}
-
-
-void QQuickShaderEffect::reset()
-{
- disconnectPropertySignals();
-
- m_source.attributeNames.clear();
- m_source.uniformNames.clear();
- m_source.respectsOpacity = false;
- m_source.respectsMatrix = false;
- m_source.className = metaObject()->className();
-
- for (int i = 0; i < m_sources.size(); ++i) {
- const SourceData &source = m_sources.at(i);
- delete source.mapper;
- if (source.sourceObject) {
- if (canvas())
- QQuickItemPrivate::get(source.sourceObject)->derefCanvas();
- disconnect(source.sourceObject, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
- }
- }
- m_sources.clear();
- m_log.clear();
- m_parseLog.clear();
- m_programDirty = true;
- m_dirtyMesh = true;
-}
-
-void QQuickShaderEffect::updateProperties()
-{
- if (m_source.vertexCode.isEmpty()) {
- m_source.attributeNames.append(QByteArray(qt_position_attribute_name));
- m_source.attributeNames.append(QByteArray(qt_texcoord_attribute_name));
- m_source.respectsMatrix = true;
- } else {
- lookThroughShaderCode(m_source.vertexCode);
- }
- if (m_source.fragmentCode.isEmpty()) {
- m_source.respectsOpacity = true;
- QByteArray name("source");
- m_source.uniformNames.insert(name);
- SourceData d;
- d.mapper = new QSignalMapper;
- d.name = name;
- d.sourceObject = 0;
- m_sources.append(d);
- } else {
- lookThroughShaderCode(m_source.fragmentCode);
- }
-
- if (!m_mesh && !m_source.attributeNames.contains(qt_position_attribute_name)) {
- m_parseLog += QLatin1String("Warning: Missing reference to \'");
- m_parseLog += QLatin1String(qt_position_attribute_name);
- m_parseLog += QLatin1String("\'.\n");
- }
- if (!m_mesh && !m_source.attributeNames.contains(qt_texcoord_attribute_name)) {
- m_parseLog += QLatin1String("Warning: Missing reference to \'");
- m_parseLog += QLatin1String(qt_texcoord_attribute_name);
- m_parseLog += QLatin1String("\'.\n");
- }
- if (!m_source.respectsMatrix) {
- m_parseLog += QLatin1String("Warning: Missing reference to \'qt_Matrix\'.\n");
- }
- if (!m_source.respectsOpacity) {
- m_parseLog += QLatin1String("Warning: Missing reference to \'qt_Opacity\'.\n");
- }
-
- for (int i = 0; i < m_sources.size(); ++i) {
- QVariant v = property(m_sources.at(i).name);
- setSource(v, i);
- }
-
- connectPropertySignals();
+ m_common.sourceDestroyed(object);
}
-namespace {
-
- enum VariableQualifier {
- AttributeQualifier,
- UniformQualifier
- };
-
- inline bool qt_isalpha(char c)
- {
- char ch = c | 0x20;
- return (ch >= 'a' && ch <= 'z') || c == '_';
- }
-
- inline bool qt_isalnum(char c)
- {
- return qt_isalpha(c) || (c >= '0' && c <= '9');
- }
-
- inline bool qt_isspace(char c)
- {
- return c == ' ' || (c >= 0x09 && c <= 0x0d);
- }
-
- // Returns -1 if not found, returns index to first character after the name if found.
- int qt_search_for_variable(const char *s, int length, int index, VariableQualifier &decl,
- int &typeIndex, int &typeLength,
- int &nameIndex, int &nameLength)
- {
- enum Identifier {
- QualifierIdentifier, // Base state
- PrecisionIdentifier,
- TypeIdentifier,
- NameIdentifier
- };
- Identifier expected = QualifierIdentifier;
- bool compilerDirectiveExpected = index == 0;
-
- while (index < length) {
- // Skip whitespace.
- while (qt_isspace(s[index])) {
- compilerDirectiveExpected |= s[index] == '\n';
- ++index;
- }
-
- if (qt_isalpha(s[index])) {
- // Read identifier.
- int idIndex = index;
- ++index;
- while (qt_isalnum(s[index]))
- ++index;
- int idLength = index - idIndex;
-
- const int attrLen = sizeof("attribute") - 1;
- const int uniLen = sizeof("uniform") - 1;
- const int loLen = sizeof("lowp") - 1;
- const int medLen = sizeof("mediump") - 1;
- const int hiLen = sizeof("highp") - 1;
-
- switch (expected) {
- case QualifierIdentifier:
- if (idLength == attrLen && qstrncmp("attribute", s + idIndex, attrLen) == 0) {
- decl = AttributeQualifier;
- expected = PrecisionIdentifier;
- } else if (idLength == uniLen && qstrncmp("uniform", s + idIndex, uniLen) == 0) {
- decl = UniformQualifier;
- expected = PrecisionIdentifier;
- }
- break;
- case PrecisionIdentifier:
- if ((idLength == loLen && qstrncmp("lowp", s + idIndex, loLen) == 0)
- || (idLength == medLen && qstrncmp("mediump", s + idIndex, medLen) == 0)
- || (idLength == hiLen && qstrncmp("highp", s + idIndex, hiLen) == 0))
- {
- expected = TypeIdentifier;
- break;
- }
- // Fall through.
- case TypeIdentifier:
- typeIndex = idIndex;
- typeLength = idLength;
- expected = NameIdentifier;
- break;
- case NameIdentifier:
- nameIndex = idIndex;
- nameLength = idLength;
- return index; // Attribute or uniform declaration found. Return result.
- default:
- break;
- }
- } else if (s[index] == '#' && compilerDirectiveExpected) {
- // Skip compiler directives.
- ++index;
- while (index < length && (s[index] != '\n' || s[index - 1] == '\\'))
- ++index;
- } else if (s[index] == '/' && s[index + 1] == '/') {
- // Skip comments.
- index += 2;
- while (index < length && s[index] != '\n')
- ++index;
- } else if (s[index] == '/' && s[index + 1] == '*') {
- // Skip comments.
- index += 2;
- while (index < length && (s[index] != '*' || s[index + 1] != '/'))
- ++index;
- if (index < length)
- index += 2; // Skip star-slash.
- } else {
- expected = QualifierIdentifier;
- ++index;
- }
- compilerDirectiveExpected = false;
- }
- return -1;
- }
-}
-void QQuickShaderEffect::lookThroughShaderCode(const QByteArray &code)
+void QQuickShaderEffect::propertyChanged(int mappedId)
{
- int index = 0;
- int typeIndex, typeLength, nameIndex, nameLength;
- const char *s = code.constData();
- VariableQualifier decl;
- while ((index = qt_search_for_variable(s, code.size(), index, decl, typeIndex, typeLength,
- nameIndex, nameLength)) != -1)
- {
- if (decl == AttributeQualifier) {
- m_source.attributeNames.append(QByteArray(s + nameIndex, nameLength));
- } else {
- Q_ASSERT(decl == UniformQualifier);
-
- const int matLen = sizeof("qt_Matrix") - 1;
- const int opLen = sizeof("qt_Opacity") - 1;
- const int sampLen = sizeof("sampler2D") - 1;
-
- if (nameLength == matLen && qstrncmp("qt_Matrix", s + nameIndex, matLen) == 0) {
- m_source.respectsMatrix = true;
- } else if (nameLength == opLen && qstrncmp("qt_Opacity", s + nameIndex, opLen) == 0) {
- m_source.respectsOpacity = true;
- } else {
- QByteArray name(s + nameIndex, nameLength);
- m_source.uniformNames.insert(name);
- if (typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0) {
- SourceData d;
- d.mapper = new QSignalMapper;
- d.name = name;
- d.sourceObject = 0;
- m_sources.append(d);
- }
- }
- }
- }
+ bool textureProviderChanged;
+ m_common.propertyChanged(this, mappedId, &textureProviderChanged);
+ m_dirtyTextureProviders |= textureProviderChanged;
+ m_dirtyUniformValues = true;
+ update();
}
void QQuickShaderEffect::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
@@ -747,10 +892,8 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
{
QQuickShaderEffectNode *node = static_cast<QQuickShaderEffectNode *>(oldNode);
- ensureCompleted();
-
// In the case of a bad vertex shader, don't try to create a node...
- if (m_source.attributeNames.isEmpty()) {
+ if (m_common.attributes.isEmpty()) {
if (node)
delete node;
return 0;
@@ -758,14 +901,14 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
if (!node) {
node = new QQuickShaderEffectNode;
- m_programDirty = true;
- m_dirtyData = true;
+ node->setMaterial(new QQuickShaderEffectMaterial(node));
+ node->setFlag(QSGNode::OwnsMaterial, true);
+ m_dirtyProgram = true;
+ m_dirtyUniforms = true;
m_dirtyGeometry = true;
connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int)));
}
- QQuickShaderEffectMaterial *material = node->shaderMaterial();
-
if (m_dirtyMesh) {
node->setGeometry(0);
m_dirtyMesh = false;
@@ -778,11 +921,11 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
QRectF rect(0, 0, width(), height());
QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
- geometry = mesh->updateGeometry(geometry, m_source.attributeNames, rect);
+ geometry = mesh->updateGeometry(geometry, m_common.attributes, rect);
if (!geometry) {
QString log = mesh->log();
if (!log.isNull()) {
- m_log = m_parseLog;
+ m_log = parseLog();
m_log += QLatin1String("*** Mesh ***\n");
m_log += log;
m_status = Error;
@@ -799,18 +942,7 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
m_dirtyGeometry = false;
}
- if (m_programDirty) {
- QQuickShaderEffectProgram s = m_source;
- if (s.fragmentCode.isEmpty())
- s.fragmentCode = qt_default_fragment_code;
- if (s.vertexCode.isEmpty())
- s.vertexCode = qt_default_vertex_code;
- s.className = metaObject()->className();
-
- material->setProgramSource(s);
- node->markDirty(QSGNode::DirtyMaterial);
- m_programDirty = false;
- }
+ QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(node->material());
// Update blending
if (bool(material->flags() & QSGMaterial::Blending) != m_blending) {
@@ -818,66 +950,48 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa
node->markDirty(QSGNode::DirtyMaterial);
}
- if (int(material->cullMode()) != int(m_cullMode)) {
- material->setCullMode(QQuickShaderEffectMaterial::CullMode(m_cullMode));
+ if (int(material->cullMode) != int(m_cullMode)) {
+ material->cullMode = QQuickShaderEffectMaterial::CullMode(m_cullMode);
node->markDirty(QSGNode::DirtyMaterial);
}
- if (m_dirtyData) {
- QVector<QPair<QByteArray, QVariant> > values;
- QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
- const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = material->textureProviders();
+ if (m_dirtyProgram) {
+ Key s = m_common.source;
+ if (s.sourceCode[Key::FragmentShader].isEmpty())
+ s.sourceCode[Key::FragmentShader] = qt_default_fragment_code;
+ if (s.sourceCode[Key::VertexShader].isEmpty())
+ s.sourceCode[Key::VertexShader] = qt_default_vertex_code;
+ s.className = metaObject()->className();
- for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
- it != m_source.uniformNames.end(); ++it) {
- values.append(qMakePair(*it, property(*it)));
- }
- for (int i = 0; i < oldTextures.size(); ++i) {
- QSGTextureProvider *t = oldTextures.at(i).second;
- if (t) {
- disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
- disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
- }
- }
- for (int i = 0; i < m_sources.size(); ++i) {
- const SourceData &source = m_sources.at(i);
- QSGTextureProvider *t = source.sourceObject ? source.sourceObject->textureProvider() : 0;
- textures.append(qMakePair(source.name, t));
- if (t) {
- Q_ASSERT_X(t->thread() == QThread::currentThread(),
- "QQuickShaderEffect::updatePaintNode",
- "Texture provider must belong to the rendering thread");
- connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
- connect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
- }
- }
- material->setUniforms(values);
- material->setTextureProviders(textures);
+ material->setProgramSource(s);
+ material->attributes = m_common.attributes;
node->markDirty(QSGNode::DirtyMaterial);
- m_dirtyData = false;
+ m_dirtyProgram = false;
+ m_dirtyUniforms = true;
+ }
+
+ if (m_dirtyUniforms || m_dirtyUniformValues || m_dirtyTextureProviders) {
+ m_common.updateMaterial(node, material, m_dirtyUniforms, m_dirtyUniformValues,
+ m_dirtyTextureProviders);
+ node->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
}
return node;
}
+void QQuickShaderEffect::componentComplete()
+{
+ m_common.updateShader(this, Key::VertexShader);
+ m_common.updateShader(this, Key::FragmentShader);
+ QQuickItem::componentComplete();
+}
+
void QQuickShaderEffect::itemChange(ItemChange change, const ItemChangeData &value)
{
- if (change == QQuickItem::ItemSceneChange) {
- // See comment in QQuickShaderEffect::setSource().
- if (value.canvas) {
- for (int i = 0; i < m_sources.size(); ++i) {
- if (m_sources.at(i).sourceObject)
- QQuickItemPrivate::get(m_sources.at(i).sourceObject)->refCanvas(value.canvas);
- }
- } else {
- for (int i = 0; i < m_sources.size(); ++i) {
- if (m_sources.at(i).sourceObject)
- QQuickItemPrivate::get(m_sources.at(i).sourceObject)->derefCanvas();
- }
- }
- }
+ if (change == QQuickItem::ItemSceneChange)
+ m_common.updateCanvas(value.canvas);
QQuickItem::itemChange(change, value);
}
-
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index db1e4e78c1..32f12fad30 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -62,6 +62,34 @@ class QSGContext;
class QSignalMapper;
class QQuickCustomMaterialShader;
+// Common class for QQuickShaderEffect and QQuickCustomParticle.
+struct QQuickShaderEffectCommon
+{
+ typedef QQuickShaderEffectMaterialKey Key;
+ typedef QQuickShaderEffectMaterial::UniformData UniformData;
+
+ ~QQuickShaderEffectCommon();
+ void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
+ void connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
+ void updateParseLog(bool ignoreAttributes);
+ void lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code);
+ void updateShader(QQuickItem *item, Key::ShaderType shaderType);
+ void updateMaterial(QQuickShaderEffectNode *node, QQuickShaderEffectMaterial *material,
+ bool updateUniforms, bool updateUniformValues, bool updateTextureProviders);
+ void updateCanvas(QQuickCanvas *canvas);
+
+ // Called by slots in QQuickShaderEffect:
+ void sourceDestroyed(QObject *object);
+ void propertyChanged(QQuickItem *item, int mappedId, bool *textureProviderChanged);
+
+ Key source;
+ QVector<QByteArray> attributes;
+ QVector<UniformData> uniformData[Key::ShaderTypeCount];
+ QVector<QSignalMapper *> signalMappers[Key::ShaderTypeCount];
+ QString parseLog;
+};
+
+
class Q_AUTOTEST_EXPORT QQuickShaderEffect : public QQuickItem
{
Q_OBJECT
@@ -93,10 +121,10 @@ public:
QQuickShaderEffect(QQuickItem *parent = 0);
~QQuickShaderEffect();
- QByteArray fragmentShader() const { return m_source.fragmentCode; }
+ QByteArray fragmentShader() const { return m_common.source.sourceCode[Key::FragmentShader]; }
void setFragmentShader(const QByteArray &code);
- QByteArray vertexShader() const { return m_source.vertexCode; }
+ QByteArray vertexShader() const { return m_common.source.sourceCode[Key::VertexShader]; }
void setVertexShader(const QByteArray &code);
bool blending() const { return m_blending; }
@@ -111,8 +139,9 @@ public:
QString log() const { return m_log; }
Status status() const { return m_status; }
- void ensureCompleted();
- QString parseLog() { return m_parseLog; }
+ QString parseLog();
+
+ virtual bool event(QEvent *);
Q_SIGNALS:
void fragmentShaderChanged();
@@ -126,27 +155,22 @@ Q_SIGNALS:
protected:
virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void componentComplete();
virtual void itemChange(ItemChange change, const ItemChangeData &value);
private Q_SLOTS:
- void changeSource(int index);
- void updateData();
void updateGeometry();
void updateLogAndStatus(const QString &log, int status);
void sourceDestroyed(QObject *object);
+ void propertyChanged(int mappedId);
private:
friend class QQuickCustomMaterialShader;
friend class QQuickShaderEffectNode;
- void setSource(const QVariant &var, int index);
- void disconnectPropertySignals();
- void connectPropertySignals();
- void reset();
- void updateProperties();
- void lookThroughShaderCode(const QByteArray &code);
+ typedef QQuickShaderEffectMaterialKey Key;
+ typedef QQuickShaderEffectMaterial::UniformData UniformData;
- QQuickShaderEffectProgram m_source;
QSize m_meshResolution;
QQuickShaderEffectMesh *m_mesh;
QQuickGridMesh m_defaultMesh;
@@ -154,23 +178,16 @@ private:
QString m_log;
Status m_status;
- struct SourceData
- {
- QSignalMapper *mapper;
- QQuickItem *sourceObject;
- QByteArray name;
- };
- QVector<SourceData> m_sources;
- QString m_parseLog;
+ QQuickShaderEffectCommon m_common;
uint m_blending : 1;
- uint m_dirtyData : 1;
-
- uint m_programDirty : 1;
+ uint m_dirtyUniforms : 1;
+ uint m_dirtyUniformValues : 1;
+ uint m_dirtyTextureProviders : 1;
+ uint m_dirtyProgram : 1;
+ uint m_dirtyParseLog : 1;
uint m_dirtyMesh : 1;
uint m_dirtyGeometry : 1;
-
- uint m_complete : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index c4b91844e0..a3cadb97a2 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -60,7 +60,6 @@ protected:
friend class QQuickShaderEffectNode;
virtual void compile();
- virtual void initialize();
virtual const char *vertexShader() const;
virtual const char *fragmentShader() const;
@@ -70,17 +69,15 @@ protected:
QString m_log;
bool m_compiled;
- QVector<int> m_uniformLocs;
- int m_opacityLoc;
- int m_matrixLoc;
- uint m_textureIndicesSet;
+ QVector<int> m_uniformLocs[QQuickShaderEffectMaterialKey::ShaderTypeCount];
+ uint m_initialized : 1;
};
QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
: m_key(key)
, m_attributes(attributes)
, m_compiled(false)
- , m_textureIndicesSet(false)
+ , m_initialized(false)
{
for (int i = 0; i < attributes.count(); ++i)
m_attributeNames.append(attributes.at(i).constData());
@@ -104,24 +101,25 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
: QQuickShaderEffect::Error);
}
- if (!m_textureIndicesSet) {
- for (int i = 0; i < material->m_textures.size(); ++i)
- program()->setUniformValue(material->m_textures.at(i).first.constData(), i);
- m_textureIndicesSet = true;
- }
+ if (!m_initialized) {
+ for (int i = 0; i < material->textureProviders.size(); ++i)
+ program()->setUniformValue(material->textureProviders.at(i).first.constData(), i);
- if (m_uniformLocs.size() != material->m_uniformValues.size()) {
- m_uniformLocs.reserve(material->m_uniformValues.size());
- for (int i = 0; i < material->m_uniformValues.size(); ++i) {
- const QByteArray &name = material->m_uniformValues.at(i).first;
- m_uniformLocs.append(program()->uniformLocation(name.constData()));
+ for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
+ Q_ASSERT(m_uniformLocs[shaderType].isEmpty());
+ m_uniformLocs[shaderType].reserve(material->uniforms[shaderType].size());
+ for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
+ const QByteArray &name = material->uniforms[shaderType].at(i).name;
+ m_uniformLocs[shaderType].append(program()->uniformLocation(name.constData()));
+ }
}
+ m_initialized = true;
}
QOpenGLFunctions *functions = state.context()->functions();
- for (int i = material->m_textures.size() - 1; i >= 0; --i) {
+ for (int i = material->textureProviders.size() - 1; i >= 0; --i) {
functions->glActiveTexture(GL_TEXTURE0 + i);
- if (QSGTextureProvider *provider = material->m_textures.at(i).second) {
+ if (QSGTextureProvider *provider = material->textureProviders.at(i).second) {
if (QSGTexture *texture = provider->texture()) {
texture->bind();
continue;
@@ -131,57 +129,67 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
glBindTexture(GL_TEXTURE_2D, 0);
}
- if (material->m_source.respectsOpacity)
- program()->setUniformValue(m_opacityLoc, state.opacity());
-
- for (int i = 0; i < material->m_uniformValues.count(); ++i) {
- const QVariant &v = material->m_uniformValues.at(i).second;
-
- switch (v.type()) {
- case QMetaType::QColor:
- program()->setUniformValue(m_uniformLocs.at(i), qt_premultiply_color(qvariant_cast<QColor>(v)));
- break;
- case QMetaType::Float:
- program()->setUniformValue(m_uniformLocs.at(i), qvariant_cast<float>(v));
- break;
- case QMetaType::Double:
- program()->setUniformValue(m_uniformLocs.at(i), (float) qvariant_cast<double>(v));
- break;
- case QMetaType::QTransform:
- program()->setUniformValue(m_uniformLocs.at(i), qvariant_cast<QTransform>(v));
- break;
- case QMetaType::Int:
- program()->setUniformValue(m_uniformLocs.at(i), v.toInt());
- break;
- case QMetaType::Bool:
- program()->setUniformValue(m_uniformLocs.at(i), GLint(v.toBool()));
- break;
- case QMetaType::QSize:
- case QMetaType::QSizeF:
- program()->setUniformValue(m_uniformLocs.at(i), v.toSizeF());
- break;
- case QMetaType::QPoint:
- case QMetaType::QPointF:
- program()->setUniformValue(m_uniformLocs.at(i), v.toPointF());
- break;
- case QMetaType::QRect:
- case QMetaType::QRectF:
- {
- QRectF r = v.toRectF();
- program()->setUniformValue(m_uniformLocs.at(i), r.x(), r.y(), r.width(), r.height());
+ for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
+ const QQuickShaderEffectMaterial::UniformData &d = material->uniforms[shaderType].at(i);
+ int loc = m_uniformLocs[shaderType].at(i);
+
+ if (d.specialType == QQuickShaderEffectMaterial::UniformData::Opacity) {
+ program()->setUniformValue(loc, state.opacity());
+ } if (d.specialType == QQuickShaderEffectMaterial::UniformData::Matrix) {
+ if (state.isMatrixDirty())
+ program()->setUniformValue(loc, state.combinedMatrix());
+ } else {
+ switch (d.value.type()) {
+ case QMetaType::QColor:
+ program()->setUniformValue(loc, qt_premultiply_color(qvariant_cast<QColor>(d.value)));
+ break;
+ case QMetaType::Float:
+ program()->setUniformValue(loc, qvariant_cast<float>(d.value));
+ break;
+ case QMetaType::Double:
+ program()->setUniformValue(loc, (float) qvariant_cast<double>(d.value));
+ break;
+ case QMetaType::QTransform:
+ program()->setUniformValue(loc, qvariant_cast<QTransform>(d.value));
+ break;
+ case QMetaType::Int:
+ program()->setUniformValue(loc, d.value.toInt());
+ break;
+ case QMetaType::Bool:
+ program()->setUniformValue(loc, GLint(d.value.toBool()));
+ break;
+ case QMetaType::QSize:
+ case QMetaType::QSizeF:
+ program()->setUniformValue(loc, d.value.toSizeF());
+ break;
+ case QMetaType::QPoint:
+ case QMetaType::QPointF:
+ program()->setUniformValue(loc, d.value.toPointF());
+ break;
+ case QMetaType::QRect:
+ case QMetaType::QRectF:
+ {
+ QRectF r = d.value.toRectF();
+ program()->setUniformValue(loc, r.x(), r.y(), r.width(), r.height());
+ }
+ break;
+ case QMetaType::QVector3D:
+ program()->setUniformValue(loc, qvariant_cast<QVector3D>(d.value));
+ break;
+ case QMetaType::QVector4D:
+ program()->setUniformValue(loc, qvariant_cast<QVector4D>(d.value));
+ break;
+ default:
+ break;
+ }
}
- break;
- case QMetaType::QVector3D:
- program()->setUniformValue(m_uniformLocs.at(i), qvariant_cast<QVector3D>(v));
- break;
- default:
- break;
}
}
const QQuickShaderEffectMaterial *oldMaterial = static_cast<const QQuickShaderEffectMaterial *>(oldEffect);
- if (oldEffect == 0 || material->cullMode() != oldMaterial->cullMode()) {
- switch (material->cullMode()) {
+ if (oldEffect == 0 || material->cullMode != oldMaterial->cullMode) {
+ switch (material->cullMode) {
case QQuickShaderEffectMaterial::FrontFaceCulling:
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
@@ -195,9 +203,6 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
break;
}
}
-
- if ((state.isMatrixDirty()) && material->m_source.respectsMatrix)
- program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
}
char const *const *QQuickCustomMaterialShader::attributeNames() const
@@ -277,38 +282,42 @@ void QQuickCustomMaterialShader::compile()
}
}
-void QQuickCustomMaterialShader::initialize()
-{
- m_opacityLoc = program()->uniformLocation("qt_Opacity");
- m_matrixLoc = program()->uniformLocation("qt_Matrix");
-}
-
const char *QQuickCustomMaterialShader::vertexShader() const
{
- return m_key.vertexCode.constData();
+ return m_key.sourceCode[QQuickShaderEffectMaterialKey::VertexShader].constData();
}
const char *QQuickCustomMaterialShader::fragmentShader() const
{
- return m_key.fragmentCode.constData();
+ return m_key.sourceCode[QQuickShaderEffectMaterialKey::FragmentShader].constData();
}
bool QQuickShaderEffectMaterialKey::operator == (const QQuickShaderEffectMaterialKey &other) const
{
- return vertexCode == other.vertexCode && fragmentCode == other.fragmentCode && className == other.className;
+ if (className != other.className)
+ return false;
+ for (int shaderType = 0; shaderType < ShaderTypeCount; ++shaderType) {
+ if (sourceCode[shaderType] != other.sourceCode[shaderType])
+ return false;
+ }
+ return true;
}
uint qHash(const QQuickShaderEffectMaterialKey &key)
{
- return qHash(qMakePair(qMakePair(key.vertexCode, key.fragmentCode), key.className));
+ uint hash = qHash((void *)key.className);
+ typedef QQuickShaderEffectMaterialKey Key;
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
+ hash = hash * 31337 + qHash(key.sourceCode[shaderType]);
+ return hash;
}
QHash<QQuickShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > QQuickShaderEffectMaterial::materialMap;
QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *node)
- : m_cullMode(NoCulling)
+ : cullMode(NoCulling)
, m_node(node)
, m_emittedLogChanged(false)
{
@@ -322,7 +331,7 @@ QSGMaterialType *QQuickShaderEffectMaterial::type() const
QSGMaterialShader *QQuickShaderEffectMaterial::createShader() const
{
- return new QQuickCustomMaterialShader(m_source, m_source.attributeNames);
+ return new QQuickCustomMaterialShader(m_source, attributes);
}
int QQuickShaderEffectMaterial::compare(const QSGMaterial *other) const
@@ -330,17 +339,7 @@ int QQuickShaderEffectMaterial::compare(const QSGMaterial *other) const
return this - static_cast<const QQuickShaderEffectMaterial *>(other);
}
-void QQuickShaderEffectMaterial::setCullMode(QQuickShaderEffectMaterial::CullMode face)
-{
- m_cullMode = face;
-}
-
-QQuickShaderEffectMaterial::CullMode QQuickShaderEffectMaterial::cullMode() const
-{
- return m_cullMode;
-}
-
-void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectProgram &source)
+void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMaterialKey &source)
{
m_source = source;
m_emittedLogChanged = false;
@@ -351,25 +350,10 @@ void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectProgra
}
}
-void QQuickShaderEffectMaterial::setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues)
-{
- m_uniformValues = uniformValues;
-}
-
-void QQuickShaderEffectMaterial::setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures)
-{
- m_textures = textures;
-}
-
-const QVector<QPair<QByteArray, QSGTextureProvider *> > &QQuickShaderEffectMaterial::textureProviders() const
-{
- return m_textures;
-}
-
void QQuickShaderEffectMaterial::updateTextures() const
{
- for (int i = 0; i < m_textures.size(); ++i) {
- if (QSGTextureProvider *provider = m_textures.at(i).second) {
+ for (int i = 0; i < textureProviders.size(); ++i) {
+ if (QSGTextureProvider *provider = textureProviders.at(i).second) {
if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(provider->texture()))
texture->updateTexture();
}
@@ -378,18 +362,16 @@ void QQuickShaderEffectMaterial::updateTextures() const
void QQuickShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider)
{
- for (int i = 0; i < m_textures.size(); ++i) {
- if (provider == m_textures.at(i).second)
- m_textures[i].second = 0;
+ for (int i = 0; i < textureProviders.size(); ++i) {
+ if (provider == textureProviders.at(i).second)
+ textureProviders[i].second = 0;
}
}
QQuickShaderEffectNode::QQuickShaderEffectNode()
- : m_material(this)
{
QSGNode::setFlag(UsePreprocess, true);
- setMaterial(&m_material);
#ifdef QML_RUNTIME_TESTING
description = QLatin1String("shadereffect");
@@ -407,8 +389,8 @@ void QQuickShaderEffectNode::markDirtyTexture()
void QQuickShaderEffectNode::textureProviderDestroyed(QObject *object)
{
- Q_ASSERT(qobject_cast<QSGTextureProvider *>(object));
- m_material.invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
+ Q_ASSERT(material());
+ static_cast<QQuickShaderEffectMaterial *>(material())->invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
}
void QQuickShaderEffectNode::preprocess()
diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h
index e22d2de9e2..1bbce86426 100644
--- a/src/quick/items/qquickshadereffectnode_p.h
+++ b/src/quick/items/qquickshadereffectnode_p.h
@@ -55,8 +55,14 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
struct QQuickShaderEffectMaterialKey {
- QByteArray vertexCode;
- QByteArray fragmentCode;
+ enum ShaderType
+ {
+ VertexShader,
+ FragmentShader,
+ ShaderTypeCount
+ };
+
+ QByteArray sourceCode[ShaderTypeCount];
const char *className;
bool operator == (const QQuickShaderEffectMaterialKey &other) const;
@@ -64,24 +70,21 @@ struct QQuickShaderEffectMaterialKey {
uint qHash(const QQuickShaderEffectMaterialKey &key);
-// TODO: Implement support for multisampling.
-struct QQuickShaderEffectProgram : public QQuickShaderEffectMaterialKey
-{
- QQuickShaderEffectProgram() : respectsOpacity(false), respectsMatrix(false) {}
-
- QVector<QByteArray> attributeNames;
- QSet<QByteArray> uniformNames;
-
- uint respectsOpacity : 1;
- uint respectsMatrix : 1;
-};
-
class QQuickCustomMaterialShader;
class QQuickShaderEffectNode;
class QQuickShaderEffectMaterial : public QSGMaterial
{
public:
+ struct UniformData
+ {
+ enum SpecialType { None, Sampler, Opacity, Matrix };
+
+ QByteArray name;
+ QVariant value;
+ SpecialType specialType;
+ };
+
enum CullMode
{
NoCulling,
@@ -94,13 +97,12 @@ public:
virtual QSGMaterialShader *createShader() const;
virtual int compare(const QSGMaterial *other) const;
- void setCullMode(CullMode face);
- CullMode cullMode() const;
+ QVector<QByteArray> attributes;
+ QVector<UniformData> uniforms[QQuickShaderEffectMaterialKey::ShaderTypeCount];
+ QVector<QPair<QByteArray, QSGTextureProvider *> > textureProviders;
+ CullMode cullMode;
- void setProgramSource(const QQuickShaderEffectProgram &);
- void setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues);
- void setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures);
- const QVector<QPair<QByteArray, QSGTextureProvider *> > &textureProviders() const;
+ void setProgramSource(const QQuickShaderEffectMaterialKey &source);
void updateTextures() const;
void invalidateTextureProvider(QSGTextureProvider *provider);
@@ -114,11 +116,8 @@ protected:
// one. To guarantee that the type pointer is unique, the type object must live as long as
// there are any CustomMaterialShaders of that type.
QSharedPointer<QSGMaterialType> m_type;
+ QQuickShaderEffectMaterialKey m_source;
- QQuickShaderEffectProgram m_source;
- QVector<QPair<QByteArray, QVariant> > m_uniformValues;
- QVector<QPair<QByteArray, QSGTextureProvider *> > m_textures;
- CullMode m_cullMode;
QQuickShaderEffectNode *m_node;
bool m_emittedLogChanged;
@@ -137,17 +136,12 @@ public:
virtual void preprocess();
- QQuickShaderEffectMaterial *shaderMaterial() { return &m_material; }
-
Q_SIGNALS:
void logAndStatusChanged(const QString &, int status);
private Q_SLOTS:
void markDirtyTexture();
void textureProviderDestroyed(QObject *object);
-
-private:
- QQuickShaderEffectMaterial m_material;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index d4ddbc400d..900cb84de8 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -389,6 +389,7 @@ QImage QQuickSpriteEngine::assembledImage()
else
qmlInfo(state) << "SpriteEngine: Animations too large to fit in one texture, pushed over the edge by:" << state->source().toLocalFile();
qmlInfo(state) << "SpriteEngine: Your texture max size today is " << maxSize;
+ return QImage();
}
state->m_generatedCount = rowsNeeded;
h += state->frameHeight() * rowsNeeded;
@@ -407,7 +408,7 @@ QImage QQuickSpriteEngine::assembledImage()
QPainter p(&image);
int y = 0;
foreach (QQuickSprite* state, m_sprites){
- QImage img(state->source().toLocalFile());
+ QImage img(state->m_pix.image());
int frameWidth = state->m_frameWidth;
int frameHeight = state->m_frameHeight;
if (img.height() == frameHeight && img.width() < maxSize){//Simple case
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index e1a28a466a..24dd10ac9f 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -748,7 +748,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
QTextLine line;
int visibleCount = 0;
bool elide;
- bool widthChanged;
qreal height = 0;
QString elideText;
bool once = true;
@@ -776,7 +775,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
bool truncateHeight = false;
truncated = false;
elide = false;
- widthChanged = false;
int characterCount = 0;
int unwrappedLineCount = 1;
int maxLineCount = maximumLineCount();
@@ -911,10 +909,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
const qreal oldWidth = lineWidth;
lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
- if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit)) {
- widthChanged = true;
+ if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit))
continue;
- }
}
// If the next needs to be elided and there's an abbreviated string available
@@ -2363,9 +2359,6 @@ void QQuickText::componentComplete()
QQuickItem::componentComplete();
if (d->updateOnComponentComplete)
d->updateLayout();
-
- // Enable accessibility for text items.
- d->setAccessibleFlagAndListener();
}
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index eefe938467..739b5f859b 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -44,6 +44,7 @@
#ifndef QT_NO_TEXTCONTROL
+#include <qcoreapplication.h>
#include <qfont.h>
#include <qpainter.h>
#include <qevent.h>
@@ -107,11 +108,12 @@ QQuickTextControlPrivate::QQuickTextControlPrivate()
ignoreAutomaticScrollbarAdjustement(false),
overwriteMode(false),
acceptRichText(true),
- hideCursor(false),
+ cursorVisible(false),
hasFocus(false),
isEnabled(true),
hadSelectionOnMousePress(false),
- wordSelectionEnabled(false)
+ wordSelectionEnabled(false),
+ hasImState(false)
{}
bool QQuickTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
@@ -292,6 +294,8 @@ void QQuickTextControlPrivate::setContent(Qt::TextFormat format, const QString &
{
Q_Q(QQuickTextControl);
+ cancelPreedit();
+
// for use when called from setPlainText. we may want to re-use the currently
// set char format then.
const QTextCharFormat charFormatForInsertion = cursor.charFormat();
@@ -1441,13 +1445,16 @@ void QQuickTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
QList<QTextLayout::FormatRange> overrides;
const int oldPreeditCursor = preeditCursor;
preeditCursor = e->preeditString().length();
- hideCursor = false;
+ hasImState = !e->preeditString().isEmpty();
+ cursorVisible = true;
for (int i = 0; i < e->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = e->attributes().at(i);
if (a.type == QInputMethodEvent::Cursor) {
+ hasImState = true;
preeditCursor = a.start;
- hideCursor = !a.length;
+ cursorVisible = a.length != 0;
} else if (a.type == QInputMethodEvent::TextFormat) {
+ hasImState = true;
QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
if (f.isValid()) {
QTextLayout::FormatRange o;
@@ -1514,6 +1521,37 @@ void QQuickTextControlPrivate::focusEvent(QFocusEvent *e)
}
}
+bool QQuickTextControl::hasImState() const
+{
+ Q_D(const QQuickTextControl);
+ return d->hasImState;
+}
+
+bool QQuickTextControl::cursorVisible() const
+{
+ Q_D(const QQuickTextControl);
+ return d->cursorVisible;
+}
+
+void QQuickTextControl::setCursorVisible(bool visible)
+{
+ Q_D(QQuickTextControl);
+ d->cursorVisible = visible;
+ d->setBlinkingCursorEnabled(d->cursorVisible
+ && (d->interactionFlags & (Qt::TextEditable | Qt::TextSelectableByKeyboard)));
+}
+
+QTextCursor QQuickTextControl::cursorForPosition(const QPointF &pos) const
+{
+ Q_D(const QQuickTextControl);
+ int cursorPos = hitTest(pos, Qt::FuzzyHit);
+ if (cursorPos == -1)
+ cursorPos = 0;
+ QTextCursor c(d->doc);
+ c.setPosition(cursorPos);
+ return c;
+}
+
QRectF QQuickTextControl::cursorRect(const QTextCursor &cursor) const
{
Q_D(const QQuickTextControl);
@@ -1727,21 +1765,31 @@ bool QQuickTextControlPrivate::isPreediting() const
void QQuickTextControlPrivate::commitPreedit()
{
- if (!isPreediting())
+ Q_Q(QQuickTextControl);
+
+ if (!hasImState)
return;
qApp->inputMethod()->commit();
- if (!isPreediting())
+ if (!hasImState)
return;
- cursor.beginEditBlock();
- preeditCursor = 0;
- QTextBlock block = cursor.block();
- QTextLayout *layout = block.layout();
- layout->setPreeditArea(-1, QString());
- layout->clearAdditionalFormats();
- cursor.endEditBlock();
+ QInputMethodEvent event;
+ QCoreApplication::sendEvent(q->parent(), &event);
+}
+
+void QQuickTextControlPrivate::cancelPreedit()
+{
+ Q_Q(QQuickTextControl);
+
+ if (!hasImState)
+ return;
+
+ qApp->inputMethod()->reset();
+
+ QInputMethodEvent event;
+ QCoreApplication::sendEvent(q->parent(), &event);
}
void QQuickTextControl::setTextInteractionFlags(Qt::TextInteractionFlags flags)
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 9e3fc90eb1..be3f7f7ccf 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -98,6 +98,10 @@ public:
QString toHtml() const;
#endif
+ bool hasImState() const;
+ bool cursorVisible() const;
+ void setCursorVisible(bool visible);
+ QTextCursor cursorForPosition(const QPointF &pos) const;
QRectF cursorRect(const QTextCursor &cursor) const;
QRectF cursorRect() const;
QRectF selectionRect(const QTextCursor &cursor) const;
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index c5a39cc759..3a10f007be 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -127,6 +127,7 @@ public:
bool isPreediting() const;
void commitPreedit();
+ void cancelPreedit();
QPointF trippleClickPoint;
QPointF mousePressPos;
@@ -155,11 +156,12 @@ public:
bool ignoreAutomaticScrollbarAdjustement : 1;
bool overwriteMode : 1;
bool acceptRichText : 1;
- bool hideCursor : 1; // used to hide the cursor in the preedit area
+ bool cursorVisible : 1; // used to hide the cursor in the preedit area
bool hasFocus : 1;
bool isEnabled : 1;
bool hadSelectionOnMousePress : 1;
bool wordSelectionEnabled : 1;
+ bool hasImState : 1;
void _q_copyLink();
void _q_updateBlock(const QTextBlock &);
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 4fa5233b9a..f727c54322 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -871,10 +871,9 @@ void QQuickTextEdit::setCursorVisible(bool on)
if (d->cursorVisible == on)
return;
d->cursorVisible = on;
- QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
if (!on && !d->persistentSelection)
d->control->setCursorIsFocusIndicator(true);
- d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
+ d->control->setCursorVisible(on);
emit cursorVisibleChanged(d->cursorVisible);
}
@@ -1536,15 +1535,18 @@ void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
Q_D(QQuickTextEdit);
const bool wasComposing = isInputMethodComposing();
d->control->processEvent(event, QPointF(0, -d->yoff));
+ setCursorVisible(d->control->cursorVisible());
if (wasComposing != isInputMethodComposing())
emit inputMethodComposingChanged();
}
void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
{
+ Q_D(QQuickTextEdit);
if (change == ItemActiveFocusHasChanged) {
setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus());
-
+ QFocusEvent focusEvent(value.boolValue ? QEvent::FocusIn : QEvent::FocusOut);
+ d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
if (value.boolValue) {
q_updateAlignment();
connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
@@ -1729,9 +1731,7 @@ bool QQuickTextEdit::canRedo() const
bool QQuickTextEdit::isInputMethodComposing() const
{
Q_D(const QQuickTextEdit);
- if (QTextLayout *layout = d->control->textCursor().block().layout())
- return layout->preeditAreaText().length() > 0;
- return false;
+ return d->control->hasImState();
}
void QQuickTextEditPrivate::init()
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index f2da67bae7..5aa01d27f3 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -45,6 +45,7 @@
#include <private/qqmlglobal_p.h>
+#include <QtCore/qcoreapplication.h>
#include <QtQml/qqmlinfo.h>
#include <QtGui/qevent.h>
#include <QTextBoundaryFinder>
@@ -62,10 +63,6 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
-static const int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
-#endif
-
/*!
\qmlclass TextInput QQuickTextInput
\inqmlmodule QtQuick 2
@@ -128,8 +125,8 @@ void QQuickTextInput::setText(const QString &s)
Q_D(QQuickTextInput);
if (s == text())
return;
- if (d->composeMode())
- qApp->inputMethod()->reset();
+
+ d->cancelPreedit();
d->internalSetText(s, -1, false);
}
@@ -678,9 +675,7 @@ QRectF QQuickTextInput::cursorRectangle() const
{
Q_D(const QQuickTextInput);
- int c = d->m_cursor;
- if (d->m_preeditCursor != -1)
- c += d->m_preeditCursor;
+ int c = d->m_cursor + d->m_preeditCursor;
if (d->m_echoMode == NoEcho)
c = 0;
QTextLine l = d->m_textLayout.lineForTextPosition(c);
@@ -1402,7 +1397,7 @@ void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
{
Q_D(QQuickTextInput);
- const bool wasComposing = d->preeditAreaText().length() > 0;
+ const bool wasComposing = d->hasImState;
if (d->m_readOnly) {
ev->ignore();
} else {
@@ -1411,7 +1406,7 @@ void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
if (!ev->isAccepted())
QQuickImplicitSizeItem::inputMethodEvent(ev);
- if (wasComposing != (d->m_textLayout.preeditAreaText().length() > 0))
+ if (wasComposing != d->hasImState)
emit inputMethodComposingChanged();
}
@@ -1929,11 +1924,11 @@ void QQuickTextInput::redo()
void QQuickTextInput::insert(int position, const QString &text)
{
Q_D(QQuickTextInput);
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
- if (d->m_echoMode == QQuickTextInput::Password)
- d->m_passwordEchoTimer.start(qt_passwordEchoDelay, this);
-#endif
-
+ if (d->m_echoMode == QQuickTextInput::Password) {
+ int delay = qGuiApp->styleHints()->passwordMaskDelay();
+ if (delay > 0)
+ d->m_passwordEchoTimer.start(delay, this);
+ }
if (position < 0 || position > d->m_text.length())
return;
@@ -2484,11 +2479,7 @@ void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
if (change == ItemActiveFocusHasChanged) {
bool hasFocus = value.boolValue;
setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
if (!hasFocus && (d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive())) {
-#else
- if (!hasFocus && d->m_passwordEchoEditing) {
-#endif
d->updatePasswordEchoEditing(false);//QQuickTextInputPrivate sets it on key events, but doesn't deal with focus events
}
@@ -2521,7 +2512,7 @@ void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
bool QQuickTextInput::isInputMethodComposing() const
{
Q_D(const QQuickTextInput);
- return d->preeditAreaText().length() > 0;
+ return d->hasImState;
}
void QQuickTextInputPrivate::init()
@@ -2660,7 +2651,6 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
if (m_echoMode == QQuickTextInput::Password) {
str.fill(m_passwordCharacter);
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
if (m_passwordEchoTimer.isActive() && m_cursor > 0 && m_cursor <= m_text.length()) {
int cursor = m_cursor - 1;
QChar uc = m_text.at(cursor);
@@ -2673,7 +2663,6 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
str[cursor - 1] = uc;
}
}
-#endif
} else if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing) {
str.fill(m_passwordCharacter);
}
@@ -2830,18 +2819,31 @@ void QQuickTextInputPrivate::paste(QClipboard::Mode clipboardMode)
*/
void QQuickTextInputPrivate::commitPreedit()
{
- if (!composeMode())
+ Q_Q(QQuickTextInput);
+
+ if (!hasImState)
return;
qApp->inputMethod()->commit();
- if (!composeMode())
+ if (!hasImState)
+ return;
+
+ QInputMethodEvent ev;
+ QCoreApplication::sendEvent(q, &ev);
+}
+
+void QQuickTextInputPrivate::cancelPreedit()
+{
+ Q_Q(QQuickTextInput);
+
+ if (!hasImState)
return;
- m_preeditCursor = 0;
- m_textLayout.setPreeditArea(-1, QString());
- m_textLayout.clearAdditionalFormats();
- updateLayout();
+ qApp->inputMethod()->reset();
+
+ QInputMethodEvent ev;
+ QCoreApplication::sendEvent(q, &ev);
}
/*!
@@ -3123,15 +3125,19 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
m_textLayout.setPreeditArea(m_cursor, event->preeditString());
#endif //QT_NO_IM
const int oldPreeditCursor = m_preeditCursor;
+ const bool oldCursorVisible = cursorVisible;
m_preeditCursor = event->preeditString().length();
- m_hideCursor = false;
+ hasImState = !event->preeditString().isEmpty();
+ cursorVisible = true;
QList<QTextLayout::FormatRange> formats;
for (int i = 0; i < event->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
if (a.type == QInputMethodEvent::Cursor) {
+ hasImState = true;
m_preeditCursor = a.start;
- m_hideCursor = !a.length;
+ cursorVisible = a.length != 0;
} else if (a.type == QInputMethodEvent::TextFormat) {
+ hasImState = true;
QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
if (f.isValid()) {
QTextLayout::FormatRange o;
@@ -3154,6 +3160,9 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
if (isGettingInput)
finishChange(priorState);
+ if (cursorVisible != oldCursorVisible)
+ emit q->cursorVisibleChanged(cursorVisible);
+
if (selectionChange) {
emit q->selectionChanged();
q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition
@@ -3333,11 +3342,12 @@ void QQuickTextInputPrivate::addCommand(const Command &cmd)
*/
void QQuickTextInputPrivate::internalInsert(const QString &s)
{
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
Q_Q(QQuickTextInput);
- if (m_echoMode == QQuickTextInput::Password)
- m_passwordEchoTimer.start(qt_passwordEchoDelay, q);
-#endif
+ if (m_echoMode == QQuickTextInput::Password) {
+ int delay = qGuiApp->styleHints()->passwordMaskDelay();
+ if (delay > 0)
+ m_passwordEchoTimer.start(delay, q);
+ }
if (hasSelectedText())
addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend));
if (m_maskData) {
@@ -3962,11 +3972,9 @@ void QQuickTextInput::timerEvent(QTimerEvent *event)
d->m_blinkStatus = !d->m_blinkStatus;
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
update();
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
} else if (event->timerId() == d->m_passwordEchoTimer.timerId()) {
d->m_passwordEchoTimer.stop();
d->updateDisplayText();
-#endif
}
}
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index 3bd34b2661..1bc2cf548b 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -115,7 +115,7 @@ public:
, selectPressed(false)
, textLayoutDirty(true)
, persistentSelection(false)
- , m_hideCursor(false)
+ , hasImState(false)
, m_separator(0)
, m_readOnly(0)
, m_textDirty(0)
@@ -202,9 +202,7 @@ public:
QColor selectionColor;
QColor selectedTextColor;
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
QBasicTimer m_passwordEchoTimer;
-#endif
int lastSelectionStart;
int lastSelectionEnd;
int m_cursor;
@@ -247,7 +245,7 @@ public:
bool selectPressed:1;
bool textLayoutDirty:1;
bool persistentSelection:1;
- bool m_hideCursor : 1; // used to hide the m_cursor inside preedit areas
+ bool hasImState : 1;
bool m_separator : 1;
bool m_readOnly : 1;
bool m_textDirty : 1;
@@ -321,6 +319,7 @@ public:
#endif
void commitPreedit();
+ void cancelPreedit();
Qt::CursorMoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); }
void setCursorMoveStyle(Qt::CursorMoveStyle style) { m_textLayout.setCursorMoveStyle(style); }
@@ -378,9 +377,7 @@ public:
void updatePasswordEchoEditing(bool editing);
void cancelPasswordEchoTimer() {
-#ifdef QT_GUI_PASSWORD_ECHO_DELAY
m_passwordEchoTimer.stop();
-#endif
}
Qt::LayoutDirection layoutDirection() const {
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 5be4963809..81340d6e66 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -254,9 +254,6 @@ namespace {
decorations |= (backgroundColor.isValid() ? QQuickTextNode::Background : QQuickTextNode::NoDecoration);
qreal ascent = glyphRun.rawFont().ascent();
- // ### QTBUG-22919 The bounding rect returned by QGlyphRun appears to start on the
- // baseline, move it by the ascent so all bounding rects are at baseline - ascent.
- searchRect.translate(0, -ascent);
insert(binaryTree, BinaryTreeNode(glyphRun, selectionState, searchRect, decorations,
textColor, backgroundColor, position, ascent));
}
@@ -1219,12 +1216,6 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex
int textPos = block.position();
QTextBlock::iterator blockIterator = block.begin();
- if (blockIterator.atEnd() && preeditLength) {
- engine.setPosition(blockPosition);
- textPos = engine.addText(block, block.charFormat(), textColor, colorChanges,
- textPos, textPos + preeditLength,
- selectionStart, selectionEnd);
- }
while (!blockIterator.atEnd()) {
QTextFragment fragment = blockIterator.fragment();
@@ -1275,6 +1266,19 @@ void QQuickTextNode::addTextDocument(const QPointF &position, QTextDocument *tex
++blockIterator;
}
+ if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) {
+ engine.setPosition(blockPosition);
+ textPos = block.position() + preeditPosition;
+ QTextLine line = block.layout()->lineForTextPosition(preeditPosition);
+ if (!engine.currentLine().isValid()
+ || line.lineNumber() != engine.currentLine().lineNumber()) {
+ engine.setCurrentLine(line);
+ }
+ textPos = engine.addText(block, block.charFormat(), textColor, colorChanges,
+ textPos, textPos + preeditLength,
+ selectionStart, selectionEnd);
+ }
+
engine.setCurrentLine(QTextLine()); // Reset current line because the text layout changed
++it;
}
diff --git a/src/quick/items/qquickvisualdatamodel.cpp b/src/quick/items/qquickvisualdatamodel.cpp
index 88d46c60ee..cea83969f3 100644
--- a/src/quick/items/qquickvisualdatamodel.cpp
+++ b/src/quick/items/qquickvisualdatamodel.cpp
@@ -803,7 +803,7 @@ QObject *QQuickVisualDataModelPrivate::object(Compositor::Group group, int index
}
if (cacheItem->incubationTask) {
- if (!asynchronous) {
+ if (!asynchronous && cacheItem->incubationTask->incubationMode() == QQmlIncubator::Asynchronous) {
// previously requested async - now needed immediately
cacheItem->incubationTask->forceCompletion();
}
diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp
index bac5cc7582..d075d3b64b 100644
--- a/src/quick/items/qquickwindowmanager.cpp
+++ b/src/quick/items/qquickwindowmanager.cpp
@@ -1221,7 +1221,7 @@ void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas)
maybeUpdate(canvas);
}
-void QQuickTrivialWindowManager::exposureChanged(QQuickCanvas *canvas)
+void QQuickTrivialWindowManager::exposureChanged(QQuickCanvas *)
{
}
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 72fd2b32bd..156ccec127 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -42,14 +42,14 @@
#ifndef QQUICKWINDOWMODULE_H
#define QQUICKWINDOWMODULE_H
-#include <qqml.h>
+#include <private/qtquickglobal_p.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QQuickWindowModule
+class Q_QUICK_PRIVATE_EXPORT QQuickWindowModule
{
public:
static void defineModule();
diff --git a/src/quick/particles/qquickcustomparticle.cpp b/src/quick/particles/qquickcustomparticle.cpp
index 8f75672e32..7d27e48c6b 100644
--- a/src/quick/particles/qquickcustomparticle.cpp
+++ b/src/quick/particles/qquickcustomparticle.cpp
@@ -130,29 +130,27 @@ struct PlainVertices {
QQuickCustomParticle::QQuickCustomParticle(QQuickItem* parent)
: QQuickParticlePainter(parent)
- , m_dirtyData(true)
- , m_material(0)
- , m_rootNode(0)
+ , m_dirtyUniforms(true)
+ , m_dirtyUniformValues(true)
+ , m_dirtyTextureProviders(true)
+ , m_dirtyProgram(true)
{
setFlag(QQuickItem::ItemHasContents);
}
-class QQuickShaderEffectMaterialObject : public QObject, public QQuickShaderEffectMaterial { };
-
void QQuickCustomParticle::sceneGraphInvalidated()
{
m_nodes.clear();
- m_rootNode = 0;
}
QQuickCustomParticle::~QQuickCustomParticle()
{
- if (m_material)
- m_material->deleteLater();
}
void QQuickCustomParticle::componentComplete()
{
+ m_common.updateShader(this, Key::FragmentShader);
+ updateVertexShader();
reset();
QQuickParticlePainter::componentComplete();
}
@@ -170,10 +168,12 @@ void QQuickCustomParticle::componentComplete()
void QQuickCustomParticle::setFragmentShader(const QByteArray &code)
{
- if (m_source.fragmentCode.constData() == code.constData())
+ if (m_common.source.sourceCode[Key::FragmentShader].constData() == code.constData())
return;
- m_source.fragmentCode = code;
+ m_common.source.sourceCode[Key::FragmentShader] = code;
+ m_dirtyProgram = true;
if (isComponentComplete()) {
+ m_common.updateShader(this, Key::FragmentShader);
reset();
}
emit fragmentShaderChanged();
@@ -222,236 +222,108 @@ void QQuickCustomParticle::setFragmentShader(const QByteArray &code)
void QQuickCustomParticle::setVertexShader(const QByteArray &code)
{
- if (m_source.vertexCode.constData() == code.constData())
+ if (m_common.source.sourceCode[Key::VertexShader].constData() == code.constData())
return;
- m_source.vertexCode = code;
+ m_common.source.sourceCode[Key::VertexShader] = code;
+
+ m_dirtyProgram = true;
if (isComponentComplete()) {
+ updateVertexShader();
reset();
}
emit vertexShaderChanged();
}
-void QQuickCustomParticle::reset()
+void QQuickCustomParticle::updateVertexShader()
{
- disconnectPropertySignals();
-
- m_source.attributeNames.clear();
- m_source.uniformNames.clear();
- m_source.respectsOpacity = false;
- m_source.respectsMatrix = false;
- m_source.className = metaObject()->className();
-
- for (int i = 0; i < m_sources.size(); ++i) {
- const SourceData &source = m_sources.at(i);
- delete source.mapper;
- if (source.item && source.item->parentItem() == this)
- source.item->setParentItem(0);
- }
- m_sources.clear();
-
- QQuickParticlePainter::reset();
- m_pleaseReset = true;
- update();
+ m_common.disconnectPropertySignals(this, Key::VertexShader);
+ qDeleteAll(m_common.signalMappers[Key::VertexShader]);
+ m_common.uniformData[Key::VertexShader].clear();
+ m_common.signalMappers[Key::VertexShader].clear();
+ m_common.attributes.clear();
+ m_common.attributes.append("qt_ParticlePos");
+ m_common.attributes.append("qt_ParticleTex");
+ m_common.attributes.append("qt_ParticleData");
+ m_common.attributes.append("qt_ParticleVec");
+ m_common.attributes.append("qt_ParticleR");
+
+ UniformData d;
+ d.name = "qt_Matrix";
+ d.specialType = UniformData::Matrix;
+ m_common.uniformData[Key::VertexShader].append(d);
+ m_common.signalMappers[Key::VertexShader].append(0);
+
+ d.name = "qt_Timestamp";
+ d.specialType = UniformData::None;
+ m_common.uniformData[Key::VertexShader].append(d);
+ m_common.signalMappers[Key::VertexShader].append(0);
+
+ const QByteArray &code = m_common.source.sourceCode[Key::VertexShader];
+ if (!code.isEmpty())
+ m_common.lookThroughShaderCode(this, Key::VertexShader, code);
+
+ m_common.connectPropertySignals(this, Key::VertexShader);
}
-
-void QQuickCustomParticle::changeSource(int index)
-{
- Q_ASSERT(index >= 0 && index < m_sources.size());
- QVariant v = property(m_sources.at(index).name.constData());
- setSource(v, index);
-}
-
-void QQuickCustomParticle::updateData()
+void QQuickCustomParticle::reset()
{
- m_dirtyData = true;
+ QQuickParticlePainter::reset();
update();
}
-void QQuickCustomParticle::setSource(const QVariant &var, int index)
-{
- Q_ASSERT(index >= 0 && index < m_sources.size());
-
- SourceData &source = m_sources[index];
-
- source.item = 0;
- if (var.isNull()) {
- return;
- } else if (!qVariantCanConvert<QObject *>(var)) {
- qWarning("Could not assign source of type '%s' to property '%s'.", var.typeName(), source.name.constData());
- return;
- }
-
- QObject *obj = qVariantValue<QObject *>(var);
- source.item = qobject_cast<QQuickItem *>(obj);
- if (!source.item || !source.item->isTextureProvider()) {
- qWarning("ShaderEffect: source uniform [%s] is not assigned a valid texture provider: %s [%s]",
- source.name.constData(), qPrintable(obj->objectName()), obj->metaObject()->className());
- return;
- }
-
- // TODO: Copy better solution in QQuickShaderEffect when they find it.
- // 'source.item' needs a canvas to get a scenegraph node.
- // The easiest way to make sure it gets a canvas is to
- // make it a part of the same item tree as 'this'.
- if (source.item && source.item->parentItem() == 0) {
- source.item->setParentItem(this);
- source.item->setVisible(false);
- }
-}
-
-void QQuickCustomParticle::disconnectPropertySignals()
-{
- disconnect(this, 0, this, SLOT(updateData()));
- for (int i = 0; i < m_sources.size(); ++i) {
- SourceData &source = m_sources[i];
- disconnect(this, 0, source.mapper, 0);
- disconnect(source.mapper, 0, this, 0);
- }
-}
-
-void QQuickCustomParticle::connectPropertySignals()
-{
- QSet<QByteArray>::const_iterator it;
- for (it = m_source.uniformNames.begin(); it != m_source.uniformNames.end(); ++it) {
- int pi = metaObject()->indexOfProperty(it->constData());
- if (pi >= 0) {
- QMetaProperty mp = metaObject()->property(pi);
- if (!mp.hasNotifySignal())
- qWarning("QQuickCustomParticle: property '%s' does not have notification method!", it->constData());
- QByteArray signalName("2");
- signalName.append(mp.notifySignal().methodSignature());
- connect(this, signalName, this, SLOT(updateData()));
- } else {
- qWarning("QQuickCustomParticle: '%s' does not have a matching property!", it->constData());
- }
- }
- for (int i = 0; i < m_sources.size(); ++i) {
- SourceData &source = m_sources[i];
- int pi = metaObject()->indexOfProperty(source.name.constData());
- if (pi >= 0) {
- QMetaProperty mp = metaObject()->property(pi);
- QByteArray signalName("2");
- signalName.append(mp.notifySignal().methodSignature());
- connect(this, signalName, source.mapper, SLOT(map()));
- source.mapper->setMapping(this, i);
- connect(source.mapper, SIGNAL(mapped(int)), this, SLOT(changeSource(int)));
- } else {
- qWarning("QQuickCustomParticle: '%s' does not have a matching source!", source.name.constData());
- }
- }
-}
-
-void QQuickCustomParticle::updateProperties()
-{
- QByteArray vertexCode = m_source.vertexCode;
- QByteArray fragmentCode = m_source.fragmentCode;
- if (vertexCode.isEmpty())
- vertexCode = qt_particles_default_vertex_code;
- if (fragmentCode.isEmpty())
- fragmentCode = qt_particles_default_fragment_code;
- vertexCode = qt_particles_template_vertex_code + vertexCode;
-
- m_source.attributeNames.clear();
- m_source.attributeNames << "qt_ParticlePos"
- << "qt_ParticleTex"
- << "qt_ParticleData"
- << "qt_ParticleVec"
- << "qt_ParticleR";
-
- lookThroughShaderCode(vertexCode);
- lookThroughShaderCode(fragmentCode);
-
- if (!m_source.respectsMatrix)
- qWarning("QQuickCustomParticle: Missing reference to \'qt_Matrix\'.");
- if (!m_source.respectsOpacity)
- qWarning("QQuickCustomParticle: Missing reference to \'qt_Opacity\'.");
-
- for (int i = 0; i < m_sources.size(); ++i) {
- QVariant v = property(m_sources.at(i).name);
- setSource(v, i);
- }
-
- connectPropertySignals();
-}
-
-void QQuickCustomParticle::lookThroughShaderCode(const QByteArray &code)
-{
- // Regexp for matching attributes and uniforms.
- // In human readable form: attribute|uniform [lowp|mediump|highp] <type> <name>
- static QRegExp re(QLatin1String("\\b(attribute|uniform)\\b\\s*\\b(?:lowp|mediump|highp)?\\b\\s*\\b(\\w+)\\b\\s*\\b(\\w+)"));
- Q_ASSERT(re.isValid());
-
- int pos = -1;
-
- QString wideCode = QString::fromLatin1(code.constData(), code.size());
-
- while ((pos = re.indexIn(wideCode, pos + 1)) != -1) {
- QByteArray decl = re.cap(1).toLatin1(); // uniform or attribute
- QByteArray type = re.cap(2).toLatin1(); // type
- QByteArray name = re.cap(3).toLatin1(); // variable name
-
- if (decl == "attribute") {
- if (!m_source.attributeNames.contains(name))
- qWarning() << "Custom Particle: Unknown attribute " << name;
- } else {
- Q_ASSERT(decl == "uniform");//TODO: Shouldn't assert
-
- if (name == "qt_Matrix") {
- m_source.respectsMatrix = true;
- } else if (name == "qt_Opacity") {
- m_source.respectsOpacity = true;
- } else if (name == "qt_Timestamp") {
- //Not strictly necessary
- } else {
- m_source.uniformNames.insert(name);
- if (type == "sampler2D") {
- SourceData d;
- d.mapper = new QSignalMapper;
- d.name = name;
- d.item = 0;
- m_sources.append(d);
- }
- }
- }
- }
-}
-
QSGNode *QQuickCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
- Q_UNUSED(oldNode);
+ QQuickShaderEffectNode *rootNode = static_cast<QQuickShaderEffectNode *>(oldNode);
if (m_pleaseReset){
-
- //delete m_material;//Shader effect item doesn't regen material?
-
- delete m_rootNode;//Automatically deletes children
- m_rootNode = 0;
+ delete rootNode;//Automatically deletes children
+ rootNode = 0;
m_nodes.clear();
m_pleaseReset = false;
- m_dirtyData = false;
+ m_dirtyProgram = true;
}
if (m_system && m_system->isRunning() && !m_system->isPaused()){
- prepareNextFrame();
- if (m_rootNode) {
+ rootNode = prepareNextFrame(rootNode);
+ if (rootNode)
update();
- foreach (QSGGeometryNode* node, m_nodes)
- node->markDirty(QSGNode::DirtyGeometry);//done in buildData?
- }
}
- return m_rootNode;
+ return rootNode;
}
-void QQuickCustomParticle::prepareNextFrame(){
- if (!m_rootNode)
- m_rootNode = buildCustomNodes();
- if (!m_rootNode)
- return;
+QQuickShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickShaderEffectNode *rootNode)
+{
+ if (!rootNode)
+ rootNode = buildCustomNodes();
+
+ if (!rootNode)
+ return 0;
+
+ if (m_dirtyProgram) {
+ QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(rootNode->material());
+ Q_ASSERT(material);
+
+ Key s = m_common.source;
+ if (s.sourceCode[Key::FragmentShader].isEmpty())
+ s.sourceCode[Key::FragmentShader] = qt_particles_default_fragment_code;
+ if (s.sourceCode[Key::VertexShader].isEmpty())
+ s.sourceCode[Key::VertexShader] = qt_particles_default_vertex_code;
+ s.sourceCode[Key::VertexShader] = qt_particles_template_vertex_code + s.sourceCode[Key::VertexShader];
+ s.className = metaObject()->className();
+
+ material->setProgramSource(s);
+ material->attributes = m_common.attributes;
+ foreach (QQuickShaderEffectNode* node, m_nodes)
+ node->markDirty(QSGNode::DirtyMaterial);
+
+ m_dirtyProgram = false;
+ m_dirtyUniforms = true;
+ }
m_lastTime = m_system->systemSync(this) / 1000.;
- if (m_dirtyData || true)//Currently this is how we update timestamp... potentially over expensive.
- buildData();
+ if (true) //Currently this is how we update timestamp... potentially over expensive.
+ buildData(rootNode);
+ return rootNode;
}
QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
@@ -468,20 +340,13 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
return 0;
}
- updateProperties();
-
- QQuickShaderEffectProgram s = m_source;
- if (s.fragmentCode.isEmpty())
- s.fragmentCode = qt_particles_default_fragment_code;
- if (s.vertexCode.isEmpty())
- s.vertexCode = qt_particles_default_vertex_code;
+ if (m_groups.isEmpty())
+ return 0;
- if (!m_material) {
- m_material = new QQuickShaderEffectMaterialObject;
- }
+ QQuickShaderEffectNode *rootNode = 0;
+ QQuickShaderEffectMaterial *material = new QQuickShaderEffectMaterial;
+ m_dirtyProgram = true;
- s.vertexCode = qt_particles_template_vertex_code + s.vertexCode;
- m_material->setProgramSource(s);
foreach (const QString &str, m_groups){
int gIdx = m_system->groupIds[str];
int count = m_system->groupData[gIdx]->size();
@@ -489,8 +354,7 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
QQuickShaderEffectNode* node = new QQuickShaderEffectNode();
m_nodes.insert(gIdx, node);
- node->setMaterial(m_material);
- node->markDirty(QSGNode::DirtyMaterial);
+ node->setMaterial(material);
//Create Particle Geometry
int vCount = count * 4;
@@ -498,6 +362,7 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
QSGGeometry *g = new QSGGeometry(PlainParticle_AttributeSet, vCount, iCount);
g->setDrawingMode(GL_TRIANGLES);
node->setGeometry(g);
+ node->setFlag(QSGNode::OwnsGeometry, true);
PlainVertex *vertices = (PlainVertex *) g->vertexData();
for (int p=0; p < count; ++p) {
commit(gIdx, p);
@@ -526,48 +391,46 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes()
indices += 6;
}
}
- foreach (QQuickShaderEffectNode* node, m_nodes){
- if (node == *(m_nodes.begin()))
- continue;
- (*(m_nodes.begin()))->appendChildNode(node);
- }
- return *(m_nodes.begin());
+ QHash<int, QQuickShaderEffectNode*>::const_iterator it = m_nodes.begin();
+ rootNode = it.value();
+ rootNode->setFlag(QSGNode::OwnsMaterial, true);
+ for (++it; it != m_nodes.end(); ++it)
+ rootNode->appendChildNode(it.value());
+
+ return rootNode;
}
+void QQuickCustomParticle::sourceDestroyed(QObject *object)
+{
+ m_common.sourceDestroyed(object);
+}
-void QQuickCustomParticle::buildData()
+void QQuickCustomParticle::propertyChanged(int mappedId)
{
- if (!m_rootNode)
+ bool textureProviderChanged;
+ m_common.propertyChanged(this, mappedId, &textureProviderChanged);
+ m_dirtyTextureProviders |= textureProviderChanged;
+ m_dirtyUniformValues = true;
+ update();
+}
+
+
+void QQuickCustomParticle::buildData(QQuickShaderEffectNode *rootNode)
+{
+ if (!rootNode)
return;
- const QByteArray timestampName("qt_Timestamp");
- QVector<QPair<QByteArray, QVariant> > values;
- QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
- const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = m_material->textureProviders();
- for (int i = 0; i < oldTextures.size(); ++i) {
- QSGTextureProvider *t = oldTextures.at(i).second;
- if (t)
- foreach (QQuickShaderEffectNode* node, m_nodes)
- disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
- }
- for (int i = 0; i < m_sources.size(); ++i) {
- const SourceData &source = m_sources.at(i);
- QSGTextureProvider *t = source.item->textureProvider();
- textures.append(qMakePair(source.name, t));
- if (t)
- foreach (QQuickShaderEffectNode* node, m_nodes)
- connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
- }
- for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
- it != m_source.uniformNames.end(); ++it) {
- values.append(qMakePair(*it, property(*it)));
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < m_common.uniformData[shaderType].size(); ++i) {
+ if (m_common.uniformData[shaderType].at(i).name == "qt_Timestamp")
+ m_common.uniformData[shaderType][i].value = qVariantFromValue(m_lastTime);
+ }
}
- values.append(qMakePair(timestampName, QVariant(m_lastTime)));
- m_material->setUniforms(values);
- m_material->setTextureProviders(textures);
- m_dirtyData = false;
+ m_common.updateMaterial(rootNode, static_cast<QQuickShaderEffectMaterial *>(rootNode->material()),
+ m_dirtyUniforms, true, m_dirtyTextureProviders);
foreach (QQuickShaderEffectNode* node, m_nodes)
node->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
}
void QQuickCustomParticle::initialize(int gIdx, int pIdx)
@@ -599,4 +462,12 @@ void QQuickCustomParticle::commit(int gIdx, int pIdx)
}
}
+void QQuickCustomParticle::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ if (change == QQuickItem::ItemSceneChange)
+ m_common.updateCanvas(value.canvas);
+ QQuickParticlePainter::itemChange(change, value);
+}
+
+
QT_END_NAMESPACE
diff --git a/src/quick/particles/qquickcustomparticle_p.h b/src/quick/particles/qquickcustomparticle_p.h
index e04ac704d0..f689091268 100644
--- a/src/quick/particles/qquickcustomparticle_p.h
+++ b/src/quick/particles/qquickcustomparticle_p.h
@@ -43,6 +43,7 @@
#define CUSTOM_PARTICLE_H
#include "qquickparticlepainter_p.h"
#include <private/qquickshadereffectnode_p.h>
+#include <private/qquickshadereffect_p.h>
#include <QSignalMapper>
QT_BEGIN_HEADER
@@ -65,53 +66,50 @@ public:
explicit QQuickCustomParticle(QQuickItem* parent=0);
~QQuickCustomParticle();
- QByteArray fragmentShader() const { return m_source.fragmentCode; }
+ QByteArray fragmentShader() const { return m_common.source.sourceCode[Key::FragmentShader]; }
void setFragmentShader(const QByteArray &code);
- QByteArray vertexShader() const { return m_source.vertexCode; }
+ QByteArray vertexShader() const { return m_common.source.sourceCode[Key::VertexShader]; }
void setVertexShader(const QByteArray &code);
-public Q_SLOTS:
- void updateData();
- void changeSource(int);
+
Q_SIGNALS:
void fragmentShaderChanged();
void vertexShaderChanged();
+
protected:
virtual void initialize(int gIdx, int pIdx);
virtual void commit(int gIdx, int pIdx);
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
- void prepareNextFrame();
- void setSource(const QVariant &var, int index);
- void disconnectPropertySignals();
- void connectPropertySignals();
+ QQuickShaderEffectNode *prepareNextFrame(QQuickShaderEffectNode *rootNode);
void reset();
void resize(int oldCount, int newCount);
- void updateProperties();
- void lookThroughShaderCode(const QByteArray &code);
virtual void componentComplete();
QQuickShaderEffectNode *buildCustomNodes();
- void performPendingResize();
void sceneGraphInvalidated();
+ void itemChange(ItemChange change, const ItemChangeData &value);
+
+private Q_SLOTS:
+ void sourceDestroyed(QObject *object);
+ void propertyChanged(int mappedId);
private:
- void buildData();
-
- bool m_dirtyData;
- QQuickShaderEffectProgram m_source;
- struct SourceData
- {
- QSignalMapper *mapper;
- QPointer<QQuickItem> item;
- QByteArray name;
- };
- QVector<SourceData> m_sources;
- QQuickShaderEffectMaterialObject *m_material;
- QQuickShaderEffectNode* m_rootNode;
+ typedef QQuickShaderEffectMaterialKey Key;
+ typedef QQuickShaderEffectMaterial::UniformData UniformData;
+
+ void buildData(QQuickShaderEffectNode *rootNode);
+ void updateVertexShader();
+
+ QQuickShaderEffectCommon m_common;
+
QHash<int, QQuickShaderEffectNode*> m_nodes;
qreal m_lastTime;
+ uint m_dirtyUniforms : 1;
+ uint m_dirtyUniformValues : 1;
+ uint m_dirtyTextureProviders : 1;
+ uint m_dirtyProgram : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/particles/qquickparticleemitter_p.h b/src/quick/particles/qquickparticleemitter_p.h
index 70adcff34c..eb9e1fd591 100644
--- a/src/quick/particles/qquickparticleemitter_p.h
+++ b/src/quick/particles/qquickparticleemitter_p.h
@@ -178,7 +178,8 @@ public slots:
{
if (m_system != arg) {
m_system = arg;
- m_system->registerParticleEmitter(this);
+ if (m_system)
+ m_system->registerParticleEmitter(this);
emit systemChanged(arg);
}
}
diff --git a/src/quick/particles/qquickparticlesmodule_p.h b/src/quick/particles/qquickparticlesmodule_p.h
index b7cf09919e..23a40488cf 100644
--- a/src/quick/particles/qquickparticlesmodule_p.h
+++ b/src/quick/particles/qquickparticlesmodule_p.h
@@ -39,16 +39,16 @@
**
****************************************************************************/
-#ifndef QQuickPARTICLESMODULE_H
-#define QQuickPARTICLESMODULE_H
+#ifndef QQUICKPARTICLESMODULE_H
+#define QQUICKPARTICLESMODULE_H
-#include <qqml.h>
+#include <private/qtquickglobal_p.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-class QQuickParticlesModule
+class Q_QUICK_PRIVATE_EXPORT QQuickParticlesModule
{
public:
static void defineModule();
@@ -58,4 +58,4 @@ QT_END_NAMESPACE
QT_END_HEADER
-#endif // QQuickPARTICLESMODULE_H
+#endif // QQUICKPARTICLESMODULE_H
diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp
index 16cf2198a2..8a0c05618a 100644
--- a/src/quick/qtquick2.cpp
+++ b/src/quick/qtquick2.cpp
@@ -44,14 +44,12 @@
#include <private/qquickutilmodule_p.h>
#include <private/qquickvaluetypes_p.h>
#include <private/qquickitemsmodule_p.h>
-#include <private/qquickparticlesmodule_p.h>
-#include <private/qquickwindowmodule_p.h>
-#include <private/qquickapplication_p.h>
#include <private/qqmlenginedebugservice_p.h>
#include <private/qqmldebugstatesdelegate_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlcontext_p.h>
+#include <private/qquickapplication_p.h>
#include <QtQuick/private/qquickpropertychanges_p.h>
#include <QtQuick/private/qquickstate_p.h>
#include <qqmlproperty.h>
@@ -176,8 +174,6 @@ void QQmlQtQuick2Module::defineModule()
QQuickUtilModule::defineModule();
QQmlEnginePrivate::defineModule();
QQuickItemsModule::defineModule();
- QQuickParticlesModule::defineModule();
- QQuickWindowModule::defineModule();
qmlRegisterUncreatableType<QQuickApplication>("QtQuick",2,0,"Application", QQuickApplication::tr("Application is an abstract class"));
diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
index cd5aaaedd7..dd9db4e904 100644
--- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
@@ -86,11 +86,11 @@ QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteAr
connect(sharedGraphicsCache, SIGNAL(itemsMissing(QByteArray,QVector<quint32>)),
this, SLOT(reportItemsMissing(QByteArray,QVector<quint32>)),
Qt::DirectConnection);
- connect(sharedGraphicsCache, SIGNAL(itemsAvailable(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
- this, SLOT(reportItemsAvailable(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
+ connect(sharedGraphicsCache, SIGNAL(itemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
+ this, SLOT(reportItemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
Qt::DirectConnection);
- connect(sharedGraphicsCache, SIGNAL(itemsUpdated(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
- this, SLOT(reportItemsUpdated(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
+ connect(sharedGraphicsCache, SIGNAL(itemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
+ this, SLOT(reportItemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
Qt::DirectConnection);
connect(sharedGraphicsCache, SIGNAL(itemsInvalidated(QByteArray,QVector<quint32>)),
this, SLOT(reportItemsInvalidated(QByteArray,QVector<quint32>)),
@@ -537,7 +537,7 @@ void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs()
while (it != textureContentForBuffer.constEnd()) {
Texture texture;
texture.textureId = m_sharedGraphicsCache->textureIdForBuffer(it.key());
- texture.size = it.value().size;
+ texture.size = m_sharedGraphicsCache->sizeOfBuffer(it.key());
#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG_)
saveTexture(texture.textureId, texture.size.width(), texture.size.height());
@@ -557,7 +557,6 @@ void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs()
void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &cacheId,
void *bufferId,
- const QSize &bufferSize,
const QVector<quint32> &itemIds,
const QVector<QPoint> &positions)
{
@@ -568,8 +567,8 @@ void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &ca
return;
#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
- qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsAvailable() called for %s (%d glyphs, bufferSize: %dx%d)",
- cacheId.constData(), itemIds.size(), bufferSize.width(), bufferSize.height());
+ qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsAvailable() called for %s (%d glyphs)",
+ cacheId.constData(), itemIds.size());
#endif
for (int i=0; i<itemIds.size(); ++i) {
@@ -581,11 +580,11 @@ void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &ca
}
if (requestedItemsInList)
- reportItemsUpdated(cacheId, bufferId, bufferSize, itemIds, positions);
+ reportItemsUpdated(cacheId, bufferId,itemIds, positions);
}
void QSGSharedDistanceFieldGlyphCache::reportItemsUpdated(const QByteArray &cacheId,
- void *bufferId, const QSize &bufferSize,
+ void *bufferId,
const QVector<quint32> &itemIds,
const QVector<QPoint> &positions)
{
@@ -597,19 +596,17 @@ void QSGSharedDistanceFieldGlyphCache::reportItemsUpdated(const QByteArray &cach
Q_ASSERT(itemIds.size() == positions.size());
#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
- qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsUpdated() called for %s (%d glyphs, bufferSize: %dx%d)",
- cacheId.constData(), itemIds.size(), bufferSize.width(), bufferSize.height());
+ qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsUpdated() called for %s (%d glyphs)",
+ cacheId.constData(), itemIds.size());
#endif
for (int i=0; i<itemIds.size(); ++i) {
if (m_requestedGlyphs.contains(itemIds.at(i))) {
PendingGlyph &pendingGlyph = m_pendingReadyGlyphs[itemIds.at(i)];
void *oldBuffer = pendingGlyph.buffer;
- Q_ASSERT(bufferSize.height() >= pendingGlyph.bufferSize.height());
pendingGlyph.buffer = bufferId;
pendingGlyph.position = positions.at(i);
- pendingGlyph.bufferSize = bufferSize;
m_sharedGraphicsCache->referenceBuffer(bufferId);
if (oldBuffer != 0)
diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h
index 19844bbda4..2d43246bb0 100644
--- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h
@@ -77,10 +77,13 @@ Q_SIGNALS:
private Q_SLOTS:
void reportItemsMissing(const QByteArray &cacheId, const QVector<quint32> &itemIds);
void reportItemsAvailable(const QByteArray &cacheId,
- void *bufferId, const QSize &bufferSize,
- const QVector<quint32> &itemIds, const QVector<QPoint> &positions);
- void reportItemsUpdated(const QByteArray &cacheId, void *bufferId, const QSize &bufferSize,
- const QVector<quint32> &itemIds, const QVector<QPoint> &positions);
+ void *bufferId,
+ const QVector<quint32> &itemIds,
+ const QVector<QPoint> &positions);
+ void reportItemsUpdated(const QByteArray &cacheId,
+ void *bufferId,
+ const QVector<quint32> &itemIds,
+ const QVector<QPoint> &positions);
void reportItemsInvalidated(const QByteArray &cacheId, const QVector<quint32> &itemIds);
private:
diff --git a/src/quick/scenegraph/util/qsgpainternode.cpp b/src/quick/scenegraph/util/qsgpainternode.cpp
index 1ea64f6205..87a54d3124 100644
--- a/src/quick/scenegraph/util/qsgpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgpainternode.cpp
@@ -73,6 +73,10 @@ QSGPainterTexture::QSGPainterTexture()
}
+#ifdef QT_OPENGL_ES
+extern void qsg_swizzleBGRAToRGBA(QImage *image);
+#endif
+
void QSGPainterTexture::bind()
{
if (m_dirty_rect.isNull()) {
@@ -91,6 +95,7 @@ void QSGPainterTexture::bind()
int h = m_dirty_rect.height();
#ifdef QT_OPENGL_ES
+ qsg_swizzleBGRAToRGBA(&subImage);
glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h,
GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits());
#else
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 24b92fa98f..7be38ff109 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -402,7 +402,7 @@ QSGPlainTexture::~QSGPlainTexture()
}
#ifdef QT_OPENGL_ES
-static void swizzleBGRAToRGBA(QImage *image)
+void qsg_swizzleBGRAToRGBA(QImage *image)
{
const int width = image->width();
const int height = image->height();
@@ -500,7 +500,7 @@ void QSGPlainTexture::bind()
updateBindOptions(m_dirty_bind_options);
#ifdef QT_OPENGL_ES
- swizzleBGRAToRGBA(&tmp);
+ qsg_swizzleBGRAToRGBA(&tmp);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tmp.constBits());
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, tmp.constBits());
diff --git a/src/quick/util/qquickconnections.cpp b/src/quick/util/qquickconnections.cpp
index acc9738f2c..27b66ba38f 100644
--- a/src/quick/util/qquickconnections.cpp
+++ b/src/quick/util/qquickconnections.cpp
@@ -280,10 +280,9 @@ void QQuickConnections::connectSignals()
location = ddata->outerContext->urlString;
}
- QQmlExpression *expression = ctxtdata ?
- QQmlExpressionPrivate::create(ctxtdata, 0, script, true, location, line, column) : 0;
+ QQmlBoundSignalExpression *expression = ctxtdata ?
+ new QQmlBoundSignalExpression(ctxtdata, 0, script, true, location, line, column) : 0;
signal->setExpression(expression);
- signal->addToObject();
d->boundsignals += signal;
} else {
if (!d->ignoreUnknownSignals)
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index 8b0818c96c..4bff006d9b 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -55,6 +55,7 @@
#include <private/qqmlproperty_p.h>
#include <private/qqmlcontext_p.h>
#include <private/qquickstate_p_p.h>
+#include <private/qqmlboundsignal_p.h>
#include <QtCore/qdebug.h>
@@ -139,7 +140,7 @@ class QQuickReplaceSignalHandler : public QQuickActionEvent
{
public:
QQuickReplaceSignalHandler() : expression(0), reverseExpression(0),
- rewindExpression(0), ownedExpression(0) {}
+ rewindExpression(0), ownedExpression(0), ownedExpressionWatcher(0) {}
~QQuickReplaceSignalHandler() {
delete ownedExpression;
}
@@ -147,22 +148,35 @@ public:
virtual EventType type() const { return SignalHandler; }
QQmlProperty property;
- QQmlExpression *expression;
- QQmlExpression *reverseExpression;
- QQmlExpression *rewindExpression;
- QQmlGuard<QQmlExpression> ownedExpression;
+ QQmlBoundSignalExpression *expression;
+ QQmlBoundSignalExpression *reverseExpression;
+ QQmlBoundSignalExpression *rewindExpression;
+ QQmlBoundSignalExpression *ownedExpression;
+ QQmlAbstractExpression::DeleteWatcher *ownedExpressionWatcher; // TODO: refactor the ownership impl.
virtual void execute(Reason) {
ownedExpression = QQmlPropertyPrivate::setSignalExpression(property, expression);
- if (ownedExpression == expression)
+ if (ownedExpression == expression) {
+ delete ownedExpressionWatcher;
+ ownedExpressionWatcher = 0;
ownedExpression = 0;
+ } else if (ownedExpression) {
+ delete ownedExpressionWatcher;
+ ownedExpressionWatcher = new QQmlAbstractExpression::DeleteWatcher(ownedExpression);
+ }
}
virtual bool isReversable() { return true; }
virtual void reverse(Reason) {
ownedExpression = QQmlPropertyPrivate::setSignalExpression(property, reverseExpression);
- if (ownedExpression == reverseExpression)
+ if (ownedExpression == reverseExpression) {
+ delete ownedExpressionWatcher;
+ ownedExpressionWatcher = 0;
ownedExpression = 0;
+ } else if (ownedExpression) {
+ delete ownedExpressionWatcher;
+ ownedExpressionWatcher = new QQmlAbstractExpression::DeleteWatcher(ownedExpression);
+ }
}
virtual void saveOriginals() {
@@ -181,6 +195,8 @@ public:
if (rsh->ownedExpression == reverseExpression) {
ownedExpression = rsh->ownedExpression;
rsh->ownedExpression = 0;
+ delete ownedExpressionWatcher;
+ ownedExpressionWatcher = new QQmlAbstractExpression::DeleteWatcher(ownedExpression);
}
}
@@ -225,11 +241,17 @@ public:
public:
ExpressionChange(const QString &_name,
QQmlBinding::Identifier _id,
- QQmlExpression *_expr)
- : name(_name), id(_id), expression(_expr) {}
+ const QString& _expr,
+ const QUrl &_url,
+ int _line,
+ int _column)
+ : name(_name), id(_id), expression(_expr), url(_url), line(_line), column(_column) {}
QString name;
QQmlBinding::Identifier id;
- QQmlExpression *expression;
+ QString expression;
+ QUrl url;
+ int line;
+ int column;
};
QList<QPair<QString, QVariant> > properties;
@@ -334,20 +356,36 @@ void QQuickPropertyChangesPrivate::decode()
QQmlProperty prop = property(name); //### better way to check for signal property?
if (prop.type() & QQmlProperty::SignalProperty) {
- QQmlExpression *expression = new QQmlExpression(qmlContext(q), object, data.toString());
+ QString expression = data.toString();
+ QUrl url = QUrl();
+ int line = -1;
+ int column = -1;
+
QQmlData *ddata = QQmlData::get(q);
- if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
- expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber, ddata->columnNumber);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
+ url = ddata->outerContext->url;
+ line = ddata->lineNumber;
+ column = ddata->columnNumber;
+ }
+
QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
handler->property = prop;
- handler->expression = expression;
+ handler->expression = new QQmlBoundSignalExpression(QQmlContextData::get(qmlContext(q)), object, expression, false, url.toString(), line, column);
signalReplacements << handler;
- } else if (isScript) {
- QQmlExpression *expression = new QQmlExpression(qmlContext(q), object, data.toString());
+ } else if (isScript) { // binding
+ QString expression = data.toString();
+ QUrl url = QUrl();
+ int line = -1;
+ int column = -1;
+
QQmlData *ddata = QQmlData::get(q);
- if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
- expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber, ddata->columnNumber);
- expressions << ExpressionChange(name, id, expression);
+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
+ url = ddata->outerContext->url;
+ line = ddata->lineNumber;
+ column = ddata->columnNumber;
+ }
+
+ expressions << ExpressionChange(name, id, expression, url, line, column);
} else {
properties << qMakePair(name, data);
}
@@ -374,8 +412,6 @@ QQuickPropertyChanges::QQuickPropertyChanges()
QQuickPropertyChanges::~QQuickPropertyChanges()
{
Q_D(QQuickPropertyChanges);
- for(int ii = 0; ii < d->expressions.count(); ++ii)
- delete d->expressions.at(ii).expression;
for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
delete d->signalReplacements.at(ii);
}
@@ -460,7 +496,8 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
for (int ii = 0; ii < d->expressions.count(); ++ii) {
- const QString &property = d->expressions.at(ii).name;
+ QQuickPropertyChangesPrivate::ExpressionChange e = d->expressions.at(ii);
+ const QString &property = e.name;
QQmlProperty prop = d->property(property);
if (prop.isValid()) {
@@ -471,16 +508,18 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
a.specifiedObject = d->object;
a.specifiedProperty = property;
+ QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this), e.url.toString(), e.column) : 0;
+ if (!newBinding)
+ newBinding = new QQmlBinding(e.expression, false, object(), QQmlContextData::get(qmlContext(this)), e.url.toString(), e.line, e.column);
+
if (d->isExplicit) {
- a.toValue = d->expressions.at(ii).expression->evaluate();
+ // in this case, we don't want to assign a binding, per se,
+ // so we evaluate the expression and assign the result.
+ // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString)
+ // so that we can avoid creating then destroying the binding in this case.
+ a.toValue = newBinding->evaluate();
+ newBinding->destroy();
} else {
- QQmlExpression *e = d->expressions.at(ii).expression;
-
- QQmlBinding::Identifier id = d->expressions.at(ii).id;
- QQmlBinding *newBinding = id != QQmlBinding::Invalid ? QQmlBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()) : 0;
- if (!newBinding)
- newBinding = new QQmlBinding(e->expression(), false, object(), QQmlContextData::get(qmlContext(this)),
- e->sourceFile(), e->lineNumber(), e->columnNumber());
newBinding->setTarget(prop);
a.toBinding = QQmlAbstractBinding::getPointer(newBinding);
a.deletableToBinding = true;
@@ -635,14 +674,14 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString
QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
while (expressionIterator.hasNext()) {
- const ExpressionEntry &entry = expressionIterator.next();
+ ExpressionEntry &entry = expressionIterator.next();
if (entry.name == name) {
- entry.expression->setExpression(expression);
+ entry.expression = expression;
if (state() && state()->isStateActive()) {
QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name));
if (oldBinding) {
- QQmlPropertyPrivate::setBinding(d->property(name), 0);
- oldBinding->destroy();
+ QQmlPropertyPrivate::setBinding(d->property(name), 0);
+ oldBinding->destroy();
}
QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
@@ -653,8 +692,8 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString
}
}
- QQmlExpression *newExpression = new QQmlExpression(qmlContext(this), d->object, expression);
- expressionIterator.insert(ExpressionEntry(name, QQmlBinding::Invalid, newExpression));
+ // adding a new expression.
+ expressionIterator.insert(ExpressionEntry(name, QQmlBinding::Invalid, expression, QUrl(), -1, -1));
if (state() && state()->isStateActive()) {
if (hadValue) {
@@ -675,11 +714,14 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString
action.specifiedObject = object();
action.specifiedProperty = name;
-
+ QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
if (d->isExplicit) {
- action.toValue = newExpression->evaluate();
+ // don't assign the binding, merely evaluate the expression.
+ // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString)
+ // so that we can avoid creating then destroying the binding in this case.
+ action.toValue = newBinding->evaluate();
+ newBinding->destroy();
} else {
- QQmlBinding *newBinding = new QQmlBinding(newExpression->expression(), object(), qmlContext(this));
newBinding->setTarget(d->property(name));
action.toBinding = QQmlAbstractBinding::getPointer(newBinding);
action.deletableToBinding = true;
@@ -714,7 +756,7 @@ QVariant QQuickPropertyChanges::property(const QString &name) const
while (expressionIterator.hasNext()) {
const ExpressionEntry &entry = expressionIterator.next();
if (entry.name == name) {
- return QVariant(entry.expression->expression());
+ return QVariant(entry.expression);
}
}
@@ -773,7 +815,7 @@ QString QQuickPropertyChanges::expression(const QString &name) const
while (expressionIterator.hasNext()) {
const ExpressionEntry &entry = expressionIterator.next();
if (entry.name == name) {
- return entry.expression->expression();
+ return entry.expression;
}
}