diff --git a/.inferconfig b/.inferconfig new file mode 100644 index 000000000000..7141b07a2302 --- /dev/null +++ b/.inferconfig @@ -0,0 +1,7 @@ +{ + "infer-blacklist-path-regex": [ + // This is full of issues, and is a dependency we need to discard + // sooner rather than later anyway: + "mobile/android/thirdparty/ch/boye/httpclientandroidlib" + ] +} \ No newline at end of file diff --git a/addon-sdk/moz.build b/addon-sdk/moz.build index 9858bc40a87a..73a3ee8663c0 100644 --- a/addon-sdk/moz.build +++ b/addon-sdk/moz.build @@ -73,108 +73,107 @@ EXTRA_JS_MODULES.sdk.system += [ 'source/modules/system/Startup.js', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk": - EXTRA_JS_MODULES.commonjs.method.test += [ - 'source/lib/method/test/browser.js', - 'source/lib/method/test/common.js', - ] +EXTRA_JS_MODULES.commonjs.method.test += [ + 'source/lib/method/test/browser.js', + 'source/lib/method/test/common.js', +] - EXTRA_JS_MODULES.commonjs.sdk.deprecated += [ - 'source/lib/sdk/deprecated/api-utils.js', - 'source/lib/sdk/deprecated/sync-worker.js', - 'source/lib/sdk/deprecated/unit-test-finder.js', - 'source/lib/sdk/deprecated/unit-test.js', - 'source/lib/sdk/deprecated/window-utils.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.deprecated += [ + 'source/lib/sdk/deprecated/api-utils.js', + 'source/lib/sdk/deprecated/sync-worker.js', + 'source/lib/sdk/deprecated/unit-test-finder.js', + 'source/lib/sdk/deprecated/unit-test.js', + 'source/lib/sdk/deprecated/window-utils.js', +] - EXTRA_JS_MODULES.commonjs.sdk.frame += [ - 'source/lib/sdk/frame/hidden-frame.js', - 'source/lib/sdk/frame/utils.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.frame += [ + 'source/lib/sdk/frame/hidden-frame.js', + 'source/lib/sdk/frame/utils.js', +] - EXTRA_JS_MODULES.commonjs.sdk.panel += [ - 'source/lib/sdk/panel/events.js', - 'source/lib/sdk/panel/utils.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.panel += [ + 'source/lib/sdk/panel/events.js', + 'source/lib/sdk/panel/utils.js', +] - EXTRA_JS_MODULES.commonjs.sdk.places += [ - 'source/lib/sdk/places/bookmarks.js', - 'source/lib/sdk/places/contract.js', - 'source/lib/sdk/places/events.js', - 'source/lib/sdk/places/favicon.js', - 'source/lib/sdk/places/history.js', - 'source/lib/sdk/places/utils.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.places += [ + 'source/lib/sdk/places/bookmarks.js', + 'source/lib/sdk/places/contract.js', + 'source/lib/sdk/places/events.js', + 'source/lib/sdk/places/favicon.js', + 'source/lib/sdk/places/history.js', + 'source/lib/sdk/places/utils.js', +] - EXTRA_JS_MODULES.commonjs.sdk.places.host += [ - 'source/lib/sdk/places/host/host-bookmarks.js', - 'source/lib/sdk/places/host/host-query.js', - 'source/lib/sdk/places/host/host-tags.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.places.host += [ + 'source/lib/sdk/places/host/host-bookmarks.js', + 'source/lib/sdk/places/host/host-query.js', + 'source/lib/sdk/places/host/host-tags.js', +] - EXTRA_JS_MODULES.commonjs.sdk.tabs += [ - 'source/lib/sdk/tabs/common.js', - 'source/lib/sdk/tabs/events.js', - 'source/lib/sdk/tabs/helpers.js', - 'source/lib/sdk/tabs/namespace.js', - 'source/lib/sdk/tabs/observer.js', - 'source/lib/sdk/tabs/tab-fennec.js', - 'source/lib/sdk/tabs/tab-firefox.js', - 'source/lib/sdk/tabs/tab.js', - 'source/lib/sdk/tabs/tabs-firefox.js', - 'source/lib/sdk/tabs/utils.js', - 'source/lib/sdk/tabs/worker.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.tabs += [ + 'source/lib/sdk/tabs/common.js', + 'source/lib/sdk/tabs/events.js', + 'source/lib/sdk/tabs/helpers.js', + 'source/lib/sdk/tabs/namespace.js', + 'source/lib/sdk/tabs/observer.js', + 'source/lib/sdk/tabs/tab-fennec.js', + 'source/lib/sdk/tabs/tab-firefox.js', + 'source/lib/sdk/tabs/tab.js', + 'source/lib/sdk/tabs/tabs-firefox.js', + 'source/lib/sdk/tabs/utils.js', + 'source/lib/sdk/tabs/worker.js', +] - EXTRA_JS_MODULES.commonjs.sdk.test += [ - 'source/lib/sdk/test/assert.js', - 'source/lib/sdk/test/harness.js', - 'source/lib/sdk/test/httpd.js', - 'source/lib/sdk/test/loader.js', - 'source/lib/sdk/test/memory.js', - 'source/lib/sdk/test/options.js', - 'source/lib/sdk/test/runner.js', - 'source/lib/sdk/test/utils.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.test += [ + 'source/lib/sdk/test/assert.js', + 'source/lib/sdk/test/harness.js', + 'source/lib/sdk/test/httpd.js', + 'source/lib/sdk/test/loader.js', + 'source/lib/sdk/test/memory.js', + 'source/lib/sdk/test/options.js', + 'source/lib/sdk/test/runner.js', + 'source/lib/sdk/test/utils.js', +] - EXTRA_JS_MODULES.commonjs.sdk.ui += [ - 'source/lib/sdk/ui/component.js', - 'source/lib/sdk/ui/frame.js', - 'source/lib/sdk/ui/id.js', - 'source/lib/sdk/ui/sidebar.js', - 'source/lib/sdk/ui/state.js', - 'source/lib/sdk/ui/toolbar.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.ui += [ + 'source/lib/sdk/ui/component.js', + 'source/lib/sdk/ui/frame.js', + 'source/lib/sdk/ui/id.js', + 'source/lib/sdk/ui/sidebar.js', + 'source/lib/sdk/ui/state.js', + 'source/lib/sdk/ui/toolbar.js', +] - EXTRA_JS_MODULES.commonjs.sdk.ui.button += [ - 'source/lib/sdk/ui/button/action.js', - 'source/lib/sdk/ui/button/contract.js', - 'source/lib/sdk/ui/button/toggle.js', - 'source/lib/sdk/ui/button/view.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.ui.button += [ + 'source/lib/sdk/ui/button/action.js', + 'source/lib/sdk/ui/button/contract.js', + 'source/lib/sdk/ui/button/toggle.js', + 'source/lib/sdk/ui/button/view.js', +] - EXTRA_JS_MODULES.commonjs.sdk.ui.sidebar += [ - 'source/lib/sdk/ui/sidebar/actions.js', - 'source/lib/sdk/ui/sidebar/contract.js', - 'source/lib/sdk/ui/sidebar/namespace.js', - 'source/lib/sdk/ui/sidebar/utils.js', - 'source/lib/sdk/ui/sidebar/view.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.ui.sidebar += [ + 'source/lib/sdk/ui/sidebar/actions.js', + 'source/lib/sdk/ui/sidebar/contract.js', + 'source/lib/sdk/ui/sidebar/namespace.js', + 'source/lib/sdk/ui/sidebar/utils.js', + 'source/lib/sdk/ui/sidebar/view.js', +] - EXTRA_JS_MODULES.commonjs.sdk.window += [ - 'source/lib/sdk/window/browser.js', - 'source/lib/sdk/window/events.js', - 'source/lib/sdk/window/helpers.js', - 'source/lib/sdk/window/namespace.js', - 'source/lib/sdk/window/utils.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.window += [ + 'source/lib/sdk/window/browser.js', + 'source/lib/sdk/window/events.js', + 'source/lib/sdk/window/helpers.js', + 'source/lib/sdk/window/namespace.js', + 'source/lib/sdk/window/utils.js', +] - EXTRA_JS_MODULES.commonjs.sdk.windows += [ - 'source/lib/sdk/windows/fennec.js', - 'source/lib/sdk/windows/firefox.js', - 'source/lib/sdk/windows/observer.js', - 'source/lib/sdk/windows/tabs-fennec.js', - ] +EXTRA_JS_MODULES.commonjs.sdk.windows += [ + 'source/lib/sdk/windows/fennec.js', + 'source/lib/sdk/windows/firefox.js', + 'source/lib/sdk/windows/observer.js', + 'source/lib/sdk/windows/tabs-fennec.js', +] EXTRA_JS_MODULES.commonjs += [ 'source/lib/index.js', @@ -542,4 +541,4 @@ EXTRA_JS_MODULES.commonjs.toolkit += [ ] with Files("**"): - BUG_COMPONENT = ("Add-on SDK", "General") \ No newline at end of file + BUG_COMPONENT = ("Add-on SDK", "General") diff --git a/addon-sdk/source/lib/sdk/loader/sandbox.js b/addon-sdk/source/lib/sdk/loader/sandbox.js index 791dbc086c15..0fc3e7759357 100644 --- a/addon-sdk/source/lib/sdk/loader/sandbox.js +++ b/addon-sdk/source/lib/sdk/loader/sandbox.js @@ -63,7 +63,9 @@ function load(sandbox, uri) { return evaluate(sandbox, decodeURIComponent(source), '1.8', uri, 0); } else { - return scriptLoader.loadSubScript(uri, sandbox, 'UTF-8'); + return scriptLoader.loadSubScriptWithOptions(uri, {target: sandbox, + charset: 'UTF-8', + wantReturnValue: true}); } } exports.load = load; diff --git a/b2g/LICENSE b/b2g/LICENSE deleted file mode 100644 index 14e2f777f6c3..000000000000 --- a/b2g/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/b2g/Makefile.in b/b2g/Makefile.in deleted file mode 100644 index 9b3e1e08ad99..000000000000 --- a/b2g/Makefile.in +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -include $(topsrcdir)/config/rules.mk -include $(topsrcdir)/testing/testsuite-targets.mk diff --git a/b2g/app.mozbuild b/b2g/app.mozbuild deleted file mode 100644 index 4587438d5f5b..000000000000 --- a/b2g/app.mozbuild +++ /dev/null @@ -1,15 +0,0 @@ -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -include('/toolkit/toolkit.mozbuild') - -if CONFIG['MOZ_EXTENSIONS']: - DIRS += ['/extensions'] - -DIRS += [ - '/%s' % CONFIG['MOZ_BRANDING_DIRECTORY'], - '/b2g', -] diff --git a/b2g/app/Makefile.in b/b2g/app/Makefile.in deleted file mode 100644 index 6b50b87f72b6..000000000000 --- a/b2g/app/Makefile.in +++ /dev/null @@ -1,66 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# Make sure the standalone glue doesn't try to get libxpcom.so from b2g/app. -NSDISTMODE = copy - -include $(topsrcdir)/config/rules.mk - -APP_ICON = app - -APP_BINARY = $(MOZ_APP_NAME)$(BIN_SUFFIX) - -ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) - -APP_NAME = $(MOZ_APP_DISPLAYNAME) -APP_VERSION = $(MOZ_APP_VERSION) - -ifdef MOZ_DEBUG -APP_NAME := $(APP_NAME)Debug -endif - -AB_CD = $(MOZ_UI_LOCALE) - -ifeq (zh-TW,$(AB_CD)) -LPROJ_ROOT := $(subst -,_,$(AB_CD)) -else -LPROJ_ROOT := $(firstword $(subst -, ,$(AB_CD))) -endif -LPROJ := Contents/Resources/$(LPROJ_ROOT).lproj - -clean clobber repackage:: - rm -rf $(DIST)/$(APP_NAME).app - -libs-preqs = \ - $(call mkdir_deps,$(DIST)/$(APP_NAME).app/Contents/MacOS) \ - $(call mkdir_deps,$(DIST)/$(APP_NAME).app/$(LPROJ)) \ - $(NULL) - -.PHONY: repackage -tools repackage:: $(libs-preqs) - rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/$(APP_NAME).app --exclude English.lproj - rsync -a --exclude '*.in' $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(DIST)/$(APP_NAME).app/$(LPROJ) - sed -e 's/%MOZ_APP_VERSION%/$(MOZ_APP_VERSION)/' -e 's/%MOZ_APP_NAME%/$(MOZ_APP_NAME)/' -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' -e 's/%APP_BINARY%/$(APP_BINARY)/' $(srcdir)/macbuild/Contents/Info.plist.in > $(DIST)/$(APP_NAME).app/Contents/Info.plist - sed -e 's/%APP_VERSION%/$(APP_VERSION)/' -e 's/%APP_NAME%/$(APP_NAME)/' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(DIST)/$(APP_NAME).app/$(LPROJ)/InfoPlist.strings - rsync -a --exclude 'mangle' --exclude 'shlibsign' --exclude-from='$(srcdir)/macbuild/Contents/MacOS-files.in' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/Resources - rsync -a --include-from='$(srcdir)/macbuild/Contents/MacOS-files.in' --exclude '*' $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/MacOS - $(RM) $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM) - rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS - cp -RL $(DIST)/branding/app.icns $(DIST)/$(APP_NAME).app/Contents/Resources/$(MOZ_APP_NAME).icns - printf APPLMOZB > $(DIST)/$(APP_NAME).app/Contents/PkgInfo - -else # MOZ_WIDGET_TOOLKIT != cocoa - -libs:: - $(NSINSTALL) -D $(DIST)/bin/chrome/icons/default - -# Copy the app icon for b2g-desktop -ifeq ($(OS_ARCH),WINNT) - cp $(DIST)/branding/$(APP_ICON).ico $(DIST)/bin/chrome/icons/default/$(APP_ICON).ico - cp $(DIST)/branding/$(APP_ICON).ico $(DIST)/bin/chrome/icons/default/default.ico -else ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) - cp $(DIST)/branding/default.png $(DIST)/bin/chrome/icons/default/default.png -endif - -endif diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js deleted file mode 100644 index 169f282ad1b9..000000000000 --- a/b2g/app/b2g.js +++ /dev/null @@ -1,941 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#filter substitution - -// For the all MOZ_MULET ifdef conditions in this file: see bug 1174234 - -#ifndef MOZ_MULET -pref("toolkit.defaultChromeURI", "chrome://b2g/content/shell.html"); -pref("browser.chromeURL", "chrome://b2g/content/"); -#endif - -#ifdef MOZ_MULET -// Set FxOS as the default homepage -// bug 1000122: this pref is fetched as a complex value, -// so that it can't be set a just a string. -// data: url is a workaround this. -pref("browser.startup.homepage", "data:text/plain,browser.startup.homepage=chrome://b2g/content/shell.html"); -pref("b2g.is_mulet", true); -// Prevent having the firstrun page -pref("startup.homepage_welcome_url", ""); -pref("browser.shell.checkDefaultBrowser", false); -// Automatically open devtools on the firefox os panel -pref("devtools.toolbox.host", "side"); -pref("devtools.toolbox.sidebar.width", 800); -// Disable session store to ensure having only one tab opened -pref("browser.sessionstore.max_tabs_undo", 0); -pref("browser.sessionstore.max_windows_undo", 0); -pref("browser.sessionstore.restore_on_demand", false); -pref("browser.sessionstore.resume_from_crash", false); -// No e10s on mulet -pref("browser.tabs.remote.autostart.1", false); -pref("browser.tabs.remote.autostart.2", false); -#endif - -// Bug 945235: Prevent all bars to be considered visible: -pref("toolkit.defaultChromeFeatures", "chrome,dialog=no,close,resizable,scrollbars,extrachrome"); - -// Disable focus rings -pref("browser.display.focus_ring_width", 0); - -// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density. -pref("browser.viewport.scaleRatio", -1); - -/* disable text selection */ -pref("browser.ignoreNativeFrameTextSelection", true); - -/* cache prefs */ -#ifdef MOZ_WIDGET_GONK -pref("browser.cache.disk.enable", true); -pref("browser.cache.disk.capacity", 55000); // kilobytes -pref("browser.cache.disk.parent_directory", "/cache"); -#endif -pref("browser.cache.disk.smart_size.enabled", false); -pref("browser.cache.disk.smart_size.first_run", false); - -pref("browser.cache.memory.enable", true); -pref("browser.cache.memory.capacity", 1024); // kilobytes - -pref("browser.cache.memory_limit", 2048); // 2 MB - -/* image cache prefs */ -pref("image.cache.size", 1048576); // bytes -pref("canvas.image.cache.limit", 20971520); // 20 MB - -/* offline cache prefs */ -pref("browser.offline-apps.notify", false); -pref("browser.cache.offline.enable", true); -pref("offline-apps.allow_by_default", true); - -/* protocol warning prefs */ -pref("network.protocol-handler.warn-external.tel", false); -pref("network.protocol-handler.warn-external.mailto", false); -pref("network.protocol-handler.warn-external.vnd.youtube", false); - -/* http prefs */ -pref("network.http.pipelining", true); -pref("network.http.pipelining.ssl", true); -pref("network.http.proxy.pipelining", true); -pref("network.http.pipelining.maxrequests" , 6); -pref("network.http.keep-alive.timeout", 109); -pref("network.http.max-connections", 20); -pref("network.http.max-persistent-connections-per-server", 6); -pref("network.http.max-persistent-connections-per-proxy", 20); - -// Keep the old default of accepting all cookies, -// no matter if you already visited the website or not -pref("network.cookie.cookieBehavior", 0); - -// spdy -pref("network.http.spdy.push-allowance", 32768); -pref("network.http.spdy.default-hpack-buffer", 4096); // 4k - -// See bug 545869 for details on why these are set the way they are -pref("network.buffer.cache.count", 24); -pref("network.buffer.cache.size", 16384); - -// predictive actions -pref("network.predictor.enabled", false); // disabled on b2g -pref("network.predictor.max-db-size", 2097152); // bytes -pref("network.predictor.preserve", 50); // percentage of predictor data to keep when cleaning up - -/* session history */ -pref("browser.sessionhistory.max_entries", 50); -pref("browser.sessionhistory.contentViewerTimeout", 360); - -/* session store */ -pref("browser.sessionstore.resume_session_once", false); -pref("browser.sessionstore.resume_from_crash", true); -pref("browser.sessionstore.resume_from_crash_timeout", 60); // minutes -pref("browser.sessionstore.interval", 10000); // milliseconds -pref("browser.sessionstore.max_tabs_undo", 1); - -/* these should help performance */ -pref("mozilla.widget.force-24bpp", true); -pref("mozilla.widget.use-buffer-pixmap", true); -pref("mozilla.widget.disable-native-theme", true); -pref("layout.reflow.synthMouseMove", false); -#ifndef MOZ_X11 -pref("layers.enable-tiles", true); -#endif -pref("layers.low-precision-buffer", true); -pref("layers.low-precision-opacity", "0.5"); -pref("layers.progressive-paint", true); - -/* download manager (don't show the window or alert) */ -pref("browser.download.useDownloadDir", true); -pref("browser.download.folderList", 1); // Default to ~/Downloads -pref("browser.download.manager.showAlertOnComplete", false); -pref("browser.download.manager.showAlertInterval", 2000); -pref("browser.download.manager.retention", 2); -pref("browser.download.manager.showWhenStarting", false); -pref("browser.download.manager.closeWhenDone", true); -pref("browser.download.manager.openDelay", 0); -pref("browser.download.manager.focusWhenStarting", false); -pref("browser.download.manager.flashCount", 2); -pref("browser.download.manager.displayedHistoryDays", 7); - -/* download helper */ -pref("browser.helperApps.deleteTempFileOnExit", false); - -/* password manager */ -pref("signon.rememberSignons", true); -pref("signon.expireMasterPassword", false); - -/* autocomplete */ -pref("browser.formfill.enable", true); - -/* spellcheck */ -pref("layout.spellcheckDefault", 0); - -/* block popups by default, and notify the user about blocked popups */ -pref("dom.disable_open_during_load", true); -pref("privacy.popups.showBrowserMessage", true); - -pref("keyword.enabled", true); -pref("browser.fixup.domainwhitelist.localhost", true); - -pref("accessibility.typeaheadfind", false); -pref("accessibility.typeaheadfind.timeout", 5000); -pref("accessibility.typeaheadfind.flashBar", 1); -pref("accessibility.typeaheadfind.linksonly", false); -pref("accessibility.typeaheadfind.casesensitive", 0); - -// SSL error page behaviour -pref("browser.ssl_override_behavior", 2); -pref("browser.xul.error_pages.expert_bad_cert", false); - -// disable updating -pref("browser.search.update", false); - -// tell the search service that we don't really expose the "current engine" -pref("browser.search.noCurrentEngine", true); - -// enable xul error pages -pref("browser.xul.error_pages.enabled", true); - -// disable color management -pref("gfx.color_management.mode", 0); - -// don't allow JS to move and resize existing windows -pref("dom.disable_window_move_resize", true); - -// prevent click image resizing for nsImageDocument -pref("browser.enable_click_image_resizing", false); - -// controls which bits of private data to clear. by default we clear them all. -pref("privacy.item.cache", true); -pref("privacy.item.cookies", true); -pref("privacy.item.offlineApps", true); -pref("privacy.item.history", true); -pref("privacy.item.formdata", true); -pref("privacy.item.downloads", true); -pref("privacy.item.passwords", true); -pref("privacy.item.sessions", true); -pref("privacy.item.geolocation", true); -pref("privacy.item.siteSettings", true); -pref("privacy.item.syncAccount", true); - -// base url for the wifi geolocation network provider -pref("geo.provider.use_mls", false); -pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%"); - -// base url for the stumbler -pref("geo.stumbler.url", "https://location.services.mozilla.com/v1/geosubmit?key=%MOZILLA_API_KEY%"); - -// enable geo -pref("geo.enabled", true); - -// content sink control -- controls responsiveness during page load -// see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9 -pref("content.sink.enable_perf_mode", 2); // 0 - switch, 1 - interactive, 2 - perf -pref("content.sink.pending_event_mode", 0); -pref("content.sink.perf_deflect_count", 1000000); -pref("content.sink.perf_parse_time", 50000000); - -// Maximum scripts runtime before showing an alert -// Disable the watchdog thread for B2G. See bug 870043 comment 31. -pref("dom.use_watchdog", false); - -// The slow script dialog can be triggered from inside the JS engine as well, -// ensure that those calls don't accidentally trigger the dialog. -pref("dom.max_script_run_time", 0); -pref("dom.max_chrome_script_run_time", 0); - -// plugins -pref("plugin.disable", true); -pref("dom.ipc.plugins.enabled", true); - -// product URLs -// The breakpad report server to link to in about:crashes -pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/"); -pref("app.releaseNotesURL", "https://www.mozilla.com/%LOCALE%/b2g/%VERSION%/releasenotes/"); -pref("app.support.baseURL", "https://support.mozilla.com/b2g"); -pref("app.privacyURL", "https://www.mozilla.com/%LOCALE%/m/privacy.html"); -pref("app.creditsURL", "https://www.mozilla.org/credits/"); -pref("app.featuresURL", "https://www.mozilla.com/%LOCALE%/b2g/features/"); -pref("app.faqURL", "https://www.mozilla.com/%LOCALE%/b2g/faq/"); - -// Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror) -pref("security.alternate_certificate_error_page", "certerror"); - -pref("security.warn_viewing_mixed", false); // Warning is disabled. See Bug 616712. - -// Block insecure active content on https pages -pref("security.mixed_content.block_active_content", true); - -// 2 = strict certificate pinning checks. -// This default preference is more strict than Firefox because B2G -// currently does not have a way to install local root certificates. -// Strict checking is effectively equivalent to non-strict checking as -// long as that is true. If an ability to add local certificates is -// added, there may be a need to change this pref. -pref("security.cert_pinning.enforcement_level", 2); - - -// Override some named colors to avoid inverse OS themes -pref("ui.-moz-dialog", "#efebe7"); -pref("ui.-moz-dialogtext", "#101010"); -pref("ui.-moz-field", "#fff"); -pref("ui.-moz-fieldtext", "#1a1a1a"); -pref("ui.-moz-buttonhoverface", "#f3f0ed"); -pref("ui.-moz-buttonhovertext", "#101010"); -pref("ui.-moz-combobox", "#fff"); -pref("ui.-moz-comboboxtext", "#101010"); -pref("ui.buttonface", "#ece7e2"); -pref("ui.buttonhighlight", "#fff"); -pref("ui.buttonshadow", "#aea194"); -pref("ui.buttontext", "#101010"); -pref("ui.captiontext", "#101010"); -pref("ui.graytext", "#b1a598"); -pref("ui.highlighttext", "#1a1a1a"); -pref("ui.threeddarkshadow", "#000"); -pref("ui.threedface", "#ece7e2"); -pref("ui.threedhighlight", "#fff"); -pref("ui.threedlightshadow", "#ece7e2"); -pref("ui.threedshadow", "#aea194"); -pref("ui.windowframe", "#efebe7"); - -pref("ui.menu", "#f97c17"); -pref("ui.menutext", "#ffffff"); -pref("ui.infobackground", "#343e40"); -pref("ui.infotext", "#686868"); -pref("ui.window", "#ffffff"); -pref("ui.windowtext", "#000000"); -pref("ui.highlight", "#b2f2ff"); - -// replace newlines with spaces on paste into single-line text boxes -pref("editor.singleLine.pasteNewlines", 2); - -// threshold where a tap becomes a drag, in 1/240" reference pixels -// The names of the preferences are to be in sync with EventStateManager.cpp -pref("ui.dragThresholdX", 25); -pref("ui.dragThresholdY", 25); - -// Layers Acceleration. We can only have nice things on gonk, because -// they're not maintained anywhere else. -#ifndef MOZ_WIDGET_GONK -pref("dom.ipc.tabs.disabled", true); -pref("layers.async-pan-zoom.enabled", false); -#else -pref("dom.ipc.tabs.disabled", false); -pref("layers.acceleration.disabled", false); -pref("gfx.content.azure.backends", "cairo"); -#endif - -// Web Notifications -pref("notification.feature.enabled", true); - -// prevent video elements from preloading too much data -pref("media.preload.default", 1); // default to preload none -pref("media.preload.auto", 2); // preload metadata if preload=auto -pref("media.cache_size", 4096); // 4MB media cache -// Try to save battery by not resuming reading from a connection until we fall -// below 10s of buffered data. -pref("media.cache_resume_threshold", 10); -pref("media.cache_readahead_limit", 30); - -#ifdef MOZ_FMP4 -// Enable/Disable Gonk Decoder Module -pref("media.gonk.enabled", true); -#endif - -//Encrypted media extensions. -pref("media.eme.enabled", true); -// The default number of decoded video frames that are enqueued in -// MediaDecoderReader's mVideoQueue. -pref("media.video-queue.default-size", 3); - -// optimize images' memory usage -pref("image.downscale-during-decode.enabled", true); -pref("image.mem.allow_locking_in_content_processes", true); -// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller. -// Almost everything that was factored into 'max_decoded_image_kb' is now stored -// in the surface cache. 1/8 of main memory is 32MB on a 256MB device, which is -// about the same as the old 'max_decoded_image_kb'. -pref("image.mem.surfacecache.max_size_kb", 131072); // 128MB -pref("image.mem.surfacecache.size_factor", 8); // 1/8 of main memory -pref("image.mem.surfacecache.discard_factor", 2); // Discard 1/2 of the surface cache at a time. -pref("image.mem.surfacecache.min_expiration_ms", 86400000); // 24h, we rely on the out of memory hook - -pref("dom.w3c_touch_events.safetyX", 0); // escape borders in units of 1/240" -pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240" - -// True if this is the first time we are showing about:firstrun -pref("browser.firstrun.show.uidiscovery", true); -pref("browser.firstrun.show.localepicker", true); - -// initiated by a user -pref("content.ime.strict_policy", true); - -// True if you always want dump() to work -// -// On Android, you also need to do the following for the output -// to show up in logcat: -// -// $ adb shell stop -// $ adb shell setprop log.redirect-stdio true -// $ adb shell start -pref("browser.dom.window.dump.enabled", false); - -// Default Content Security Policy to apply to certified apps. -// If you change this CSP, make sure to update the fast path in nsCSPService.cpp -pref("security.apps.certified.CSP.default", "default-src * data: blob:; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline' app://theme.gaiamobile.org"); - -// handle links targeting new windows -// 1=current window/tab, 2=new window, 3=new tab in most recent window -pref("browser.link.open_newwindow", 3); - -// 0: no restrictions - divert everything -// 1: don't divert window.open at all -// 2: don't divert window.open with features -pref("browser.link.open_newwindow.restriction", 0); - -// Enable browser frames (including OOP, except on Windows, where it doesn't -// work), but make in-process browser frames the default. -pref("dom.mozBrowserFramesEnabled", true); - -// Enable a (virtually) unlimited number of mozbrowser processes. -// We'll run out of PIDs on UNIX-y systems before we hit this limit. -pref("dom.ipc.processCount", 100000); - -pref("dom.ipc.browser_frames.oop_by_default", false); - -#if !defined(MOZ_MULET) && !defined(MOZ_GRAPHENE) -pref("dom.meta-viewport.enabled", true); -#endif - -//The waiting time in network manager. -pref("network.gonk.ms-release-mms-connection", 30000); - -// Shortnumber matching needed for e.g. Brazil: -// 03187654321 can be found with 87654321 -pref("dom.phonenumber.substringmatching.BR", 8); -pref("dom.phonenumber.substringmatching.CO", 10); -pref("dom.phonenumber.substringmatching.VE", 7); -pref("dom.phonenumber.substringmatching.CL", 8); -pref("dom.phonenumber.substringmatching.PE", 7); - -#ifdef MOZ_WIDGET_GONK -pref("dom.webapps.firstRunWithSIM", true); -#endif - -#ifdef MOZ_B2G_RIL -// SingleVariant -pref("dom.mozApps.single_variant_sourcedir", "/persist/svoperapps"); -#endif - -// controls if we want camera support -pref("device.camera.enabled", true); -pref("media.realtime_decoder.enabled", true); - -// TCPSocket -pref("dom.mozTCPSocket.enabled", true); - -// Handle hardware buttons in the b2g chrome package -pref("b2g.keys.menu.enabled", true); - -// Display simulator software buttons -pref("b2g.software-buttons", false); - -// Screen timeout in seconds -pref("power.screen.timeout", 60); - -pref("full-screen-api.enabled", true); - -#ifndef MOZ_WIDGET_GONK -// If we're not actually on physical hardware, don't make the top level widget -// fullscreen when transitioning to fullscreen. This means in emulated -// environments (like the b2g desktop client) we won't make the client window -// fill the whole screen, we'll just make the content fill the client window, -// i.e. it won't give the impression to content that the number of device -// screen pixels changes! -pref("full-screen-api.ignore-widgets", true); -#endif - -pref("media.volume.steps", 10); - -#ifdef MOZ_UPDATER -// When we're applying updates, we can't let anything hang us on -// quit+restart. The user has no recourse. -pref("shutdown.watchdog.timeoutSecs", 10); -// Timeout before the update prompt automatically installs the update -pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds -// Amount of time to wait after the user is idle before prompting to apply an update -pref("b2g.update.apply-idle-timeout", 600000); // milliseconds -// Amount of time after which connection will be restarted if no progress -pref("b2g.update.download-watchdog-timeout", 120000); // milliseconds -pref("b2g.update.download-watchdog-max-retries", 5); - -pref("app.update.enabled", true); -pref("app.update.auto", false); -pref("app.update.silent", false); -pref("app.update.staging.enabled", true); -pref("app.update.service.enabled", true); - -pref("app.update.url", "https://aus5.mozilla.org/update/5/%PRODUCT%/%VERSION%/%BUILD_ID%/%PRODUCT_DEVICE%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%IMEI%/update.xml"); -pref("app.update.channel", "@MOZ_UPDATE_CHANNEL@"); - -// Interval at which update manifest is fetched. In units of seconds. -pref("app.update.interval", 86400); // 1 day -// Don't throttle background updates. -pref("app.update.download.backgroundInterval", 0); - -// Retry update socket connections every 30 seconds in the cases of certain kinds of errors -pref("app.update.socket.retryTimeout", 30000); - -// Max of 20 consecutive retries (total 10 minutes) before giving up and marking -// the update download as failed. -// Note: Offline errors will always retry when the network comes online. -pref("app.update.socket.maxErrors", 20); - -// Enable update logging for now, to diagnose growing pains in the -// field. -pref("app.update.log", true); -#else -// Explicitly disable the shutdown watchdog. It's enabled by default. -// When the updater is disabled, we want to know about shutdown hangs. -pref("shutdown.watchdog.timeoutSecs", -1); -#endif - -// Allow webapps update checking -pref("webapps.update.enabled", true); - -// Check daily for apps updates. -pref("webapps.update.interval", 86400); - -// Extensions preferences -pref("extensions.update.enabled", false); -pref("extensions.getAddons.cache.enabled", false); - -// Context Menu -pref("ui.click_hold_context_menus", true); -pref("ui.click_hold_context_menus.delay", 400); - -// Enable device storage -pref("device.storage.enabled", true); - -// Enable pre-installed applications -pref("dom.webapps.useCurrentProfile", true); - -// Enable system message -pref("dom.sysmsg.enabled", true); -pref("media.plugins.enabled", false); -pref("media.rtsp.enabled", true); -pref("media.rtsp.video.enabled", true); - -// Disable printing (particularly, window.print()) -pref("dom.disable_window_print", true); - -// Disable window.showModalDialog -pref("dom.disable_window_showModalDialog", true); - -// Enable new experimental html forms -pref("dom.experimental_forms", true); -pref("dom.forms.number", true); - -// Don't enable yet as we don't have a color picker -// implemented for b2g (bug 875751) -pref("dom.forms.color", false); - -// This preference instructs the JS engine to discard the -// source of any privileged JS after compilation. This saves -// memory, but makes things like Function.prototype.toSource() -// fail. -pref("javascript.options.discardSystemSource", true); - -// XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging -pref("javascript.options.mem.log", false); - -// Increase mark slice time from 10ms to 30ms -pref("javascript.options.mem.gc_incremental_slice_ms", 30); - -// Increase time to get more high frequency GC on benchmarks from 1000ms to 1500ms -pref("javascript.options.mem.gc_high_frequency_time_limit_ms", 1500); - -pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 300); -pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 120); -pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 40); -pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 0); -pref("javascript.options.mem.gc_low_frequency_heap_growth", 120); -pref("javascript.options.mem.high_water_mark", 6); -pref("javascript.options.mem.gc_allocation_threshold_mb", 1); -pref("javascript.options.mem.gc_min_empty_chunk_count", 1); -pref("javascript.options.mem.gc_max_empty_chunk_count", 2); - -// Show/Hide scrollbars when active/inactive -pref("ui.showHideScrollbars", 1); -pref("ui.useOverlayScrollbars", 1); -pref("ui.scrollbarFadeBeginDelay", 450); -pref("ui.scrollbarFadeDuration", 0); - -// Scrollbar position follows the document `dir` attribute -pref("layout.scrollbar.side", 1); - -// CSS Scroll Snapping -pref("layout.css.scroll-snap.enabled", true); - -// Enable the ProcessPriorityManager, and give processes with no visible -// documents a 1s grace period before they're eligible to be marked as -// background. Background processes that are perceivable due to playing -// media are given a longer grace period to accomodate changing tracks, etc. -pref("dom.ipc.processPriorityManager.enabled", true); -pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000); -pref("dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", 5000); -pref("dom.ipc.processPriorityManager.temporaryPriorityLockMS", 5000); - -// Number of different background/foreground levels for background/foreground -// processes. We use these different levels to force the low-memory killer to -// kill processes in a LRU order. -pref("dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels", 5); -pref("dom.ipc.processPriorityManager.BACKGROUND_PERCEIVABLE.LRUPoolLevels", 4); - -// Kernel parameters for process priorities. These affect how processes are -// killed on low-memory and their relative CPU priorities. -// -// The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is -// okay, kernel will still kill processes with larger OomScoreAdjust first even -// its OomScoreAdjust don't have a corresponding KillUnderKB. - -pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0); -pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096); -pref("hal.processPriorityManager.gonk.MASTER.cgroup", ""); - -pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67); -pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120); -pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.cgroup", "apps/critical"); - -pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134); -pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144); -pref("hal.processPriorityManager.gonk.FOREGROUND.cgroup", "apps"); - -pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200); -pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.cgroup", "apps"); - -pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400); -pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 8192); -pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.cgroup", "apps/bg_perceivable"); - -pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667); -pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480); -pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive"); - -// Control group definitions (i.e., CPU priority groups) for B2G processes. -// -// memory_swappiness - 0 - The kernel will swap only to avoid an out of memory condition -// memory_swappiness - 60 - The default value. -// memory_swappiness - 100 - The kernel will swap aggressively. - -// Foreground apps -pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024); -pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 0); -pref("hal.processPriorityManager.gonk.cgroups.apps.memory_swappiness", 10); - -// Foreground apps with high priority, 16x more CPU than foreground ones -pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_shares", 16384); -pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_notify_on_migrate", 0); -pref("hal.processPriorityManager.gonk.cgroups.apps/critical.memory_swappiness", 0); - -// Background perceivable apps, ~10x less CPU than foreground ones -pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_shares", 103); -pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_notify_on_migrate", 0); -pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.memory_swappiness", 60); - -// Background apps, ~20x less CPU than foreground ones and ~2x less than perceivable ones -pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_shares", 52); -pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_notify_on_migrate", 0); -pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.memory_swappiness", 100); - -// By default the compositor thread on gonk runs without real-time priority. RT -// priority can be enabled by setting this pref to a value between 1 and 99. -// Note that audio processing currently runs at RT priority 2 or 3 at most. -// -// If RT priority is disabled, then the compositor nice value is used. We prefer -// to use a nice value of -4, which matches Android's preferences. Setting a preference -// of RT priority 1 would mean it is higher than audio, which is -16. The compositor -// priority must be below the audio thread. -// -// Do not change these values without gfx team review. -pref("hal.gonk.COMPOSITOR.rt_priority", 0); -pref("hal.gonk.COMPOSITOR.nice", -4); - -// Fire a memory pressure event when the system has less than Xmb of memory -// remaining. You should probably set this just above Y.KillUnderKB for -// the highest priority class Y that you want to make an effort to keep alive. -// (For example, we want BACKGROUND_PERCEIVABLE to stay alive.) If you set -// this too high, then we'll send out a memory pressure event every Z seconds -// (see below), even while we have processes that we would happily kill in -// order to free up memory. -pref("gonk.notifyHardLowMemUnderKB", 14336); - -// Fire a memory pressure event when the system has less than Xmb of memory -// remaining and then switch to the hard trigger, see above. This should be -// placed above the BACKGROUND priority class. -pref("gonk.notifySoftLowMemUnderKB", 43008); - -// We wait this long before polling the memory-pressure fd after seeing one -// memory pressure event. (When we're not under memory pressure, we sit -// blocked on a poll(), and this pref has no effect.) -pref("gonk.systemMemoryPressureRecoveryPollMS", 5000); - -pref("dom.ipc.reuse_parent_app", false); - -// When a process receives a system message, we hold a CPU wake lock on its -// behalf for this many seconds, or until it handles the system message, -// whichever comes first. -pref("dom.ipc.systemMessageCPULockTimeoutSec", 30); - -// Ignore the "dialog=1" feature in window.open. -pref("dom.disable_window_open_dialog_feature", true); - -// Screen reader support -pref("accessibility.accessfu.activate", 2); -pref("accessibility.accessfu.quicknav_modes", "Link,Heading,FormElement,Landmark,ListItem"); -// Active quicknav mode, index value of list from quicknav_modes -pref("accessibility.accessfu.quicknav_index", 0); -// Setting for an utterance order (0 - description first, 1 - description last). -pref("accessibility.accessfu.utterance", 1); -// Whether to skip images with empty alt text -pref("accessibility.accessfu.skip_empty_images", true); -// Setting to change the verbosity of entered text (0 - none, 1 - characters, -// 2 - words, 3 - both) -pref("accessibility.accessfu.keyboard_echo", 3); - -// Enable hit-target fluffing -pref("ui.touch.radius.enabled", true); -pref("ui.touch.radius.leftmm", 3); -pref("ui.touch.radius.topmm", 5); -pref("ui.touch.radius.rightmm", 3); -pref("ui.touch.radius.bottommm", 2); - -pref("ui.mouse.radius.enabled", true); -pref("ui.mouse.radius.leftmm", 3); -pref("ui.mouse.radius.topmm", 5); -pref("ui.mouse.radius.rightmm", 3); -pref("ui.mouse.radius.bottommm", 2); - -// Disable native prompt -pref("browser.prompt.allowNative", false); - -// Minimum delay in milliseconds between network activity notifications (0 means -// no notifications). The delay is the same for both download and upload, though -// they are handled separately. This pref is only read once at startup: -// a restart is required to enable a new value. -pref("network.activity.blipIntervalMilliseconds", 250); - -// By default we want the NetworkManager service to manage Gecko's offline -// status for us according to the state of Wifi/cellular data connections. -// In some environments, such as the emulator or hardware with other network -// connectivity, this is not desireable, however, in which case this pref -// can be flipped to false. -pref("network.gonk.manage-offline-status", true); - -// On Firefox Mulet, we can't enable shared JSM scope -// as it breaks most Firefox JSMs (see bug 961777) -#ifndef MOZ_MULET -// Break any JSMs or JS components that rely on shared scope -#ifndef DEBUG -pref("jsloader.reuseGlobal", true); -#endif -#endif - -// Enable font inflation for browser tab content. -pref("font.size.inflation.minTwips", 120); -// And disable it for lingering master-process UI. -pref("font.size.inflation.disabledInMasterProcess", true); - -// Enable freeing dirty pages when minimizing memory; this reduces memory -// consumption when applications are sent to the background. -pref("memory.free_dirty_pages", true); - -// Enable the Linux-specific, system-wide memory reporter. -pref("memory.system_memory_reporter", true); - -// Don't dump memory reports on OOM, by default. -pref("memory.dump_reports_on_oom", false); - -pref("layout.framevisibility.numscrollportwidths", 1); -pref("layout.framevisibility.numscrollportheights", 1); - -// Wait up to this much milliseconds when orientation changed -pref("layers.orientation.sync.timeout", 1000); - -// Animate the orientation change -pref("b2g.orientation.animate", true); - -// Don't discard WebGL contexts for foreground apps on memory -// pressure. -pref("webgl.can-lose-context-in-foreground", false); - -// Allow nsMemoryInfoDumper to create a fifo in the temp directory. We use -// this fifo to trigger about:memory dumps, among other things. -pref("memory_info_dumper.watch_fifo.enabled", true); -pref("memory_info_dumper.watch_fifo.directory", "/data/local"); - -// See ua-update.json.in for the packaged UA override list -pref("general.useragent.updates.enabled", true); -pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%"); -pref("general.useragent.updates.interval", 604800); // 1 week -pref("general.useragent.updates.retry", 86400); // 1 day -// Device ID can be composed of letter, numbers, hyphen ("-") and dot (".") -pref("general.useragent.device_id", ""); - -// Add Mozilla AudioChannel APIs. -pref("media.useAudioChannelAPI", true); - -pref("b2g.version", @MOZ_B2G_VERSION@); -pref("b2g.osName", @MOZ_B2G_OS_NAME@); - -// Disable console buffering to save memory. -pref("consoleservice.buffered", false); - -#ifdef MOZ_WIDGET_GONK -// Performance testing suggests 2k is a better page size for SQLite. -pref("toolkit.storage.pageSize", 2048); -#endif - -// The url of the manifest we use for ADU pings. -pref("ping.manifestURL", "https://marketplace.firefox.com/packaged.webapp"); - -// Enable the disk space watcher -pref("disk_space_watcher.enabled", true); - -// SNTP preferences. -pref("network.sntp.maxRetryCount", 10); -pref("network.sntp.refreshPeriod", 86400); // In seconds. -pref("network.sntp.pools", // Servers separated by ';'. - "0.pool.ntp.org;1.pool.ntp.org;2.pool.ntp.org;3.pool.ntp.org"); -pref("network.sntp.port", 123); -pref("network.sntp.timeout", 30); // In seconds. - -// Allow ADB to run for this many hours before disabling. -// 0 disables the timer. -pref("b2g.adb.timeout-hours", 12); - -// Absolute path to the devtool unix domain socket file used -// to communicate with a usb cable via adb forward -pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket"); - -// enable Skia/GL (OpenGL-accelerated 2D drawing) for large enough 2d canvases, -// falling back to Skia/software for smaller canvases -#ifdef MOZ_WIDGET_GONK -pref("gfx.canvas.azure.backends", "skia"); -pref("gfx.canvas.azure.accelerated", true); -#endif - -// Turn on dynamic cache size for Skia -pref("gfx.canvas.skiagl.dynamic-cache", true); - -// Limit skia to canvases the size of the device screen or smaller -pref("gfx.canvas.max-size-for-skia-gl", -1); - -// enable fence with readpixels for SurfaceStream -pref("gfx.gralloc.fence-with-readpixels", true); - -// enable screen mirroring to external display -pref("gfx.screen-mirroring.enabled", true); - -// The url of the page used to display network error details. -pref("b2g.neterror.url", "net_error.html"); - -// Enable Web Speech synthesis API -pref("media.webspeech.synth.enabled", true); - -// Enable Web Speech recognition API -pref("media.webspeech.recognition.enable", true); - -// External Helper Application Handling -// -// All external helper application handling can require the docshell to be -// active before allowing the external helper app service to handle content. -// -// To prevent SD card DoS attacks via downloads we disable background handling. -// -pref("security.exthelperapp.disable_background_handling", true); - -// Inactivity time in milliseconds after which we shut down the OS.File worker. -pref("osfile.reset_worker_delay", 5000); - -// APZ physics settings, tuned by UX designers -pref("apz.axis_lock.mode", 2); // Use "sticky" axis locking -pref("apz.fling_curve_function_x1", "0.41"); -pref("apz.fling_curve_function_y1", "0.0"); -pref("apz.fling_curve_function_x2", "0.80"); -pref("apz.fling_curve_function_y2", "1.0"); -pref("apz.fling_curve_threshold_inches_per_ms", "0.01"); -pref("apz.fling_friction", "0.0019"); -pref("apz.max_velocity_inches_per_ms", "0.07"); -pref("apz.overscroll.enabled", true); -pref("apz.displayport_expiry_ms", 0); // causes issues on B2G, see bug 1250924 - -// For event-regions based hit-testing -pref("layout.event-regions.enabled", true); - -// This preference allows FirefoxOS apps (and content, I think) to force -// the use of software (instead of hardware accelerated) 2D canvases by -// creating a context like this: -// -// canvas.getContext('2d', { willReadFrequently: true }) -// -// Using a software canvas can save memory when JS calls getImageData() -// on the canvas frequently. See bug 884226. -pref("gfx.canvas.willReadFrequently.enable", true); - -// Disable autofocus until we can have it not bring up the keyboard. -// https://bugzilla.mozilla.org/show_bug.cgi?id=965763 -pref("browser.autofocus", false); - -// Enable wakelock -pref("dom.wakelock.enabled", true); - -// Enable webapps add-ons -pref("dom.apps.reviewer_paths", "/reviewers/,/extension/reviewers/"); - -// New implementation to unify touch-caret and selection-carets. -pref("layout.accessiblecaret.enabled", true); - -// Show the selection bars at the two ends of the selection highlight. Required -// by the spec in bug 921965. -pref("layout.accessiblecaret.bar.enabled", true); - -// Hide carets and text selection dialog during scrolling. -pref("layout.accessiblecaret.always_show_when_scrolling", false); - -// Enable sync with Firefox Accounts. -pref("services.sync.fxaccounts.enabled", true); -pref("identity.fxaccounts.enabled", true); - -pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1"); -pref("identity.fxaccounts.remote.profile.uri", "https://profile.accounts.firefox.com/v1"); - -// Disable Firefox Accounts device registration until bug 1238895 is fixed. -pref("identity.fxaccounts.skipDeviceRegistration", true); - -// Enable mapped array buffer. -pref("dom.mapped_arraybuffer.enabled", true); - -// UDPSocket API -pref("dom.udpsocket.enabled", true); - -// Comma separated list of activity names that can only be provided by -// the system app in dev mode. -pref("dom.activities.developer_mode_only", "import-app"); - -// mulet apparently loads firefox.js as well as b2g.js, so we have to explicitly -// disable serviceworkers and push here to get them disabled in mulet. -pref("dom.serviceWorkers.enabled", false); -pref("dom.push.enabled", false); - -#if defined(RELEASE_OR_BETA) -// Bug 1278848: Enable service worker notifications on release B2G once -// they're ready. -pref("dom.webnotifications.serviceworker.enabled", false); -#else -pref("dom.webnotifications.serviceworker.enabled", true); -#endif - -// Retain at most 10 processes' layers buffers -pref("layers.compositor-lru-size", 10); - -// In B2G by deafult any AudioChannelAgent is muted when created. -pref("dom.audiochannel.mutedByDefault", true); - -// Default device name for Presentation API -pref("dom.presentation.device.name", "Firefox OS"); - -// Enable notification of performance timing -pref("dom.performance.enable_notify_performance_timing", true); - -// Multi-screen -pref("b2g.multiscreen.chrome_remote_url", "chrome://b2g/content/shell_remote.html"); -pref("b2g.multiscreen.system_remote_url", "index_remote.html"); - -// Audio competing between tabs -pref("dom.audiochannel.audioCompeting", false); - -// Because we can't have nice things. -#ifdef MOZ_GRAPHENE -#include ../graphene/graphene.js -#endif diff --git a/b2g/app/macbuild/Contents/Info.plist.in b/b2g/app/macbuild/Contents/Info.plist.in deleted file mode 100644 index d5ea85f4d94c..000000000000 --- a/b2g/app/macbuild/Contents/Info.plist.in +++ /dev/null @@ -1,67 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - %APP_BINARY% - CFBundleGetInfoString - %APP_NAME% %APP_VERSION% - CFBundleIconFile - %MOZ_APP_NAME%.icns - CFBundleIdentifier - org.mozilla.b2g - CFBundleInfoDictionaryVersion - %MOZ_APP_VERSION% - CFBundleName - %APP_NAME% - CFBundlePackageType - APPL - CFBundleShortVersionString - %APP_VERSION% - CFBundleSignature - MOZB - CFBundleVersion - %APP_VERSION% - NSAppleScriptEnabled - - CGDisableCoalescedUpdates - - NSHighResolutionCapable - - NSPrincipalClass - GeckoNSApplication - CFBundleURLTypes - - - CFBundleURLIconFile - document.icns - CFBundleURLName - http URL - CFBundleURLSchemes - - http - - - - CFBundleURLIconFile - document.icns - CFBundleURLName - https URL - CFBundleURLSchemes - - https - - - - CFBundleURLName - ftp URL - CFBundleURLSchemes - - ftp - - - - - diff --git a/b2g/app/macbuild/Contents/MacOS-files.in b/b2g/app/macbuild/Contents/MacOS-files.in deleted file mode 100644 index 4cefd2ff96e7..000000000000 --- a/b2g/app/macbuild/Contents/MacOS-files.in +++ /dev/null @@ -1,9 +0,0 @@ -/*.app/*** -/*.dylib -/b2g -/certutil -/gtest/*** -/pk12util -/ssltunnel -/xpcshell -/XUL diff --git a/b2g/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/b2g/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in deleted file mode 100644 index ddd3e0afa5ee..000000000000 --- a/b2g/app/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in +++ /dev/null @@ -1,5 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -CFBundleName = "%APP_NAME%"; diff --git a/b2g/app/moz.build b/b2g/app/moz.build deleted file mode 100644 index b28889065fef..000000000000 --- a/b2g/app/moz.build +++ /dev/null @@ -1,76 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -if CONFIG['GAIADIR']: - GeckoProgram(CONFIG['MOZ_APP_NAME'] + "-bin") -else: - GeckoProgram(CONFIG['MOZ_APP_NAME']) - -SOURCES += [ - 'nsBrowserApp.cpp', -] -if CONFIG['_MSC_VER']: - # Always enter a Windows program through wmain, whether or not we're - # a console application. - WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup'] - -USE_LIBS += [ - 'zlib', -] - -for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'): - DEFINES[var] = CONFIG[var] - -LOCAL_INCLUDES += [ - '!/build', - '/toolkit/xre', - '/xpcom/base', - '/xpcom/build', -] - -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - LOCAL_INCLUDES += [ - '/widget/gonk/libdisplay', - ] - - LDFLAGS += ['-Wl,--export-dynamic'] - - USE_LIBS += [ - 'display', - 'mozpng', - ] - OS_LIBS += [ - 'ui', - 'EGL', - 'hardware_legacy', - 'hardware', - 'cutils', - ] - OS_LIBS += CONFIG['MOZ_ZLIB_LIBS'] - if CONFIG['ANDROID_VERSION'] in ('17', '18', '19', '21', '22'): - OS_LIBS += [ - 'gui', - 'suspend', - ] - OS_LIBS += [ - 'binder', - 'utils', - ] - -DISABLE_STL_WRAPPING = True - -if CONFIG['OS_ARCH'] == 'WINNT': - OS_LIBS += [ - 'version', - ] - -JS_PREFERENCE_PP_FILES += [ - 'b2g.js', -] - -FINAL_TARGET_PP_FILES += [ - 'ua-update.json.in', -] diff --git a/b2g/app/nsBrowserApp.cpp b/b2g/app/nsBrowserApp.cpp deleted file mode 100644 index 547d42f43f6e..000000000000 --- a/b2g/app/nsBrowserApp.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsXULAppAPI.h" -#include "application.ini.h" -#include "nsXPCOMGlue.h" -#if defined(XP_WIN) -#include -#include -#elif defined(XP_UNIX) -#include -#include -#include -#endif - -#include -#include -#include - -#include "nsCOMPtr.h" -#include "nsIFile.h" -#include "nsStringGlue.h" - -#ifdef XP_WIN -// we want a wmain entry point -#include "nsWindowsWMain.cpp" -#define strcasecmp _stricmp -#endif - -#ifdef MOZ_WIDGET_GONK -#include "BootAnimation.h" -#endif - -#include "BinaryPath.h" - -#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL - -#ifdef MOZ_WIDGET_GONK -# include -#endif - -#include "mozilla/Sprintf.h" -#include "mozilla/Telemetry.h" -#include "mozilla/WindowsDllBlocklist.h" - -static void Output(const char *fmt, ... ) -{ - va_list ap; - va_start(ap, fmt); - -#if defined(XP_WIN) && !MOZ_WINCONSOLE - wchar_t msg[2048]; - _vsnwprintf(msg, sizeof(msg)/sizeof(msg[0]), NS_ConvertUTF8toUTF16(fmt).get(), ap); - MessageBoxW(nullptr, msg, L"XULRunner", MB_OK | MB_ICONERROR); -#else - vfprintf(stderr, fmt, ap); -#endif - - va_end(ap); -} - -/** - * Return true if |arg| matches the given argument name. - */ -static bool IsArg(const char* arg, const char* s) -{ - if (*arg == '-') - { - if (*++arg == '-') - ++arg; - return !strcasecmp(arg, s); - } - -#if defined(XP_WIN) - if (*arg == '/') - return !strcasecmp(++arg, s); -#endif - - return false; -} - -XRE_GetFileFromPathType XRE_GetFileFromPath; -XRE_CreateAppDataType XRE_CreateAppData; -XRE_FreeAppDataType XRE_FreeAppData; -XRE_TelemetryAccumulateType XRE_TelemetryAccumulate; -XRE_mainType XRE_main; - -static const nsDynamicFunctionLoad kXULFuncs[] = { - { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, - { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, - { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, - { "XRE_TelemetryAccumulate", (NSFuncPtr*) &XRE_TelemetryAccumulate }, - { "XRE_main", (NSFuncPtr*) &XRE_main }, - { nullptr, nullptr } -}; - -static int do_main(int argc, char* argv[]) -{ - nsCOMPtr appini; - nsresult rv; - - // Allow firefox.exe to launch XULRunner apps via -app - // Note that -app must be the *first* argument. - const char *appDataFile = getenv("XUL_APP_FILE"); - if (appDataFile && *appDataFile) { - rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); - if (NS_FAILED(rv)) { - Output("Invalid path found: '%s'", appDataFile); - return 255; - } - } - else if (argc > 1 && IsArg(argv[1], "app")) { - if (argc == 2) { - Output("Incorrect number of arguments passed to -app"); - return 255; - } - - rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini)); - if (NS_FAILED(rv)) { - Output("application.ini path not recognized: '%s'", argv[2]); - return 255; - } - - char appEnv[MAXPATHLEN]; - SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]); - if (putenv(strdup(appEnv))) { - Output("Couldn't set %s.\n", appEnv); - return 255; - } - argv[2] = argv[0]; - argv += 2; - argc -= 2; - } - -#ifdef MOZ_WIDGET_GONK - /* Start boot animation */ - mozilla::StartBootAnimation(); -#endif - - if (appini) { - nsXREAppData *appData; - rv = XRE_CreateAppData(appini, &appData); - if (NS_FAILED(rv)) { - Output("Couldn't read application.ini"); - return 255; - } - int result = XRE_main(argc, argv, appData); - XRE_FreeAppData(appData); - return result; - } - - return XRE_main(argc, argv, &sAppData); -} - -int main(int argc, char* argv[]) -{ - char exePath[MAXPATHLEN]; - -#ifdef MOZ_WIDGET_GONK - // This creates a ThreadPool for binder ipc. A ThreadPool is necessary to - // receive binder calls, though not necessary to send binder calls. - // ProcessState::Self() also needs to be called once on the main thread to - // register the main thread with the binder driver. - android::ProcessState::self()->startThreadPool(); -#endif - - nsresult rv; - rv = mozilla::BinaryPath::Get(argv[0], exePath); - if (NS_FAILED(rv)) { - Output("Couldn't calculate the application directory.\n"); - return 255; - } - - char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); - if (!lastSlash || ((lastSlash - exePath) + sizeof(XPCOM_DLL) + 1 > MAXPATHLEN)) - return 255; - - strcpy(++lastSlash, XPCOM_DLL); - -#if defined(XP_UNIX) - // If the b2g app is launched from adb shell, then the shell will wind - // up being the process group controller. This means that we can't send - // signals to the process group (useful for profiling). - // We ignore the return value since setsid() fails if we're already the - // process group controller (the normal situation). - (void)setsid(); -#endif - -#ifdef HAS_DLL_BLOCKLIST - DllBlocklist_Initialize(); -#endif - - rv = XPCOMGlueStartup(exePath); - if (NS_FAILED(rv)) { - Output("Couldn't load XPCOM.\n"); - return 255; - } - // Reset exePath so that it is the directory name and not the xpcom dll name - *lastSlash = 0; - - rv = XPCOMGlueLoadXULFunctions(kXULFuncs); - if (NS_FAILED(rv)) { - Output("Couldn't load XRE functions.\n"); - return 255; - } - - int result; - { - ScopedLogging log; - char **_argv; - - /* - * Duplicate argument vector to conform non-const argv of - * do_main() since XRE_main() is very stupid with non-const argv. - */ - _argv = new char *[argc + 1]; - for (int i = 0; i < argc; i++) { - size_t len = strlen(argv[i]) + 1; - _argv[i] = new char[len]; - MOZ_ASSERT(_argv[i] != nullptr); - memcpy(_argv[i], argv[i], len); - } - _argv[argc] = nullptr; - - result = do_main(argc, _argv); - - for (int i = 0; i < argc; i++) { - delete[] _argv[i]; - } - delete[] _argv; - } - - return result; -} diff --git a/b2g/app/ua-update.json.in b/b2g/app/ua-update.json.in deleted file mode 100644 index cb4c66d124fb..000000000000 --- a/b2g/app/ua-update.json.in +++ /dev/null @@ -1,51 +0,0 @@ -#filter slashslash -// Everything after the first // on a line will be removed by the preproccesor. -// Send these sites a custom user-agent. Bugs should be included with an entry. -{ - // bug 826347, msn.com - "msn.com": "\\(Mobile#(Android 4.4.4; Mobile", - // bug 826353, itau.com.br - "itau.com.br": "\\(Mobile#(Android; Mobile", - // bug 826510, r7.com - "r7.com": "\\(Mobile#(Android; Mobile", - // bug 827622, bing.com - "bing.com": "\\(Mobile#(Android; Mobile", - // bug 827626, magazineluiza.com.br - "magazineluiza.com.br": "\\(Mobile#(Android; Mobile", - // bug 827670, elpais.com.co - "elpais.com.co": "\\(Mobile#(Android 4.4.4; Mobile", - // bug 828416, loteriasyapuestas.es - "loteriasyapuestas.es": "\\(Mobile#(Android; Mobile", - // bug 828418, bbva.es - "bbva.es": "\\(Mobile#(Android; Mobile", - // bug 828439, movistar.com.ve - "movistar.com.ve": "\\(Mobile#(Android; Mobile", - // bug 843132, comunio.es - "comunio.es": "\\(Mobile#(Android; Mobile", - // bug 843151, citibank.com - "citibank.com": "\\(Mobile#(Android; Mobile", - // bug 843153, games.com - "games.com": "\\(Mobile#(Android; Mobile", - // bug 843160, ehow.com - "ehow.com": "\\(Mobile#(Android; Mobile", - // bug 878228, blikk.hu - "blikk.hu": "\\(Mobile#(Android; Mobile", - // bug 878238, koponyeg.hu - "koponyeg.hu": "\\(Mobile#(Android; Mobile", - // bug 878240, kuruc.info - "kuruc.info": "\\(Mobile#(Android; Mobile", - // bug 878242, nemzetisport.hu - "nemzetisport.hu": "\\(Mobile#(Android; Mobile", - // bug 878246, port.hu - "port.hu": "\\(Mobile#(Android; Mobile", - // bug 878249, portfolio.hu - "portfolio.hu": "\\(Mobile#(Android; Mobile", - // bug 878260, cdm.me - "cdm.me": "\\(Mobile#(Android; Mobile", - // bug 878262, download.com - "download.com": "\\(Mobile#(Android; Mobile", - // bug 878273, livescore.com - "livescore.com": "\\(Mobile#(Android; Mobile", - // bug 878653, redstarbelgrade.info - "redstarbelgrade.info": "\\(Mobile#(Android; Mobile" -} diff --git a/b2g/branding/branding-common.mozbuild b/b2g/branding/branding-common.mozbuild deleted file mode 100644 index ae4aeb285bac..000000000000 --- a/b2g/branding/branding-common.mozbuild +++ /dev/null @@ -1,23 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -@template -def B2GBranding(): - if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': - BRANDING_FILES += [ - 'app.ico', - ] - elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': - BRANDING_FILES += [ - 'app.icns', - 'background.png', - 'disk.icns', - 'dsstore', - ] - elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: - BRANDING_FILES += [ - 'default.png', - ] diff --git a/b2g/branding/browserhtml/app.icns b/b2g/branding/browserhtml/app.icns deleted file mode 100644 index 3d680134e260..000000000000 Binary files a/b2g/branding/browserhtml/app.icns and /dev/null differ diff --git a/b2g/branding/browserhtml/app.ico b/b2g/branding/browserhtml/app.ico deleted file mode 100644 index 04596e4d0602..000000000000 Binary files a/b2g/branding/browserhtml/app.ico and /dev/null differ diff --git a/b2g/branding/browserhtml/background.png b/b2g/branding/browserhtml/background.png deleted file mode 100644 index db5576a3360e..000000000000 Binary files a/b2g/branding/browserhtml/background.png and /dev/null differ diff --git a/b2g/branding/browserhtml/configure.sh b/b2g/branding/browserhtml/configure.sh deleted file mode 100644 index 71c6129d2721..000000000000 --- a/b2g/branding/browserhtml/configure.sh +++ /dev/null @@ -1,5 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOZ_APP_DISPLAYNAME=Browser.html diff --git a/b2g/branding/browserhtml/content/about.png b/b2g/branding/browserhtml/content/about.png deleted file mode 100644 index 3cc1444f645b..000000000000 Binary files a/b2g/branding/browserhtml/content/about.png and /dev/null differ diff --git a/b2g/branding/browserhtml/content/favicon32.png b/b2g/branding/browserhtml/content/favicon32.png deleted file mode 100644 index ac4a6968bf27..000000000000 Binary files a/b2g/branding/browserhtml/content/favicon32.png and /dev/null differ diff --git a/b2g/branding/browserhtml/content/icon48.png b/b2g/branding/browserhtml/content/icon48.png deleted file mode 100644 index b7513c2e4689..000000000000 Binary files a/b2g/branding/browserhtml/content/icon48.png and /dev/null differ diff --git a/b2g/branding/browserhtml/content/icon64.png b/b2g/branding/browserhtml/content/icon64.png deleted file mode 100644 index c8bee8fca98d..000000000000 Binary files a/b2g/branding/browserhtml/content/icon64.png and /dev/null differ diff --git a/b2g/branding/browserhtml/content/jar.mn b/b2g/branding/browserhtml/content/jar.mn deleted file mode 100644 index 8a2c16964f67..000000000000 --- a/b2g/branding/browserhtml/content/jar.mn +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -chrome.jar: -% content branding %content/branding/ contentaccessible=yes - content/branding/about.png (about.png) - content/branding/logoWordmark.png (logoWordmark.png) - content/branding/logo.png (logo.png) - content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/browserhtml/content/logo.png b/b2g/branding/browserhtml/content/logo.png deleted file mode 100644 index 9d9d0c57e030..000000000000 Binary files a/b2g/branding/browserhtml/content/logo.png and /dev/null differ diff --git a/b2g/branding/browserhtml/content/logoWordmark.png b/b2g/branding/browserhtml/content/logoWordmark.png deleted file mode 100644 index 878363181ace..000000000000 Binary files a/b2g/branding/browserhtml/content/logoWordmark.png and /dev/null differ diff --git a/b2g/branding/browserhtml/content/moz.build b/b2g/branding/browserhtml/content/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/browserhtml/content/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/browserhtml/content/splash.png b/b2g/branding/browserhtml/content/splash.png deleted file mode 100644 index 84ab581d20e5..000000000000 Binary files a/b2g/branding/browserhtml/content/splash.png and /dev/null differ diff --git a/b2g/branding/browserhtml/default.png b/b2g/branding/browserhtml/default.png deleted file mode 100644 index ae4736223a85..000000000000 Binary files a/b2g/branding/browserhtml/default.png and /dev/null differ diff --git a/b2g/branding/browserhtml/disk.icns b/b2g/branding/browserhtml/disk.icns deleted file mode 100644 index c49b7b878e41..000000000000 Binary files a/b2g/branding/browserhtml/disk.icns and /dev/null differ diff --git a/b2g/branding/browserhtml/dsstore b/b2g/branding/browserhtml/dsstore deleted file mode 100644 index 657101d6e220..000000000000 Binary files a/b2g/branding/browserhtml/dsstore and /dev/null differ diff --git a/b2g/branding/browserhtml/locales/en-US/brand.dtd b/b2g/branding/browserhtml/locales/en-US/brand.dtd deleted file mode 100644 index 6c3088d70c1d..000000000000 --- a/b2g/branding/browserhtml/locales/en-US/brand.dtd +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/b2g/branding/browserhtml/locales/en-US/brand.properties b/b2g/branding/browserhtml/locales/en-US/brand.properties deleted file mode 100644 index 897d1a8007e7..000000000000 --- a/b2g/branding/browserhtml/locales/en-US/brand.properties +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -brandShortName=Browser.html -brandFullName=Mozilla Browser.html diff --git a/b2g/branding/browserhtml/locales/jar.mn b/b2g/branding/browserhtml/locales/jar.mn deleted file mode 100644 index 2ea47e1684a9..000000000000 --- a/b2g/branding/browserhtml/locales/jar.mn +++ /dev/null @@ -1,11 +0,0 @@ -#filter substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -@AB_CD@.jar: -% locale branding @AB_CD@ %locale/branding/ -# Branding only exists in en-US - locale/branding/brand.dtd (en-US/brand.dtd) - locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/browserhtml/locales/moz.build b/b2g/branding/browserhtml/locales/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/browserhtml/locales/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/browserhtml/moz.build b/b2g/branding/browserhtml/moz.build deleted file mode 100644 index bf7aff4c04fb..000000000000 --- a/b2g/branding/browserhtml/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ['content', 'locales'] - -include('../branding-common.mozbuild') -B2GBranding() diff --git a/b2g/branding/horizon/app.icns b/b2g/branding/horizon/app.icns deleted file mode 100644 index 6c7b9f5b500e..000000000000 Binary files a/b2g/branding/horizon/app.icns and /dev/null differ diff --git a/b2g/branding/horizon/app.ico b/b2g/branding/horizon/app.ico deleted file mode 100644 index 49eb90419234..000000000000 Binary files a/b2g/branding/horizon/app.ico and /dev/null differ diff --git a/b2g/branding/horizon/background.png b/b2g/branding/horizon/background.png deleted file mode 100644 index db5576a3360e..000000000000 Binary files a/b2g/branding/horizon/background.png and /dev/null differ diff --git a/b2g/branding/horizon/configure.sh b/b2g/branding/horizon/configure.sh deleted file mode 100644 index 65774e3841e5..000000000000 --- a/b2g/branding/horizon/configure.sh +++ /dev/null @@ -1,5 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOZ_APP_DISPLAYNAME=Horizon diff --git a/b2g/branding/horizon/content/about.png b/b2g/branding/horizon/content/about.png deleted file mode 100644 index 3cc1444f645b..000000000000 Binary files a/b2g/branding/horizon/content/about.png and /dev/null differ diff --git a/b2g/branding/horizon/content/favicon32.png b/b2g/branding/horizon/content/favicon32.png deleted file mode 100644 index ac4a6968bf27..000000000000 Binary files a/b2g/branding/horizon/content/favicon32.png and /dev/null differ diff --git a/b2g/branding/horizon/content/icon48.png b/b2g/branding/horizon/content/icon48.png deleted file mode 100644 index b7513c2e4689..000000000000 Binary files a/b2g/branding/horizon/content/icon48.png and /dev/null differ diff --git a/b2g/branding/horizon/content/icon64.png b/b2g/branding/horizon/content/icon64.png deleted file mode 100644 index c8bee8fca98d..000000000000 Binary files a/b2g/branding/horizon/content/icon64.png and /dev/null differ diff --git a/b2g/branding/horizon/content/jar.mn b/b2g/branding/horizon/content/jar.mn deleted file mode 100644 index 8a2c16964f67..000000000000 --- a/b2g/branding/horizon/content/jar.mn +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -chrome.jar: -% content branding %content/branding/ contentaccessible=yes - content/branding/about.png (about.png) - content/branding/logoWordmark.png (logoWordmark.png) - content/branding/logo.png (logo.png) - content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/horizon/content/logo.png b/b2g/branding/horizon/content/logo.png deleted file mode 100644 index 9d9d0c57e030..000000000000 Binary files a/b2g/branding/horizon/content/logo.png and /dev/null differ diff --git a/b2g/branding/horizon/content/logoWordmark.png b/b2g/branding/horizon/content/logoWordmark.png deleted file mode 100644 index 878363181ace..000000000000 Binary files a/b2g/branding/horizon/content/logoWordmark.png and /dev/null differ diff --git a/b2g/branding/horizon/content/moz.build b/b2g/branding/horizon/content/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/horizon/content/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/horizon/content/splash.png b/b2g/branding/horizon/content/splash.png deleted file mode 100644 index 84ab581d20e5..000000000000 Binary files a/b2g/branding/horizon/content/splash.png and /dev/null differ diff --git a/b2g/branding/horizon/default.png b/b2g/branding/horizon/default.png deleted file mode 100644 index 0e6a4016ca52..000000000000 Binary files a/b2g/branding/horizon/default.png and /dev/null differ diff --git a/b2g/branding/horizon/disk.icns b/b2g/branding/horizon/disk.icns deleted file mode 100644 index c49b7b878e41..000000000000 Binary files a/b2g/branding/horizon/disk.icns and /dev/null differ diff --git a/b2g/branding/horizon/dsstore b/b2g/branding/horizon/dsstore deleted file mode 100644 index 657101d6e220..000000000000 Binary files a/b2g/branding/horizon/dsstore and /dev/null differ diff --git a/b2g/branding/horizon/locales/en-US/brand.dtd b/b2g/branding/horizon/locales/en-US/brand.dtd deleted file mode 100644 index ad7a938b56c2..000000000000 --- a/b2g/branding/horizon/locales/en-US/brand.dtd +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/b2g/branding/horizon/locales/en-US/brand.properties b/b2g/branding/horizon/locales/en-US/brand.properties deleted file mode 100644 index ce9e209cff20..000000000000 --- a/b2g/branding/horizon/locales/en-US/brand.properties +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -brandShortName=Horizon -brandFullName=Mozilla Horizon diff --git a/b2g/branding/horizon/locales/jar.mn b/b2g/branding/horizon/locales/jar.mn deleted file mode 100644 index 2ea47e1684a9..000000000000 --- a/b2g/branding/horizon/locales/jar.mn +++ /dev/null @@ -1,11 +0,0 @@ -#filter substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -@AB_CD@.jar: -% locale branding @AB_CD@ %locale/branding/ -# Branding only exists in en-US - locale/branding/brand.dtd (en-US/brand.dtd) - locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/horizon/locales/moz.build b/b2g/branding/horizon/locales/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/horizon/locales/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/horizon/moz.build b/b2g/branding/horizon/moz.build deleted file mode 100644 index bf7aff4c04fb..000000000000 --- a/b2g/branding/horizon/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ['content', 'locales'] - -include('../branding-common.mozbuild') -B2GBranding() diff --git a/b2g/branding/official/app.icns b/b2g/branding/official/app.icns deleted file mode 100644 index eba850aaee10..000000000000 Binary files a/b2g/branding/official/app.icns and /dev/null differ diff --git a/b2g/branding/official/app.ico b/b2g/branding/official/app.ico deleted file mode 100644 index 5d4a61dc92ba..000000000000 Binary files a/b2g/branding/official/app.ico and /dev/null differ diff --git a/b2g/branding/official/background.png b/b2g/branding/official/background.png deleted file mode 100644 index db5576a3360e..000000000000 Binary files a/b2g/branding/official/background.png and /dev/null differ diff --git a/b2g/branding/official/configure.sh b/b2g/branding/official/configure.sh deleted file mode 100644 index 127a0f1a175d..000000000000 --- a/b2g/branding/official/configure.sh +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOZ_APP_DISPLAYNAME=B2G -MOZ_UPDATER= diff --git a/b2g/branding/official/content/about.png b/b2g/branding/official/content/about.png deleted file mode 100644 index 3cc1444f645b..000000000000 Binary files a/b2g/branding/official/content/about.png and /dev/null differ diff --git a/b2g/branding/official/content/favicon32.png b/b2g/branding/official/content/favicon32.png deleted file mode 100644 index ac4a6968bf27..000000000000 Binary files a/b2g/branding/official/content/favicon32.png and /dev/null differ diff --git a/b2g/branding/official/content/icon48.png b/b2g/branding/official/content/icon48.png deleted file mode 100644 index b7513c2e4689..000000000000 Binary files a/b2g/branding/official/content/icon48.png and /dev/null differ diff --git a/b2g/branding/official/content/icon64.png b/b2g/branding/official/content/icon64.png deleted file mode 100644 index c8bee8fca98d..000000000000 Binary files a/b2g/branding/official/content/icon64.png and /dev/null differ diff --git a/b2g/branding/official/content/jar.mn b/b2g/branding/official/content/jar.mn deleted file mode 100644 index 8a2c16964f67..000000000000 --- a/b2g/branding/official/content/jar.mn +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -chrome.jar: -% content branding %content/branding/ contentaccessible=yes - content/branding/about.png (about.png) - content/branding/logoWordmark.png (logoWordmark.png) - content/branding/logo.png (logo.png) - content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/official/content/logo.png b/b2g/branding/official/content/logo.png deleted file mode 100644 index 9d9d0c57e030..000000000000 Binary files a/b2g/branding/official/content/logo.png and /dev/null differ diff --git a/b2g/branding/official/content/logoWordmark.png b/b2g/branding/official/content/logoWordmark.png deleted file mode 100644 index 878363181ace..000000000000 Binary files a/b2g/branding/official/content/logoWordmark.png and /dev/null differ diff --git a/b2g/branding/official/content/moz.build b/b2g/branding/official/content/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/official/content/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/official/content/splash.png b/b2g/branding/official/content/splash.png deleted file mode 100644 index 84ab581d20e5..000000000000 Binary files a/b2g/branding/official/content/splash.png and /dev/null differ diff --git a/b2g/branding/official/default.png b/b2g/branding/official/default.png deleted file mode 100644 index c4307fc84184..000000000000 Binary files a/b2g/branding/official/default.png and /dev/null differ diff --git a/b2g/branding/official/disk.icns b/b2g/branding/official/disk.icns deleted file mode 100644 index c49b7b878e41..000000000000 Binary files a/b2g/branding/official/disk.icns and /dev/null differ diff --git a/b2g/branding/official/dsstore b/b2g/branding/official/dsstore deleted file mode 100644 index 657101d6e220..000000000000 Binary files a/b2g/branding/official/dsstore and /dev/null differ diff --git a/b2g/branding/official/locales/en-US/brand.dtd b/b2g/branding/official/locales/en-US/brand.dtd deleted file mode 100644 index 1a6f391481e1..000000000000 --- a/b2g/branding/official/locales/en-US/brand.dtd +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/b2g/branding/official/locales/en-US/brand.properties b/b2g/branding/official/locales/en-US/brand.properties deleted file mode 100644 index d0203e35a492..000000000000 --- a/b2g/branding/official/locales/en-US/brand.properties +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -brandShortName=Firefox -brandFullName=Mozilla Firefox diff --git a/b2g/branding/official/locales/jar.mn b/b2g/branding/official/locales/jar.mn deleted file mode 100644 index 2ea47e1684a9..000000000000 --- a/b2g/branding/official/locales/jar.mn +++ /dev/null @@ -1,11 +0,0 @@ -#filter substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -@AB_CD@.jar: -% locale branding @AB_CD@ %locale/branding/ -# Branding only exists in en-US - locale/branding/brand.dtd (en-US/brand.dtd) - locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/official/locales/moz.build b/b2g/branding/official/locales/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/official/locales/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/official/moz.build b/b2g/branding/official/moz.build deleted file mode 100644 index bf7aff4c04fb..000000000000 --- a/b2g/branding/official/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ['content', 'locales'] - -include('../branding-common.mozbuild') -B2GBranding() diff --git a/b2g/branding/unofficial/app.icns b/b2g/branding/unofficial/app.icns deleted file mode 100644 index eba850aaee10..000000000000 Binary files a/b2g/branding/unofficial/app.icns and /dev/null differ diff --git a/b2g/branding/unofficial/app.ico b/b2g/branding/unofficial/app.ico deleted file mode 100644 index 5d4a61dc92ba..000000000000 Binary files a/b2g/branding/unofficial/app.ico and /dev/null differ diff --git a/b2g/branding/unofficial/background.png b/b2g/branding/unofficial/background.png deleted file mode 100644 index db5576a3360e..000000000000 Binary files a/b2g/branding/unofficial/background.png and /dev/null differ diff --git a/b2g/branding/unofficial/configure.sh b/b2g/branding/unofficial/configure.sh deleted file mode 100644 index 127a0f1a175d..000000000000 --- a/b2g/branding/unofficial/configure.sh +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOZ_APP_DISPLAYNAME=B2G -MOZ_UPDATER= diff --git a/b2g/branding/unofficial/content/about.png b/b2g/branding/unofficial/content/about.png deleted file mode 100644 index 3819f6337a17..000000000000 Binary files a/b2g/branding/unofficial/content/about.png and /dev/null differ diff --git a/b2g/branding/unofficial/content/favicon32.png b/b2g/branding/unofficial/content/favicon32.png deleted file mode 100644 index 3f04acd50d30..000000000000 Binary files a/b2g/branding/unofficial/content/favicon32.png and /dev/null differ diff --git a/b2g/branding/unofficial/content/icon48.png b/b2g/branding/unofficial/content/icon48.png deleted file mode 100644 index 3ae248c857d7..000000000000 Binary files a/b2g/branding/unofficial/content/icon48.png and /dev/null differ diff --git a/b2g/branding/unofficial/content/icon64.png b/b2g/branding/unofficial/content/icon64.png deleted file mode 100644 index fe980153be29..000000000000 Binary files a/b2g/branding/unofficial/content/icon64.png and /dev/null differ diff --git a/b2g/branding/unofficial/content/jar.mn b/b2g/branding/unofficial/content/jar.mn deleted file mode 100644 index 8a2c16964f67..000000000000 --- a/b2g/branding/unofficial/content/jar.mn +++ /dev/null @@ -1,10 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -chrome.jar: -% content branding %content/branding/ contentaccessible=yes - content/branding/about.png (about.png) - content/branding/logoWordmark.png (logoWordmark.png) - content/branding/logo.png (logo.png) - content/branding/favicon32.png (favicon32.png) diff --git a/b2g/branding/unofficial/content/logo.png b/b2g/branding/unofficial/content/logo.png deleted file mode 100644 index 91377a312090..000000000000 Binary files a/b2g/branding/unofficial/content/logo.png and /dev/null differ diff --git a/b2g/branding/unofficial/content/logoWordmark.png b/b2g/branding/unofficial/content/logoWordmark.png deleted file mode 100644 index a3017f59ecf0..000000000000 Binary files a/b2g/branding/unofficial/content/logoWordmark.png and /dev/null differ diff --git a/b2g/branding/unofficial/content/moz.build b/b2g/branding/unofficial/content/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/unofficial/content/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/unofficial/content/splash.png b/b2g/branding/unofficial/content/splash.png deleted file mode 100644 index 25a0830eac70..000000000000 Binary files a/b2g/branding/unofficial/content/splash.png and /dev/null differ diff --git a/b2g/branding/unofficial/default.png b/b2g/branding/unofficial/default.png deleted file mode 100644 index c4307fc84184..000000000000 Binary files a/b2g/branding/unofficial/default.png and /dev/null differ diff --git a/b2g/branding/unofficial/disk.icns b/b2g/branding/unofficial/disk.icns deleted file mode 100644 index c49b7b878e41..000000000000 Binary files a/b2g/branding/unofficial/disk.icns and /dev/null differ diff --git a/b2g/branding/unofficial/dsstore b/b2g/branding/unofficial/dsstore deleted file mode 100644 index 657101d6e220..000000000000 Binary files a/b2g/branding/unofficial/dsstore and /dev/null differ diff --git a/b2g/branding/unofficial/locales/en-US/brand.dtd b/b2g/branding/unofficial/locales/en-US/brand.dtd deleted file mode 100644 index 1a6f391481e1..000000000000 --- a/b2g/branding/unofficial/locales/en-US/brand.dtd +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/b2g/branding/unofficial/locales/en-US/brand.properties b/b2g/branding/unofficial/locales/en-US/brand.properties deleted file mode 100644 index d0203e35a492..000000000000 --- a/b2g/branding/unofficial/locales/en-US/brand.properties +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -brandShortName=Firefox -brandFullName=Mozilla Firefox diff --git a/b2g/branding/unofficial/locales/jar.mn b/b2g/branding/unofficial/locales/jar.mn deleted file mode 100644 index 5a77695c91aa..000000000000 --- a/b2g/branding/unofficial/locales/jar.mn +++ /dev/null @@ -1,11 +0,0 @@ -#filter substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -@AB_CD@.jar: -% locale branding @AB_CD@ %locale/branding/ -# Nightly branding only exists in en-US - locale/branding/brand.dtd (en-US/brand.dtd) - locale/branding/brand.properties (en-US/brand.properties) diff --git a/b2g/branding/unofficial/locales/moz.build b/b2g/branding/unofficial/locales/moz.build deleted file mode 100644 index eb4454d28f88..000000000000 --- a/b2g/branding/unofficial/locales/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file diff --git a/b2g/branding/unofficial/moz.build b/b2g/branding/unofficial/moz.build deleted file mode 100644 index bf7aff4c04fb..000000000000 --- a/b2g/branding/unofficial/moz.build +++ /dev/null @@ -1,10 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DIRS += ['content', 'locales'] - -include('../branding-common.mozbuild') -B2GBranding() diff --git a/b2g/build.mk b/b2g/build.mk deleted file mode 100644 index 31e20b580ee4..000000000000 --- a/b2g/build.mk +++ /dev/null @@ -1,31 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk - -installer: - @$(MAKE) -C b2g/installer installer - -package: - @$(MAKE) -C b2g/installer - -install:: - @echo 'B2G can't be installed directly.' - @exit 1 - -upload:: - @$(MAKE) -C b2g/installer upload - -ifdef ENABLE_TESTS -# Implemented in testing/testsuite-targets.mk - -mochitest-browser-chrome: - $(RUN_MOCHITEST) --flavor=browser - $(CHECK_TEST_ERROR) - -mochitest:: mochitest-browser-chrome - -.PHONY: mochitest-browser-chrome -endif - diff --git a/b2g/chrome/content/ErrorPage.js b/b2g/chrome/content/ErrorPage.js deleted file mode 100644 index d51782466346..000000000000 --- a/b2g/chrome/content/ErrorPage.js +++ /dev/null @@ -1,73 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -var Cu = Components.utils; -var Cc = Components.classes; -var Ci = Components.interfaces; - -dump("############ ErrorPage.js\n"); - -var ErrorPageHandler = { - _reload: function() { - docShell.QueryInterface(Ci.nsIWebNavigation).reload(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); - }, - - _certErrorPageEventHandler: function(e) { - let target = e.originalTarget; - let errorDoc = target.ownerDocument; - - // If the event came from an ssl error page, it is one of the "Add - // Exception…" buttons. - if (/^about:certerror\?e=nssBadCert/.test(errorDoc.documentURI)) { - let permanent = errorDoc.getElementById("permanentExceptionButton"); - let temp = errorDoc.getElementById("temporaryExceptionButton"); - if (target == temp || target == permanent) { - sendAsyncMessage("ErrorPage:AddCertException", { - url: errorDoc.location.href, - isPermanent: target == permanent - }); - } - } - }, - - _bindPageEvent: function(target) { - if (!target) { - return; - } - - if (/^about:certerror/.test(target.documentURI)) { - let errorPageEventHandler = this._certErrorPageEventHandler.bind(this); - addEventListener("click", errorPageEventHandler, true, false); - let listener = function() { - removeEventListener("click", errorPageEventHandler, true); - removeEventListener("pagehide", listener, true); - }.bind(this); - - addEventListener("pagehide", listener, true); - } - }, - - domContentLoadedHandler: function(e) { - let target = e.originalTarget; - let targetDocShell = target.defaultView - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation); - if (targetDocShell != docShell) { - return; - } - this._bindPageEvent(target); - }, - - init: function() { - addMessageListener("ErrorPage:ReloadPage", this._reload.bind(this)); - addEventListener('DOMContentLoaded', - this.domContentLoadedHandler.bind(this), - true); - this._bindPageEvent(content.document); - } -}; - -ErrorPageHandler.init(); diff --git a/b2g/chrome/content/aboutCertError.xhtml b/b2g/chrome/content/aboutCertError.xhtml deleted file mode 100644 index 616657e54059..000000000000 --- a/b2g/chrome/content/aboutCertError.xhtml +++ /dev/null @@ -1,233 +0,0 @@ - - - - %htmlDTD; - - %globalDTD; - - %certerrorDTD; -]> - - - - - &certerror.pagetitle; - - - - - - - - - - - -
-

&certerror.longpagetitle;

-
- - -
- - -
-
-

&certerror.introPara1;

-
- - -
-

&certerror.technical.heading;

-

-

- -
-

&certerror.expert.heading;

-
-

&certerror.expert.content;

-

&certerror.expert.contentPara2;

- - -
-
-
-
- - - - - - diff --git a/b2g/chrome/content/arrow.svg b/b2g/chrome/content/arrow.svg deleted file mode 100644 index d3d9e8246aec..000000000000 --- a/b2g/chrome/content/arrow.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/b2g/chrome/content/blank.css b/b2g/chrome/content/blank.css deleted file mode 100644 index 71914be1f5f3..000000000000 --- a/b2g/chrome/content/blank.css +++ /dev/null @@ -1,7 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -body { - background: black; -} diff --git a/b2g/chrome/content/blank.html b/b2g/chrome/content/blank.html deleted file mode 100644 index b8b20e2c6797..000000000000 --- a/b2g/chrome/content/blank.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/b2g/chrome/content/content.css b/b2g/chrome/content/content.css deleted file mode 100644 index 2b73b16b38e8..000000000000 --- a/b2g/chrome/content/content.css +++ /dev/null @@ -1,321 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -@namespace url("http://www.w3.org/1999/xhtml"); -@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); - -/* Style the scrollbars */ -xul|window xul|scrollbar { - display: none; -} - -/* Bug 1041576 - Scrollable with scrollgrab should not have scrollbars */ - -@-moz-document domain(system.gaiamobile.org) { - .browser-container > xul|scrollbar { - display: none; - } -} - -%ifdef MOZ_GRAPHENE -.moz-noscrollbars > xul|scrollbar { - display: none; -} -%endif - -xul|scrollbar[root="true"] { - position: relative; - z-index: 2147483647; -} - -xul|scrollbar { - -moz-appearance: none !important; - background-color: transparent !important; - background-image: none !important; - border: 0px solid transparent !important; - pointer-events: none; -} - -/* Scrollbar code will reset the margin to the correct side depending on - where layout actually puts the scrollbar */ -xul|scrollbar[orient="vertical"] { - margin-left: -8px; - min-width: 8px; - max-width: 8px; -} - -xul|scrollbar[orient="vertical"] xul|thumb { - max-width: 6px !important; - min-width: 6px !important; -} - -xul|scrollbar[orient="horizontal"] { - margin-top: -8px; - min-height: 8px; - max-height: 8px; -} - -xul|scrollbar[orient="horizontal"] xul|thumb { - max-height: 6px !important; - min-height: 6px !important; -} - -xul|scrollbar:not([active="true"]), -xul|scrollbar[disabled] { - opacity: 0; -} - -xul|scrollbarbutton { - min-height: 8px !important; - min-width: 8px !important; - -moz-appearance: none !important; - visibility: hidden; -} - -xul|scrollbarbutton[sbattr="scrollbar-up-top"], -xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] { - display: none; -} - -xul|thumb { - background-color: rgba(0, 0, 0, 0.4) !important; - -moz-border-top-colors: none !important; - -moz-border-bottom-colors: none !important; - -moz-border-right-colors: none !important; - -moz-border-left-colors: none !important; - border: 1px solid rgba(255, 255, 255, 0.4) !important; - border-radius: 3px; -} - -xul|scrollbarbutton { - background-image: none !important; -} - -%ifndef MOZ_GRAPHENE -/* -moz-touch-enabled? media elements */ -:-moz-any(video, audio) > xul|videocontrols { - -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControls"); -} - -select:not([size]):not([multiple]) > xul|scrollbar, -select[size="1"] > xul|scrollbar, -select:not([size]):not([multiple]) xul|scrollbarbutton, -select[size="1"] xul|scrollbarbutton { - display: block; - margin-left: 0; - min-width: 16px; -} - -/* Override inverse OS themes */ -select, -textarea, -button, -xul|button, -* > input:not([type="image"]) { - -moz-appearance: none !important; /* See bug 598421 for fixing the platform */ - border-radius: 3px; -} - -select[size], -select[multiple], -select[size][multiple], -textarea, -* > input:not([type="image"]) { - border-style: solid; - border-color: #7d7d7d; - color: #414141; - background-color: white; -} - -/* Selects are handled by the form helper, see bug 685197 */ -select option, select optgroup { - pointer-events: none; -} - -select:not([size]):not([multiple]), -select[size="0"], -select[size="1"], -* > input[type="button"], -* > input[type="submit"], -* > input[type="reset"], -button { - border-style: solid; - border-color: #7d7d7d; - color: #414141; - background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(215,215,215,0.5) 18px, rgba(115,115,115,0.5) 100%); -} - -input[type="checkbox"] { - background-color: white; -} - -input[type="radio"] { - background-color: white; -} - -select { - border-width: 1px; - padding: 1px; -} - -select:not([size]):not([multiple]), -select[size="0"], -select[size="1"] { - padding: 0 1px 0 1px; -} - -* > input:not([type="image"]) { - border-width: 1px; - padding: 1px; -} - -textarea { - resize: none; - border-width: 1px; - padding-inline-start: 1px; - padding-inline-end: 1px; - padding-block-start: 2px; - padding-block-end: 2px; -} - -input[type="button"], -input[type="submit"], -input[type="reset"], -button { - border-width: 1px; - padding-inline-start: 7px; - padding-inline-end: 7px; - padding-block-start: 0; - padding-block-end: 0; -} - -input[type="radio"], -input[type="checkbox"] { - border: 1px solid #a7a7a7 !important; - padding-inline-start: 1px; - padding-inline-end: 1px; - padding-block-start: 2px; - padding-block-end: 2px; -} - -select > button { - border-width: 0px !important; - margin: 0px !important; - padding: 0px !important; - border-radius: 0; - color: #414141; - - background-image: radial-gradient(at bottom left, #bbbbbb 40%, #f5f5f5), url(arrow.svg) !important; - background-color: transparent; - background-position: -15px center, 4px center !important; - background-repeat: no-repeat, no-repeat !important; - background-size: 100% 90%, auto auto; - - -moz-binding: none !important; - position: relative !important; - font-size: inherit; -} - -select[size]:focus, -select[multiple]:focus, -select[size][multiple]:focus, -textarea:focus, -input[type="file"]:focus > input[type="text"], -* > input:not([type="image"]):focus { - outline: 0px !important; - border-style: solid; - border-color: rgb(94,128,153); - background-color: white; -} - -select:not([size]):not([multiple]):focus, -select[size="0"]:focus, -select[size="1"]:focus, -input[type="button"]:focus, -input[type="submit"]:focus, -input[type="reset"]:focus, -button:focus { - outline: 0px !important; - border-style: solid; - border-color: rgb(94,128,153); - background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(198,225,256,0.2) 18px, rgba(27,113,177,0.5) 100%); -} - -input[type="checkbox"]:focus, -input[type="radio"]:focus { - border-color: #99c6e0 !important; -} - -/* we need to be specific for selects because the above rules are specific too */ -textarea[disabled], -select[size][disabled], -select[multiple][disabled], -select[size][multiple][disabled], -select:not([size]):not([multiple])[disabled], -select[size="0"][disabled], -select[size="1"][disabled], -button[disabled], -* > input:not([type="image"])[disabled] { - color: rgba(0,0,0,0.3); - border-color: rgba(125,125,125,0.4); - border-style: solid; - border-width: 1px; - background-color: #f5f5f5; -} - -select:not([size]):not([multiple])[disabled], -select[size="0"][disabled], -select[size="1"][disabled] { - background-color: #f5f5f5; -} - -input[type="button"][disabled], -input[type="submit"][disabled], -input[type="reset"][disabled], -button[disabled] { - padding-inline-start: 7px; - padding-inline-end: 7px; - padding-block-start: 0; - padding-block-end: 0; - background-color: #f5f5f5; -} - -input[type="radio"][disabled], -input[type="radio"][disabled]:active, -input[type="radio"][disabled]:hover, -input[type="radio"][disabled]:hover:active, -input[type="checkbox"][disabled], -input[type="checkbox"][disabled]:active, -input[type="checkbox"][disabled]:hover, -input[type="checkbox"][disabled]:hover:active { - border:1px solid rgba(125,125,125,0.4) !important; -} - -select[disabled] > button { - opacity: 0.6; - padding: 1px 7px 1px 7px; -} - -*:any-link:active, -*[role=button]:active, -button:active, -option:active, -select:active, -label:active { - background-color: rgba(141, 184, 216, 0.5); -} - -input[type=number] > div > div, /* work around bug 946184 */ -input[type=number]::-moz-number-spin-box { - display: none; -} -%endif - -%ifdef MOZ_WIDGET_GONK -/* This binding only provide key shortcuts that we can't use on devices */ -input, -textarea { --moz-binding: none !important; -} -%endif diff --git a/b2g/chrome/content/desktop.css b/b2g/chrome/content/desktop.css deleted file mode 100644 index 9612d732c354..000000000000 --- a/b2g/chrome/content/desktop.css +++ /dev/null @@ -1,59 +0,0 @@ -#controls { - position: absolute; - left: 0; - bottom:0; - right: 0; - height: 30px; - background-color: -moz-dialog; -} - -#home-button { - margin: auto; - margin-top: 3px; - width: 24px; - height: 24px; - background: #eee url("images/desktop/home-black.png") center no-repeat; - border: 1px solid #888; - border-radius: 12px; - display: block; -} - -#home-button::-moz-focus-inner { - padding: 0; - border: 0; -} - -#home-button:hover { - background-image: url("images/desktop/home-white.png"); - background-color: #ccc; - border-color: #555; -} - -#home-button.active { - background-image: url("images/desktop/home-white.png"); - background-color: #888; - border-color: black; -} - -#rotate-button { - position: absolute; - top: 3px; - bottom: 3px; - right: 3px; - width: 24px; - height: 24px; - background: #eee url("images/desktop/rotate.png") center no-repeat; - border: 1px solid #888; - border-radius: 12px; - display: block; -} - -#rotate-button:hover { - background-color: #ccc; - border-color: #555; -} - -#rotate-button.active { - background-color: #888; - border-color: black; -} diff --git a/b2g/chrome/content/desktop.js b/b2g/chrome/content/desktop.js deleted file mode 100644 index 83b443e21936..000000000000 --- a/b2g/chrome/content/desktop.js +++ /dev/null @@ -1,177 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var browserWindow = Services.wm.getMostRecentWindow("navigator:browser"); -var isMulet = "ResponsiveUI" in browserWindow; - -// Enable touch event shim on desktop that translates mouse events -// into touch ones -function enableTouch() { - let require = Cu.import('resource://devtools/shared/Loader.jsm', {}) - .devtools.require; - let { TouchEventSimulator } = require('devtools/shared/touch/simulator'); - let touchEventSimulator = new TouchEventSimulator(shell.contentBrowser); - touchEventSimulator.start(); -} - -// Some additional buttons are displayed on simulators to fake hardware buttons. -function setupButtons() { - let link = document.createElement('link'); - link.type = 'text/css'; - link.rel = 'stylesheet'; - link.href = 'chrome://b2g/content/desktop.css'; - document.head.appendChild(link); - - let footer = document.createElement('footer'); - footer.id = 'controls'; - document.body.appendChild(footer); - let homeButton = document.createElement('button'); - homeButton.id = 'home-button'; - footer.appendChild(homeButton); - let rotateButton = document.createElement('button'); - rotateButton.id = 'rotate-button'; - footer.appendChild(rotateButton); - - homeButton.addEventListener('mousedown', function() { - let window = shell.contentBrowser.contentWindow; - let e = new window.KeyboardEvent('keydown', {key: 'Home'}); - window.dispatchEvent(e); - homeButton.classList.add('active'); - }); - homeButton.addEventListener('mouseup', function() { - let window = shell.contentBrowser.contentWindow; - let e = new window.KeyboardEvent('keyup', {key: 'Home'}); - window.dispatchEvent(e); - homeButton.classList.remove('active'); - }); - - Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm"); - rotateButton.addEventListener('mousedown', function() { - rotateButton.classList.add('active'); - }); - rotateButton.addEventListener('mouseup', function() { - GlobalSimulatorScreen.flipScreen(); - rotateButton.classList.remove('active'); - }); -} - -function setupStorage() { - let directory = null; - - // Get the --storage-path argument from the command line. - try { - let service = Cc['@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds'].getService(Ci.nsISupports); - let args = service.wrappedJSObject.cmdLine; - if (args) { - let path = args.handleFlagWithParam('storage-path', false); - directory = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); - directory.initWithPath(path); - } - } catch(e) { - directory = null; - } - - // Otherwise, default to 'storage' folder within current profile. - if (!directory) { - directory = Services.dirsvc.get('ProfD', Ci.nsIFile); - directory.append('storage'); - if (!directory.exists()) { - directory.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("755", 8)); - } - } - dump("Set storage path to: " + directory.path + "\n"); - - // This is the magic, where we override the default location for the storages. - Services.prefs.setCharPref('device.storage.overrideRootDir', directory.path); -} - -function checkDebuggerPort() { - // XXX: To be removed once bug 942756 lands. - // We are hacking 'unix-domain-socket' pref by setting a tcp port (number). - // SocketListener.open detects that it isn't a file path (string), and starts - // listening on the tcp port given here as command line argument. - - // Get the command line arguments that were passed to the b2g client - let args; - try { - let service = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"].getService(Ci.nsISupports); - args = service.wrappedJSObject.cmdLine; - } catch(e) {} - - if (!args) { - return; - } - - let dbgport; - try { - dbgport = args.handleFlagWithParam('start-debugger-server', false); - } catch(e) {} - - if (dbgport) { - dump('Opening debugger server on ' + dbgport + '\n'); - Services.prefs.setCharPref('devtools.debugger.unix-domain-socket', dbgport); - } -} - - -function initResponsiveDesign() { - Cu.import('resource://devtools/client/responsivedesign/responsivedesign.jsm'); - ResponsiveUIManager.on('on', function(event, {tab:tab}) { - let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab); - let document = tab.ownerDocument; - - // Only tweak reponsive mode for shell.html tabs. - if (tab.linkedBrowser.contentWindow != window) { - return; - } - - // Disable transition as they mess up with screen size handler - responsive.transitionsEnabled = false; - - responsive.buildPhoneUI(); - - responsive.rotatebutton.addEventListener('command', function (evt) { - GlobalSimulatorScreen.flipScreen(); - evt.stopImmediatePropagation(); - evt.preventDefault(); - }, true); - - // Enable touch events - responsive.enableTouch(); - }); - - - let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager; - mgr.toggle(browserWindow, browserWindow.gBrowser.selectedTab); - -} - -function openDevtools() { - // Open devtool panel while maximizing its size according to screen size - Services.prefs.setIntPref('devtools.toolbox.sidebar.width', - browserWindow.outerWidth - 550); - Services.prefs.setCharPref('devtools.toolbox.host', 'side'); - let {gDevTools} = Cu.import('resource://devtools/client/framework/gDevTools.jsm', {}); - let {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {}); - let target = devtools.TargetFactory.forTab(browserWindow.gBrowser.selectedTab); - gDevTools.showToolbox(target); -} - -window.addEventListener('ContentStart', function() { - // On Firefox Mulet, touch events are enabled within the responsive mode - if (!isMulet) { - enableTouch(); - } - if (Services.prefs.getBoolPref('b2g.software-buttons')) { - setupButtons(); - } - checkDebuggerPort(); - setupStorage(); - // On Firefox mulet, we automagically enable the responsive mode - // and show the devtools - if (isMulet) { - initResponsiveDesign(browserWindow); - openDevtools(); - } -}); diff --git a/b2g/chrome/content/devtools/adb.js b/b2g/chrome/content/devtools/adb.js deleted file mode 100644 index b609132923d9..000000000000 --- a/b2g/chrome/content/devtools/adb.js +++ /dev/null @@ -1,221 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -// This file is only loaded on Gonk to manage ADB state - -Components.utils.import("resource://gre/modules/FileUtils.jsm"); - -const DEBUG = false; -var debug = function(str) { - dump("AdbController: " + str + "\n"); -} - -var AdbController = { - locked: undefined, - remoteDebuggerEnabled: undefined, - lockEnabled: undefined, - disableAdbTimer: null, - disableAdbTimeoutHours: 12, - umsActive: false, - - setLockscreenEnabled: function(value) { - this.lockEnabled = value; - DEBUG && debug("setLockscreenEnabled = " + this.lockEnabled); - this.updateState(); - }, - - setLockscreenState: function(value) { - this.locked = value; - DEBUG && debug("setLockscreenState = " + this.locked); - this.updateState(); - }, - - setRemoteDebuggerState: function(value) { - this.remoteDebuggerEnabled = value; - DEBUG && debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled); - this.updateState(); - }, - - startDisableAdbTimer: function() { - if (this.disableAdbTimer) { - this.disableAdbTimer.cancel(); - } else { - this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - // eslint-disable-next-line mozilla/use-default-preference-values - try { - this.disableAdbTimeoutHours = - Services.prefs.getIntPref("b2g.adb.timeout-hours"); - } catch (e) { - // This happens if the pref doesn't exist, in which case - // disableAdbTimeoutHours will still be set to the default. - } - } - if (this.disableAdbTimeoutHours <= 0) { - DEBUG && debug("Timer to disable ADB not started due to zero timeout"); - return; - } - - DEBUG && debug("Starting timer to disable ADB in " + - this.disableAdbTimeoutHours + " hours"); - let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000; - this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds, - Ci.nsITimer.TYPE_ONE_SHOT); - }, - - stopDisableAdbTimer: function() { - DEBUG && debug("Stopping timer to disable ADB"); - if (this.disableAdbTimer) { - this.disableAdbTimer.cancel(); - this.disableAdbTimer = null; - } - }, - - notify: function(aTimer) { - if (aTimer == this.disableAdbTimer) { - this.disableAdbTimer = null; - // The following dump will be the last thing that shows up in logcat, - // and will at least give the user a clue about why logcat was - // disconnected, if the user happens to be using logcat. - debug("ADB timer expired - disabling ADB\n"); - navigator.mozSettings.createLock().set( - {'debugger.remote-mode': 'disabled'}); - } - }, - - updateState: function() { - this.umsActive = false; - }, - - updateStateInternal: function() { - DEBUG && debug("updateStateInternal: called"); - - if (this.remoteDebuggerEnabled === undefined || - this.lockEnabled === undefined || - this.locked === undefined) { - // Part of initializing the settings database will cause the observers - // to trigger. We want to wait until both have been initialized before - // we start changing ther adb state. Without this then we can wind up - // toggling adb off and back on again (or on and back off again). - // - // For completeness, one scenario which toggles adb is using the unagi. - // The unagi has adb enabled by default (prior to b2g starting). If you - // have the phone lock disabled and remote debugging enabled, then we'll - // receive an unlock event and an rde event. However at the time we - // receive the unlock event we haven't yet received the rde event, so - // we turn adb off momentarily, which disconnects a logcat that might - // be running. Changing the defaults (in AdbController) just moves the - // problem to a different phone, which has adb disabled by default and - // we wind up turning on adb for a short period when we shouldn't. - // - // By waiting until both values are properly initialized, we avoid - // turning adb on or off accidentally. - DEBUG && debug("updateState: Waiting for all vars to be initialized"); - return; - } - - // Check if we have a remote debugging session going on. If so, we won't - // disable adb even if the screen is locked. - let isDebugging = USBRemoteDebugger.isDebugging; - DEBUG && debug("isDebugging=" + isDebugging); - - // If USB Mass Storage, USB tethering, or a debug session is active, - // then we don't want to disable adb in an automatic fashion (i.e. - // when the screen locks or due to timeout). - let sysUsbConfig = libcutils.property_get("sys.usb.config").split(","); - let usbFuncActive = this.umsActive || isDebugging; - usbFuncActive |= (sysUsbConfig.indexOf("rndis") >= 0); - usbFuncActive |= (sysUsbConfig.indexOf("mtp") >= 0); - - let enableAdb = this.remoteDebuggerEnabled && - (!(this.lockEnabled && this.locked) || usbFuncActive); - - let useDisableAdbTimer = true; - - // Check wakelock to prevent adb from disconnecting when phone is locked - let lockFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); - lockFile.initWithPath('/sys/power/wake_lock'); - if(lockFile.exists()) { - let foStream = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - let coStream = Cc["@mozilla.org/intl/converter-input-stream;1"] - .createInstance(Ci.nsIConverterInputStream); - let str = {}; - foStream.init(lockFile, FileUtils.MODE_RDONLY, 0, 0); - coStream.init(foStream, "UTF-8", 0, 0); - coStream.readString(-1, str); - coStream.close(); - foStream.close(); - let wakeLockContents = str.value.replace(/\n/, ""); - let wakeLockList = wakeLockContents.split(" "); - if (wakeLockList.indexOf("adb") >= 0) { - enableAdb = true; - useDisableAdbTimer = false; - DEBUG && debug("Keeping ADB enabled as ADB wakelock is present."); - } else { - DEBUG && debug("ADB wakelock not found."); - } - } else { - DEBUG && debug("Wake_lock file not found."); - } - - DEBUG && debug("updateState: enableAdb = " + enableAdb + - " remoteDebuggerEnabled = " + this.remoteDebuggerEnabled + - " lockEnabled = " + this.lockEnabled + - " locked = " + this.locked + - " usbFuncActive = " + usbFuncActive); - - // Configure adb. - let currentConfig = libcutils.property_get("persist.sys.usb.config"); - let configFuncs = currentConfig.split(","); - if (currentConfig == "" || currentConfig == "none") { - // We want to treat none like the empty string. - // "".split(",") yields [""] and not [] - configFuncs = []; - } - let adbIndex = configFuncs.indexOf("adb"); - - if (enableAdb) { - // Add adb to the list of functions, if not already present - if (adbIndex < 0) { - configFuncs.push("adb"); - } - } else { - // Remove adb from the list of functions, if present - if (adbIndex >= 0) { - configFuncs.splice(adbIndex, 1); - } - } - let newConfig = configFuncs.join(","); - if (newConfig == "") { - // Convert the empty string back into none, since that's what init.rc - // needs. - newConfig = "none"; - } - if (newConfig != currentConfig) { - DEBUG && debug("updateState: currentConfig = " + currentConfig); - DEBUG && debug("updateState: newConfig = " + newConfig); - try { - libcutils.property_set("persist.sys.usb.config", newConfig); - } catch(e) { - Cu.reportError("Error configuring adb: " + e); - } - } - if (useDisableAdbTimer) { - if (enableAdb && !usbFuncActive) { - this.startDisableAdbTimer(); - } else { - this.stopDisableAdbTimer(); - } - } - } -}; - -SettingsListener.observe("lockscreen.locked", false, - AdbController.setLockscreenState.bind(AdbController)); -SettingsListener.observe("lockscreen.enabled", false, - AdbController.setLockscreenEnabled.bind(AdbController)); diff --git a/b2g/chrome/content/devtools/debugger.js b/b2g/chrome/content/devtools/debugger.js deleted file mode 100644 index a8ed8e91acb6..000000000000 --- a/b2g/chrome/content/devtools/debugger.js +++ /dev/null @@ -1,397 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -XPCOMUtils.defineLazyGetter(this, "devtools", function() { - const { devtools } = - Cu.import("resource://devtools/shared/Loader.jsm", {}); - return devtools; -}); - -XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function() { - const { DebuggerServer } = devtools.require("devtools/server/main"); - return DebuggerServer; -}); - -XPCOMUtils.defineLazyGetter(this, "B2GTabList", function() { - const { B2GTabList } = - devtools.require("resource://gre/modules/DebuggerActors.js"); - return B2GTabList; -}); - -// Load the discovery module eagerly, so that it can set a device name at -// startup. This does not cause discovery to start listening for packets, as -// that only happens once DevTools is enabled. -devtools.require("devtools/shared/discovery/discovery"); - -var RemoteDebugger = { - _listening: false, - - /** - * Prompt the user to accept or decline the incoming connection. - * - * @param session object - * The session object will contain at least the following fields: - * { - * authentication, - * client: { - * host, - * port - * }, - * server: { - * host, - * port - * } - * } - * Specific authentication modes may include additional fields. Check - * the different |allowConnection| methods in - * devtools/shared/security/auth.js. - * @return An AuthenticationResult value. - * A promise that will be resolved to the above is also allowed. - */ - allowConnection(session) { - if (this._promptingForAllow) { - // Don't stack connection prompts if one is already open - return DebuggerServer.AuthenticationResult.DENY; - } - this._listen(); - - this._promptingForAllow = new Promise(resolve => { - this._handleAllowResult = detail => { - this._handleAllowResult = null; - this._promptingForAllow = null; - // Newer Gaia supplies |authResult|, which is one of the - // AuthenticationResult values. - if (detail.authResult) { - resolve(detail.authResult); - } else if (detail.value) { - resolve(DebuggerServer.AuthenticationResult.ALLOW); - } else { - resolve(DebuggerServer.AuthenticationResult.DENY); - } - }; - - shell.sendChromeEvent({ - type: "remote-debugger-prompt", - session - }); - }); - - return this._promptingForAllow; - }, - - /** - * During OOB_CERT authentication, the user must transfer some data through some - * out of band mechanism from the client to the server to authenticate the - * devices. - * - * This implementation instructs Gaia to continually capture images which are - * passed back here and run through a QR decoder. - * - * @return An object containing: - * * sha256: hash(ClientCert) - * * k : K(random 128-bit number) - * A promise that will be resolved to the above is also allowed. - */ - receiveOOB() { - if (this._receivingOOB) { - return this._receivingOOB; - } - this._listen(); - - const QR = devtools.require("devtools/shared/qrcode/index"); - this._receivingOOB = new Promise((resolve, reject) => { - this._handleAuthEvent = detail => { - debug(detail.action); - if (detail.action === "abort") { - this._handleAuthEvent = null; - this._receivingOOB = null; - reject(); - return; - } - - if (detail.action !== "capture") { - return; - } - - let url = detail.url; - QR.decodeFromURI(url).then(data => { - debug("Got auth data: " + data); - let oob = JSON.parse(data); - - shell.sendChromeEvent({ - type: "devtools-auth", - action: "stop" - }); - - this._handleAuthEvent = null; - this._receivingOOB = null; - resolve(oob); - }).catch(() => { - debug("No auth data, requesting new capture"); - shell.sendChromeEvent({ - type: "devtools-auth", - action: "capture" - }); - }); - }; - - // Show QR scanning dialog, get an initial capture - shell.sendChromeEvent({ - type: "devtools-auth", - action: "start" - }); - }); - - return this._receivingOOB; - }, - - _listen: function() { - if (this._listening) { - return; - } - - this.handleEvent = this.handleEvent.bind(this); - let content = shell.contentBrowser.contentWindow; - content.addEventListener("mozContentEvent", this, false, true); - this._listening = true; - }, - - handleEvent: function(event) { - let detail = event.detail; - if (detail.type === "remote-debugger-prompt" && this._handleAllowResult) { - this._handleAllowResult(detail); - } - if (detail.type === "devtools-auth" && this._handleAuthEvent) { - this._handleAuthEvent(detail); - } - }, - - initServer: function() { - if (DebuggerServer.initialized) { - return; - } - - // Ask for remote connections. - DebuggerServer.init(); - - // /!\ Be careful when adding a new actor, especially global actors. - // Any new global actor will be exposed and returned by the root actor. - - // Add Firefox-specific actors, but prevent tab actors to be loaded in - // the parent process, unless we enable certified apps debugging. - let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps"); - DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges); - - // Allow debugging of chrome for any process - if (!restrictPrivileges) { - DebuggerServer.allowChromeProcess = true; - } - - /** - * Construct a root actor appropriate for use in a server running in B2G. - * The returned root actor respects the factories registered with - * DebuggerServer.addGlobalActor only if certified apps debugging is on, - * otherwise we used an explicit limited list of global actors - * - * * @param connection DebuggerServerConnection - * The conection to the client. - */ - DebuggerServer.createRootActor = function createRootActor(connection) - { - let parameters = { - tabList: new B2GTabList(connection), - // Use an explicit global actor list to prevent exposing - // unexpected actors - globalActorFactories: restrictPrivileges ? { - webappsActor: DebuggerServer.globalActorFactories.webappsActor, - deviceActor: DebuggerServer.globalActorFactories.deviceActor, - settingsActor: DebuggerServer.globalActorFactories.settingsActor - } : DebuggerServer.globalActorFactories - }; - let { RootActor } = devtools.require("devtools/server/actors/root"); - let root = new RootActor(connection, parameters); - root.applicationType = "operating-system"; - return root; - }; - - if (isGonk) { - DebuggerServer.on("connectionchange", function() { - AdbController.updateState(); - }); - } - } -}; - -RemoteDebugger.allowConnection = - RemoteDebugger.allowConnection.bind(RemoteDebugger); -RemoteDebugger.receiveOOB = - RemoteDebugger.receiveOOB.bind(RemoteDebugger); - -var USBRemoteDebugger = { - - get isDebugging() { - if (!this._listener) { - return false; - } - - return DebuggerServer._connections && - Object.keys(DebuggerServer._connections).length > 0; - }, - - start: function() { - if (this._listener) { - return; - } - - RemoteDebugger.initServer(); - - let portOrPath = - Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") || - "/data/local/debugger-socket"; - - try { - debug("Starting USB debugger on " + portOrPath); - let AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT"); - let authenticator = new AuthenticatorType.Server(); - authenticator.allowConnection = RemoteDebugger.allowConnection; - this._listener = DebuggerServer.createListener(); - this._listener.portOrPath = portOrPath; - this._listener.authenticator = authenticator; - this._listener.open(); - // Temporary event, until bug 942756 lands and offers a way to know - // when the server is up and running. - Services.obs.notifyObservers(null, "debugger-server-started"); - } catch (e) { - debug("Unable to start USB debugger server: " + e); - } - }, - - stop: function() { - if (!this._listener) { - return; - } - - try { - this._listener.close(); - this._listener = null; - } catch (e) { - debug("Unable to stop USB debugger server: " + e); - } - } - -}; - -var WiFiRemoteDebugger = { - - start: function() { - if (this._listener) { - return; - } - - RemoteDebugger.initServer(); - - try { - debug("Starting WiFi debugger"); - let AuthenticatorType = DebuggerServer.Authenticators.get("OOB_CERT"); - let authenticator = new AuthenticatorType.Server(); - authenticator.allowConnection = RemoteDebugger.allowConnection; - authenticator.receiveOOB = RemoteDebugger.receiveOOB; - this._listener = DebuggerServer.createListener(); - this._listener.portOrPath = -1 /* any available port */; - this._listener.authenticator = authenticator; - this._listener.discoverable = true; - this._listener.encryption = true; - this._listener.open(); - let port = this._listener.port; - debug("Started WiFi debugger on " + port); - } catch (e) { - debug("Unable to start WiFi debugger server: " + e); - } - }, - - stop: function() { - if (!this._listener) { - return; - } - - try { - this._listener.close(); - this._listener = null; - } catch (e) { - debug("Unable to stop WiFi debugger server: " + e); - } - } - -}; - -(function() { - // Track these separately here so we can determine the correct value for the - // pref "devtools.debugger.remote-enabled", which is true when either mode of - // using DevTools is enabled. - let devtoolsUSB = false; - let devtoolsWiFi = false; - - // Keep the old setting to not break people that won't have updated - // gaia and gecko. - SettingsListener.observe("devtools.debugger.remote-enabled", false, - function(value) { - devtoolsUSB = value; - Services.prefs.setBoolPref("devtools.debugger.remote-enabled", - devtoolsUSB || devtoolsWiFi); - // This preference is consulted during startup - Services.prefs.savePrefFile(null); - try { - value ? USBRemoteDebugger.start() : USBRemoteDebugger.stop(); - } catch(e) { - dump("Error while initializing USB devtools: " + - e + "\n" + e.stack + "\n"); - } - }); - - SettingsListener.observe("debugger.remote-mode", "disabled", function(value) { - if (["disabled", "adb-only", "adb-devtools"].indexOf(value) == -1) { - dump("Illegal value for debugger.remote-mode: " + value + "\n"); - return; - } - - devtoolsUSB = value == "adb-devtools"; - Services.prefs.setBoolPref("devtools.debugger.remote-enabled", - devtoolsUSB || devtoolsWiFi); - // This preference is consulted during startup - Services.prefs.savePrefFile(null); - - try { - (value == "adb-devtools") ? USBRemoteDebugger.start() - : USBRemoteDebugger.stop(); - } catch(e) { - dump("Error while initializing USB devtools: " + - e + "\n" + e.stack + "\n"); - } - - isGonk && AdbController.setRemoteDebuggerState(value != "disabled"); - }); - - SettingsListener.observe("devtools.remote.wifi.enabled", false, - function(value) { - devtoolsWiFi = value; - Services.prefs.setBoolPref("devtools.debugger.remote-enabled", - devtoolsUSB || devtoolsWiFi); - // Allow remote debugging on non-local interfaces when WiFi debug is enabled - // TODO: Bug 1034411: Lock down to WiFi interface, instead of all interfaces - Services.prefs.setBoolPref("devtools.debugger.force-local", !value); - // This preference is consulted during startup - Services.prefs.savePrefFile(null); - - try { - value ? WiFiRemoteDebugger.start() : WiFiRemoteDebugger.stop(); - } catch(e) { - dump("Error while initializing WiFi devtools: " + - e + "\n" + e.stack + "\n"); - } - }); -})(); diff --git a/b2g/chrome/content/devtools/hud.js b/b2g/chrome/content/devtools/hud.js deleted file mode 100644 index fffa6b5e8eac..000000000000 --- a/b2g/chrome/content/devtools/hud.js +++ /dev/null @@ -1,867 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -// settings.js loads this file when the HUD setting is enabled. - -const DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD'; -const CUSTOM_HISTOGRAM_PREFIX = 'DEVTOOLS_HUD_CUSTOM_'; -const APPNAME_IDX = 3; -const HISTNAME_IDX = 4; - -XPCOMUtils.defineLazyGetter(this, 'devtools', function() { - const {devtools} = Cu.import('resource://devtools/shared/Loader.jsm', {}); - return devtools; -}); - -XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() { - return devtools.require('devtools/shared/client/main').DebuggerClient; -}); - -XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() { - return devtools.require('devtools/shared/webconsole/utils').Utils; -}); - -XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() { - return devtools.require('devtools/shared/fronts/eventlooplag').EventLoopLagFront; -}); - -XPCOMUtils.defineLazyGetter(this, 'PerformanceEntriesFront', function() { - return devtools.require('devtools/server/actors/performance-entries').PerformanceEntriesFront; -}); - -XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() { - return devtools.require('devtools/server/actors/memory').MemoryFront; -}); - -var _telemetryDebug = false; - -function telemetryDebug(...args) { - if (_telemetryDebug) { - args.unshift('[AdvancedTelemetry]'); - console.log(...args); - } -} - -/** - * The Developer HUD is an on-device developer tool that displays widgets, - * showing visual debug information about apps. Each widget corresponds to a - * metric as tracked by a metric watcher (e.g. consoleWatcher). - */ -var developerHUD = { - - _histograms: new Set(), - _customHistograms: new Set(), - _client: null, - _conn: null, - _watchers: [], - _logging: true, - _telemetry: false, - - /** - * This method registers a metric watcher that will watch one or more metrics - * on app frames that are being tracked. A watcher must implement the - * `trackTarget(target)` and `untrackTarget(target)` methods, register - * observed metrics with `target.register(metric)`, and keep them up-to-date - * with `target.update(metric, message)` when necessary. - */ - registerWatcher(watcher) { - this._watchers.unshift(watcher); - }, - - init() { - if (this._client) { - return; - } - - if (!DebuggerServer.initialized) { - RemoteDebugger.initServer(); - } - - // We instantiate a local debugger connection so that watchers can use our - // DebuggerClient to send requests to tab actors (e.g. the consoleActor). - // Note the special usage of the private _serverConnection, which we need - // to call connectToChild and set up child process actors on a frame we - // intend to track. These actors will use the connection to communicate with - // our DebuggerServer in the parent process. - let transport = DebuggerServer.connectPipe(); - this._conn = transport._serverConnection; - this._client = new DebuggerClient(transport); - - for (let w of this._watchers) { - if (w.init) { - w.init(this._client); - } - } - - SettingsListener.observe('hud.logging', this._logging, enabled => { - this._logging = enabled; - }); - - SettingsListener.observe('hud.telemetry.logging', _telemetryDebug, enabled => { - _telemetryDebug = enabled; - }); - - SettingsListener.observe('metrics.selectedMetrics.level', "", level => { - this._telemetry = (level === 'Enhanced'); - }); - }, - - uninit() { - if (!this._client) { - return; - } - - this._client.close(); - delete this._client; - }, - - log(message) { - if (this._logging) { - dump(DEVELOPER_HUD_LOG_PREFIX + ': ' + message + '\n'); - } - } - -}; - - -/** - * A Target object represents all there is to know about a Firefox OS app frame - * that is being tracked, e.g. a pointer to the frame, current values of watched - * metrics, and how to notify the front-end when metrics have changed. - */ -function Target(frame, actor) { - this.frame = frame; - this.actor = actor; - this.metrics = new Map(); - this._appName = null; -} - -Target.prototype = { - - get manifest() { - return this.frame.appManifestURL; - }, - - get appName() { - - if (this._appName) { - return this._appName; - } - - let manifest = this.manifest; - if (!manifest) { - let msg = DEVELOPER_HUD_LOG_PREFIX + ': Unable to determine app for telemetry metric. src: ' + - this.frame.src; - console.error(msg); - return null; - } - - // "communications" apps are a special case - if (manifest.indexOf('communications') === -1) { - let start = manifest.indexOf('/') + 2; - let end = manifest.indexOf('.', start); - this._appName = manifest.substring(start, end).toLowerCase(); - } else { - let src = this.frame.src; - if (src) { - // e.g., `app://communications.gaiamobile.org/contacts/index.html` - let parts = src.split('/'); - let APP = 3; - let EXPECTED_PARTS_LENGTH = 5; - if (parts.length === EXPECTED_PARTS_LENGTH) { - this._appName = parts[APP]; - } - } - } - - return this._appName; - }, - - /** - * Register a metric that can later be updated. Does not update the front-end. - */ - register(metric) { - this.metrics.set(metric, 0); - }, - - /** - * Modify one of a target's metrics, and send out an event to notify relevant - * parties (e.g. the developer HUD, automated tests, etc). - */ - update(metric, message) { - if (!metric.name) { - throw new Error('Missing metric.name'); - } - - if (!metric.value) { - metric.value = 0; - } - - let metrics = this.metrics; - if (metrics) { - metrics.set(metric.name, metric.value); - } - - let data = { - metrics: [], // FIXME(Bug 982066) Remove this field. - manifest: this.manifest, - metric: metric, - message: message - }; - - // FIXME(Bug 982066) Remove this loop. - if (metrics && metrics.size > 0) { - for (let name of metrics.keys()) { - data.metrics.push({name: name, value: metrics.get(name)}); - } - } - - if (message) { - developerHUD.log('[' + data.manifest + '] ' + data.message); - } - - this._send(data); - }, - - /** - * Nicer way to call update() when the metric value is a number that needs - * to be incremented. - */ - bump(metric, message) { - metric.value = (this.metrics.get(metric.name) || 0) + 1; - this.update(metric, message); - }, - - /** - * Void a metric value and make sure it isn't displayed on the front-end - * anymore. - */ - clear(metric) { - metric.value = 0; - this.update(metric); - }, - - /** - * Tear everything down, including the front-end by sending a message without - * widgets. - */ - destroy() { - delete this.metrics; - this._send({metric: {skipTelemetry: true}}); - }, - - _send(data) { - let frame = this.frame; - - shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, frame)); - this._logHistogram(data.metric); - }, - - _clearTelemetryData() { - developerHUD._histograms.forEach(function(item) { - Services.telemetry.getKeyedHistogramById(item).clear(); - }); - }, - - _sendTelemetryData() { - if (!developerHUD._telemetry) { - return; - } - telemetryDebug('calling sendTelemetryData'); - let frame = this.frame; - let payload = { - keyedHistograms: {}, - }; - // Package the hud histograms. - developerHUD._histograms.forEach(function(item) { - payload.keyedHistograms[item] = - Services.telemetry.getKeyedHistogramById(item).snapshot(); - }); - - shell.sendEvent(frame, 'advanced-telemetry-update', Cu.cloneInto(payload, frame)); - }, - - _logHistogram(metric) { - //method left as no-op as histograms are not in use anymore. - } -}; - - -/** - * The Console Watcher tracks the following metrics in apps: reflows, warnings, - * and errors, with security errors reported separately. - */ -var consoleWatcher = { - - _client: null, - _targets: new Map(), - _watching: { - reflows: false, - warnings: false, - errors: false, - security: false - }, - _security: [ - 'Mixed Content Blocker', - 'Mixed Content Message', - 'CSP', - 'Invalid HSTS Headers', - 'Invalid HPKP Headers', - 'Insecure Password Field', - 'SSL', - 'CORS' - ], - _reflowThreshold: 0, - - init(client) { - this._client = client; - this.consoleListener = this.consoleListener.bind(this); - - let watching = this._watching; - - for (let key in watching) { - let metric = key; - SettingsListener.observe('hud.' + metric, watching[metric], watch => { - // Watch or unwatch the metric. - if (watching[metric] = watch) { - return; - } - - // If unwatched, remove any existing widgets for that metric. - for (let target of this._targets.values()) { - target.clear({name: metric}); - } - }); - } - - SettingsListener.observe('hud.reflows.duration', this._reflowThreshold, threshold => { - this._reflowThreshold = threshold; - }); - - client.addListener('logMessage', this.consoleListener); - client.addListener('pageError', this.consoleListener); - client.addListener('consoleAPICall', this.consoleListener); - client.addListener('reflowActivity', this.consoleListener); - }, - - trackTarget(target) { - target.register('reflows'); - target.register('warnings'); - target.register('errors'); - target.register('security'); - - this._client.request({ - to: target.actor.consoleActor, - type: 'startListeners', - listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity'] - }, (res) => { - this._targets.set(target.actor.consoleActor, target); - }); - }, - - untrackTarget(target) { - this._client.request({ - to: target.actor.consoleActor, - type: 'stopListeners', - listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity'] - }, (res) => { }); - - this._targets.delete(target.actor.consoleActor); - }, - - consoleListener(type, packet) { - let target = this._targets.get(packet.from); - let metric = {}; - let output = ''; - - switch (packet.type) { - - case 'pageError': - let pageError = packet.pageError; - - if (pageError.warning || pageError.strict) { - metric.name = 'warnings'; - output += 'Warning ('; - } else { - metric.name = 'errors'; - output += 'Error ('; - } - - if (this._security.indexOf(pageError.category) > -1) { - metric.name = 'security'; - - // Telemetry sends the security error category not the - // count of security errors. - target._logHistogram({ - name: 'security_category', - value: pageError.category - }); - - // Indicate that the 'hud' security metric (the count of security - // errors) should not be sent as a telemetry metric since the - // security error category is being sent instead. - metric.skipTelemetry = true; - } - - let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError; - output += category + '): "' + (errorMessage.initial || errorMessage) + - '" in ' + sourceName + ':' + lineNumber + ':' + columnNumber; - break; - - case 'consoleAPICall': - switch (packet.message.level) { - - case 'error': - metric.name = 'errors'; - output += 'Error (console)'; - break; - - case 'warn': - metric.name = 'warnings'; - output += 'Warning (console)'; - break; - - case 'info': - this.handleTelemetryMessage(target, packet); - - // Currently, informational log entries are tracked only by - // telemetry. Nonetheless, for consistency, we continue here - // and let the function return normally, when it concludes 'info' - // entries are not being watched. - metric.name = 'info'; - break; - - default: - return; - } - break; - - case 'reflowActivity': - metric.name = 'reflows'; - - let {start, end, sourceURL, interruptible} = packet; - metric.interruptible = interruptible; - let duration = Math.round((end - start) * 100) / 100; - - // Record the reflow if the duration exceeds the threshold. - if (duration < this._reflowThreshold) { - return; - } - - output += 'Reflow: ' + duration + 'ms'; - if (sourceURL) { - output += ' ' + this.formatSourceURL(packet); - } - - // Telemetry also records reflow duration. - target._logHistogram({ - name: 'reflow_duration', - value: Math.round(duration) - }); - break; - - default: - return; - } - - if (developerHUD._telemetry) { - // Always record telemetry for these metrics. - if (metric.name === 'errors' || metric.name === 'warnings' || metric.name === 'reflows') { - let value = target.metrics.get(metric.name); - metric.value = (value || 0) + 1; - target._logHistogram(metric); - - // Telemetry has already been recorded. - metric.skipTelemetry = true; - - // If the metric is not being watched, persist the incremented value. - // If the metric is being watched, `target.bump` will increment the value - // of the metric and will persist the incremented value. - if (!this._watching[metric.name]) { - target.metrics.set(metric.name, metric.value); - } - } - } - - if (!this._watching[metric.name]) { - return; - } - - target.bump(metric, output); - }, - - formatSourceURL(packet) { - // Abbreviate source URL - let source = WebConsoleUtils.abbreviateSourceURL(packet.sourceURL); - - // Add function name and line number - let {functionName, sourceLine} = packet; - source = 'in ' + (functionName || '') + - ', ' + source + ':' + sourceLine; - - return source; - }, - - handleTelemetryMessage(target, packet) { - if (!developerHUD._telemetry) { - return; - } - - // If this is a 'telemetry' log entry, create a telemetry metric from - // the log content. - let separator = '|'; - let logContent = packet.message.arguments.toString(); - - if (logContent.indexOf('telemetry') < 0) { - return; - } - - let telemetryData = logContent.split(separator); - - // Positions of the components of a telemetry log entry. - let TELEMETRY_IDENTIFIER_IDX = 0; - let NAME_IDX = 1; - let VALUE_IDX = 2; - let TYPE_IDX = 2; - let MIN_IDX = 3; - let MAX_IDX = 4; - let BUCKETS_IDX = 5; - let MAX_CUSTOM_ARGS = 6; - let MIN_CUSTOM_ARGS = 3; - - if (telemetryData[TELEMETRY_IDENTIFIER_IDX] != 'telemetry' || - telemetryData.length < MIN_CUSTOM_ARGS || - telemetryData.length > MAX_CUSTOM_ARGS) { - return; - } - - let metric = { - name: telemetryData[NAME_IDX] - }; - - if (metric.name === 'MGMT') { - metric.value = telemetryData[VALUE_IDX]; - if (metric.value === 'TIMETOSHIP') { - telemetryDebug('Received a Ship event'); - target._sendTelemetryData(); - } else if (metric.value === 'CLEARMETRICS') { - target._clearTelemetryData(); - } - } else { - if (telemetryData.length === MIN_CUSTOM_ARGS) { - metric.value = telemetryData[VALUE_IDX]; - } else if (telemetryData.length === MAX_CUSTOM_ARGS) { - metric.type = telemetryData[TYPE_IDX]; - metric.min = telemetryData[MIN_IDX]; - metric.max = telemetryData[MAX_IDX]; - metric.buckets = telemetryData[BUCKETS_IDX]; - } - metric.custom = true; - target._logHistogram(metric); - } - } -}; -developerHUD.registerWatcher(consoleWatcher); - - -var eventLoopLagWatcher = { - _client: null, - _fronts: new Map(), - _active: false, - - init(client) { - this._client = client; - - SettingsListener.observe('hud.jank', false, this.settingsListener.bind(this)); - }, - - settingsListener(value) { - if (this._active == value) { - return; - } - - this._active = value; - - // Toggle the state of existing fronts. - let fronts = this._fronts; - for (let target of fronts.keys()) { - if (value) { - fronts.get(target).start(); - } else { - fronts.get(target).stop(); - target.clear({name: 'jank'}); - } - } - }, - - trackTarget(target) { - target.register('jank'); - - let front = new EventLoopLagFront(this._client, target.actor); - this._fronts.set(target, front); - - front.on('event-loop-lag', time => { - target.update({name: 'jank', value: time}, 'Jank: ' + time + 'ms'); - }); - - if (this._active) { - front.start(); - } - }, - - untrackTarget(target) { - let fronts = this._fronts; - if (fronts.has(target)) { - fronts.get(target).destroy(); - fronts.delete(target); - } - } -}; -developerHUD.registerWatcher(eventLoopLagWatcher); - -/* - * The performanceEntriesWatcher determines the delta between the epoch - * of an app's launch time and the epoch of the app's performance entry marks. - * When it receives an "appLaunch" performance entry mark it records the - * name of the app being launched and the epoch of when the launch ocurred. - * When it receives subsequent performance entry events for the app being - * launched, it records the delta of the performance entry opoch compared - * to the app-launch epoch and emits an "app-start-time-" - * event containing the delta. - * - * Additionally, while recording the "app-start-time" for a performance mark, - * USS memory at the time of the performance mark is also recorded. - */ -var performanceEntriesWatcher = { - _client: null, - _fronts: new Map(), - _appLaunch: new Map(), - _supported: [ - 'contentInteractive', - 'navigationInteractive', - 'navigationLoaded', - 'visuallyLoaded', - 'fullyLoaded', - 'mediaEnumerated', - 'scanEnd' - ], - - init(client) { - this._client = client; - let setting = 'devtools.telemetry.supported_performance_marks'; - let defaultValue = this._supported.join(','); - - SettingsListener.observe(setting, defaultValue, supported => { - this._supported = supported.split(','); - }); - }, - - trackTarget(target) { - // The performanceEntries watcher doesn't register a metric because - // currently the metrics generated are not displayed in - // in the front-end. - - let front = new PerformanceEntriesFront(this._client, target.actor); - this._fronts.set(target, front); - - // User timings are always gathered; there is no setting to enable/ - // disable. - front.start(); - - front.on('entry', detail => { - - // Only process performance marks. - if (detail.type !== 'mark') { - return; - } - - let name = detail.name; - let epoch = detail.epoch; - - // If this is an "app launch" mark, record the app that was - // launched and the epoch of when it was launched. - if (name.indexOf('appLaunch') !== -1) { - let CHARS_UNTIL_APP_NAME = 7; // '@app://' - let startPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME; - let endPos = name.indexOf('.'); - let appName = name.slice(startPos, endPos); - this._appLaunch.set(appName, epoch); - return; - } - - // Only process supported performance marks - if (this._supported.indexOf(name) === -1) { - return; - } - - let origin = detail.origin; - origin = origin.slice(0, origin.indexOf('.')); - - let appLaunchTime = this._appLaunch.get(origin); - - // Sanity check: ensure we have an app launch time for the app - // corresponding to this performance mark. - if (!appLaunchTime) { - return; - } - - let time = epoch - appLaunchTime; - let eventName = 'app_startup_time_' + name; - - // Events based on performance marks are for telemetry only, they are - // not displayed in the HUD front end. - target._logHistogram({name: eventName, value: time}); - - memoryWatcher.front(target).residentUnique().then(value => { - // bug 1215277, need 'v2' for app-memory histograms - eventName = 'app_memory_' + name + '_v2'; - target._logHistogram({name: eventName, value: value}); - }, err => { - console.error(err); - }); - }); - }, - - untrackTarget(target) { - let fronts = this._fronts; - if (fronts.has(target)) { - fronts.get(target).destroy(); - fronts.delete(target); - } - } -}; -developerHUD.registerWatcher(performanceEntriesWatcher); - -/** - * The Memory Watcher uses devtools actors to track memory usage. - */ -var memoryWatcher = { - - _client: null, - _fronts: new Map(), - _timers: new Map(), - _watching: { - uss: false, - appmemory: false, - jsobjects: false, - jsstrings: false, - jsother: false, - dom: false, - style: false, - other: false - }, - _active: false, - - init(client) { - this._client = client; - let watching = this._watching; - - for (let key in watching) { - let category = key; - SettingsListener.observe('hud.' + category, false, watch => { - watching[category] = watch; - this.update(); - }); - } - }, - - update() { - let watching = this._watching; - let active = watching.appmemory || watching.uss; - - if (this._active) { - for (let target of this._fronts.keys()) { - if (!watching.appmemory) target.clear({name: 'memory'}); - if (!watching.uss) target.clear({name: 'uss'}); - if (!active) clearTimeout(this._timers.get(target)); - } - } else if (active) { - for (let target of this._fronts.keys()) { - this.measure(target); - } - } - this._active = active; - }, - - measure(target) { - let watch = this._watching; - let format = this.formatMemory; - - if (watch.uss) { - this.front(target).residentUnique().then(value => { - target.update({name: 'uss', value: value}, 'USS: ' + format(value)); - }, err => { - console.error(err); - }); - } - - if (watch.appmemory) { - front.measure().then(data => { - let total = 0; - let details = []; - - function item(name, condition, value) { - if (!condition) { - return; - } - - let v = parseInt(value); - total += v; - details.push(name + ': ' + format(v)); - } - - item('JS objects', watch.jsobjects, data.jsObjectsSize); - item('JS strings', watch.jsstrings, data.jsStringsSize); - item('JS other', watch.jsother, data.jsOtherSize); - item('DOM', watch.dom, data.domSize); - item('Style', watch.style, data.styleSize); - item('Other', watch.other, data.otherSize); - // TODO Also count images size (bug #976007). - - target.update({name: 'memory', value: total}, - 'App Memory: ' + format(total) + ' (' + details.join(', ') + ')'); - }, err => { - console.error(err); - }); - } - - let timer = setTimeout(() => this.measure(target), 2000); - this._timers.set(target, timer); - }, - - formatMemory(bytes) { - var prefix = ['','K','M','G','T','P','E','Z','Y']; - var i = 0; - for (; bytes > 1024 && i < prefix.length; ++i) { - bytes /= 1024; - } - return (Math.round(bytes * 100) / 100) + ' ' + prefix[i] + 'B'; - }, - - trackTarget(target) { - target.register('uss'); - target.register('memory'); - this._fronts.set(target, MemoryFront(this._client, target.actor)); - if (this._active) { - this.measure(target); - } - }, - - untrackTarget(target) { - let front = this._fronts.get(target); - if (front) { - front.destroy(); - clearTimeout(this._timers.get(target)); - this._fronts.delete(target); - this._timers.delete(target); - } - }, - - front(target) { - return this._fronts.get(target); - } -}; -developerHUD.registerWatcher(memoryWatcher); diff --git a/b2g/chrome/content/identity.js b/b2g/chrome/content/identity.js deleted file mode 100644 index 9c0ad50a2a89..000000000000 --- a/b2g/chrome/content/identity.js +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// This JS shim contains the callbacks to fire DOMRequest events for -// navigator.pay API within the payment processor's scope. - -"use strict"; - -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsIMessageSender"); - -XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -XPCOMUtils.defineLazyModuleGetter(this, "Logger", - "resource://gre/modules/identity/LogUtils.jsm"); - -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["injected identity.js"].concat(aMessageArgs)); -} - -log("\n\n======================= identity.js =======================\n\n"); - -// This script may be injected more than once into an iframe. -// It's hard to do this with |const| like we should, so use var instead. -if (typeof kIdentityJSLoaded === 'undefined') { - var kIdentityDelegateWatch = "identity-delegate-watch"; - var kIdentityDelegateRequest = "identity-delegate-request"; - var kIdentityDelegateLogout = "identity-delegate-logout"; - var kIdentityDelegateReady = "identity-delegate-ready"; - var kIdentityDelegateFinished = "identity-delegate-finished"; - var kIdentityControllerDoMethod = "identity-controller-doMethod"; - var kIdentktyJSLoaded = true; -} - -var showUI = false; -var options = {}; -var isLoaded = false; -var func = null; - -/* - * Message back to the SignInToWebsite pipe. Message should be an - * object with the following keys: - * - * method: one of 'login', 'logout', 'ready' - * assertion: optional assertion - */ -function identityCall(message) { - if (options._internal) { - message._internal = options._internal; - } - sendAsyncMessage(kIdentityControllerDoMethod, message); -} - -/* - * To close the dialog, we first tell the gecko SignInToWebsite manager that it - * can clean up. Then we tell the gaia component that we are finished. It is - * necessary to notify gecko first, so that the message can be sent before gaia - * destroys our context. - */ -function closeIdentityDialog() { - // tell gecko we're done. - func = null; options = null; - sendAsyncMessage(kIdentityDelegateFinished); -} - -/* - * doInternalWatch - call the internal.watch api and relay the results - * up to the controller. - */ -function doInternalWatch() { - log("doInternalWatch:", options, isLoaded); - if (options && isLoaded) { - let BrowserID = content.wrappedJSObject.BrowserID; - BrowserID.internal.watch(function(aParams, aInternalParams) { - identityCall(aParams); - if (aParams.method === "ready") { - closeIdentityDialog(); - } - }, - JSON.stringify(options), - function(...things) { - // internal watch log callback - log("(watch) internal: ", things); - } - ); - } -} - -function doInternalRequest() { - log("doInternalRequest:", options && isLoaded); - if (options && isLoaded) { - var stringifiedOptions = JSON.stringify(options); - content.wrappedJSObject.BrowserID.internal.get( - options.origin, - function(assertion, internalParams) { - internalParams = internalParams || {}; - if (assertion) { - identityCall({ - method: 'login', - assertion: assertion, - _internalParams: internalParams}); - } else { - identityCall({ - method: 'cancel' - }); - } - closeIdentityDialog(); - }, - stringifiedOptions); - } -} -function doInternalLogout(aOptions) { - log("doInternalLogout:", (options && isLoaded)); - if (options && isLoaded) { - let BrowserID = content.wrappedJSObject.BrowserID; - BrowserID.internal.logout(options.origin, function() { - identityCall({method:'logout'}); - closeIdentityDialog(); - }); - } -} - -addEventListener("DOMContentLoaded", function(e) { - content.addEventListener("load", function(e) { - isLoaded = true; - // bring da func - if (func) func(); - }); -}); - -// listen for request -addMessageListener(kIdentityDelegateRequest, function(aMessage) { - log("injected identity.js received", kIdentityDelegateRequest); - options = aMessage.json; - showUI = true; - func = doInternalRequest; - func(); -}); - -// listen for watch -addMessageListener(kIdentityDelegateWatch, function(aMessage) { - log("injected identity.js received", kIdentityDelegateWatch); - options = aMessage.json; - showUI = false; - func = doInternalWatch; - func(); -}); - -// listen for logout -addMessageListener(kIdentityDelegateLogout, function(aMessage) { - log("injected identity.js received", kIdentityDelegateLogout); - options = aMessage.json; - showUI = false; - func = doInternalLogout; - func(); -}); diff --git a/b2g/chrome/content/images/arrowdown-16.png b/b2g/chrome/content/images/arrowdown-16.png deleted file mode 100644 index c982426f2ade..000000000000 Binary files a/b2g/chrome/content/images/arrowdown-16.png and /dev/null differ diff --git a/b2g/chrome/content/images/arrowright-16.png b/b2g/chrome/content/images/arrowright-16.png deleted file mode 100644 index 859e98ba64b6..000000000000 Binary files a/b2g/chrome/content/images/arrowright-16.png and /dev/null differ diff --git a/b2g/chrome/content/images/desktop/home-black.png b/b2g/chrome/content/images/desktop/home-black.png deleted file mode 100644 index c51187ed49e1..000000000000 Binary files a/b2g/chrome/content/images/desktop/home-black.png and /dev/null differ diff --git a/b2g/chrome/content/images/desktop/home-white.png b/b2g/chrome/content/images/desktop/home-white.png deleted file mode 100644 index 43379d0e949c..000000000000 Binary files a/b2g/chrome/content/images/desktop/home-white.png and /dev/null differ diff --git a/b2g/chrome/content/images/desktop/rotate.png b/b2g/chrome/content/images/desktop/rotate.png deleted file mode 100644 index 9da1b5674dbb..000000000000 Binary files a/b2g/chrome/content/images/desktop/rotate.png and /dev/null differ diff --git a/b2g/chrome/content/images/error.png b/b2g/chrome/content/images/error.png deleted file mode 100644 index 58e37283a73e..000000000000 Binary files a/b2g/chrome/content/images/error.png and /dev/null differ diff --git a/b2g/chrome/content/images/errorpage-larry-black.png b/b2g/chrome/content/images/errorpage-larry-black.png deleted file mode 100644 index 9f2e4a6e7366..000000000000 Binary files a/b2g/chrome/content/images/errorpage-larry-black.png and /dev/null differ diff --git a/b2g/chrome/content/images/errorpage-larry-white.png b/b2g/chrome/content/images/errorpage-larry-white.png deleted file mode 100644 index fc153c7314e8..000000000000 Binary files a/b2g/chrome/content/images/errorpage-larry-white.png and /dev/null differ diff --git a/b2g/chrome/content/images/errorpage-warning.png b/b2g/chrome/content/images/errorpage-warning.png deleted file mode 100644 index 8bf9d8e7decc..000000000000 Binary files a/b2g/chrome/content/images/errorpage-warning.png and /dev/null differ diff --git a/b2g/chrome/content/images/exitfullscreen-hdpi.png b/b2g/chrome/content/images/exitfullscreen-hdpi.png deleted file mode 100644 index 826e53408432..000000000000 Binary files a/b2g/chrome/content/images/exitfullscreen-hdpi.png and /dev/null differ diff --git a/b2g/chrome/content/images/fullscreen-hdpi.png b/b2g/chrome/content/images/fullscreen-hdpi.png deleted file mode 100644 index 980e787310a9..000000000000 Binary files a/b2g/chrome/content/images/fullscreen-hdpi.png and /dev/null differ diff --git a/b2g/chrome/content/images/mute-hdpi.png b/b2g/chrome/content/images/mute-hdpi.png deleted file mode 100644 index 6daf7cf7188b..000000000000 Binary files a/b2g/chrome/content/images/mute-hdpi.png and /dev/null differ diff --git a/b2g/chrome/content/images/pause-hdpi.png b/b2g/chrome/content/images/pause-hdpi.png deleted file mode 100644 index c7837f8229c0..000000000000 Binary files a/b2g/chrome/content/images/pause-hdpi.png and /dev/null differ diff --git a/b2g/chrome/content/images/play-hdpi.png b/b2g/chrome/content/images/play-hdpi.png deleted file mode 100644 index fd64f9697246..000000000000 Binary files a/b2g/chrome/content/images/play-hdpi.png and /dev/null differ diff --git a/b2g/chrome/content/images/scrubber-hdpi.png b/b2g/chrome/content/images/scrubber-hdpi.png deleted file mode 100644 index b965b73d55b7..000000000000 Binary files a/b2g/chrome/content/images/scrubber-hdpi.png and /dev/null differ diff --git a/b2g/chrome/content/images/throbber.png b/b2g/chrome/content/images/throbber.png deleted file mode 100644 index c601ec80ba7c..000000000000 Binary files a/b2g/chrome/content/images/throbber.png and /dev/null differ diff --git a/b2g/chrome/content/images/unmute-hdpi.png b/b2g/chrome/content/images/unmute-hdpi.png deleted file mode 100644 index 5de342bda53b..000000000000 Binary files a/b2g/chrome/content/images/unmute-hdpi.png and /dev/null differ diff --git a/b2g/chrome/content/netError.css b/b2g/chrome/content/netError.css deleted file mode 100644 index 59d06a00c579..000000000000 --- a/b2g/chrome/content/netError.css +++ /dev/null @@ -1,131 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * This defines the look-and-feel styling of the error pages. - * (see: netError.xhtml) - * - * Original styling by William Price - * Updated for mobile by: Wes Johnston - */ - -body { - margin: 0; - padding: 0 8px 8px; - font-family: "Nokia Sans", Tahoma, sans-serif !important; -} - -h1 { - font-size: 22px; -} - -h2 { - font-size: 16px; -} - -ul { - margin: 0px; - padding: 0px 0px 0px 1em; -} - -li { - margin: 0px; - padding: 8px 0px; -} - -#errorPage { - background-color: #CEE6F4; -} - -#errorPage.certerror { - background-color: #EFD400; -} - -#errorPage.blockedsite { - background-color: #BF0000; -} - -#errorTitle { - background: url("chrome://b2g/content/images/errorpage-warning.png") left center no-repeat; - /* Scaled by .666 of their actual size */ - background-size: 40px 40px; - background-origin: content-box; - min-height: 60px; - margin-left: auto; - margin-right: auto; - max-width: 500px; - margin-left: auto; - margin-right: auto; -} - -#errorPage.certerror #errorTitle { - background-image: url("chrome://b2g/content/images/errorpage-larry-black.png"); -} - -#errorPage.blockedsite #errorTitle { - background-image: url("chrome://b2g/content/images/errorpage-larry-white.png"); - color: white; -} - -.errorTitleText { - padding: 0px 0px 0px 50px; - display: inline-block; - vertical-align: middle -} - -#errorPageContainer { - background-color: white; - border: 1px solid #999999; - border-radius: 6px; - padding: 6px 20px 20px; - font-size: 14px; - max-width: 500px; - margin-left: auto; - margin-right: auto; -} - -#errorShortDesc > p:empty { - display: none; -} - -#errorShortDesc > p { - overflow: auto; - border-bottom: 1px solid #999999; - padding-bottom: 1em; -} - -#errorPage.blockedsite #errorShortDesc > p { - font-weight: bold; - border-bottom: none; - padding-bottom: 0px; -} - -#securityOverrideDiv { - padding-top: 10px; -} - -div[collapsed] { - padding-left: 15px; - background-image: url("chrome://b2g/content/images/arrowright-16.png"); - background-size: 11px 11px; - background-repeat: no-repeat; - background-position: left 0.3em; -} - -div[collapsed="true"] { - background-image: url("chrome://b2g/content/images/arrowright-16.png"); -} - -div[collapsed="false"] { - background-image: url("chrome://b2g/content/images/arrowdown-16.png"); -} - -div[collapsed="true"] > p, -div[collapsed="true"] > div { - display: none; -} - -button { - padding: 0.3em !important; -} diff --git a/b2g/chrome/content/screen.js b/b2g/chrome/content/screen.js deleted file mode 100644 index 6c1ab2dcdce2..000000000000 --- a/b2g/chrome/content/screen.js +++ /dev/null @@ -1,276 +0,0 @@ -// screen.js: -// Set the screen size, pixel density and scaling of the b2g client screen -// based on the --screen command-line option, if there is one. -// -// TODO: support multiple device pixels per CSS pixel -// - -var browserWindow = Services.wm.getMostRecentWindow("navigator:browser"); -var isMulet = "ResponsiveUI" in browserWindow; -Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm"); - -window.addEventListener('ContentStart', onStart); -window.addEventListener('SafeModeStart', onStart); - -// We do this on ContentStart and SafeModeStart because querying the -// displayDPI fails otherwise. -function onStart() { - // This is the toplevel element - let shell = document.getElementById('shell'); - - // The element inside it - let browser = document.getElementById('systemapp'); - - // Figure out the native resolution of the screen - let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIDOMWindowUtils); - let hostDPI = windowUtils.displayDPI; - - let DEFAULT_SCREEN = '320x480'; - - // This is a somewhat random selection of named screens. - // Add more to this list when we support more hardware. - // Data from: http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density - let screens = { - iphone: { - name: 'Apple iPhone', width:320, height:480, dpi:163 - }, - ipad: { - name: 'Apple iPad', width:1024, height:768, dpi:132 - }, - nexus_s: { - name: 'Samsung Nexus S', width:480, height:800, dpi:235 - }, - galaxy_s2: { - name: 'Samsung Galaxy SII (I9100)', width:480, height:800, dpi:219 - }, - galaxy_nexus: { - name: 'Samsung Galaxy Nexus', width:720, height:1280, dpi:316 - }, - galaxy_tab: { - name: 'Samsung Galaxy Tab 10.1', width:800, height:1280, dpi:149 - }, - wildfire: { - name: 'HTC Wildfire', width:240, height:320, dpi:125 - }, - tattoo: { - name: 'HTC Tattoo', width:240, height:320, dpi:143 - }, - salsa: { - name: 'HTC Salsa', width:320, height:480, dpi:170 - }, - chacha: { - name: 'HTC ChaCha', width:320, height:480, dpi:222 - }, - }; - - // Get the command line arguments that were passed to the b2g client - let args; - try { - let service = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"].getService(Ci.nsISupports); - args = service.wrappedJSObject.cmdLine; - } catch(e) {} - - let screenarg = null; - - // Get the --screen argument from the command line - try { - if (args) { - screenarg = args.handleFlagWithParam('screen', false); - } - - // Override default screen size with a pref - if (screenarg === null && Services.prefs.prefHasUserValue('b2g.screen.size')) { - screenarg = Services.prefs.getCharPref('b2g.screen.size'); - } - - // If there isn't one, use the default screen - if (screenarg === null) - screenarg = DEFAULT_SCREEN; - - // With no value, tell the user how to use it - if (screenarg == '') - usage(); - } - catch(e) { - // If getting the argument value fails, its an error - usage(); - } - - // Special case --screen=full goes into fullscreen mode - if (screenarg === 'full') { - shell.setAttribute('sizemode', 'fullscreen'); - return; - } - - let width, height, ratio = 1.0; - let lastResizedWidth; - - if (screenarg in screens) { - // If this is a named screen, get its data - let screen = screens[screenarg]; - width = screen.width; - height = screen.height; - ratio = screen.ratio; - } else { - // Otherwise, parse the resolution and density from the --screen value. - // The supported syntax is WIDTHxHEIGHT[@DPI] - let match = screenarg.match(/^(\d+)x(\d+)(@(\d+(\.\d+)?))?$/); - - // Display usage information on syntax errors - if (match == null) - usage(); - - // Convert strings to integers - width = parseInt(match[1], 10); - height = parseInt(match[2], 10); - if (match[4]) - ratio = parseFloat(match[4], 10); - - // If any of the values came out 0 or NaN or undefined, display usage - if (!width || !height || !ratio) { - usage(); - } - } - - Services.prefs.setCharPref('layout.css.devPixelsPerPx', - ratio == 1 ? -1 : ratio); - let defaultOrientation = width < height ? 'portrait' : 'landscape'; - GlobalSimulatorScreen.mozOrientation = GlobalSimulatorScreen.screenOrientation = defaultOrientation; - - function resize() { - GlobalSimulatorScreen.width = width; - GlobalSimulatorScreen.height = height; - - // Set the window width and height to desired size plus chrome - // Include the size of the toolbox displayed under the system app - let controls = document.getElementById('controls'); - let controlsHeight = controls ? controls.getBoundingClientRect().height : 0; - - if (isMulet) { - let tab = browserWindow.gBrowser.selectedTab; - let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab); - responsive.setSize(width + 16*2, - height + controlsHeight + 61); - } else { - let chromewidth = window.outerWidth - window.innerWidth; - let chromeheight = window.outerHeight - window.innerHeight + controlsHeight; - - if (lastResizedWidth == width) { - return; - } - lastResizedWidth = width; - - window.resizeTo(width + chromewidth, - height + chromeheight); - } - - let frameWidth = width, frameHeight = height; - - // If the current app doesn't supports the current screen orientation - // still resize the window, but rotate its frame so that - // it is displayed rotated on the side - let shouldFlip = GlobalSimulatorScreen.mozOrientation != GlobalSimulatorScreen.screenOrientation; - - if (shouldFlip) { - frameWidth = height; - frameHeight = width; - } - - // Set the browser element to the full unscaled size of the screen - let style = browser.style; - style.transform = ''; - style.height = 'calc(100% - ' + controlsHeight + 'px)'; - style.bottom = controlsHeight; - - style.width = frameWidth + "px"; - style.height = frameHeight + "px"; - - if (shouldFlip) { - // Display the system app with a 90° clockwise rotation - let shift = Math.floor(Math.abs(frameWidth - frameHeight) / 2); - style.transform += - ' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)'; - } - } - - // Resize on startup - resize(); - - // Catch manual resizes to update the internal device size. - window.onresize = function() { - let controls = document.getElementById('controls'); - let controlsHeight = controls ? controls.getBoundingClientRect().height : 0; - - width = window.innerWidth; - height = window.innerHeight - controlsHeight; - - queueResize(); - }; - - // Then resize on each rotation button click, - // or when the system app lock/unlock the orientation - Services.obs.addObserver(function orientationChangeListener(subject) { - let screen = subject.wrappedJSObject; - let { mozOrientation, screenOrientation } = screen; - - // If we have an orientation different than the current one, - // we switch the sizes - if (screenOrientation != defaultOrientation) { - let w = width; - width = height; - height = w; - } - defaultOrientation = screenOrientation; - - queueResize(); - }, 'simulator-adjust-window-size'); - - // Queue resize request in order to prevent race and slowdowns - // by requesting resize multiple times per loop - let resizeTimeout; - function queueResize() { - if (resizeTimeout) { - clearTimeout(resizeTimeout); - } - resizeTimeout = setTimeout(function () { - resizeTimeout = null; - resize(); - }, 0); - } - - // A utility function like console.log() for printing to the terminal window - // Uses dump(), but enables it first, if necessary - function print() { - let dump_enabled = - Services.prefs.getBoolPref('browser.dom.window.dump.enabled'); - - if (!dump_enabled) - Services.prefs.setBoolPref('browser.dom.window.dump.enabled', true); - - dump(Array.prototype.join.call(arguments, ' ') + '\n'); - - if (!dump_enabled) - Services.prefs.setBoolPref('browser.dom.window.dump.enabled', false); - } - - // Print usage info for --screen and exit - function usage() { - // Documentation for the --screen argument - let msg = - 'The --screen argument specifies the desired resolution and\n' + - 'pixel density of the simulated device screen. Use it like this:\n' + - '\t--screen=WIDTHxHEIGHT\t\t\t// E.g.: --screen=320x480\n' + - '\t--screen=WIDTHxHEIGHT@DOTS_PER_INCH\t// E.g.: --screen=480x800@250\n' + - '\t--screen=full\t\t\t\t// run in fullscreen mode\n' + - '\nYou can also specify certain device names:\n'; - for(let p in screens) - msg += '\t--screen=' + p + '\t// ' + screens[p].name + '\n'; - - // Display the usage message - print(msg); - - // Exit the b2g client - Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit); - } -} diff --git a/b2g/chrome/content/settings.js b/b2g/chrome/content/settings.js deleted file mode 100644 index 391d8d3ae103..000000000000 --- a/b2g/chrome/content/settings.js +++ /dev/null @@ -1,673 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -window.performance.mark('gecko-settings-loadstart'); - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; - -// The load order is important here SettingsRequestManager _must_ be loaded -// prior to using SettingsListener otherwise there is a race in acquiring the -// lock and fulfilling it. If we ever move SettingsListener or this file down in -// the load order of shell.html things will likely break. -Cu.import('resource://gre/modules/SettingsRequestManager.jsm'); -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); -Cu.import('resource://gre/modules/Services.jsm'); -Cu.import('resource://gre/modules/AppConstants.jsm'); - -const isGonk = AppConstants.platform === 'gonk'; - -if (isGonk) { - XPCOMUtils.defineLazyGetter(this, "libcutils", function () { - Cu.import("resource://gre/modules/systemlibs.js"); - return libcutils; - }); -} - -XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget -// is resolved this helper could be removed. -var SettingsListener = { - _callbacks: {}, - - init: function sl_init() { - if ('mozSettings' in navigator && navigator.mozSettings) { - navigator.mozSettings.onsettingchange = this.onchange.bind(this); - } - }, - - onchange: function sl_onchange(evt) { - var callback = this._callbacks[evt.settingName]; - if (callback) { - callback(evt.settingValue); - } - }, - - observe: function sl_observe(name, defaultValue, callback) { - var settings = window.navigator.mozSettings; - if (!settings) { - window.setTimeout(function() { callback(defaultValue); }); - return; - } - - if (!callback || typeof callback !== 'function') { - throw new Error('Callback is not a function'); - } - - var req = settings.createLock().get(name); - req.addEventListener('success', (function onsuccess() { - callback(typeof(req.result[name]) != 'undefined' ? - req.result[name] : defaultValue); - })); - - this._callbacks[name] = callback; - } -}; - -SettingsListener.init(); - -// =================== Mono Audio ====================== - -SettingsListener.observe('accessibility.monoaudio.enable', false, function(value) { - Services.prefs.setBoolPref('accessibility.monoaudio.enable', value); -}); - -// =================== Console ====================== - -SettingsListener.observe('debug.console.enabled', true, function(value) { - Services.prefs.setBoolPref('consoleservice.enabled', value); - Services.prefs.setBoolPref('layout.css.report_errors', value); -}); - -SettingsListener.observe('homescreen.manifestURL', 'Sentinel Value' , function(value) { - Services.prefs.setCharPref('dom.mozApps.homescreenURL', value); -}); - -// =================== Languages ==================== -SettingsListener.observe('language.current', 'en-US', function(value) { - Services.prefs.setCharPref('general.useragent.locale', value); - - let prefName = 'intl.accept_languages'; - let defaultBranch = Services.prefs.getDefaultBranch(null); - - let intl = ''; - try { - intl = defaultBranch.getComplexValue(prefName, - Ci.nsIPrefLocalizedString).data; - } catch(e) {} - - // Bug 830782 - Homescreen is in English instead of selected locale after - // the first run experience. - // In order to ensure the current intl value is reflected on the child - // process let's always write a user value, even if this one match the - // current localized pref value. - if (!((new RegExp('^' + value + '[^a-z-_] *[,;]?', 'i')).test(intl))) { - value = value + ', ' + intl; - } else { - value = intl; - } - Services.prefs.setCharPref(prefName, value); - - if (shell.hasStarted() == false) { - shell.bootstrap(); - } -}); - -// =================== RIL ==================== -(function RILSettingsToPrefs() { - // DSDS default service IDs - ['mms', 'sms', 'telephony'].forEach(function(key) { - SettingsListener.observe('ril.' + key + '.defaultServiceId', 0, - function(value) { - if (value != null) { - Services.prefs.setIntPref('dom.' + key + '.defaultServiceId', value); - } - }); - }); -})(); - -//=================== DeviceInfo ==================== -Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); -Components.utils.import('resource://gre/modules/ctypes.jsm'); -(function DeviceInfoToSettings() { - // MOZ_B2G_VERSION is set in b2g/confvars.sh, and is output as a #define value - // from configure.in, defaults to 1.0.0 if this value is not exist. - let os_version = AppConstants.MOZ_B2G_VERSION; - let os_name = AppConstants.MOZ_B2G_OS_NAME; - - let appInfo = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULAppInfo); - - // Get the hardware info and firmware revision from device properties. - let hardware_info = null; - let firmware_revision = null; - let product_manufacturer = null; - let product_model = null; - let product_device = null; - let build_number = null; - if (isGonk) { - hardware_info = libcutils.property_get('ro.hardware'); - firmware_revision = libcutils.property_get('ro.firmware_revision'); - product_manufacturer = libcutils.property_get('ro.product.manufacturer'); - product_model = libcutils.property_get('ro.product.model'); - product_device = libcutils.property_get('ro.product.device'); - build_number = libcutils.property_get('ro.build.version.incremental'); - } - - // Populate deviceinfo settings, - // copying any existing deviceinfo.os into deviceinfo.previous_os - let lock = window.navigator.mozSettings.createLock(); - let req = lock.get('deviceinfo.os'); - req.onsuccess = req.onerror = () => { - let previous_os = req.result && req.result['deviceinfo.os'] || ''; - let software = os_name + ' ' + os_version; - let setting = { - 'deviceinfo.build_number': build_number, - 'deviceinfo.os': os_version, - 'deviceinfo.previous_os': previous_os, - 'deviceinfo.software': software, - 'deviceinfo.platform_version': appInfo.platformVersion, - 'deviceinfo.platform_build_id': appInfo.platformBuildID, - 'deviceinfo.hardware': hardware_info, - 'deviceinfo.firmware_revision': firmware_revision, - 'deviceinfo.product_manufacturer': product_manufacturer, - 'deviceinfo.product_model': product_model, - 'deviceinfo.product_device': product_device - } - lock.set(setting); - } -})(); - -// =================== DevTools ==================== - -var developerHUD; -SettingsListener.observe('devtools.overlay', false, (value) => { - if (value) { - if (!developerHUD) { - let scope = {}; - Services.scriptloader.loadSubScript('chrome://b2g/content/devtools/hud.js', scope); - developerHUD = scope.developerHUD; - } - developerHUD.init(); - } else { - if (developerHUD) { - developerHUD.uninit(); - } - } -}); - -if (isGonk) { - var LogShake; - (function() { - let scope = {}; - Cu.import('resource://gre/modules/LogShake.jsm', scope); - LogShake = scope.LogShake; - LogShake.init(); - })(); - - SettingsListener.observe('devtools.logshake.enabled', false, value => { - if (value) { - LogShake.enableDeviceMotionListener(); - } else { - LogShake.disableDeviceMotionListener(); - } - }); - - SettingsListener.observe('devtools.logshake.qa_enabled', false, value => { - if (value) { - LogShake.enableQAMode(); - } else { - LogShake.disableQAMode(); - } - }); -} - -// =================== Device Storage ==================== -SettingsListener.observe('device.storage.writable.name', 'sdcard', function(value) { - if (Services.prefs.getPrefType('device.storage.writable.name') != Ci.nsIPrefBranch.PREF_STRING) { - // We clear the pref because it used to be erroneously written as a bool - // and we need to clear it before we can change it to have the correct type. - Services.prefs.clearUserPref('device.storage.writable.name'); - } - Services.prefs.setCharPref('device.storage.writable.name', value); -}); - -// =================== Privacy ==================== -SettingsListener.observe('privacy.donottrackheader.value', 1, function(value) { - Services.prefs.setIntPref('privacy.donottrackheader.value', value); - // If the user specifically disallows tracking, we set the value of - // app.update.custom (update tracking ID) to an empty string. - if (value == 1) { - Services.prefs.setCharPref('app.update.custom', ''); - return; - } - // Otherwise, we assure that the update tracking ID exists. - setUpdateTrackingId(); -}); - -// =================== Crash Reporting ==================== -SettingsListener.observe('app.reportCrashes', 'ask', function(value) { - if (value == 'always') { - Services.prefs.setBoolPref('app.reportCrashes', true); - } else if (value == 'never') { - Services.prefs.setBoolPref('app.reportCrashes', false); - } else { - Services.prefs.clearUserPref('app.reportCrashes'); - } - // This preference is consulted during startup. - Services.prefs.savePrefFile(null); -}); - -// ================ Updates ================ -/** - * For tracking purposes some partners require us to add an UUID to the - * update URL. The update tracking ID will be an empty string if the - * do-not-track feature specifically disallows tracking and it is reseted - * to a different ID if the do-not-track value changes from disallow to allow. - */ -function setUpdateTrackingId() { - try { - let dntEnabled = Services.prefs.getBoolPref('privacy.donottrackheader.enabled'); - let dntValue = Services.prefs.getIntPref('privacy.donottrackheader.value'); - // If the user specifically decides to disallow tracking (1), we just bail out. - if (dntEnabled && (dntValue == 1)) { - return; - } - - let trackingId = - Services.prefs.getPrefType('app.update.custom') == - Ci.nsIPrefBranch.PREF_STRING && - Services.prefs.getCharPref('app.update.custom'); - - // If there is no previous registered tracking ID, we generate a new one. - // This should only happen on first usage or after changing the - // do-not-track value from disallow to allow. - if (!trackingId) { - trackingId = uuidgen.generateUUID().toString().replace(/[{}]/g, ""); - Services.prefs.setCharPref('app.update.custom', trackingId); - } - } catch(e) { - dump('Error getting tracking ID ' + e + '\n'); - } -} -setUpdateTrackingId(); - -(function syncUpdatePrefs() { - // The update service reads the prefs from the default branch. This is by - // design, as explained in bug 302721 comment 43. If we are to successfully - // modify them, that's where we need to make our changes. - let defaultBranch = Services.prefs.getDefaultBranch(null); - - function syncPrefDefault(prefName) { - // The pref value at boot-time will serve as default for the setting. - let defaultValue = defaultBranch.getCharPref(prefName); - let defaultSetting = {}; - defaultSetting[prefName] = defaultValue; - - // We back up that value in order to detect pref changes across reboots. - // Such a change can happen e.g. when the user installs an OTA update that - // changes the update URL format. - let backupName = prefName + '.old'; - try { - // Everything relies on the comparison below: When pushing a new Gecko - // that changes app.update.url or app.update.channel, we overwrite any - // existing setting with the new pref value. - let backupValue = Services.prefs.getCharPref(backupName); - if (defaultValue !== backupValue) { - // If the pref has changed since our last backup, overwrite the setting. - navigator.mozSettings.createLock().set(defaultSetting); - } - } catch(e) { - // There was no backup: Overwrite the setting and create a backup below. - navigator.mozSettings.createLock().set(defaultSetting); - } - - // Initialize or update the backup value. - Services.prefs.setCharPref(backupName, defaultValue); - - // Propagate setting changes to the pref. - SettingsListener.observe(prefName, defaultValue, value => { - if (!value) { - // If the setting value is invalid, reset it to its default. - navigator.mozSettings.createLock().set(defaultSetting); - return; - } - // Here we will overwrite the pref with the setting value. - defaultBranch.setCharPref(prefName, value); - }); - } - - syncPrefDefault('app.update.url'); - syncPrefDefault('app.update.channel'); -})(); - -// ================ Debug ================ -(function Composer2DSettingToPref() { - //layers.composer.enabled can be enabled in three ways - //In order of precedence they are: - // - //1. mozSettings "layers.composer.enabled" - //2. a gecko pref "layers.composer.enabled" - //3. presence of ro.display.colorfill at the Gonk level - - var req = navigator.mozSettings.createLock().get('layers.composer2d.enabled'); - req.onsuccess = function() { - if (typeof(req.result['layers.composer2d.enabled']) === 'undefined') { - var enabled = false; - if (Services.prefs.getPrefType('layers.composer2d.enabled') == Ci.nsIPrefBranch.PREF_BOOL) { - enabled = Services.prefs.getBoolPref('layers.composer2d.enabled'); - } else if (isGonk) { - let androidVersion = libcutils.property_get("ro.build.version.sdk"); - if (androidVersion >= 17 ) { - enabled = true; - } else { - enabled = (libcutils.property_get('ro.display.colorfill') === '1'); - } - } - navigator.mozSettings.createLock().set({'layers.composer2d.enabled': enabled }); - } - - SettingsListener.observe("layers.composer2d.enabled", true, function(value) { - Services.prefs.setBoolPref("layers.composer2d.enabled", value); - }); - }; - req.onerror = function() { - dump("Error configuring layers.composer2d.enabled setting"); - }; - -})(); - -// ================ Accessibility ============ -(function setupAccessibility() { - let accessibilityScope = {}; - SettingsListener.observe("accessibility.screenreader", false, function(value) { - if (!value) { - return; - } - if (!('AccessFu' in accessibilityScope)) { - Cu.import('resource://gre/modules/accessibility/AccessFu.jsm', - accessibilityScope); - accessibilityScope.AccessFu.attach(window); - } - }); -})(); - -// ================ Theming ============ -(function themingSettingsListener() { - let themingPrefs = ['ui.menu', 'ui.menutext', 'ui.infobackground', 'ui.infotext', - 'ui.window', 'ui.windowtext', 'ui.highlight']; - - themingPrefs.forEach(function(pref) { - SettingsListener.observe('gaia.' + pref, null, function(value) { - if (value) { - Services.prefs.setCharPref(pref, value); - } - }); - }); -})(); - -// =================== Telemetry ====================== -(function setupTelemetrySettings() { - let gaiaSettingName = 'debug.performance_data.shared'; - let geckoPrefName = 'toolkit.telemetry.enabled'; - SettingsListener.observe(gaiaSettingName, null, function(value) { - if (value !== null) { - // Gaia setting has been set; update Gecko pref to that. - Services.prefs.setBoolPref(geckoPrefName, value); - return; - } - // Gaia setting has not been set; set the gaia setting to default. - let prefValue = Services.prefs.getBoolPref(geckoPrefName, - AppConstants.MOZ_TELEMETRY_ON_BY_DEFAULT); - let setting = {}; - setting[gaiaSettingName] = prefValue; - window.navigator.mozSettings.createLock().set(setting); - }); -})(); - -// =================== Low-precision buffer ====================== -(function setupLowPrecisionSettings() { - // The gaia setting layers.low-precision maps to two gecko prefs - SettingsListener.observe('layers.low-precision', null, function(value) { - if (value !== null) { - // Update gecko from the new Gaia setting - Services.prefs.setBoolPref('layers.low-precision-buffer', value); - Services.prefs.setBoolPref('layers.progressive-paint', value); - } else { - // Update gaia setting from gecko value - try { - let prefValue = Services.prefs.getBoolPref('layers.low-precision-buffer'); - let setting = { 'layers.low-precision': prefValue }; - window.navigator.mozSettings.createLock().set(setting); - } catch (e) { - console.log('Unable to read pref layers.low-precision-buffer: ' + e); - } - } - }); - - // The gaia setting layers.low-opacity maps to a string gecko pref (0.5/1.0) - SettingsListener.observe('layers.low-opacity', null, function(value) { - if (value !== null) { - // Update gecko from the new Gaia setting - Services.prefs.setCharPref('layers.low-precision-opacity', value ? '0.5' : '1.0'); - } else { - // Update gaia setting from gecko value - try { - let prefValue = Services.prefs.getCharPref('layers.low-precision-opacity'); - let setting = { 'layers.low-opacity': (prefValue == '0.5') }; - window.navigator.mozSettings.createLock().set(setting); - } catch (e) { - console.log('Unable to read pref layers.low-precision-opacity: ' + e); - } - } - }); -})(); - -// ======================= Dogfooders FOTA ========================== -if (AppConstants.MOZ_B2G_RIL) { - SettingsListener.observe('debug.performance_data.dogfooding', false, - isDogfooder => { - if (!isDogfooder) { - dump('AUS:Settings: Not a dogfooder!\n'); - return; - } - - if (!('mozTelephony' in navigator)) { - dump('AUS:Settings: There is no mozTelephony!\n'); - return; - } - - if (!('mozMobileConnections' in navigator)) { - dump('AUS:Settings: There is no mozMobileConnections!\n'); - return; - } - }); -} - -// =================== Various simple mapping ====================== -var settingsToObserve = { - 'accessibility.screenreader_quicknav_modes': { - prefName: 'accessibility.accessfu.quicknav_modes', - resetToPref: true, - defaultValue: '' - }, - 'accessibility.screenreader_quicknav_index': { - prefName: 'accessibility.accessfu.quicknav_index', - resetToPref: true, - defaultValue: 0 - }, - 'app.update.interval': 86400, - 'apz.overscroll.enabled': true, - 'browser.safebrowsing.phishing.enabled': true, - 'browser.safebrowsing.malware.enabled': true, - 'debug.fps.enabled': { - prefName: 'layers.acceleration.draw-fps', - defaultValue: false - }, - 'debug.log-animations.enabled': { - prefName: 'layers.offmainthreadcomposition.log-animations', - defaultValue: false - }, - 'debug.paint-flashing.enabled': { - prefName: 'nglayout.debug.paint_flashing', - defaultValue: false - }, - // FIXME: Bug 1185806 - Provide a common device name setting. - // Borrow device name from developer's menu to avoid multiple name settings. - 'devtools.discovery.device': { - prefName: 'dom.presentation.device.name', - defaultValue: 'Firefox OS' - }, - 'devtools.eventlooplag.threshold': 100, - 'devtools.remote.wifi.visible': { - resetToPref: true - }, - 'devtools.telemetry.supported_performance_marks': { - resetToPref: true - }, - - 'dom.presentation.discovery.enabled': false, - 'dom.presentation.discoverable': false, - 'dom.serviceWorkers.testing.enabled': false, - 'gfx.layerscope.enabled': false, - 'layers.draw-borders': false, - 'layers.draw-tile-borders': false, - 'layers.dump': false, - 'layers.enable-tiles': AppConstants.platform !== "win", - 'layers.enable-tiles': true, - 'layers.effect.invert': false, - 'layers.effect.grayscale': false, - 'layers.effect.contrast': '0.0', - 'layout.display-list.dump': false, - 'mms.debugging.enabled': false, - 'network.debugging.enabled': false, - 'privacy.donottrackheader.enabled': false, - 'privacy.trackingprotection.enabled': false, - 'ril.debugging.enabled': false, - 'ril.radio.disabled': false, - 'ril.mms.requestReadReport.enabled': { - prefName: 'dom.mms.requestReadReport', - defaultValue: true - }, - 'ril.mms.requestStatusReport.enabled': { - prefName: 'dom.mms.requestStatusReport', - defaultValue: false - }, - 'ril.mms.retrieval_mode': { - prefName: 'dom.mms.retrieval_mode', - defaultValue: 'manual' - }, - 'ril.sms.requestStatusReport.enabled': { - prefName: 'dom.sms.requestStatusReport', - defaultValue: false - }, - 'ril.sms.strict7BitEncoding.enabled': { - prefName: 'dom.sms.strict7BitEncoding', - defaultValue: false - }, - 'ril.sms.maxReadAheadEntries': { - prefName: 'dom.sms.maxReadAheadEntries', - defaultValue: 7 - }, - 'services.sync.enabled': { - defaultValue: false, - notifyChange: true - }, - 'ui.touch.radius.leftmm': { - resetToPref: true - }, - 'ui.touch.radius.topmm': { - resetToPref: true - }, - 'ui.touch.radius.rightmm': { - resetToPref: true - }, - 'ui.touch.radius.bottommm': { - resetToPref: true - }, - 'ui.click_hold_context_menus.delay': { - resetToPref: true - }, - 'wap.UAProf.tagname': 'x-wap-profile', - 'wap.UAProf.url': '' -}; - -if (AppConstants.MOZ_GRAPHENE) { - // Restart required - settingsToObserve['layers.async-pan-zoom.enabled'] = false; -} - -function settingObserver(setPref, prefName, setting) { - return value => { - setPref(prefName, value); - if (setting.notifyChange) { - SystemAppProxy._sendCustomEvent('mozPrefChromeEvent', { - prefName: prefName, - value: value - }); - } - }; -} - -for (let key in settingsToObserve) { - let setting = settingsToObserve[key]; - - // Allow setting to contain flags redefining prefName and defaultValue. - let prefName = setting.prefName || key; - let defaultValue = setting.defaultValue; - if (defaultValue === undefined) { - defaultValue = setting; - } - - let prefs = Services.prefs; - - // If requested, reset setting value and defaultValue to the pref value. - if (setting.resetToPref) { - switch (prefs.getPrefType(prefName)) { - case Ci.nsIPrefBranch.PREF_BOOL: - defaultValue = prefs.getBoolPref(prefName); - break; - - case Ci.nsIPrefBranch.PREF_INT: - defaultValue = prefs.getIntPref(prefName); - break; - - case Ci.nsIPrefBranch.PREF_STRING: - defaultValue = prefs.getCharPref(prefName); - break; - } - - let setting = {}; - setting[key] = defaultValue; - window.navigator.mozSettings.createLock().set(setting); - } - - // Figure out the right setter function for this type of pref. - let setPref; - switch (typeof defaultValue) { - case 'boolean': - setPref = prefs.setBoolPref.bind(prefs); - break; - - case 'number': - setPref = prefs.setIntPref.bind(prefs); - break; - - case 'string': - setPref = prefs.setCharPref.bind(prefs); - break; - } - - SettingsListener.observe(key, defaultValue, - settingObserver(setPref, prefName, setting)); -}; diff --git a/b2g/chrome/content/shell.css b/b2g/chrome/content/shell.css deleted file mode 100644 index 34daafd9910e..000000000000 --- a/b2g/chrome/content/shell.css +++ /dev/null @@ -1,81 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -html { - background: black; - overflow: hidden; - width: 100%; - height: 100%; - padding: 0 !important; -} -body { - margin: 0; - width: 100%; - height: 100%; - overflow: hidden; -} -iframe { - overflow: hidden; - height: 100%; - width: 100%; - border: none; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - z-index: 1; - -moz-user-select: none; -} - -%ifdef MOZ_GRAPHENE - -body.content-loaded > #installing { - display: none; -} - -#installing { - z-index: 2; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - background-color: #F1C40F; - color: #FFF; -} - -.throbber { - width: 3px; - height: 3px; - border-radius: 100px; - background-color: #FFF; - animation-name: throbber; - animation-duration: 1500ms; - animation-iteration-count: infinite; - animation-timing-function: linear; -} - -#titlebar-buttonbox { - margin: 6px 7px; - -moz-appearance: -moz-window-button-box; -} - -@keyframes throbber{ - from { - transform: scale(0); - opacity: 0.4; - } - to { - transform: scale(400); - opacity: 0; - } -} - -%endif diff --git a/b2g/chrome/content/shell.html b/b2g/chrome/content/shell.html deleted file mode 100644 index 7ab6d0c93ba2..000000000000 --- a/b2g/chrome/content/shell.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - -#ifndef ANDROID -#ifndef MOZ_GRAPHENE - - - - -#endif -#else - - -#endif - - - - -#ifndef MOZ_GRAPHENE -#ifdef MOZ_WIDGET_COCOA - -

wtf mac os!

-#endif -#else -
-
-
-
-
-#endif - - - diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js deleted file mode 100644 index 545a2bb3b295..000000000000 --- a/b2g/chrome/content/shell.js +++ /dev/null @@ -1,1298 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -window.performance.mark('gecko-shell-loadstart'); - -Cu.import('resource://gre/modules/NotificationDB.jsm'); -Cu.import('resource://gre/modules/UserAgentOverrides.jsm'); -Cu.import('resource://gre/modules/Keyboard.jsm'); -Cu.import('resource://gre/modules/ErrorPage.jsm'); -Cu.import('resource://gre/modules/AlertsHelper.jsm'); -Cu.import('resource://gre/modules/SystemUpdateService.jsm'); - -if (isGonk) { - Cu.import('resource://gre/modules/ResourceStatsService.jsm'); -} - -// Identity -Cu.import('resource://gre/modules/SignInToWebsite.jsm'); -SignInToWebsiteController.init(); - -Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm'); -Cu.import('resource://gre/modules/DownloadsAPI.jsm'); -Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm'); -Cu.import('resource://gre/modules/AboutServiceWorkers.jsm'); - -XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", - "resource://gre/modules/SystemAppProxy.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Screenshot", - "resource://gre/modules/Screenshot.jsm"); - -XPCOMUtils.defineLazyServiceGetter(Services, 'env', - '@mozilla.org/process/environment;1', - 'nsIEnvironment'); - -XPCOMUtils.defineLazyServiceGetter(Services, 'ss', - '@mozilla.org/content/style-sheet-service;1', - 'nsIStyleSheetService'); - -XPCOMUtils.defineLazyServiceGetter(this, 'gSystemMessenger', - '@mozilla.org/system-message-internal;1', - 'nsISystemMessagesInternal'); - -XPCOMUtils.defineLazyGetter(this, "ppmm", function() { - return Cc["@mozilla.org/parentprocessmessagemanager;1"] - .getService(Ci.nsIMessageListenerManager); -}); - -if (isGonk) { - XPCOMUtils.defineLazyGetter(this, "libcutils", function () { - Cu.import("resource://gre/modules/systemlibs.js"); - return libcutils; - }); -} - -XPCOMUtils.defineLazyServiceGetter(Services, 'captivePortalDetector', - '@mozilla.org/toolkit/captive-detector;1', - 'nsICaptivePortalDetector'); - -XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing", - "resource://gre/modules/SafeBrowsing.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "SafeMode", - "resource://gre/modules/SafeMode.jsm"); - -window.performance.measure('gecko-shell-jsm-loaded', 'gecko-shell-loadstart'); - -function debug(str) { - dump(' -*- Shell.js: ' + str + '\n'); -} - -const once = event => { - let target = shell.contentBrowser; - return new Promise((resolve, reject) => { - target.addEventListener(event, function(evt) { - resolve(evt); - }, {once: true}); - }); -} - -function clearCache() { - let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"] - .getService(Ci.nsICacheStorageService); - cache.clear(); -} - -function clearCacheAndReload() { - // Reload the main frame with a cleared cache. - debug('Reloading ' + shell.contentBrowser.contentWindow.location); - clearCache(); - shell.contentBrowser.contentWindow.location.reload(true); - once('mozbrowserlocationchange').then( - evt => { - shell.sendEvent(window, "ContentStart"); - }); -} - -function restart() { - let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eForceQuit | Ci.nsIAppStartup.eRestart); -} - -function debugCrashReport(aStr) { - AppConstants.MOZ_CRASHREPORTER && dump('Crash reporter : ' + aStr); -} - -var shell = { - - get CrashSubmit() { - delete this.CrashSubmit; - if (AppConstants.MOZ_CRASHREPORTER) { - Cu.import("resource://gre/modules/CrashSubmit.jsm", this); - return this.CrashSubmit; - } else { - dump('Crash reporter : disabled at build time.'); - return this.CrashSubmit = null; - } - }, - - onlineForCrashReport: function shell_onlineForCrashReport() { - let wifiManager = navigator.mozWifiManager; - let onWifi = (wifiManager && - (wifiManager.connection.status == 'connected')); - return !Services.io.offline && onWifi; - }, - - reportCrash: function shell_reportCrash(isChrome, aCrashID) { - let crashID = aCrashID; - try { - // For chrome crashes, we want to report the lastRunCrashID. - if (isChrome) { - crashID = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULRuntime).lastRunCrashID; - } - } catch(e) { - debugCrashReport('Failed to fetch crash id. Crash ID is "' + crashID - + '" Exception: ' + e); - } - - // Bail if there isn't a valid crashID. - if (!this.CrashSubmit || !crashID && !this.CrashSubmit.pendingIDs().length) { - return; - } - - // purge the queue. - this.CrashSubmit.pruneSavedDumps(); - - // check for environment affecting crash reporting - let env = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - let shutdown = env.get("MOZ_CRASHREPORTER_SHUTDOWN"); - if (shutdown) { - let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eForceQuit); - } - - let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT"); - if (noReport) { - return; - } - - try { - // Check if we should automatically submit this crash. - if (Services.prefs.getBoolPref('app.reportCrashes')) { - this.submitCrash(crashID); - } else { - this.deleteCrash(crashID); - } - } catch (e) { - debugCrashReport('Can\'t fetch app.reportCrashes. Exception: ' + e); - } - - // We can get here if we're just submitting old pending crashes. - // Check that there's a valid crashID so that we only notify the - // user if a crash just happened and not when we OOM. Bug 829477 - if (crashID) { - this.sendChromeEvent({ - type: "handle-crash", - crashID: crashID, - chrome: isChrome - }); - } - }, - - deleteCrash: function shell_deleteCrash(aCrashID) { - if (aCrashID) { - debugCrashReport('Deleting pending crash: ' + aCrashID); - shell.CrashSubmit.delete(aCrashID); - } - }, - - // this function submit the pending crashes. - // make sure you are online. - submitQueuedCrashes: function shell_submitQueuedCrashes() { - // submit the pending queue. - let pending = shell.CrashSubmit.pendingIDs(); - for (let crashid of pending) { - debugCrashReport('Submitting crash: ' + crashid); - shell.CrashSubmit.submit(crashid); - } - }, - - // This function submits a crash when we're online. - submitCrash: function shell_submitCrash(aCrashID) { - if (this.onlineForCrashReport()) { - this.submitQueuedCrashes(); - return; - } - - debugCrashReport('Not online, postponing.'); - - Services.obs.addObserver(function observer(subject, topic, state) { - let network = subject.QueryInterface(Ci.nsINetworkInfo); - if (network.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED - && network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) { - shell.submitQueuedCrashes(); - - Services.obs.removeObserver(observer, topic); - } - }, "network-connection-state-changed"); - }, - - get homeURL() { - try { - let homeSrc = Services.env.get('B2G_HOMESCREEN'); - if (homeSrc) - return homeSrc; - } catch (e) {} - - return Services.prefs.getCharPref('b2g.system_startup_url'); - }, - - get manifestURL() { - return Services.prefs.getCharPref('b2g.system_manifest_url'); - }, - - _started: false, - hasStarted: function shell_hasStarted() { - return this._started; - }, - - bootstrap: function() { - window.performance.mark('gecko-shell-bootstrap'); - - // Before anything, check if we want to start in safe mode. - SafeMode.check(window).then(() => { - let startManifestURL = - Cc['@mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap'] - .getService(Ci.nsISupports).wrappedJSObject.startManifestURL; - - // If --start-manifest hasn't been specified, we re-use the latest specified manifest. - // If it's the first launch, we will fallback to b2g.default.start_manifest_url - if (AppConstants.MOZ_GRAPHENE && !startManifestURL) { - startManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url", ""); - } - - if (!startManifestURL) { - startManifestURL = Services.prefs.getCharPref("b2g.default.start_manifest_url", ""); - } - - if (startManifestURL) { - Cu.import('resource://gre/modules/Bootstraper.jsm'); - - if (AppConstants.MOZ_GRAPHENE && Bootstraper.isInstallRequired(startManifestURL)) { - // Installing the app my take some time. We don't want to keep the - // native window hidden. - showInstallScreen(); - } - - Bootstraper.ensureSystemAppInstall(startManifestURL) - .then(this.start.bind(this)) - .catch(Bootstraper.bailout); - } else { - this.start(); - } - }); - }, - - start: function shell_start() { - window.performance.mark('gecko-shell-start'); - this._started = true; - - // This forces the initialization of the cookie service before we hit the - // network. - // See bug 810209 - let cookies = Cc["@mozilla.org/cookieService;1"]; - - try { - let cr = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsICrashReporter); - // Dogfood id. We might want to remove it in the future. - // see bug 789466 - try { - let dogfoodId = Services.prefs.getCharPref('prerelease.dogfood.id'); - if (dogfoodId != "") { - cr.annotateCrashReport("Email", dogfoodId); - } - } - catch (e) { } - - if (isGonk) { - // Annotate crash report - let annotations = [ [ "Android_Hardware", "ro.hardware" ], - [ "Android_Device", "ro.product.device" ], - [ "Android_CPU_ABI2", "ro.product.cpu.abi2" ], - [ "Android_CPU_ABI", "ro.product.cpu.abi" ], - [ "Android_Manufacturer", "ro.product.manufacturer" ], - [ "Android_Brand", "ro.product.brand" ], - [ "Android_Model", "ro.product.model" ], - [ "Android_Board", "ro.product.board" ], - ]; - - annotations.forEach(function (element) { - cr.annotateCrashReport(element[0], libcutils.property_get(element[1])); - }); - - let androidVersion = libcutils.property_get("ro.build.version.sdk") + - "(" + libcutils.property_get("ro.build.version.codename") + ")"; - cr.annotateCrashReport("Android_Version", androidVersion); - - SettingsListener.observe("deviceinfo.os", "", function(value) { - try { - let cr = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsICrashReporter); - cr.annotateCrashReport("B2G_OS_Version", value); - } catch(e) { } - }); - } - } catch(e) { - debugCrashReport('exception: ' + e); - } - - let homeURL = this.homeURL; - if (!homeURL) { - let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN'; - alert(msg); - return; - } - - let manifestURL = this.manifestURL; - // - let systemAppFrame = - document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe'); - systemAppFrame.setAttribute('id', 'systemapp'); - systemAppFrame.setAttribute('mozbrowser', 'true'); - systemAppFrame.setAttribute('allowfullscreen', 'true'); - systemAppFrame.setAttribute('src', 'blank.html'); - let container = document.getElementById('container'); - - if (AppConstants.platform == 'macosx') { - // See shell.html - let hotfix = document.getElementById('placeholder'); - if (hotfix) { - container.removeChild(hotfix); - } - } - - this.contentBrowser = container.appendChild(systemAppFrame); - - let webNav = systemAppFrame.contentWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation); - webNav.sessionHistory = Cc["@mozilla.org/browser/shistory;1"].createInstance(Ci.nsISHistory); - - if (AppConstants.MOZ_GRAPHENE) { - webNav.QueryInterface(Ci.nsIDocShell).windowDraggingAllowed = true; - } - - let audioChannels = systemAppFrame.allowedAudioChannels; - audioChannels && audioChannels.forEach(function(audioChannel) { - // Set all audio channels as unmuted by default - // because some audio in System app will be played - // before AudioChannelService[1] is Gaia is loaded. - // [1]: https://github.com/mozilla-b2g/gaia/blob/master/apps/system/js/audio_channel_service.js - audioChannel.setMuted(false); - }); - - // On firefox mulet, shell.html is loaded in a tab - // and we have to listen on the chrome event handler - // to catch key events - let chromeEventHandler = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler || window; - // Capture all key events so we can filter out hardware buttons - // And send them to Gaia via mozChromeEvents. - // Ideally, hardware buttons wouldn't generate key events at all, or - // if they did, they would use keycodes that conform to DOM 3 Events. - // See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=762362 - chromeEventHandler.addEventListener('keydown', this, true); - chromeEventHandler.addEventListener('keyup', this, true); - - window.addEventListener('MozApplicationManifest', this); - window.addEventListener('MozAfterPaint', this); - window.addEventListener('sizemodechange', this); - window.addEventListener('unload', this); - this.contentBrowser.addEventListener('mozbrowserloadstart', this, true); - this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true); - this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this); - - CustomEventManager.init(); - UserAgentOverrides.init(); - CaptivePortalLoginHelper.init(); - - this.contentBrowser.src = homeURL; - - this._isEventListenerReady = false; - - window.performance.mark('gecko-shell-system-frame-set'); - - ppmm.addMessageListener("content-handler", this); - ppmm.addMessageListener("dial-handler", this); - ppmm.addMessageListener("sms-handler", this); - ppmm.addMessageListener("mail-handler", this); - ppmm.addMessageListener("file-picker", this); - - setTimeout(function() { - SafeBrowsing.init(); - }, 5000); - }, - - stop: function shell_stop() { - window.removeEventListener('unload', this); - window.removeEventListener('keydown', this, true); - window.removeEventListener('keyup', this, true); - window.removeEventListener('MozApplicationManifest', this); - window.removeEventListener('sizemodechange', this); - this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true); - this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true); - this.contentBrowser.removeEventListener('mozbrowsercaretstatechanged', this); - ppmm.removeMessageListener("content-handler", this); - - UserAgentOverrides.uninit(); - }, - - // If this key event represents a hardware button which needs to be send as - // a message, broadcasts it with the message set to 'xxx-button-press' or - // 'xxx-button-release'. - broadcastHardwareKeys: function shell_broadcastHardwareKeys(evt) { - let type; - let message; - - let mediaKeys = { - 'MediaTrackNext': 'media-next-track-button', - 'MediaTrackPrevious': 'media-previous-track-button', - 'MediaPause': 'media-pause-button', - 'MediaPlay': 'media-play-button', - 'MediaPlayPause': 'media-play-pause-button', - 'MediaStop': 'media-stop-button', - 'MediaRewind': 'media-rewind-button', - 'MediaFastForward': 'media-fast-forward-button' - }; - - if (evt.keyCode == evt.DOM_VK_F1) { - type = 'headset-button'; - message = 'headset-button'; - } else if (mediaKeys[evt.key]) { - type = 'media-button'; - message = mediaKeys[evt.key]; - } else { - return; - } - - switch (evt.type) { - case 'keydown': - message = message + '-press'; - break; - case 'keyup': - message = message + '-release'; - break; - } - - // Let applications receive the headset button and media key press/release message. - if (message !== this.lastHardwareButtonMessage) { - this.lastHardwareButtonMessage = message; - gSystemMessenger.broadcastMessage(type, message); - } - }, - - lastHardwareButtonMessage: null, // property for the hack above - visibleNormalAudioActive: false, - - handleEvent: function shell_handleEvent(evt) { - function checkReloadKey() { - if (evt.type !== 'keyup') { - return false; - } - - try { - let key = JSON.parse(Services.prefs.getCharPref('b2g.reload_key')); - return (evt.keyCode == key.key && - evt.ctrlKey == key.ctrl && - evt.altKey == key.alt && - evt.shiftKey == key.shift && - evt.metaKey == key.meta); - } catch(e) { - debug('Failed to get key: ' + e); - } - - return false; - } - - let content = this.contentBrowser.contentWindow; - switch (evt.type) { - case 'keydown': - case 'keyup': - if (checkReloadKey()) { - clearCacheAndReload(); - } else { - this.broadcastHardwareKeys(evt); - } - break; - case 'sizemodechange': - if (window.windowState == window.STATE_MINIMIZED && !this.visibleNormalAudioActive) { - this.contentBrowser.setVisible(false); - } else { - this.contentBrowser.setVisible(true); - } - break; - case 'load': - if (content.document.location == 'about:blank') { - return; - } - content.removeEventListener('load', this, true); - this.notifyContentWindowLoaded(); - break; - case 'mozbrowserloadstart': - if (content.document.location == 'about:blank') { - this.contentBrowser.addEventListener('mozbrowserlocationchange', this, true); - return; - } - - this.notifyContentStart(); - break; - case 'mozbrowserlocationchange': - if (content.document.location == 'about:blank') { - return; - } - - this.notifyContentStart(); - break; - case 'mozbrowserscrollviewchange': - this.sendChromeEvent({ - type: 'scrollviewchange', - detail: evt.detail, - }); - break; - case 'mozbrowsercaretstatechanged': - { - let elt = evt.target; - let win = elt.ownerGlobal; - let offsetX = win.mozInnerScreenX - window.mozInnerScreenX; - let offsetY = win.mozInnerScreenY - window.mozInnerScreenY; - - let rect = elt.getBoundingClientRect(); - offsetX += rect.left; - offsetY += rect.top; - - let data = evt.detail; - data.offsetX = offsetX; - data.offsetY = offsetY; - data.sendDoCommandMsg = null; - - shell.sendChromeEvent({ - type: 'caretstatechanged', - detail: data, - }); - } - break; - - case 'MozApplicationManifest': - try { - if (!Services.prefs.getBoolPref('browser.cache.offline.enable')) - return; - - let contentWindow = evt.originalTarget.defaultView; - let documentElement = contentWindow.document.documentElement; - if (!documentElement) - return; - - let manifest = documentElement.getAttribute('manifest'); - if (!manifest) - return; - - let principal = contentWindow.document.nodePrincipal; - if (Services.perms.testPermissionFromPrincipal(principal, 'offline-app') == Ci.nsIPermissionManager.UNKNOWN_ACTION) { - if (Services.prefs.getBoolPref('browser.offline-apps.notify')) { - // FIXME Bug 710729 - Add a UI for offline cache notifications - return; - } - return; - } - - Services.perms.addFromPrincipal(principal, 'offline-app', - Ci.nsIPermissionManager.ALLOW_ACTION); - - let documentURI = Services.io.newURI(contentWindow.document.documentURI); - let manifestURI = Services.io.newURI(manifest, null, documentURI); - let updateService = Cc['@mozilla.org/offlinecacheupdate-service;1'] - .getService(Ci.nsIOfflineCacheUpdateService); - updateService.scheduleUpdate(manifestURI, documentURI, principal, window); - } catch (e) { - dump('Error while creating offline cache: ' + e + '\n'); - } - break; - case 'MozAfterPaint': - window.removeEventListener('MozAfterPaint', this); - // This event should be sent before System app returns with - // system-message-listener-ready mozContentEvent, because it's on - // the critical launch path of the app. - SystemAppProxy._sendCustomEvent('mozChromeEvent', { - type: 'system-first-paint' - }, /* noPending */ true); - break; - case 'unload': - this.stop(); - break; - } - }, - - // Send an event to a specific window, document or element. - sendEvent: function shell_sendEvent(target, type, details) { - if (target === this.contentBrowser) { - // We must ask SystemAppProxy to send the event in this case so - // that event would be dispatched from frame.contentWindow instead of - // on the System app frame. - SystemAppProxy._sendCustomEvent(type, details); - return; - } - - let doc = target.document || target.ownerDocument || target; - let event = doc.createEvent('CustomEvent'); - event.initCustomEvent(type, true, true, details ? details : {}); - target.dispatchEvent(event); - }, - - sendCustomEvent: function shell_sendCustomEvent(type, details) { - SystemAppProxy._sendCustomEvent(type, details); - }, - - sendChromeEvent: function shell_sendChromeEvent(details) { - this.sendCustomEvent("mozChromeEvent", details); - }, - - receiveMessage: function shell_receiveMessage(message) { - var activities = { 'content-handler': { name: 'view', response: null }, - 'dial-handler': { name: 'dial', response: null }, - 'mail-handler': { name: 'new', response: null }, - 'sms-handler': { name: 'new', response: null }, - 'file-picker': { name: 'pick', response: 'file-picked' } }; - - if (!(message.name in activities)) - return; - - let data = message.data; - let activity = activities[message.name]; - - let a = new MozActivity({ - name: activity.name, - data: data - }); - - if (activity.response) { - a.onsuccess = function() { - let sender = message.target.QueryInterface(Ci.nsIMessageSender); - sender.sendAsyncMessage(activity.response, { success: true, - result: a.result }); - } - a.onerror = function() { - let sender = message.target.QueryInterface(Ci.nsIMessageSender); - sender.sendAsyncMessage(activity.response, { success: false }); - } - } - }, - - notifyContentStart: function shell_notifyContentStart() { - window.performance.mark('gecko-shell-notify-content-start'); - this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true); - this.contentBrowser.removeEventListener('mozbrowserlocationchange', this, true); - - let content = this.contentBrowser.contentWindow; - content.addEventListener('load', this, true); - - this.reportCrash(true); - - SystemAppProxy.registerFrame(shell.contentBrowser); - - this.sendEvent(window, 'ContentStart'); - - Services.obs.notifyObservers(null, 'content-start'); - - if (AppConstants.MOZ_GRAPHENE && - Services.prefs.getBoolPref("b2g.nativeWindowGeometry.fullscreen")) { - window.fullScreen = true; - } - - shell.handleCmdLine(); - }, - - handleCmdLine: function() { - // This isn't supported on devices. - if (!isGonk) { - let b2gcmds = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"] - .getService(Ci.nsISupports); - let args = b2gcmds.wrappedJSObject.cmdLine; - try { - // Returns null if -url is not present. - let url = args.handleFlagWithParam("url", false); - if (url) { - this.sendChromeEvent({type: "mozbrowseropenwindow", url}); - args.preventDefault = true; - } - } catch(e) { - // Throws if -url is present with no params. - } - } - }, - - // This gets called when window.onload fires on the System app content window, - // which means things in are parsed and statically referenced - - - - diff --git a/b2g/chrome/content/shell_remote.js b/b2g/chrome/content/shell_remote.js deleted file mode 100644 index 30c7ee5ae864..000000000000 --- a/b2g/chrome/content/shell_remote.js +++ /dev/null @@ -1,138 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/SystemAppProxy.jsm"); - -function debug(aStr) { - // dump(" -*- ShellRemote.js: " + aStr + "\n"); -} - -var remoteShell = { - - _started: false, - - get homeURL() { - let systemAppManifestURL = Services.io.newURI(this.systemAppManifestURL); - let shellRemoteURL = Services.prefs.getCharPref("b2g.multiscreen.system_remote_url"); - shellRemoteURL = Services.io.newURI(shellRemoteURL, null, systemAppManifestURL); - return shellRemoteURL.spec; - }, - - get systemAppManifestURL() { - return Services.prefs.getCharPref("b2g.system_manifest_url"); - }, - - hasStarted: function () { - return this._started; - }, - - start: function () { - this._started = true; - this._isEventListenerReady = false; - this.id = window.location.hash.substring(1); - - let homeURL = this.homeURL; - if (!homeURL) { - debug("ERROR! Remote home URL undefined."); - return; - } - let manifestURL = this.systemAppManifestURL; - // - let systemAppFrame = - document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe"); - systemAppFrame.setAttribute("id", this.id); - systemAppFrame.setAttribute("mozbrowser", "true"); - systemAppFrame.setAttribute("allowfullscreen", "true"); - systemAppFrame.setAttribute("src", "blank.html"); - - let container = document.getElementById("container"); - this.contentBrowser = container.appendChild(systemAppFrame); - this.contentBrowser.src = homeURL + window.location.hash; - - window.addEventListener("unload", this); - this.contentBrowser.addEventListener("mozbrowserloadstart", this); - }, - - stop: function () { - window.removeEventListener("unload", this); - this.contentBrowser.removeEventListener("mozbrowserloadstart", this); - this.contentBrowser.removeEventListener("mozbrowserlocationchange", this, true); - SystemAppProxy.unregisterFrameWithId(this.id); - }, - - notifyContentStart: function(evt) { - this.contentBrowser.removeEventListener("mozbrowserloadstart", this); - this.contentBrowser.removeEventListener("mozbrowserlocationchange", this, true); - - SystemAppProxy.registerFrameWithId(remoteShell.id, remoteShell.contentBrowser); - SystemAppProxy.addEventListenerWithId(this.id, "mozContentEvent", this); - - let content = this.contentBrowser.contentWindow; - content.addEventListener("load", this, true); - }, - - notifyContentWindowLoaded: function () { - SystemAppProxy.setIsLoadedWithId(this.id); - }, - - notifyEventListenerReady: function () { - if (this._isEventListenerReady) { - Cu.reportError("shell_remote.js: SystemApp has already been declared as being ready."); - return; - } - this._isEventListenerReady = true; - SystemAppProxy.setIsReadyWithId(this.id); - }, - - handleEvent: function(evt) { - debug("Got an event: " + evt.type); - let content = this.contentBrowser.contentWindow; - - switch(evt.type) { - case "mozContentEvent": - if (evt.detail.type === "system-message-listener-ready") { - this.notifyEventListenerReady(); - } - break; - case "load": - if (content.document.location == "about:blank") { - return; - } - content.removeEventListener("load", this, true); - this.notifyContentWindowLoaded(); - break; - case "mozbrowserloadstart": - if (content.document.location == "about:blank") { - this.contentBrowser.addEventListener("mozbrowserlocationchange", this, true); - return; - } - case "mozbrowserlocationchange": - if (content.document.location == "about:blank") { - return; - } - this.notifyContentStart(); - break; - case "unload": - this.stop(); - break; - } - } -}; - -window.onload = function() { - if (remoteShell.hasStarted() == false) { - remoteShell.start(); - } -}; - diff --git a/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js b/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js deleted file mode 100644 index 4ce16df6c306..000000000000 --- a/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; -const { Services } = Cu.import('resource://gre/modules/Services.jsm', {}); -const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm', {}); - -var processId; - -function peekChildId(aSubject, aTopic, aData) { - Services.obs.removeObserver(peekChildId, 'recording-device-events'); - Services.obs.removeObserver(peekChildId, 'recording-device-ipc-events'); - let props = aSubject.QueryInterface(Ci.nsIPropertyBag2); - if (props.hasKey('childID')) { - processId = props.get('childID'); - } -} - -addMessageListener('init-chrome-event', function(message) { - // listen mozChromeEvent and forward to content process. - let type = message.type; - SystemAppProxy.addEventListener('mozChromeEvent', function(event) { - let details = event.detail; - if (details.type === type) { - sendAsyncMessage('chrome-event', details); - } - }, true); - - Services.obs.addObserver(peekChildId, 'recording-device-events'); - Services.obs.addObserver(peekChildId, 'recording-device-ipc-events'); -}); - -addMessageListener('fake-content-shutdown', function(message) { - let props = Cc["@mozilla.org/hash-property-bag;1"] - .createInstance(Ci.nsIWritablePropertyBag2); - if (processId) { - props.setPropertyAsUint64('childID', processId); - } - Services.obs.notifyObservers(props, 'recording-device-ipc-events', 'content-shutdown'); -}); diff --git a/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js b/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js deleted file mode 100644 index 5e3e6814e1fd..000000000000 --- a/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -// resolve multiple promise in parallel -function expectAll(aValue) { - let deferred = new Promise(function(resolve, reject) { - let countdown = aValue.length; - let resolutionValues = new Array(countdown); - - for (let i = 0; i < aValue.length; i++) { - let index = i; - aValue[i].then(function(val) { - resolutionValues[index] = val; - if (--countdown === 0) { - resolve(resolutionValues); - } - }, reject); - } - }); - - return deferred; -} - -function TestInit() { - let url = SimpleTest.getTestFileURL("RecordingStatusChromeScript.js") - let script = SpecialPowers.loadChromeScript(url); - - let helper = { - finish: function () { - script.destroy(); - }, - fakeShutdown: function () { - script.sendAsyncMessage('fake-content-shutdown', {}); - } - }; - - script.addMessageListener('chrome-event', function (message) { - if (helper.hasOwnProperty('onEvent')) { - helper.onEvent(message); - } else { - ok(false, 'unexpected message: ' + JSON.stringify(message)); - } - }); - - script.sendAsyncMessage("init-chrome-event", { - type: 'recording-status' - }); - - return Promise.resolve(helper); -} - -function expectEvent(expected, eventHelper) { - return new Promise(function(resolve, reject) { - eventHelper.onEvent = function(message) { - delete eventHelper.onEvent; - ok(message, JSON.stringify(message)); - is(message.type, 'recording-status', 'event type: ' + message.type); - is(message.active, expected.active, 'recording active: ' + message.active); - is(message.isAudio, expected.isAudio, 'audio recording active: ' + message.isAudio); - is(message.isVideo, expected.isVideo, 'video recording active: ' + message.isVideo); - resolve(eventHelper); - }; - info('waiting for recording-status'); - }); -} - -function expectStream(params, callback) { - return new Promise(function(resolve, reject) { - var req = navigator.mozGetUserMedia( - params, - function(stream) { - ok(true, 'create media stream'); - callback(stream); - resolve(); - }, - function(err) { - ok(false, 'fail to create media stream'); - reject(err); - } - ); - info('waiting for gUM result'); - }); -} diff --git a/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html b/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html deleted file mode 100644 index 3354eccd8ee9..000000000000 --- a/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - Iframe for Recording Status - - - - - - -
-
-
- - diff --git a/b2g/chrome/content/test/mochitest/mochitest.ini b/b2g/chrome/content/test/mochitest/mochitest.ini deleted file mode 100644 index d18a20401abf..000000000000 --- a/b2g/chrome/content/test/mochitest/mochitest.ini +++ /dev/null @@ -1,11 +0,0 @@ -[DEFAULT] -skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #require OOP support for mochitest-b2g-desktop, Bug 957554 -support-files = - RecordingStatusChromeScript.js - RecordingStatusHelper.js - file_getusermedia_iframe.html - -[test_recordingStatus_basic.html] -[test_recordingStatus_multiple_requests.html] -[test_recordingStatus_iframe.html] -[test_recordingStatus_kill_content_process.html] diff --git a/b2g/chrome/content/test/mochitest/moz.build b/b2g/chrome/content/test/mochitest/moz.build deleted file mode 100644 index 3b13ba431aa9..000000000000 --- a/b2g/chrome/content/test/mochitest/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOCHITEST_MANIFESTS += ['mochitest.ini'] diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html deleted file mode 100644 index e80d15b9af26..000000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - Test for Recording Status - - - - - - -
-
-
- - diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html deleted file mode 100644 index 0b4113fac23f..000000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - Test for Recording Status in iframe - - - - - - -
-
-
-
- - diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html deleted file mode 100644 index bc1fc403e7c4..000000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - Test for Recording Status after process shutdown - - - - - - -
-
-
- - diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html deleted file mode 100644 index 9d09d7f7ec18..000000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - Test for Recording Status with multiple gUM requests - - - - - - -
-
-
- - diff --git a/b2g/chrome/content/touchcontrols.css b/b2g/chrome/content/touchcontrols.css deleted file mode 100644 index 7c407c331d6a..000000000000 --- a/b2g/chrome/content/touchcontrols.css +++ /dev/null @@ -1,233 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); - -/* video controls */ -.controlsOverlay { - -moz-box-pack: center; - -moz-box-align: end; - -moz-box-flex: 1; - -moz-box-orient: horizontal; -} - -.controlsOverlay[scaled] { - /* scaled attribute in videocontrols.css causes conflict - due to different -moz-box-orient values */ - -moz-box-align: end; -} - -.controlBar { - -moz-box-flex: 1; - background-color: rgba(50,50,50,0.8); - width: 100%; -} - -.buttonsBar { - -moz-box-flex: 1; - -moz-box-align: center; -} - -.controlsSpacer { - display: none; - -moz-box-flex: 0; -} - -.fullscreenButton, -.playButton, -.castingButton, -.muteButton { - -moz-appearance: none; - padding: 2px; - border: none !important; - min-height: 24px; - min-width: 24px; -} - -.fullscreenButton { - background: url("chrome://b2g/content/images/fullscreen-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.fullscreenButton[fullscreened="true"] { - background: url("chrome://b2g/content/images/exitfullscreen-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.controlBar[fullscreen-unavailable] .fullscreenButton { - display: none; -} - -.playButton { - background: url("chrome://b2g/content/images/pause-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -/* - * Normally the button bar has fullscreen spacer play spacer mute, but if - * this is an audio control rather than a video control, the fullscreen button - * is hidden by videocontrols.xml, and that alters the position of the - * play button. This workaround moves it back to center. - */ -.controlBar[fullscreen-unavailable] .playButton { - transform: translateX(28px); -} - -.playButton[paused="true"] { - background: url("chrome://b2g/content/images/play-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.castingButton { - display: none; -} - -.muteButton { - background: url("chrome://b2g/content/images/mute-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.muteButton[muted="true"] { - background: url("chrome://b2g/content/images/unmute-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -/* bars */ -.scrubberStack { - -moz-box-flex: 1; - padding: 0px 18px; -} - -.flexibleBar, -.flexibleBar .progress-bar, -.bufferBar, -.bufferBar .progress-bar, -.progressBar, -.progressBar .progress-bar, -.scrubber, -.scrubber .scale-slider, -.scrubber .scale-thumb { - -moz-appearance: none; - border: none; - padding: 0px; - margin: 0px; - background-color: transparent; -} - -.flexibleBar, -.bufferBar, -.progressBar { - height: 24px; - padding: 11px 0px; -} - -.flexibleBar { - padding: 12px 0px; -} - -.flexibleBar .progress-bar { - border: 1px #777777 solid; - border-radius: 1px; -} - -.bufferBar .progress-bar { - border: 2px #AFB1B3 solid; - border-radius: 2px; -} - -.progressBar .progress-bar { - border: 2px #FF9500 solid; - border-radius: 2px; -} - - -.scrubber { - margin-left: -8px; - margin-right: -8px; -} - -.positionLabel, .durationLabel { - font-family: 'Roboto', Helvetica, Arial, sans-serif; - font-size: 12px; - color: white; -} - -.scrubber .scale-thumb { - display: -moz-box; - margin: 0px !important; - padding: 0px !important; - background: url("chrome://b2g/content/images/scrubber-hdpi.png") no-repeat; - background-size: 12px 12px; - height: 12px; - width: 12px; -} - -.statusOverlay { - -moz-box-align: center; - -moz-box-pack: center; - background-color: rgb(50,50,50); -} - -.statusIcon { - margin-bottom: 28px; - width: 36px; - height: 36px; -} - -.statusIcon[type="throbber"] { - background: url("chrome://b2g/content/images/throbber.png") no-repeat center; -} - -.statusIcon[type="error"] { - background: url("chrome://b2g/content/images/error.png") no-repeat center; -} - -/* CSS Transitions */ -.controlBar:not([immediate]) { - transition-property: opacity; - transition-duration: 200ms; -} - -.controlBar[fadeout] { - opacity: 0; -} - -.statusOverlay:not([immediate]) { - transition-property: opacity; - transition-duration: 300ms; - transition-delay: 750ms; -} - -.statusOverlay[fadeout] { - opacity: 0; -} - -.volumeStack, -.controlBar[firstshow="true"] .fullscreenButton, -.controlBar[firstshow="true"] .muteButton, -.controlBar[firstshow="true"] .scrubberStack, -.controlBar[firstshow="true"] .durationBox, -.timeLabel { - display: none; -} - -/* Error description formatting */ -.errorLabel { - font-family: Helvetica, Arial, sans-serif; - font-size: 11px; - color: #bbb; - text-shadow: - -1px -1px 0 #000, - 1px -1px 0 #000, - -1px 1px 0 #000, - 1px 1px 0 #000; - padding: 0 10px; - text-align: center; -} diff --git a/b2g/chrome/jar.mn b/b2g/chrome/jar.mn deleted file mode 100644 index 1fdea9a50f3b..000000000000 --- a/b2g/chrome/jar.mn +++ /dev/null @@ -1,60 +0,0 @@ -#filter substitution -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - - -chrome.jar: -% content branding %content/branding/ contentaccessible=yes -% content b2g %content/ - - content/arrow.svg (content/arrow.svg) - content/settings.js (content/settings.js) -* content/shell.html (content/shell.html) - content/shell.js (content/shell.js) - content/shell_remote.html (content/shell_remote.html) - content/shell_remote.js (content/shell_remote.js) -* content/shell.css (content/shell.css) - content/blank.html (content/blank.html) - content/blank.css (content/blank.css) -#ifdef MOZ_WIDGET_GONK - content/devtools/adb.js (content/devtools/adb.js) -#endif - content/devtools/debugger.js (content/devtools/debugger.js) - content/devtools/hud.js (content/devtools/hud.js) -#ifndef MOZ_WIDGET_GONK - content/desktop.css (content/desktop.css) - content/images/desktop/home-black.png (content/images/desktop/home-black.png) - content/images/desktop/home-white.png (content/images/desktop/home-white.png) - content/images/desktop/rotate.png (content/images/desktop/rotate.png) - content/desktop.js (content/desktop.js) - content/screen.js (content/screen.js) -#endif -* content/content.css (content/content.css) - content/touchcontrols.css (content/touchcontrols.css) - - content/identity.js (content/identity.js) - -#ifndef MOZ_GRAPHENE -% override chrome://global/skin/media/videocontrols.css chrome://b2g/content/touchcontrols.css -#endif -% override chrome://global/content/aboutCertError.xhtml chrome://b2g/content/aboutCertError.xhtml -% override chrome://global/skin/netError.css chrome://b2g/content/netError.css - - content/ErrorPage.js (content/ErrorPage.js) - content/aboutCertError.xhtml (content/aboutCertError.xhtml) - content/netError.css (content/netError.css) - content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png) - content/images/errorpage-larry-white.png (content/images/errorpage-larry-white.png) - content/images/errorpage-warning.png (content/images/errorpage-warning.png) - content/images/arrowdown-16.png (content/images/arrowdown-16.png) - content/images/arrowright-16.png (content/images/arrowright-16.png) - content/images/scrubber-hdpi.png (content/images/scrubber-hdpi.png) - content/images/unmute-hdpi.png (content/images/unmute-hdpi.png) - content/images/pause-hdpi.png (content/images/pause-hdpi.png) - content/images/play-hdpi.png (content/images/play-hdpi.png) - content/images/mute-hdpi.png (content/images/mute-hdpi.png) - content/images/fullscreen-hdpi.png (content/images/fullscreen-hdpi.png) - content/images/exitfullscreen-hdpi.png (content/images/exitfullscreen-hdpi.png) - content/images/throbber.png (content/images/throbber.png) - content/images/error.png (content/images/error.png) diff --git a/b2g/chrome/moz.build b/b2g/chrome/moz.build deleted file mode 100644 index 99af44a5ca20..000000000000 --- a/b2g/chrome/moz.build +++ /dev/null @@ -1,13 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -DEFINES['AB_CD'] = CONFIG['MOZ_UI_LOCALE'] -DEFINES['PACKAGE'] = 'b2g' -DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] - -JAR_MANIFESTS += ['jar.mn'] - -TEST_DIRS += ['content/test/mochitest'] diff --git a/b2g/common.configure b/b2g/common.configure deleted file mode 100644 index 854de4b15da4..000000000000 --- a/b2g/common.configure +++ /dev/null @@ -1,32 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# Truetype fonts for B2G -# ============================================================== -option(env='MOZTTDIR', nargs=1, help='Path to truetype fonts for B2G') - -@depends('MOZTTDIR') -@imports('os') -def mozttdir(value): - if value: - path = value[0] - if not os.path.isdir(path): - die('MOZTTDIR "%s" is not a valid directory', path) - return path - -set_config('MOZTTDIR', mozttdir) - -@depends('MOZTTDIR') -def package_moztt(value): - if value: - return True - -set_define('PACKAGE_MOZTT', package_moztt) - -imply_option('MOZ_ENABLE_WARNINGS_AS_ERRORS', - depends(target)(lambda t: t.os == 'Android'), reason='--target') - -include('../toolkit/moz.configure') diff --git a/b2g/components/AboutServiceWorkers.jsm b/b2g/components/AboutServiceWorkers.jsm deleted file mode 100644 index 735c0182388d..000000000000 --- a/b2g/components/AboutServiceWorkers.jsm +++ /dev/null @@ -1,180 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict" - -this.EXPORTED_SYMBOLS = ["AboutServiceWorkers"]; - -const { interfaces: Ci, utils: Cu } = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", - "resource://gre/modules/SystemAppProxy.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "gServiceWorkerManager", - "@mozilla.org/serviceworkers/manager;1", - "nsIServiceWorkerManager"); - -function debug(aMsg) { - dump("AboutServiceWorkers - " + aMsg + "\n"); -} - -function serializeServiceWorkerInfo(aServiceWorkerInfo) { - if (!aServiceWorkerInfo) { - throw new Error("Invalid service worker information"); - } - - let result = {}; - - result.principal = { - origin: aServiceWorkerInfo.principal.originNoSuffix, - originAttributes: aServiceWorkerInfo.principal.originAttributes - }; - - ["scope", "scriptSpec"].forEach(property => { - result[property] = aServiceWorkerInfo[property]; - }); - - return result; -} - - -this.AboutServiceWorkers = { - get enabled() { - if (this._enabled) { - return this._enabled; - } - this._enabled = Services.prefs.getBoolPref("dom.serviceWorkers.enabled", false); - return this._enabled; - }, - - init: function() { - SystemAppProxy.addEventListener("mozAboutServiceWorkersContentEvent", - AboutServiceWorkers); - }, - - sendResult: function(aId, aResult) { - SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", { - id: aId, - result: aResult - }); - }, - - sendError: function(aId, aError) { - SystemAppProxy._sendCustomEvent("mozAboutServiceWorkersChromeEvent", { - id: aId, - error: aError - }); - }, - - handleEvent: function(aEvent) { - let message = aEvent.detail; - - debug("Got content event " + JSON.stringify(message)); - - if (!message.id || !message.name) { - dump("Invalid event " + JSON.stringify(message) + "\n"); - return; - } - - let self = AboutServiceWorkers; - - switch(message.name) { - case "init": - if (!self.enabled) { - self.sendResult(message.id, { - enabled: false, - registrations: [] - }); - return; - }; - - let data = gServiceWorkerManager.getAllRegistrations(); - if (!data) { - self.sendError(message.id, "NoServiceWorkersRegistrations"); - return; - } - - let registrations = []; - - for (let i = 0; i < data.length; i++) { - let info = data.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo); - if (!info) { - dump("AboutServiceWorkers: Invalid nsIServiceWorkerRegistrationInfo " + - "interface.\n"); - continue; - } - registrations.push(serializeServiceWorkerInfo(info)); - } - - self.sendResult(message.id, { - enabled: self.enabled, - registrations: registrations - }); - break; - - case "update": - if (!message.scope) { - self.sendError(message.id, "MissingScope"); - return; - } - - if (!message.principal || - !message.principal.originAttributes) { - self.sendError(message.id, "MissingOriginAttributes"); - return; - } - - gServiceWorkerManager.propagateSoftUpdate( - message.principal.originAttributes, - message.scope - ); - - self.sendResult(message.id, true); - break; - - case "unregister": - if (!message.principal || - !message.principal.origin || - !message.principal.originAttributes || - !message.principal.originAttributes.appId || - (message.principal.originAttributes.inIsolatedMozBrowser == null)) { - self.sendError(message.id, "MissingPrincipal"); - return; - } - - let principal = Services.scriptSecurityManager.createCodebasePrincipal( - // TODO: Bug 1196652. use originNoSuffix - Services.io.newURI(message.principal.origin), - message.principal.originAttributes); - - if (!message.scope) { - self.sendError(message.id, "MissingScope"); - return; - } - - let serviceWorkerUnregisterCallback = { - unregisterSucceeded: function() { - self.sendResult(message.id, true); - }, - - unregisterFailed: function() { - self.sendError(message.id, "UnregisterError"); - }, - - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIServiceWorkerUnregisterCallback - ]) - }; - gServiceWorkerManager.propagateUnregister(principal, - serviceWorkerUnregisterCallback, - message.scope); - break; - } - } -}; - -AboutServiceWorkers.init(); diff --git a/b2g/components/ActivityChannel.jsm b/b2g/components/ActivityChannel.jsm deleted file mode 100644 index 9dfa13d67caa..000000000000 --- a/b2g/components/ActivityChannel.jsm +++ /dev/null @@ -1,64 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsIMessageSender"); - -XPCOMUtils.defineLazyServiceGetter(this, "contentSecManager", - "@mozilla.org/contentsecuritymanager;1", - "nsIContentSecurityManager"); - -this.EXPORTED_SYMBOLS = ["ActivityChannel"]; - -this.ActivityChannel = function(aURI, aLoadInfo, aName, aDetails) { - this._activityName = aName; - this._activityDetails = aDetails; - this.originalURI = aURI; - this.URI = aURI; - this.loadInfo = aLoadInfo; -} - -this.ActivityChannel.prototype = { - originalURI: null, - URI: null, - owner: null, - notificationCallbacks: null, - securityInfo: null, - contentType: null, - contentCharset: null, - contentLength: 0, - contentDisposition: Ci.nsIChannel.DISPOSITION_INLINE, - contentDispositionFilename: null, - contentDispositionHeader: null, - loadInfo: null, - - open: function() { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - - open2: function() { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - - asyncOpen: function(aListener, aContext) { - cpmm.sendAsyncMessage(this._activityName, this._activityDetails); - // Let the listener cleanup. - aListener.onStopRequest(this, aContext, Cr.NS_OK); - }, - - asyncOpen2: function(aListener) { - // throws an error if security checks fail - var outListener = contentSecManager.performSecurityCheck(this, aListener); - this.asyncOpen(outListener, null); - }, - - QueryInterface2: XPCOMUtils.generateQI([Ci.nsIChannel]) -} diff --git a/b2g/components/AlertsHelper.jsm b/b2g/components/AlertsHelper.jsm deleted file mode 100644 index 746b99ca2c30..000000000000 --- a/b2g/components/AlertsHelper.jsm +++ /dev/null @@ -1,230 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = []; - -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cc = Components.classes; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", - "@mozilla.org/system-message-internal;1", - "nsISystemMessagesInternal"); - -XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", - "resource://gre/modules/SystemAppProxy.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "notificationStorage", - "@mozilla.org/notificationStorage;1", - "nsINotificationStorage"); - -XPCOMUtils.defineLazyGetter(this, "ppmm", function() { - return Cc["@mozilla.org/parentprocessmessagemanager;1"] - .getService(Ci.nsIMessageListenerManager); -}); - -function debug(str) { - //dump("=*= AlertsHelper.jsm : " + str + "\n"); -} - -const kNotificationIconSize = 128; - -const kNotificationSystemMessageName = "notification"; - -const kDesktopNotification = "desktop-notification"; -const kDesktopNotificationShow = "desktop-notification-show"; -const kDesktopNotificationClick = "desktop-notification-click"; -const kDesktopNotificationClose = "desktop-notification-close"; - -const kTopicAlertClickCallback = "alertclickcallback"; -const kTopicAlertShow = "alertshow"; -const kTopicAlertFinished = "alertfinished"; - -const kMozChromeNotificationEvent = "mozChromeNotificationEvent"; -const kMozContentNotificationEvent = "mozContentNotificationEvent"; - -const kMessageAlertNotificationSend = "alert-notification-send"; -const kMessageAlertNotificationClose = "alert-notification-close"; - -const kMessages = [ - kMessageAlertNotificationSend, - kMessageAlertNotificationClose -]; - -var AlertsHelper = { - - _listeners: {}, - - init: function() { - Services.obs.addObserver(this, "xpcom-shutdown"); - for (let message of kMessages) { - ppmm.addMessageListener(message, this); - } - SystemAppProxy.addEventListener(kMozContentNotificationEvent, this); - }, - - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case "xpcom-shutdown": - Services.obs.removeObserver(this, "xpcom-shutdown"); - for (let message of kMessages) { - ppmm.removeMessageListener(message, this); - } - SystemAppProxy.removeEventListener(kMozContentNotificationEvent, this); - break; - } - }, - - handleEvent: function(evt) { - let detail = evt.detail; - - switch(detail.type) { - case kDesktopNotificationShow: - case kDesktopNotificationClick: - case kDesktopNotificationClose: - this.handleNotificationEvent(detail); - break; - default: - debug("FIXME: Unhandled notification event: " + detail.type); - break; - } - }, - - handleNotificationEvent: function(detail) { - if (!detail || !detail.id) { - return; - } - - let uid = detail.id; - let listener = this._listeners[uid]; - if (!listener) { - return; - } - - let topic; - if (detail.type === kDesktopNotificationClick) { - topic = kTopicAlertClickCallback; - } else if (detail.type === kDesktopNotificationShow) { - topic = kTopicAlertShow; - } else { - /* kDesktopNotificationClose */ - topic = kTopicAlertFinished; - } - - if (listener.cookie) { - try { - listener.observer.observe(null, topic, listener.cookie); - } catch (e) { } - } else { - if (detail.type === kDesktopNotificationClose && listener.dbId) { - notificationStorage.delete(listener.manifestURL, listener.dbId); - } - } - - // we"re done with this notification - if (detail.type === kDesktopNotificationClose) { - delete this._listeners[uid]; - } - }, - - registerListener: function(alertId, cookie, alertListener) { - this._listeners[alertId] = { observer: alertListener, cookie: cookie }; - }, - - registerAppListener: function(uid, listener) { - this._listeners[uid] = listener; - }, - - deserializeStructuredClone: function(dataString) { - if (!dataString) { - return null; - } - let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"]. - createInstance(Ci.nsIStructuredCloneContainer); - - // The maximum supported structured-clone serialization format version - // as defined in "js/public/StructuredClone.h" - let JS_STRUCTURED_CLONE_VERSION = 4; - scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION); - let dataObj = scContainer.deserializeToVariant(); - - // We have to check whether dataObj contains DOM objects (supported by - // nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData. - // After the structured clone callback systems will be unified, we'll not - // have to perform this check anymore. - try { - let data = Cu.cloneInto(dataObj, {}); - } catch(e) { dataObj = null; } - - return dataObj; - }, - - showNotification: function(imageURL, title, text, textClickable, cookie, - uid, dir, lang, dataObj, manifestURL, timestamp, - behavior) { - function send(appName, appIcon) { - SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, { - type: kDesktopNotification, - id: uid, - icon: imageURL, - title: title, - text: text, - dir: dir, - lang: lang, - appName: appName, - appIcon: appIcon, - manifestURL: manifestURL, - timestamp: timestamp, - data: dataObj, - mozbehavior: behavior - }); - } - - if (!manifestURL || !manifestURL.length) { - send(null, null); - return; - } - }, - - showAlertNotification: function(aMessage) { - let data = aMessage.data; - let currentListener = this._listeners[data.name]; - if (currentListener && currentListener.observer) { - currentListener.observer.observe(null, kTopicAlertFinished, currentListener.cookie); - } - - let dataObj = this.deserializeStructuredClone(data.dataStr); - this.registerListener(data.name, data.cookie, data.alertListener); - this.showNotification(data.imageURL, data.title, data.text, - data.textClickable, data.cookie, data.name, data.dir, - data.lang, dataObj, null, data.inPrivateBrowsing); - }, - - closeAlert: function(name) { - SystemAppProxy._sendCustomEvent(kMozChromeNotificationEvent, { - type: kDesktopNotificationClose, - id: name - }); - }, - - receiveMessage: function(aMessage) { - switch(aMessage.name) { - case kMessageAlertNotificationSend: - this.showAlertNotification(aMessage); - break; - - case kMessageAlertNotificationClose: - this.closeAlert(aMessage.data.name); - break; - } - - }, -} - -AlertsHelper.init(); diff --git a/b2g/components/AlertsService.js b/b2g/components/AlertsService.js deleted file mode 100644 index 8f295525805a..000000000000 --- a/b2g/components/AlertsService.js +++ /dev/null @@ -1,153 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const Ci = Components.interfaces; -const Cu = Components.utils; -const Cc = Components.classes; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", - "@mozilla.org/system-message-internal;1", - "nsISystemMessagesInternal"); - -XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -XPCOMUtils.defineLazyServiceGetter(this, "notificationStorage", - "@mozilla.org/notificationStorage;1", - "nsINotificationStorage"); - -XPCOMUtils.defineLazyGetter(this, "cpmm", function() { - return Cc["@mozilla.org/childprocessmessagemanager;1"] - .getService(Ci.nsIMessageSender); -}); - -function debug(str) { - dump("=*= AlertsService.js : " + str + "\n"); -} - -// ----------------------------------------------------------------------- -// Alerts Service -// ----------------------------------------------------------------------- - -const kNotificationSystemMessageName = "notification"; - -const kMessageAlertNotificationSend = "alert-notification-send"; -const kMessageAlertNotificationClose = "alert-notification-close"; - -const kTopicAlertShow = "alertshow"; -const kTopicAlertFinished = "alertfinished"; -const kTopicAlertClickCallback = "alertclickcallback"; - -function AlertsService() { - Services.obs.addObserver(this, "xpcom-shutdown"); -} - -AlertsService.prototype = { - classID: Components.ID("{fe33c107-82a4-41d6-8c64-5353267e04c9}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAlertsService, - Ci.nsIObserver]), - - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case "xpcom-shutdown": - Services.obs.removeObserver(this, "xpcom-shutdown"); - break; - } - }, - - // nsIAlertsService - showAlert: function(aAlert, aAlertListener) { - if (!aAlert) { - return; - } - cpmm.sendAsyncMessage(kMessageAlertNotificationSend, { - imageURL: aAlert.imageURL, - title: aAlert.title, - text: aAlert.text, - clickable: aAlert.textClickable, - cookie: aAlert.cookie, - listener: aAlertListener, - id: aAlert.name, - dir: aAlert.dir, - lang: aAlert.lang, - dataStr: aAlert.data, - inPrivateBrowsing: aAlert.inPrivateBrowsing - }); - }, - - showAlertNotification: function(aImageUrl, aTitle, aText, aTextClickable, - aCookie, aAlertListener, aName, aBidi, - aLang, aDataStr, aPrincipal, - aInPrivateBrowsing) { - let alert = Cc["@mozilla.org/alert-notification;1"]. - createInstance(Ci.nsIAlertNotification); - - alert.init(aName, aImageUrl, aTitle, aText, aTextClickable, aCookie, - aBidi, aLang, aDataStr, aPrincipal, aInPrivateBrowsing); - - this.showAlert(alert, aAlertListener); - }, - - closeAlert: function(aName) { - cpmm.sendAsyncMessage(kMessageAlertNotificationClose, { - name: aName - }); - }, - - // AlertsService.js custom implementation - _listeners: [], - - receiveMessage: function(aMessage) { - let data = aMessage.data; - let listener = this._listeners[data.uid]; - if (!listener) { - return; - } - - let topic = data.topic; - - try { - listener.observer.observe(null, topic, null); - } catch (e) { - if (topic === kTopicAlertFinished && listener.dbId) { - notificationStorage.delete(listener.manifestURL, listener.dbId); - } - } - - // we're done with this notification - if (topic === kTopicAlertFinished) { - delete this._listeners[data.uid]; - } - }, - - deserializeStructuredClone: function(dataString) { - if (!dataString) { - return null; - } - let scContainer = Cc["@mozilla.org/docshell/structured-clone-container;1"]. - createInstance(Ci.nsIStructuredCloneContainer); - - // The maximum supported structured-clone serialization format version - // as defined in "js/public/StructuredClone.h" - let JS_STRUCTURED_CLONE_VERSION = 4; - scContainer.initFromBase64(dataString, JS_STRUCTURED_CLONE_VERSION); - let dataObj = scContainer.deserializeToVariant(); - - // We have to check whether dataObj contains DOM objects (supported by - // nsIStructuredCloneContainer, but not by Cu.cloneInto), e.g. ImageData. - // After the structured clone callback systems will be unified, we'll not - // have to perform this check anymore. - try { - let data = Cu.cloneInto(dataObj, {}); - } catch(e) { dataObj = null; } - - return dataObj; - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AlertsService]); diff --git a/b2g/components/B2GAboutRedirector.js b/b2g/components/B2GAboutRedirector.js deleted file mode 100644 index fb874133e578..000000000000 --- a/b2g/components/B2GAboutRedirector.js +++ /dev/null @@ -1,78 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const Cc = Components.classes; -const Ci = Components.interfaces; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -function debug(msg) { - //dump("B2GAboutRedirector: " + msg + "\n"); -} - -function netErrorURL() { - let systemManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url"); - systemManifestURL = Services.io.newURI(systemManifestURL); - let netErrorURL = Services.prefs.getCharPref("b2g.neterror.url"); - netErrorURL = Services.io.newURI(netErrorURL, null, systemManifestURL); - return netErrorURL.spec; -} - -var modules = { - certerror: { - uri: "chrome://b2g/content/aboutCertError.xhtml", - privileged: false, - hide: true - }, - neterror: { - uri: netErrorURL(), - privileged: false, - hide: true - } -}; - -function B2GAboutRedirector() {} -B2GAboutRedirector.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]), - classID: Components.ID("{920400b1-cf8f-4760-a9c4-441417b15134}"), - - _getModuleInfo: function (aURI) { - let moduleName = aURI.path.replace(/[?#].*/, "").toLowerCase(); - return modules[moduleName]; - }, - - // nsIAboutModule - getURIFlags: function(aURI) { - let flags; - let moduleInfo = this._getModuleInfo(aURI); - if (moduleInfo.hide) - flags = Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT; - - return flags | Ci.nsIAboutModule.ALLOW_SCRIPT; - }, - - newChannel: function(aURI, aLoadInfo) { - let moduleInfo = this._getModuleInfo(aURI); - - var ios = Cc["@mozilla.org/network/io-service;1"]. - getService(Ci.nsIIOService); - - var newURI = ios.newURI(moduleInfo.uri); - - var channel = ios.newChannelFromURIWithLoadInfo(newURI, aLoadInfo); - - if (!moduleInfo.privileged) { - // Setting the owner to null means that we'll go through the normal - // path in GetChannelPrincipal and create a codebase principal based - // on the channel's originalURI - channel.owner = null; - } - - channel.originalURI = aURI; - - return channel; - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GAboutRedirector]); diff --git a/b2g/components/B2GComponents.manifest b/b2g/components/B2GComponents.manifest deleted file mode 100644 index 7247562632b3..000000000000 --- a/b2g/components/B2GComponents.manifest +++ /dev/null @@ -1,97 +0,0 @@ -# Scrollbars -category agent-style-sheets browser-content-stylesheet chrome://b2g/content/content.css - -# AlertsService.js -component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js -contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9} - -# ContentPermissionPrompt.js -component {8c719f03-afe0-4aac-91ff-6c215895d467} ContentPermissionPrompt.js -contract @mozilla.org/content-permission/prompt;1 {8c719f03-afe0-4aac-91ff-6c215895d467} - -#ifdef MOZ_B2G -# DirectoryProvider.js -component {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5} DirectoryProvider.js -contract @mozilla.org/b2g/directory-provider;1 {9181eb7c-6f87-11e1-90b1-4f59d80dd2e5} -category xpcom-directory-providers b2g-directory-provider @mozilla.org/b2g/directory-provider;1 -#endif - -# SystemMessageGlue.js -component {2846f034-e614-11e3-93cd-74d02b97e723} SystemMessageGlue.js -contract @mozilla.org/dom/messages/system-message-glue;1 {2846f034-e614-11e3-93cd-74d02b97e723} - -# ProcessGlobal.js -component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js -contract @mozilla.org/b2g-process-global;1 {1a94c87a-5ece-4d11-91e1-d29c29f21b28} -category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1 - -# OMAContentHandler.js -component {a6b2ab13-9037-423a-9897-dde1081be323} OMAContentHandler.js -contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.oma.drm.message {a6b2ab13-9037-423a-9897-dde1081be323} -contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.oma.dd+xml {a6b2ab13-9037-423a-9897-dde1081be323} - -# TelProtocolHandler.js -component {782775dd-7351-45ea-aff1-0ffa872cfdd2} TelProtocolHandler.js -contract @mozilla.org/network/protocol;1?name=tel {782775dd-7351-45ea-aff1-0ffa872cfdd2} - -# SmsProtocolHandler.js -component {81ca20cb-0dad-4e32-8566-979c8998bd73} SmsProtocolHandler.js -contract @mozilla.org/network/protocol;1?name=sms {81ca20cb-0dad-4e32-8566-979c8998bd73} - -# MailtoProtocolHandler.js -component {50777e53-0331-4366-a191-900999be386c} MailtoProtocolHandler.js -contract @mozilla.org/network/protocol;1?name=mailto {50777e53-0331-4366-a191-900999be386c} - -# RecoveryService.js -component {b3caca5d-0bb0-48c6-912b-6be6cbf08832} RecoveryService.js -contract @mozilla.org/recovery-service;1 {b3caca5d-0bb0-48c6-912b-6be6cbf08832} - -# B2GAboutRedirector -component {920400b1-cf8f-4760-a9c4-441417b15134} B2GAboutRedirector.js -contract @mozilla.org/network/protocol/about;1?what=certerror {920400b1-cf8f-4760-a9c4-441417b15134} -contract @mozilla.org/network/protocol/about;1?what=neterror {920400b1-cf8f-4760-a9c4-441417b15134} - -#ifndef MOZ_GRAPHENE -# FilePicker.js -component {436ff8f9-0acc-4b11-8ec7-e293efba3141} FilePicker.js -contract @mozilla.org/filepicker;1 {436ff8f9-0acc-4b11-8ec7-e293efba3141} -#endif - -# FxAccountsUIGlue.js -component {51875c14-91d7-4b8c-b65d-3549e101228c} FxAccountsUIGlue.js -contract @mozilla.org/fxaccounts/fxaccounts-ui-glue;1 {51875c14-91d7-4b8c-b65d-3549e101228c} - -# HelperAppDialog.js -component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js -contract @mozilla.org/helperapplauncherdialog;1 {710322af-e6ae-4b0c-b2c9-1474a87b077e} - -#ifndef MOZ_WIDGET_GONK -component {c83c02c0-5d43-4e3e-987f-9173b313e880} SimulatorScreen.js -contract @mozilla.org/simulator-screen;1 {c83c02c0-5d43-4e3e-987f-9173b313e880} -category profile-after-change SimulatorScreen @mozilla.org/simulator-screen;1 - -component {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e} OopCommandLine.js -contract @mozilla.org/commandlinehandler/general-startup;1?type=b2goop {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e} -category command-line-handler m-b2goop @mozilla.org/commandlinehandler/general-startup;1?type=b2goop - -component {385993fe-8710-4621-9fb1-00a09d8bec37} CommandLine.js -contract @mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds {385993fe-8710-4621-9fb1-00a09d8bec37} -category command-line-handler m-b2gcmds @mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds -#endif - -# BootstrapCommandLine.js -component {fd663ec8-cf3f-4c2b-aacb-17a6915ccb44} BootstrapCommandLine.js -contract @mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap {fd663ec8-cf3f-4c2b-aacb-17a6915ccb44} -category command-line-handler m-b2gbootstrap @mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap - -# B2GPresentationDevicePrompt.js -component {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} B2GPresentationDevicePrompt.js -contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} - -# PresentationRequestUIGlue.js -component {ccc8a839-0b64-422b-8a60-fb2af0e376d0} PresentationRequestUIGlue.js -contract @mozilla.org/presentation/requestuiglue;1 {ccc8a839-0b64-422b-8a60-fb2af0e376d0} - -# SystemMessageInternal.js -component {70589ca5-91ac-4b9e-b839-d6a88167d714} SystemMessageInternal.js -contract @mozilla.org/system-message-internal;1 {70589ca5-91ac-4b9e-b839-d6a88167d714} diff --git a/b2g/components/B2GPresentationDevicePrompt.js b/b2g/components/B2GPresentationDevicePrompt.js deleted file mode 100644 index 998e0b7ac0d7..000000000000 --- a/b2g/components/B2GPresentationDevicePrompt.js +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -function debug(aMsg) { - //dump("-*- B2GPresentationDevicePrompt: " + aMsg + "\n"); -} - -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; - -const kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID = "@mozilla.org/presentation-device/prompt;1"; -const kB2GPRESENTATIONDEVICEPROMPT_CID = Components.ID("{4a300c26-e99b-4018-ab9b-c48cf9bc4de1}"); - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", - "resource://gre/modules/SystemAppProxy.jsm"); - -function B2GPresentationDevicePrompt() {} - -B2GPresentationDevicePrompt.prototype = { - classID: kB2GPRESENTATIONDEVICEPROMPT_CID, - contractID: kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID, - classDescription: "B2G Presentation Device Prompt", - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt]), - - // nsIPresentationDevicePrompt - promptDeviceSelection: function(aRequest) { - let self = this; - let requestId = Cc["@mozilla.org/uuid-generator;1"] - .getService(Ci.nsIUUIDGenerator).generateUUID().toString(); - - SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(aEvent) { - let detail = aEvent.detail; - if (detail.id !== requestId) { - return; - } - - SystemAppProxy.removeEventListener("mozContentEvent", contentEvent); - - switch (detail.type) { - case "presentation-select-result": - debug("device " + detail.deviceId + " is selected by user"); - let device = self._getDeviceById(detail.deviceId); - if (!device) { - debug("cancel request because device is not found"); - aRequest.cancel(Cr.NS_ERROR_DOM_NOT_FOUND_ERR); - } - aRequest.select(device); - break; - case "presentation-select-deny": - debug("request canceled by user"); - aRequest.cancel(Cr.NS_ERROR_DOM_NOT_ALLOWED_ERR); - break; - } - }); - - let detail = { - type: "presentation-select-device", - origin: aRequest.origin, - requestURL: aRequest.requestURL, - id: requestId, - }; - - SystemAppProxy.dispatchEvent(detail); - }, - - _getDeviceById: function(aDeviceId) { - let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"] - .getService(Ci.nsIPresentationDeviceManager); - let devices = deviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray); - - for (let i = 0; i < devices.length; i++) { - let device = devices.queryElementAt(i, Ci.nsIPresentationDevice); - if (device.id === aDeviceId) { - return device; - } - } - - return null; - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GPresentationDevicePrompt]); diff --git a/b2g/components/BootstrapCommandLine.js b/b2g/components/BootstrapCommandLine.js deleted file mode 100644 index 7ed09c4aa485..000000000000 --- a/b2g/components/BootstrapCommandLine.js +++ /dev/null @@ -1,46 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -function BootstrapCommandlineHandler() { - this.wrappedJSObject = this; - this.startManifestURL = null; -} - -BootstrapCommandlineHandler.prototype = { - bailout: function(aMsg) { - dump("************************************************************\n"); - dump("* /!\\ " + aMsg + "\n"); - dump("************************************************************\n"); - let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - appStartup.quit(appStartup.eForceQuit); - }, - - handle: function(aCmdLine) { - this.startManifestURL = null; - - try { - // Returns null if the argument was not specified. Throws - // NS_ERROR_INVALID_ARG if there is no parameter specified (because - // it was the last argument or the next argument starts with '-'). - // However, someone could still explicitly pass an empty argument! - this.startManifestURL = aCmdLine.handleFlagWithParam("start-manifest", false); - } catch(e) { - return; - } - - if (!this.startManifestURL) { - return; - } - }, - - helpInfo: "--start-manifest=manifest_url", - classID: Components.ID("{fd663ec8-cf3f-4c2b-aacb-17a6915ccb44}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BootstrapCommandlineHandler]); diff --git a/b2g/components/Bootstraper.jsm b/b2g/components/Bootstraper.jsm deleted file mode 100644 index 863cc3381f6c..000000000000 --- a/b2g/components/Bootstraper.jsm +++ /dev/null @@ -1,126 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["Bootstraper"]; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cu = Components.utils; -const CC = Components.Constructor; - -Cu.import("resource://gre/modules/Services.jsm"); - -function debug(aMsg) { - //dump("-*- Bootstraper: " + aMsg + "\n"); -} - -/** - * This module loads the manifest for app from the --start-url enpoint and - * ensures that it's installed as the system app. - */ -this.Bootstraper = { - _manifestURL: null, - - bailout: function(aMsg) { - dump("************************************************************\n"); - dump("* /!\\ " + aMsg + "\n"); - dump("************************************************************\n"); - let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - appStartup.quit(appStartup.eForceQuit); - }, - - /** - * Resolves to a json manifest. - */ - loadManifest: function() { - return new Promise((aResolve, aReject) => { - debug("Loading manifest " + this._manifestURL); - - let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Ci.nsIXMLHttpRequest); - xhr.mozBackgroundRequest = true; - xhr.open("GET", this._manifestURL); - xhr.responseType = "json"; - xhr.addEventListener("load", () => { - if (xhr.status >= 200 && xhr.status < 400) { - debug("Success loading " + this._manifestURL); - aResolve(xhr.response); - } else { - aReject("Error loading " + this._manifestURL); - } - }); - xhr.addEventListener("error", () => { - aReject("Error loading " + this._manifestURL); - }); - xhr.send(null); - }); - }, - - configure: function() { - Services.prefs.setCharPref("b2g.system_manifest_url", this._manifestURL); - Services.prefs.setCharPref("b2g.system_startup_url", ""); - return Promise.resolve(); - }, - - /** - * If a system app is already installed, uninstall it so that we can - * cleanly replace it by the current one. - */ - uninstallPreviousSystemApp: function() { - // TODO: FIXME - return Promise.resolve(); - - let oldManifestURL; - // eslint-disable-next-line mozilla/use-default-preference-values - try{ - oldManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url"); - } catch(e) { - // No preference set, so nothing to uninstall. - return Promise.resolve(); - } - - let id = DOMApplicationRegistry.getAppLocalIdByManifestURL(oldManifestURL); - if (id == Ci.nsIScriptSecurityManager.NO_APP_ID) { - return Promise.resolve(); - } - debug("Uninstalling " + oldManifestURL); - return DOMApplicationRegistry.uninstall(oldManifestURL); - }, - - /** - * Check if we are already configured to run from this manifest url. - */ - isInstallRequired: function(aManifestURL) { - try { - if (Services.prefs.getCharPref("b2g.system_manifest_url") == aManifestURL) { - return false; - } - } catch(e) { } - return true; - }, - - /** - * Resolves once we have installed the app. - */ - ensureSystemAppInstall: function(aManifestURL) { - this._manifestURL = aManifestURL; - debug("Installing app from " + this._manifestURL); - - if (!this.isInstallRequired(this._manifestURL)) { - debug("Already configured for " + this._manifestURL); - return Promise.resolve(); - } - - return new Promise((aResolve, aReject) => { - this.uninstallPreviousSystemApp.bind(this) - .then(this.loadManifest.bind(this)) - .then(this.configure.bind(this)) - .then(aResolve) - .catch(aReject); - }); - } -}; diff --git a/b2g/components/CommandLine.js b/b2g/components/CommandLine.js deleted file mode 100644 index 6dc48bd3389f..000000000000 --- a/b2g/components/CommandLine.js +++ /dev/null @@ -1,29 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); - -// Small helper to expose nsICommandLine object to chrome code - -function CommandlineHandler() { - this.wrappedJSObject = this; -} - -CommandlineHandler.prototype = { - handle: function(cmdLine) { - this.cmdLine = cmdLine; - let win = Services.wm.getMostRecentWindow("navigator:browser"); - if (win && win.shell) { - win.shell.handleCmdLine(); - } - }, - - helpInfo: "", - classID: Components.ID("{385993fe-8710-4621-9fb1-00a09d8bec37}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CommandlineHandler]); diff --git a/b2g/components/ContentPermissionPrompt.js b/b2g/components/ContentPermissionPrompt.js deleted file mode 100644 index 965f9090df45..000000000000 --- a/b2g/components/ContentPermissionPrompt.js +++ /dev/null @@ -1,315 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict" - -function debug(str) { - //dump("-*- ContentPermissionPrompt: " + str + "\n"); -} - -const Ci = Components.interfaces; -const Cr = Components.results; -const Cu = Components.utils; -const Cc = Components.classes; - -const PROMPT_FOR_UNKNOWN = ["desktop-notification", - "geolocation"]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); -var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); - -var permissionSpecificChecker = {}; - -XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", - "resource://gre/modules/SystemAppProxy.jsm"); - -/** - * Determine if a permission should be prompt to user or not. - * - * @param aPerm requested permission - * @param aAction the action according to principal - * @return true if prompt is required - */ -function shouldPrompt(aPerm, aAction) { - return ((aAction == Ci.nsIPermissionManager.PROMPT_ACTION) || - (aAction == Ci.nsIPermissionManager.UNKNOWN_ACTION && - PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)); -} - -/** - * Create the default choices for the requested permissions - * - * @param aTypesInfo requested permissions - * @return the default choices for permissions with options, return - * undefined if no option in all requested permissions. - */ -function buildDefaultChoices(aTypesInfo) { - let choices; - for (let type of aTypesInfo) { - if (type.options.length > 0) { - if (!choices) { - choices = {}; - } - choices[type.access] = type.options[0]; - } - } - return choices; -} - -function ContentPermissionPrompt() {} - -ContentPermissionPrompt.prototype = { - - handleExistingPermission: function handleExistingPermission(request, - typesInfo) { - typesInfo.forEach(function(type) { - type.action = - Services.perms.testExactPermissionFromPrincipal(request.principal, - type.access); - if (shouldPrompt(type.access, type.action)) { - type.action = Ci.nsIPermissionManager.PROMPT_ACTION; - } - }); - - // If all permissions are allowed already and no more than one option, - // call allow() without prompting. - let checkAllowPermission = function(type) { - if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION && - type.options.length <= 1) { - return true; - } - return false; - } - if (typesInfo.every(checkAllowPermission)) { - debug("all permission requests are allowed"); - request.allow(buildDefaultChoices(typesInfo)); - return true; - } - - // If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel() - // without prompting. - let checkDenyPermission = function(type) { - if (type.action == Ci.nsIPermissionManager.DENY_ACTION || - type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION) { - return true; - } - return false; - } - if (typesInfo.every(checkDenyPermission)) { - debug("all permission requests are denied"); - request.cancel(); - return true; - } - return false; - }, - - handledByPermissionType: function handledByPermissionType(request, typesInfo) { - for (let i in typesInfo) { - if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) && - permissionSpecificChecker[typesInfo[i].permission](request)) { - return true; - } - } - - return false; - }, - - prompt: function(request) { - // Initialize the typesInfo and set the default value. - let typesInfo = []; - let perms = request.types.QueryInterface(Ci.nsIArray); - for (let idx = 0; idx < perms.length; idx++) { - let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType); - let tmp = { - permission: perm.type, - access: (perm.access && perm.access !== "unused") ? - perm.type + "-" + perm.access : perm.type, - options: [], - deny: true, - action: Ci.nsIPermissionManager.UNKNOWN_ACTION - }; - - // Append available options, if any. - let options = perm.options.QueryInterface(Ci.nsIArray); - for (let i = 0; i < options.length; i++) { - let option = options.queryElementAt(i, Ci.nsISupportsString).data; - tmp.options.push(option); - } - typesInfo.push(tmp); - } - - if (secMan.isSystemPrincipal(request.principal)) { - request.allow(buildDefaultChoices(typesInfo)); - return; - } - - - if (typesInfo.length == 0) { - request.cancel(); - return; - } - - if (this.handledByPermissionType(request, typesInfo)) { - return; - } - - // returns true if the request was handled - if (this.handleExistingPermission(request, typesInfo)) { - return; - } - - // prompt PROMPT_ACTION request or request with options. - typesInfo = typesInfo.filter(function(type) { - return !type.deny && (type.action == Ci.nsIPermissionManager.PROMPT_ACTION || type.options.length > 0) ; - }); - - if (!request.element) { - this.delegatePrompt(request, typesInfo); - return; - } - - var cancelRequest = function() { - request.requester.onVisibilityChange = null; - request.cancel(); - } - - var self = this; - - // If the request was initiated from a hidden iframe - // we don't forward it to content and cancel it right away - request.requester.getVisibility( { - notifyVisibility: function(isVisible) { - if (!isVisible) { - cancelRequest(); - return; - } - - // Monitor the frame visibility and cancel the request if the frame goes - // away but the request is still here. - request.requester.onVisibilityChange = { - notifyVisibility: function(isVisible) { - if (isVisible) - return; - - self.cancelPrompt(request, typesInfo); - cancelRequest(); - } - } - - self.delegatePrompt(request, typesInfo, function onCallback() { - request.requester.onVisibilityChange = null; - }); - } - }); - - }, - - cancelPrompt: function(request, typesInfo) { - this.sendToBrowserWindow("cancel-permission-prompt", request, - typesInfo); - }, - - delegatePrompt: function(request, typesInfo, callback) { - this.sendToBrowserWindow("permission-prompt", request, typesInfo, - function(type, remember, choices) { - if (type == "permission-allow") { - if (callback) { - callback(); - } - request.allow(choices); - return; - } - - let addDenyPermission = function(type) { - debug("add " + type.permission + - " to permission manager with DENY_ACTION"); - if (remember) { - Services.perms.addFromPrincipal(request.principal, type.access, - Ci.nsIPermissionManager.DENY_ACTION); - } - } - try { - // This will trow if we are canceling because the remote process died. - // Just eat the exception and call the callback that will cleanup the - // visibility event listener. - typesInfo.forEach(addDenyPermission); - } catch(e) { } - - if (callback) { - callback(); - } - - try { - request.cancel(); - } catch(e) { } - }); - }, - - sendToBrowserWindow: function(type, request, typesInfo, callback) { - let requestId = Cc["@mozilla.org/uuid-generator;1"] - .getService(Ci.nsIUUIDGenerator).generateUUID().toString(); - if (callback) { - SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(evt) { - let detail = evt.detail; - if (detail.id != requestId) - return; - SystemAppProxy.removeEventListener("mozContentEvent", contentEvent); - - callback(detail.type, detail.remember, detail.choices); - }) - } - - let principal = request.principal; - let remember = request.remember; - let isGranted = typesInfo.every(function(type) { - return type.action == Ci.nsIPermissionManager.ALLOW_ACTION; - }); - let permissions = {}; - for (let i in typesInfo) { - debug("prompt " + typesInfo[i].permission); - permissions[typesInfo[i].permission] = typesInfo[i].options; - } - - let details = { - type: type, - permissions: permissions, - id: requestId, - // This system app uses the origin from permission events to - // compare against the mozApp.origin of app windows, so we - // are not concerned with origin suffixes here (appId, etc). - origin: principal.originNoSuffix, - isApp: false, - remember: remember, - isGranted: isGranted, - }; - - // request.element is defined for OOP content, while request.window - // is defined for In-Process content. - // In both cases the message needs to be dispatched to the top-level - // I'm a normal link -Back in browser history -Forward in browser history I go to an anchor I open a window with javascript Click me diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index 96204edc5ae8..1d0899879896 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -117,10 +117,8 @@ var sandboxName = "default"; */ var loadListener = { command_id: null, - seenUnload: null, timeout: null, - timerPageLoad: null, - timerPageUnload: null, + timer: null, /** * Start listening for page unload/load events. @@ -138,44 +136,35 @@ var loadListener = { this.command_id = command_id; this.timeout = timeout; - this.seenUnload = false; - - this.timerPageLoad = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this.timerPageUnload = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - // In case of a remoteness change, only wait the remaining time timeout = startTime + timeout - new Date().getTime(); if (timeout <= 0) { - this.notify(this.timerPageLoad); + this.notify(); return; } + this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + this.timer.initWithCallback(this, timeout, Ci.nsITimer.TYPE_ONE_SHOT); + if (waitForUnloaded) { - addEventListener("beforeunload", this, false); addEventListener("hashchange", this, false); addEventListener("pagehide", this, false); } else { addEventListener("DOMContentLoaded", loadListener, false); addEventListener("pageshow", loadListener, false); } - - this.timerPageLoad.initWithCallback(this, timeout, Ci.nsITimer.TYPE_ONE_SHOT); }, /** * Stop listening for page unload/load events. */ stop: function () { - if (this.timerPageLoad) { - this.timerPageLoad.cancel(); + if (this.timer) { + this.timer.cancel(); + this.timer = null; } - if (this.timerPageUnload) { - this.timerPageUnload.cancel(); - } - - removeEventListener("beforeunload", this); removeEventListener("hashchange", this); removeEventListener("pagehide", this); removeEventListener("DOMContentLoaded", this); @@ -186,16 +175,9 @@ var loadListener = { * Callback for registered DOM events. */ handleEvent: function (event) { - logger.debug(`Handled DOM event "${event.type}" for "${event.originalTarget.baseURI}"`); - switch (event.type) { - case "beforeunload": - this.seenUnload = true; - break; - case "pagehide": if (event.originalTarget === curContainer.frame.document) { - removeEventListener("beforeunload", this); removeEventListener("hashchange", this); removeEventListener("pagehide", this); @@ -241,23 +223,9 @@ var loadListener = { * Callback for navigation timeout timer. */ notify: function (timer) { - switch (timer) { - // If the page unload timer is raised, ensure to properly stop the load - // listener, and return from the currently active command. - case this.timerPageUnload: - if (!this.seenUnload) { - logger.debug("Canceled page load listener because no page unload has been detected"); - this.stop(); - sendOk(this.command_id); - } - break; - - case this.timerPageLoad: - this.stop(); - sendError(new TimeoutError(`Timeout loading page after ${this.timeout}ms`), - this.command_id); - break; - } + this.stop(); + sendError(new TimeoutError("Timeout loading page after " + this.timeout + "ms"), + this.command_id); }, /** @@ -284,39 +252,40 @@ var loadListener = { * ID of the currently handled message between the driver and listener. * @param {number} pageTimeout * Timeout in milliseconds the method has to wait for the page being finished loading. - * @param {boolean=} loadEventExpected - * TODO * @param {string=} url * Optional URL, which is used to check if a page load is expected. */ - navigate: function (trigger, command_id, timeout, loadEventExpected = true, - useUnloadTimer = false) { + navigate: function (trigger, command_id, timeout, url = undefined) { + let loadEventExpected = true; + + if (typeof url == "string") { + try { + let requestedURL = new URL(url).toString(); + loadEventExpected = navigate.isLoadEventExpected(requestedURL); + } catch (e) { + sendError(new InvalidArgumentError("Malformed URL: " + e.message), command_id); + return; + } + } + if (loadEventExpected) { let startTime = new Date().getTime(); this.start(command_id, timeout, startTime, true); } - return Task.spawn(function* () { - yield trigger(); - - }).then(val => { - if (loadEventExpected) { - // Setup timer to detect a possible page load - if (useUnloadTimer) { - this.timerPageUnload.initWithCallback(this, "200", Ci.nsITimer.TYPE_ONE_SHOT); - } - } else { - sendOk(command_id); - } - - }).catch(err => { + try { + trigger(); + } catch (e) { if (loadEventExpected) { this.stop(); } - - sendError(err, command_id); + sendError(new UnknownCommandError(e.message), command_id); return; - }); + } + + if (!loadEventExpected) { + sendOk(command_id); + } }, } @@ -429,6 +398,7 @@ function removeMessageListenerId(messageName, handler) { var getTitleFn = dispatch(getTitle); var getPageSourceFn = dispatch(getPageSource); var getActiveElementFn = dispatch(getActiveElement); +var clickElementFn = dispatch(clickElement); var getElementAttributeFn = dispatch(getElementAttribute); var getElementPropertyFn = dispatch(getElementProperty); var getElementTextFn = dispatch(getElementText); @@ -483,7 +453,7 @@ function startListeners() { addMessageListenerId("Marionette:findElementContent", findElementContentFn); addMessageListenerId("Marionette:findElementsContent", findElementsContentFn); addMessageListenerId("Marionette:getActiveElement", getActiveElementFn); - addMessageListenerId("Marionette:clickElement", clickElement); + addMessageListenerId("Marionette:clickElement", clickElementFn); addMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn); addMessageListenerId("Marionette:getElementProperty", getElementPropertyFn); addMessageListenerId("Marionette:getElementText", getElementTextFn); @@ -588,7 +558,7 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:findElementContent", findElementContentFn); removeMessageListenerId("Marionette:findElementsContent", findElementsContentFn); removeMessageListenerId("Marionette:getActiveElement", getActiveElementFn); - removeMessageListenerId("Marionette:clickElement", clickElement); + removeMessageListenerId("Marionette:clickElement", clickElementFn); removeMessageListenerId("Marionette:getElementAttribute", getElementAttributeFn); removeMessageListenerId("Marionette:getElementProperty", getElementPropertyFn); removeMessageListenerId("Marionette:getElementText", getElementTextFn); @@ -1127,26 +1097,15 @@ function waitForPageLoaded(msg) { */ function get(msg) { let {command_id, pageTimeout, url} = msg.json; - let loadEventExpected = true; try { - if (typeof url == "string") { - try { - let requestedURL = new URL(url).toString(); - loadEventExpected = navigate.isLoadEventExpected(requestedURL); - } catch (e) { - sendError(new InvalidArgumentError("Malformed URL: " + e.message), command_id); - return; - } - } - // We need to move to the top frame before navigating sendSyncMessage("Marionette:switchedToFrame", {frameValue: null}); curContainer.frame = content; loadListener.navigate(() => { curContainer.frame.location = url; - }, command_id, pageTimeout, loadEventExpected); + }, command_id, pageTimeout, url); } catch (e) { sendError(e, command_id); @@ -1292,36 +1251,15 @@ function getActiveElement() { /** * Send click event to element. * - * @param {number} command_id - * ID of the currently handled message between the driver and listener. * @param {WebElement} id * Reference to the web element to click. - * @param {number} pageTimeout - * Timeout in milliseconds the method has to wait for the page being finished loading. */ -function clickElement(msg) { - let {command_id, id, pageTimeout} = msg.json; - - try { - let loadEventExpected = true; - - let target = getElementAttribute(id, "target"); - - if (target === "_blank") { - loadEventExpected = false; - } - - loadListener.navigate(() => { - return interaction.clickElement( - seenEls.get(id, curContainer), - capabilities.get("moz:accessibilityChecks"), - capabilities.get("specificationLevel") >= 1 - ); - }, command_id, pageTimeout, loadEventExpected, true); - - } catch (e) { - sendError(e, command_id); - } +function clickElement(id) { + let el = seenEls.get(id, curContainer); + return interaction.clickElement( + el, + capabilities.get("moz:accessibilityChecks"), + capabilities.get("specificationLevel") >= 1); } function getElementAttribute(id, name) { diff --git a/testing/marionette/server.js b/testing/marionette/server.js index ce46eb1cf5ef..cd32aa39790a 100644 --- a/testing/marionette/server.js +++ b/testing/marionette/server.js @@ -126,8 +126,8 @@ const RECOMMENDED_PREFS = new Map([ // Do not redirect user when a milstone upgrade of Firefox is detected ["browser.startup.homepage_override.mstone", "ignore"], - // Disable tab animation - ["browser.tabs.animate", false], + // Disable browser animations + ["toolkit.cosmeticAnimations.enabled", false], // Do not allow background tabs to be zombified, otherwise for tests // that open additional tabs, the test harness tab itself might get diff --git a/testing/mozharness/mozharness/mozilla/building/buildbase.py b/testing/mozharness/mozharness/mozilla/building/buildbase.py index ae91e00f0e69..e644f670dc25 100755 --- a/testing/mozharness/mozharness/mozilla/building/buildbase.py +++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py @@ -2019,13 +2019,22 @@ or run without that action (ie: --no-{action})" }, "suites": [], } - if installer_size or size_measurements: - perfherder_data["suites"].append({ - "name": "installer size", - "value": installer_size, - "alertThreshold": 0.25, - "subtests": size_measurements - }) + if (installer_size or size_measurements) and not c.get('debug_build'): + if installer.endswith('.apk'): # Android + perfherder_data["suites"].append({ + "name": "installer size", + "value": installer_size, + "alertChangeType": "absolute", + "alertThreshold": (200 * 1024), + "subtests": size_measurements + }) + else: + perfherder_data["suites"].append({ + "name": "installer size", + "value": installer_size, + "alertThreshold": 1.0, + "subtests": size_measurements + }) build_metrics = self._load_build_resources() if build_metrics: diff --git a/testing/talos/talos/tests/tabpaint/bootstrap.js b/testing/talos/talos/tests/tabpaint/bootstrap.js index 6d72e31fca85..e3155be9de4c 100644 --- a/testing/talos/talos/tests/tabpaint/bootstrap.js +++ b/testing/talos/talos/tests/tabpaint/bootstrap.js @@ -26,7 +26,7 @@ Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource:///modules/RecentWindow.jsm"); -const TAB_ANIMATION_PREF = "browser.tabs.animate"; +const ANIMATION_PREF = "toolkit.cosmeticAnimations.enabled"; const PROCESS_COUNT_PREF = "dom.ipc.processCount"; @@ -70,8 +70,8 @@ var TabPaint = { Services.mm.addMessageListener(msgName, this); } - this.originalTabsAnimate = Services.prefs.getBoolPref(TAB_ANIMATION_PREF); - Services.prefs.setBoolPref(TAB_ANIMATION_PREF, false); + this.originalAnimate = Services.prefs.getBoolPref(ANIMATION_PREF); + Services.prefs.setBoolPref(ANIMATION_PREF, false); this.originalProcessCount = Services.prefs.getIntPref(PROCESS_COUNT_PREF); Services.prefs.setIntPref(PROCESS_COUNT_PREF, 1); }, @@ -81,7 +81,7 @@ var TabPaint = { Services.mm.removeMessageListener(msgName, this); } - Services.prefs.setBoolPref(TAB_ANIMATION_PREF, this.originalTabsAnimate); + Services.prefs.setBoolPref(ANIMATION_PREF, this.originalAnimate); Services.prefs.setIntPref(PROCESS_COUNT_PREF, this.originalProcessCount); }, diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 3ee8a5982bdb..67a96bc063fd 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -162613,7 +162613,7 @@ "testharness" ], "dom/nodes/Element-classlist.html": [ - "c6f2331b2479606064cc7d4428912ff275718390", + "46a9b0e29b876f32a47675eee1b7c8330dfa5625", "testharness" ], "dom/nodes/Element-closest.html": [ @@ -181341,7 +181341,7 @@ "testharness" ], "html/webappapis/idle-callbacks/callback-multiple-calls.html": [ - "6375309c43a1e7c9fafdc95f01fcccb4c92f8afc", + "af6e6a65fda2486ac8669340988b1d57a178e77a", "testharness" ], "html/webappapis/idle-callbacks/callback-removed-frame.html": [ @@ -208161,7 +208161,7 @@ "wdspec" ], "webdriver/actions/mouse.py": [ - "86b27e994042b37b4889175a10a02c30a24d3c7e", + "823e2b1e5ba200487d0598eecbb051f73b5ea69f", "wdspec" ], "webdriver/actions/sequence.py": [ @@ -208185,7 +208185,7 @@ "support" ], "webdriver/actions/support/test_actions_wdspec.html": [ - "ccd55308840f1b7ab6e9c56b7123b9ac370f0d25", + "c56cc117512bf9a5b6378dcead8e2640493d23a4", "support" ], "webdriver/conftest.py": [ diff --git a/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini b/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini index 4b1b04056027..96472ce23853 100644 --- a/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini +++ b/testing/web-platform/meta/dom/nodes/Element-classlist.html.ini @@ -1,33 +1,377 @@ [Element-classlist.html] type: testharness - [classList must be correct for an element that has classes] - expected: FAIL - bug: 869788, https://github.com/whatwg/dom/issues/105 - - [empty classList should return the empty string since the ordered set parser skip the whitespaces] + [classList.length when set to "a a" (HTML node)] expected: FAIL - [classList.remove must collapse whitespaces around each token and remove duplicates] - expected: FAIL - bug: 869788, https://github.com/whatwg/dom/issues/105 - - [classList.add must collapse whitespaces and remove duplicates when adding a token that already exists] - expected: FAIL - bug: 869788, https://github.com/whatwg/dom/issues/105 - - [classList.add should treat \\t as a space] + [classList.length when set to "a a a a a a" (HTML node)] expected: FAIL - [classList.add should treat \\r as a space] + [classList.length when set to "a a b b" (HTML node)] expected: FAIL - [classList.add should treat \\n as a space] + [classList.length when set to "a b c c b a a b c c" (HTML node)] expected: FAIL - [classList.add should treat \\f as a space] + [classList.length when set to " a a b" (HTML node)] expected: FAIL - [classList.replace must collapse whitespaces around each token and remove duplicates] + [classList.item() when set to "aa AA aa" (HTML node)] + expected: FAIL + + [classList.item() when set to " a a b" (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value " " (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (HTML node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (HTML node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (HTML node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (HTML node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (HTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (HTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (HTML node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (HTML node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (HTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.length when set to "a a" (XHTML node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (XHTML node)] + expected: FAIL + + [classList.length when set to "a a b b" (XHTML node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (XHTML node)] + expected: FAIL + + [classList.length when set to " a a b" (XHTML node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (XHTML node)] + expected: FAIL + + [classList.item() when set to " a a b" (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value " " (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (XHTML node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (XHTML node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (XHTML node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XHTML node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (XHTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (XHTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (XHTML node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (XHTML node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (XHTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.length when set to "a a" (MathML node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (MathML node)] + expected: FAIL + + [classList.length when set to "a a b b" (MathML node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (MathML node)] + expected: FAIL + + [classList.length when set to " a a b" (MathML node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (MathML node)] + expected: FAIL + + [classList.item() when set to " a a b" (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value " " (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (MathML node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (MathML node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (MathML node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (MathML node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (MathML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (MathML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (MathML node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (MathML node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (MathML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.length when set to "a a" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a a a a a a" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a a b b" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (XML node with null namespace)] + expected: FAIL + + [classList.item() when set to " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value " " (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (XML node with null namespace)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (XML node with null namespace)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (XML node with null namespace)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XML node with null namespace)] + expected: FAIL + + [classList.remove() with attribute value "a a" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (XML node with null namespace)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (XML node with null namespace)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (XML node with null namespace)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a a" (foo node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (foo node)] + expected: FAIL + + [classList.length when set to "a a b b" (foo node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (foo node)] + expected: FAIL + + [classList.length when set to " a a b" (foo node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (foo node)] + expected: FAIL + + [classList.item() when set to " a a b" (foo node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (foo node)] + expected: FAIL + + [classList.add("a") with attribute value " " (foo node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (foo node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (foo node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (foo node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (foo node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (foo node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (foo node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (foo node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (foo node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (foo node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (foo node)] expected: FAIL - bug: 869788, https://github.com/whatwg/dom/issues/105 diff --git a/testing/web-platform/meta/fetch/api/headers/header-values-normalize.html.ini b/testing/web-platform/meta/fetch/api/headers/header-values-normalize.html.ini deleted file mode 100644 index de5c4a064b90..000000000000 --- a/testing/web-platform/meta/fetch/api/headers/header-values-normalize.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[header-values-normalize.html] - type: testharness - [fetch() with value %0A] - expected: FAIL - - [fetch() with value %0D] - expected: FAIL - diff --git a/testing/web-platform/meta/fetch/api/headers/headers-normalize.html.ini b/testing/web-platform/meta/fetch/api/headers/headers-normalize.html.ini deleted file mode 100644 index 5d11d0adbdd4..000000000000 --- a/testing/web-platform/meta/fetch/api/headers/headers-normalize.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[headers-normalize.html] - type: testharness - [Create headers with not normalized values] - expected: FAIL - - [Check append method with not normalized values] - expected: FAIL - - [Check set method with not normalized values] - expected: FAIL - diff --git a/testing/web-platform/mozilla/meta/MANIFEST.json b/testing/web-platform/mozilla/meta/MANIFEST.json index 9a0ab9582040..19ed919a8659 100644 --- a/testing/web-platform/mozilla/meta/MANIFEST.json +++ b/testing/web-platform/mozilla/meta/MANIFEST.json @@ -350,6 +350,12 @@ ] }, "testharness": { + "dom/classList.html": [ + [ + "/_mozilla/dom/classList.html", + {} + ] + ], "fetch/api/redirect/redirect-referrer.https.html": [ [ "/_mozilla/fetch/api/redirect/redirect-referrer.https.html", @@ -831,6 +837,10 @@ "74e16eb87ecdfeb2dfc28f36e0c73a584abdf9c2", "support" ], + "dom/classList.html": [ + "37b0684fa9b869ab3a538cceac4fb5a825f3fff9", + "testharness" + ], "fetch/api/redirect/redirect-referrer-mixed-content.js": [ "f9d7ec9cf9fa8c847e45664b05482e3f8c191385", "support" diff --git a/testing/web-platform/mozilla/meta/dom/classList.html.ini b/testing/web-platform/mozilla/meta/dom/classList.html.ini new file mode 100644 index 000000000000..ad220e029996 --- /dev/null +++ b/testing/web-platform/mozilla/meta/dom/classList.html.ini @@ -0,0 +1,452 @@ +[classList.html] + type: testharness + [classList.length when set to "a a" (HTML node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (HTML node)] + expected: FAIL + + [classList.length when set to "a a b b" (HTML node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (HTML node)] + expected: FAIL + + [classList.length when set to " a a b" (HTML node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (HTML node)] + expected: FAIL + + [classList.item() when set to " a a b" (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value " " (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (HTML node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (HTML node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (HTML node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (HTML node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (HTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (HTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (HTML node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (HTML node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (HTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (HTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (HTML node)] + expected: FAIL + + [classList.length when set to "a a" (XHTML node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (XHTML node)] + expected: FAIL + + [classList.length when set to "a a b b" (XHTML node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (XHTML node)] + expected: FAIL + + [classList.length when set to " a a b" (XHTML node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (XHTML node)] + expected: FAIL + + [classList.item() when set to " a a b" (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value " " (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (XHTML node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (XHTML node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (XHTML node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XHTML node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (XHTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (XHTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (XHTML node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (XHTML node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XHTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (XHTML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (XHTML node)] + expected: FAIL + + [classList.length when set to "a a" (XUL node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (XUL node)] + expected: FAIL + + [classList.length when set to "a a b b" (XUL node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (XUL node)] + expected: FAIL + + [classList.length when set to " a a b" (XUL node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (XUL node)] + expected: FAIL + + [classList.item() when set to " a a b" (XUL node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (XUL node)] + expected: FAIL + + [classList.add("a") with attribute value " " (XUL node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (XUL node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (XUL node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (XUL node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XUL node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (XUL node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (XUL node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XUL node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (XUL node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (XUL node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (XUL node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (XUL node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (XUL node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (XUL node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XUL node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (XUL node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (XUL node)] + expected: FAIL + + [classList.length when set to "a a" (MathML node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (MathML node)] + expected: FAIL + + [classList.length when set to "a a b b" (MathML node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (MathML node)] + expected: FAIL + + [classList.length when set to " a a b" (MathML node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (MathML node)] + expected: FAIL + + [classList.item() when set to " a a b" (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value " " (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (MathML node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (MathML node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (MathML node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (MathML node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (MathML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (MathML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (MathML node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (MathML node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (MathML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (MathML node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (MathML node)] + expected: FAIL + + [classList.length when set to "a a" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a a a a a a" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a a b b" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (XML node with null namespace)] + expected: FAIL + + [classList.item() when set to " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value " " (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (XML node with null namespace)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (XML node with null namespace)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (XML node with null namespace)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (XML node with null namespace)] + expected: FAIL + + [classList.remove() with attribute value "a a" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (XML node with null namespace)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (XML node with null namespace)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (XML node with null namespace)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (XML node with null namespace)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (XML node with null namespace)] + expected: FAIL + + [classList.length when set to "a a" (foo node)] + expected: FAIL + + [classList.length when set to "a a a a a a" (foo node)] + expected: FAIL + + [classList.length when set to "a a b b" (foo node)] + expected: FAIL + + [classList.length when set to "a b c c b a a b c c" (foo node)] + expected: FAIL + + [classList.length when set to " a a b" (foo node)] + expected: FAIL + + [classList.item() when set to "aa AA aa" (foo node)] + expected: FAIL + + [classList.item() when set to " a a b" (foo node)] + expected: FAIL + + [classList.add("a") with attribute value "a a a b" (foo node)] + expected: FAIL + + [classList.add("a") with attribute value " " (foo node)] + expected: FAIL + + [classList.add("a") with attribute value " \\f" (foo node)] + expected: FAIL + + [classList.add("c") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.add("a") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.add("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)] + expected: FAIL + + [classList.add("a", "a") with attribute value "a b c " (foo node)] + expected: FAIL + + [classList.add() with attribute value "a b c a " (foo node)] + expected: FAIL + + [classList.remove("AA") with attribute value "AA BB aa CC AA dd aa" (foo node)] + expected: FAIL + + [classList.remove() with attribute value "a a" (foo node)] + expected: FAIL + + [classList.toggle("a") with attribute value " " (foo node)] + expected: FAIL + + [classList.toggle("a") with attribute value " \\f" (foo node)] + expected: FAIL + + [classList.toggle("d") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.toggle("a") with attribute value " A A A " (foo node)] + expected: FAIL + + [classList.toggle("b") with attribute value " a a b" (foo node)] + expected: FAIL + + [classList.toggle("c") with attribute value "\\t\\n\\f\\r a\\t\\n\\f\\r b\\t\\n\\f\\r " (foo node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value "a b a" (foo node)] + expected: FAIL + + [classList.replace("b", "c") with attribute value " a a b" (foo node)] + expected: FAIL + diff --git a/testing/web-platform/mozilla/tests/dom/classList.html b/testing/web-platform/mozilla/tests/dom/classList.html new file mode 100644 index 000000000000..ecefb0096ec6 --- /dev/null +++ b/testing/web-platform/mozilla/tests/dom/classList.html @@ -0,0 +1,520 @@ + + +Test for the classList element attribute + + +
+ diff --git a/testing/web-platform/tests/dom/nodes/Element-classlist.html b/testing/web-platform/tests/dom/nodes/Element-classlist.html index 22b499e931f1..5beee0942064 100644 --- a/testing/web-platform/tests/dom/nodes/Element-classlist.html +++ b/testing/web-platform/tests/dom/nodes/Element-classlist.html @@ -1,407 +1,462 @@ - - - Element.classList in case-sensitive documents - - - - - + +
+ - - + var expectedAfter = after; -
+ assert_equals(e.getAttribute("class"), expectedAfter, + "wrong class after modification"); + }, "classList." + funcName + "(" + args.map(format_value).join(", ") + + ") with attribute value " + format_value(before) + desc); +} - - +function assignToClassListStrict(e) { + "use strict"; + e.classList = "foo"; + e.removeAttribute("class"); +} + +function assignToClassList(e) { + var expect = e.classList; + e.classList = "foo"; + assert_equals(e.classList, expect, + "classList should be unchanged after assignment"); + e.removeAttribute("class"); +} + +function testClassList(e, desc) { + + // assignment + + test(function() { + assignToClassListStrict(e); + assignToClassList(e); + }, "Assigning to classList" + desc); + + // supports + test(function() { + assert_throws(TypeError(), function() { + e.classList.supports("a"); + }) + }, ".supports() must throw TypeError" + desc); + + // length attribute + + function checkLength(value, length) { + test(function() { + setClass(e, value); + assert_equals(e.classList.length, length); + }, "classList.length when " + + (value === null ? "removed" : "set to " + format_value(value)) + desc); + } + + checkLength(null, 0); + checkLength("", 0); + checkLength(" \t \f", 0); + checkLength("a", 1); + checkLength("a A", 2); + checkLength("\r\na\t\f", 1); + checkLength("a a", 1); + checkLength("a a a a a a", 1); + checkLength("a a b b", 2); + checkLength("a A B b", 4); + checkLength("a b c c b a a b c c", 3); + checkLength(" a a b", 2); + checkLength("a\tb\nc\fd\re f", 6); + + // [Stringifies] + + function checkStringifier(value, expected) { + test(function() { + setClass(e, value); + assert_equals(e.classList.toString(), expected); + }, "classList.toString() when " + + (value === null ? "removed" : "set to " + format_value(value)) + desc); + } + + checkStringifier(null, ""); + checkStringifier("foo", "foo"); + checkStringifier(" a a b", " a a b"); + + // item() method + + function checkItems(attributeValue, expectedValues) { + function checkItemFunction(index, expected) { + assert_equals(e.classList.item(index), expected, + "classList.item(" + index + ")"); + } + + function checkItemArray(index, expected) { + assert_equals(e.classList[index], expected, "classList[" + index + "]"); + } + + test(function() { + setClass(e, attributeValue); + + checkItemFunction(-1, null); + checkItemArray(-1, undefined); + + var i = 0; + while (i < expectedValues.length) { + checkItemFunction(i, expectedValues[i]); + checkItemArray(i, expectedValues[i]); + i++; + } + + checkItemFunction(i, null); + checkItemArray(i, undefined); + + checkItemFunction(0xffffffff, null); + checkItemArray(0xffffffff, undefined); + + checkItemFunction(0xfffffffe, null); + checkItemArray(0xfffffffe, undefined); + }, "classList.item() when set to " + format_value(attributeValue) + desc); + } + + checkItems(null, []); + checkItems("a", ["a"]); + checkItems("aa AA aa", ["aa", "AA"]); + checkItems("a b", ["a", "b"]); + checkItems(" a a b", ["a", "b"]); + checkItems("\t\n\f\r a\t\n\f\r b\t\n\f\r ", ["a", "b"]); + + // contains() method + + function checkContains(attributeValue, args, expectedRes) { + if (!Array.isArray(expectedRes)) { + expectedRes = Array(args.length).fill(expectedRes); + } + setClass(e, attributeValue); + for (var i = 0; i < args.length; i++) { + test(function() { + assert_equals(e.classList.contains(args[i]), expectedRes[i], + "classList.contains(\"" + args[i] + "\")"); + }, "classList.contains(" + format_value(args[i]) + ") when set to " + + format_value(attributeValue) + desc); + } + } + + checkContains(null, ["a", "", " "], false); + checkContains("", ["a"], false); + + checkContains("a", ["a"], true); + checkContains("a", ["aa", "b", "A", "a.", "a)",, "a'", 'a"', "a$", "a~", + "a?", "a\\"], false); + + // All "ASCII whitespace" per spec, before and after + checkContains("a", ["a\t", "\ta", "a\n", "\na", "a\f", "\fa", "a\r", "\ra", + "a ", " a"], false); + + checkContains("aa AA", ["aa", "AA", "aA"], [true, true, false]); + checkContains("a a a", ["a", "aa", "b"], [true, false, false]); + checkContains("a b c", ["a", "b"], true); + + checkContains("null undefined", [null, undefined], true); + checkContains("\t\n\f\r a\t\n\f\r b\t\n\f\r ", ["a", "b"], true); + + // add() method + + function checkAdd(before, argument, after, expectedException) { + checkModification(e, "add", argument, undefined, before, after, + expectedException, desc); + // Also check force toggle + // XXX https://github.com/whatwg/dom/issues/443 + //if (!Array.isArray(argument)) { + // checkModification(e, "toggle", [argument, true], true, before, after, + // expectedException); + //} + } + + checkAdd(null, "", null, "SyntaxError"); + checkAdd(null, ["a", ""], null, "SyntaxError"); + checkAdd(null, " ", null, "InvalidCharacterError"); + checkAdd(null, "\ta", null, "InvalidCharacterError"); + checkAdd(null, "a\t", null, "InvalidCharacterError"); + checkAdd(null, "\na", null, "InvalidCharacterError"); + checkAdd(null, "a\n", null, "InvalidCharacterError"); + checkAdd(null, "\fa", null, "InvalidCharacterError"); + checkAdd(null, "a\f", null, "InvalidCharacterError"); + checkAdd(null, "\ra", null, "InvalidCharacterError"); + checkAdd(null, "a\r", null, "InvalidCharacterError"); + checkAdd(null, " a", null, "InvalidCharacterError"); + checkAdd(null, "a ", null, "InvalidCharacterError"); + checkAdd(null, ["a", " "], null, "InvalidCharacterError"); + checkAdd(null, ["a", "aa "], null, "InvalidCharacterError"); + + checkAdd("a", "a", "a"); + checkAdd("aa", "AA", "aa AA"); + checkAdd("a b c", "a", "a b c"); + checkAdd("a a a b", "a", "a b"); + checkAdd(null, "a", "a"); + checkAdd("", "a", "a"); + checkAdd(" ", "a", "a"); + checkAdd(" \f", "a", "a"); + checkAdd("a", "b", "a b"); + checkAdd("a b c", "d", "a b c d"); + checkAdd("a b c ", "d", "a b c d"); + checkAdd(" a a b", "c", "a b c"); + checkAdd(" a a b", "a", "a b"); + checkAdd("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "c", "a b c"); + + // multiple add + checkAdd("a b c ", ["d", "e"], "a b c d e"); + checkAdd("a b c ", ["a", "a"], "a b c"); + checkAdd("a b c ", ["d", "d"], "a b c d"); + checkAdd("a b c a ", [], "a b c"); + checkAdd(null, ["a", "b"], "a b"); + checkAdd("", ["a", "b"], "a b"); + + checkAdd(null, null, "null"); + checkAdd(null, undefined, "undefined"); + + // remove() method + + function checkRemove(before, argument, after, expectedException) { + checkModification(e, "remove", argument, undefined, before, after, + expectedException, desc); + // Also check force toggle + // XXX https://github.com/whatwg/dom/issues/443 + //if (!Array.isArray(argument)) { + // checkModification(e, "toggle", [argument, false], false, before, after, + // expectedException); + //} + } + + checkRemove(null, "", null, "SyntaxError"); + checkRemove(null, " ", null, "InvalidCharacterError"); + checkRemove("\ta", "\ta", "\ta", "InvalidCharacterError"); + checkRemove("a\t", "a\t", "a\t", "InvalidCharacterError"); + checkRemove("\na", "\na", "\na", "InvalidCharacterError"); + checkRemove("a\n", "a\n", "a\n", "InvalidCharacterError"); + checkRemove("\fa", "\fa", "\fa", "InvalidCharacterError"); + checkRemove("a\f", "a\f", "a\f", "InvalidCharacterError"); + checkRemove("\ra", "\ra", "\ra", "InvalidCharacterError"); + checkRemove("a\r", "a\r", "a\r", "InvalidCharacterError"); + checkRemove(" a", " a", " a", "InvalidCharacterError"); + checkRemove("a ", "a ", "a ", "InvalidCharacterError"); + checkRemove("aa ", "aa ", null, "InvalidCharacterError"); + + checkRemove(null, "a", null); + checkRemove("", "a", ""); + checkRemove("a b c", "d", "a b c"); + checkRemove("a b c", "A", "a b c"); + checkRemove(" a a a ", "a", ""); + checkRemove("a b", "a", "b"); + checkRemove("a b ", "a", "b"); + checkRemove("a a b", "a", "b"); + checkRemove("aa aa bb", "aa", "bb"); + checkRemove("a a b a a c a a", "a", "b c"); + + checkRemove("a b c", "b", "a c"); + checkRemove("aaa bbb ccc", "bbb", "aaa ccc"); + checkRemove(" a b c ", "b", "a c"); + checkRemove("a b b b c", "b", "a c"); + + checkRemove("a b c", "c", "a b"); + checkRemove(" a b c ", "c", "a b"); + checkRemove("a b c c c", "c", "a b"); + + checkRemove("a b a c a d a", "a", "b c d"); + checkRemove("AA BB aa CC AA dd aa", "AA", "BB aa CC dd"); + + checkRemove("\ra\na\ta\f", "a", ""); + checkRemove("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", "b"); + + // multiple remove + checkRemove("a b c ", ["d", "e"], "a b c"); + checkRemove("a b c ", ["a", "b"], "c"); + checkRemove("a b c ", ["a", "c"], "b"); + checkRemove("a b c ", ["a", "a"], "b c"); + checkRemove("a b c ", ["d", "d"], "a b c"); + checkRemove("a b c ", [], "a b c"); + checkRemove(null, ["a", "b"], null); + checkRemove("", ["a", "b"], ""); + checkRemove("a a", [], "a"); + + checkRemove("null", null, ""); + checkRemove("undefined", undefined, ""); + + // toggle() method + + function checkToggle(before, argument, expectedRes, after, expectedException) { + checkModification(e, "toggle", argument, expectedRes, before, after, + expectedException, desc); + } + + checkToggle(null, "", null, null, "SyntaxError"); + checkToggle(null, "aa ", null, null, "InvalidCharacterError"); + + checkToggle(null, "a", true, "a"); + checkToggle("", "a", true, "a"); + checkToggle(" ", "a", true, "a"); + checkToggle(" \f", "a", true, "a"); + checkToggle("a", "b", true, "a b"); + checkToggle("a", "A", true, "a A"); + checkToggle("a b c", "d", true, "a b c d"); + checkToggle(" a a b", "d", true, "a b d"); + + checkToggle("a", "a", false, ""); + checkToggle(" a a a ", "a", false, ""); + checkToggle(" A A A ", "a", true, "A a"); + checkToggle(" a b c ", "b", false, "a c"); + checkToggle(" a b c b b", "b", false, "a c"); + checkToggle(" a b c ", "c", false, "a b"); + checkToggle(" a b c ", "a", false, "b c"); + checkToggle(" a a b", "b", false, "a"); + checkToggle("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", false, "b"); + checkToggle("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "c", true, "a b c"); + + checkToggle("null", null, false, ""); + checkToggle("", null, true, "null"); + checkToggle("undefined", undefined, false, ""); + checkToggle("", undefined, true, "undefined"); + + + // tests for the force argument handling + // XXX Remove these if https://github.com/whatwg/dom/issues/443 is fixed + + function checkForceToggle(before, argument, force, expectedRes, after, expectedException) { + checkModification(e, "toggle", [argument, force], expectedRes, before, + after, expectedException, desc); + } + + checkForceToggle("", "a", true, true, "a"); + checkForceToggle("a", "a", true, true, "a"); + checkForceToggle("a", "b", true, true, "a b"); + checkForceToggle("a b", "b", true, true, "a b"); + checkForceToggle("", "a", false, false, ""); + checkForceToggle("a", "a", false, false, ""); + checkForceToggle("a", "b", false, false, "a"); + checkForceToggle("a b", "b", false, false, "a"); + + + // replace() method + function checkReplace(before, token, newToken, after, expectedException) { + checkModification(e, "replace", [token, newToken], undefined, before, + after, expectedException, desc); + } + + checkReplace(null, "", "a", null, "SyntaxError"); + checkReplace(null, "", " ", null, "SyntaxError"); + checkReplace(null, " ", "a", null, "InvalidCharacterError"); + checkReplace(null, "\ta", "b", null, "InvalidCharacterError"); + checkReplace(null, "a\t", "b", null, "InvalidCharacterError"); + checkReplace(null, "\na", "b", null, "InvalidCharacterError"); + checkReplace(null, "a\n", "b", null, "InvalidCharacterError"); + checkReplace(null, "\fa", "b", null, "InvalidCharacterError"); + checkReplace(null, "a\f", "b", null, "InvalidCharacterError"); + checkReplace(null, "\ra", "b", null, "InvalidCharacterError"); + checkReplace(null, "a\r", "b", null, "InvalidCharacterError"); + checkReplace(null, " a", "b", null, "InvalidCharacterError"); + checkReplace(null, "a ", "b", null, "InvalidCharacterError"); + + checkReplace(null, "a", "", null, "SyntaxError"); + checkReplace(null, " ", "", null, "SyntaxError"); + checkReplace(null, "a", " ", null, "InvalidCharacterError"); + checkReplace(null, "b", "\ta", null, "InvalidCharacterError"); + checkReplace(null, "b", "a\t", null, "InvalidCharacterError"); + checkReplace(null, "b", "\na", null, "InvalidCharacterError"); + checkReplace(null, "b", "a\n", null, "InvalidCharacterError"); + checkReplace(null, "b", "\fa", null, "InvalidCharacterError"); + checkReplace(null, "b", "a\f", null, "InvalidCharacterError"); + checkReplace(null, "b", "\ra", null, "InvalidCharacterError"); + checkReplace(null, "b", "a\r", null, "InvalidCharacterError"); + checkReplace(null, "b", " a", null, "InvalidCharacterError"); + checkReplace(null, "b", "a ", null, "InvalidCharacterError"); + + checkReplace("a", "a", "a", "a"); + checkReplace("a", "a", "b", "b"); + checkReplace("a", "A", "b", "a"); + checkReplace("a b", "b", "A", "a A"); + checkReplace("a b c", "d", "e", "a b c"); + // https://github.com/whatwg/dom/issues/443 + checkReplace("a a a b", "a", "a", "a b"); + checkReplace("a a a b", "c", "d", "a a a b"); + checkReplace(null, "a", "b", null); + checkReplace("", "a", "b", ""); + checkReplace(" ", "a", "b", " "); + checkReplace(" a \f", "a", "b", "b"); + checkReplace("a b c", "b", "d", "a d c"); + // https://github.com/whatwg/dom/issues/442 + // Implementations agree on the first one here, so I test it, but disagree on + // the second, so no test until the spec decides what to say. + checkReplace("a b c", "c", "a", "a b"); + //checkReplace("c b a", "c", "a", ???); + checkReplace("a b a", "a", "c", "c b"); + checkReplace("a b a", "b", "c", "a c"); + checkReplace(" a a b", "a", "c", "c b"); + checkReplace(" a a b", "b", "c", "a c"); + checkReplace("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", "c", "c b"); + checkReplace("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "b", "c", "a c"); + + checkReplace("a null", null, "b", "a b"); + checkReplace("a b", "a", null, "null b"); + checkReplace("a undefined", undefined, "b", "a b"); + checkReplace("a b", "a", undefined, "undefined b"); +} + +var content = document.getElementById("content"); + +var htmlNode = document.createElement("div"); +content.appendChild(htmlNode); +testClassList(htmlNode, " (HTML node)"); + +var xhtmlNode = document.createElementNS(XHTML_NS, "div"); +content.appendChild(xhtmlNode); +testClassList(xhtmlNode, " (XHTML node)"); + +var mathMLNode = document.createElementNS(MATHML_NS, "math"); +content.appendChild(mathMLNode); +testClassList(mathMLNode, " (MathML node)"); + +var xmlNode = document.createElementNS(null, "foo"); +content.appendChild(xmlNode); +testClassList(xmlNode, " (XML node with null namespace)"); + +var fooNode = document.createElementNS("http://example.org/foo", "foo"); +content.appendChild(fooNode); +testClassList(fooNode, " (foo node)"); + diff --git a/testing/web-platform/tests/tools/webdriver/webdriver/client.py b/testing/web-platform/tests/tools/webdriver/webdriver/client.py index f152c75ea009..1e5399eb77db 100644 --- a/testing/web-platform/tests/tools/webdriver/webdriver/client.py +++ b/testing/web-platform/tests/tools/webdriver/webdriver/client.py @@ -151,18 +151,20 @@ class ActionSequence(object): self._actions.append(action) return self - def pointer_up(self, button): + def pointer_up(self, button=0): """Queue a pointerUp action for `button`. :param button: Pointer button to perform action with. + Default: 0, which represents main device button. """ self._pointer_action("pointerUp", button) return self - def pointer_down(self, button): + def pointer_down(self, button=0): """Queue a pointerDown action for `button`. :param button: Pointer button to perform action with. + Default: 0, which represents main device button. """ self._pointer_action("pointerDown", button) return self diff --git a/testing/web-platform/tests/webdriver/actions/mouse.py b/testing/web-platform/tests/webdriver/actions/mouse.py index 8f83de680d33..bf4ad6c9da97 100644 --- a/testing/web-platform/tests/webdriver/actions/mouse.py +++ b/testing/web-platform/tests/webdriver/actions/mouse.py @@ -1,3 +1,4 @@ +import pytest import urllib from support.refine import get_events, filter_dict @@ -13,6 +14,18 @@ def link_doc(dest): return inline(content) +def get_center(rect): + return { + "x": rect["width"] / 2 + rect["x"], + "y": rect["height"] / 2 + rect["y"], + } + + +# TODO use pytest.approx once we upgrade to pytest > 3.0 +def approx(n, m, tolerance=1): + return abs(n - m) < tolerance + + def test_click_at_coordinates(session, test_actions_page, mouse_chain): div_point = { "x": 82, @@ -43,9 +56,7 @@ def test_click_at_coordinates(session, test_actions_page, mouse_chain): def test_click_element_center(session, test_actions_page, mouse_chain): outer = session.find.css("#outer", all=False) - outer_rect = outer.rect - center_x = outer_rect["width"] / 2 + outer_rect["x"] - center_y = outer_rect["height"] / 2 + outer_rect["y"] + center = get_center(outer.rect) mouse_chain.click(element=outer).perform() events = get_events(session) assert len(events) == 4 @@ -53,9 +64,8 @@ def test_click_element_center(session, test_actions_page, mouse_chain): assert ["mousemove", "mousedown", "mouseup", "click"] == event_types for e in events: if e["type"] != "mousemove": - # TODO use pytest.approx once we upgrade to pytest > 3.0 - assert abs(e["pageX"] - center_x) < 1 - assert abs(e["pageY"] - center_y) < 1 + assert approx(e["pageX"], center["x"]) + assert approx(e["pageY"], center["y"]) assert e["target"] == "outer" @@ -75,3 +85,29 @@ def test_click_navigation(session, url): session.url = start click(session.find.css("#link", all=False)) assert session.url == destination + + +@pytest.mark.parametrize("drag_duration", [0, 300, 800]) +@pytest.mark.parametrize("dx, dy", [(20, 0), (0, 15), (10, 15)]) +def test_drag_and_drop(session, test_actions_page, mouse_chain, dx, dy, drag_duration): + drag_target = session.find.css("#dragTarget", all=False) + initial_rect = drag_target.rect + initial_center = get_center(initial_rect) + # Conclude chain with extra move to allow time for last queued + # coordinate-update of drag_target and to test that drag_target is "dropped". + mouse_chain \ + .pointer_move(0, 0, origin=drag_target) \ + .pointer_down() \ + .pointer_move(dx, dy, duration=drag_duration, origin="pointer") \ + .pointer_up() \ + .pointer_move(80, 50, duration=100, origin="pointer") \ + .perform() + # mouseup that ends the drag is at the expected destination + e = get_events(session)[1] + assert e["type"] == "mouseup" + assert approx(e["pageX"], initial_center["x"] + dx) + assert approx(e["pageY"], initial_center["y"] + dy) + # check resulting location of the dragged element + final_rect = drag_target.rect + assert initial_rect["x"] + dx == final_rect["x"] + assert initial_rect["y"] + dy == final_rect["y"] diff --git a/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html b/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html index 97579ab03df6..1d3ea891a086 100644 --- a/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html +++ b/testing/web-platform/tests/webdriver/actions/support/test_actions_wdspec.html @@ -4,15 +4,16 @@ Test Actions -
+

KeyReporter

ClickReporter

-
+
+
+
+
+

DragReporter

+
+
diff --git a/toolkit/components/alerts/resources/content/alert.js b/toolkit/components/alerts/resources/content/alert.js index 1adfc4c1e4d7..ec2c87d367ea 100644 --- a/toolkit/components/alerts/resources/content/alert.js +++ b/toolkit/components/alerts/resources/content/alert.js @@ -169,7 +169,7 @@ function onAlertLoad() { // If the require interaction flag is set, prevent auto-closing the notification. if (!gRequireInteraction) { - if (Services.prefs.getBoolPref("alerts.disableSlidingEffect")) { + if (!Services.prefs.getBoolPref("toolkit.cosmeticAnimations.enabled")) { setTimeout(function() { window.close(); }, ALERT_DURATION_IMMEDIATE); } else { let alertBox = document.getElementById("alertBox"); diff --git a/toolkit/components/extensions/.eslintrc.js b/toolkit/components/extensions/.eslintrc.js index ae8064fcc396..4e9bcbcd9aaa 100644 --- a/toolkit/components/extensions/.eslintrc.js +++ b/toolkit/components/extensions/.eslintrc.js @@ -1,19 +1,12 @@ "use strict"; module.exports = { - "extends": "../../.eslintrc.js", - - "env": { - "browser": false, - }, "globals": { "Cc": true, "Ci": true, - "Components": true, "Cr": true, "Cu": true, - "dump": true, "TextDecoder": false, "TextEncoder": false, // Specific to WebExtensions: @@ -64,15 +57,6 @@ module.exports = { "requireReturnDescription": false, }], - // Braces only needed for multi-line arrow function blocks - // "arrow-body-style": ["error", "as-needed"], - - // Require spacing around => - "arrow-spacing": "error", - - // Always require spacing around a single line block - "block-spacing": "warn", - // Forbid spaces inside the square brackets of array literals. "array-bracket-spacing": ["error", "never"], @@ -82,61 +66,27 @@ module.exports = { // No space padding in parentheses "space-in-parens": ["error", "never"], - // Enforce one true brace style (opening brace on the same line) and avoid - // start and end braces on the same line. - "brace-style": ["error", "1tbs", {"allowSingleLine": true}], - - // No space before always a space after a comma - "comma-spacing": ["error", {"before": false, "after": true}], - // Commas at the end of the line not the start "comma-style": "error", - // Don't require spaces around computed properties - "computed-property-spacing": ["error", "never"], - // Functions are not required to consistently return something or nothing "consistent-return": "off", // Require braces around blocks that start a new line "curly": ["error", "all"], - // Always require a trailing EOL - "eol-last": "error", - // Require function* name() "generator-star-spacing": ["error", {"before": false, "after": true}], // Two space indent "indent": ["error", 2, {"SwitchCase": 1, "ArrayExpression": "first", "ObjectExpression": "first"}], - // Space after colon not before in property declarations - "key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "minimum"}], - - // Require spaces before and after finally, catch, etc. - "keyword-spacing": "error", - - // Unix linebreaks - "linebreak-style": ["error", "unix"], - // Always require parenthesis for new calls "new-parens": "error", // Use [] instead of Array() "no-array-constructor": "error", - // No duplicate arguments in function declarations - "no-dupe-args": "error", - - // No duplicate keys in object declarations - "no-dupe-keys": "error", - - // No duplicate cases in switch statements - "no-duplicate-case": "error", - - // If an if block ends with a return no need for an else block - // "no-else-return": "error", - // Disallow empty statements. This will report an error for: // try { something(); } catch (e) {} // but will not report it for: @@ -144,77 +94,17 @@ module.exports = { // which is a valid use case. "no-empty": "error", - // No empty character classes in regex - "no-empty-character-class": "error", - - // Disallow empty destructuring - "no-empty-pattern": "error", - - // No assiging to exception variable - "no-ex-assign": "error", - - // No using !! where casting to boolean is already happening - "no-extra-boolean-cast": "warn", - - // No double semicolon - "no-extra-semi": "error", - - // No overwriting defined functions - "no-func-assign": "error", - - // No invalid regular expresions - "no-invalid-regexp": "error", - - // No odd whitespace characters - "no-irregular-whitespace": "error", - - // No single if block inside an else block - "no-lonely-if": "warn", - // No mixing different operators without parens "no-mixed-operators": ["error", {"groups": [["&&", "||"], ["==", "!=", "===", "!==", ">", ">=", "<", "<="], ["in", "instanceof"]]}], - // No mixing spaces and tabs in indent - "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], - // Disallow use of multiple spaces (sometimes used to align const values, // array or object items, etc.). It's hard to maintain and doesn't add that // much benefit. "no-multi-spaces": "warn", - // No reassigning native JS objects - "no-native-reassign": "error", - - // Nested ternary statements are confusing - "no-nested-ternary": "error", - - // Use {} instead of new Object() - "no-new-object": "error", - - // No Math() or JSON() - "no-obj-calls": "error", - - // No octal literals - "no-octal": "error", - - // No redeclaring variables - "no-redeclare": "error", - - // No unnecessary comparisons - "no-self-compare": "error", - // No spaces between function name and parentheses "no-spaced-func": "warn", - // No trailing whitespace - "no-trailing-spaces": "error", - - // Error on newline where a semicolon is needed - "no-unexpected-multiline": "error", - - // No unreachable statements - "no-unreachable": "error", - // No expressions where a statement is expected "no-unused-expressions": "error", @@ -224,30 +114,15 @@ module.exports = { // No using variables before defined "no-use-before-define": "error", - // No using with - "no-with": "error", - // Always require semicolon at end of statement "semi": ["error", "always"], - // Require space before blocks - "space-before-blocks": "error", - // Never use spaces before function parentheses "space-before-function-paren": ["error", {"anonymous": "never", "named": "never"}], - // Require spaces around operators, except for a|0. - "space-infix-ops": ["error", {"int32Hint": true}], - // ++ and -- should not need spacing "space-unary-ops": ["warn", {"nonwords": false, "words": true, "overrides": {"typeof": false}}], - // No comparisons to NaN - "use-isnan": "error", - - // Only check typeof against valid results - "valid-typeof": "error", - // Disallow using variables outside the blocks they are defined (especially // since only let and const are used, see "no-var"). "block-scoped-var": "error", @@ -287,10 +162,6 @@ module.exports = { // Allow use of function declarations and expressions. "func-style": "off", - // Don't enforce the maximum depth that blocks can be nested. The complexity - // rule is a better rule to check this. - "max-depth": "off", - // Maximum length of a line. // Disabled because we exceed this in too many places. "max-len": [0, 80], @@ -320,9 +191,6 @@ module.exports = { // the outer scope, to avoid confusion. "no-catch-shadow": "off", - // Disallow assignment in conditional expressions. - "no-cond-assign": "error", - // Disallow using the console API. "no-console": "error", @@ -335,12 +203,6 @@ module.exports = { // Disallow control characters in regular expressions. "no-control-regex": "error", - // Disallow use of debugger. - "no-debugger": "error", - - // Disallow deletion of variables (deleting properties is fine). - "no-delete-var": "error", - // Allow division operators explicitly at beginning of regular expression. "no-div-regex": "off", @@ -350,9 +212,6 @@ module.exports = { // Disallow adding to native types "no-extend-native": "error", - // Disallow unnecessary function binding. - "no-extra-bind": "error", - // Allow unnecessary parentheses, as they may make the code more readable. "no-extra-parens": "off", @@ -392,9 +251,6 @@ module.exports = { // Disallow usage of __proto__ property. "no-proto": "error", - // Disallow multiple spaces in a regular expression literal. - "no-regex-spaces": "error", - // Allow reserved words being used as object literal keys. "no-reserved-keys": "off", @@ -408,9 +264,6 @@ module.exports = { // Don't warn about declaration of variables already declared in the outer scope. "no-shadow": "off", - // Disallow shadowing of names such as arguments. - "no-shadow-restricted-names": "error", - // Allow use of synchronous methods (not a node environment). "no-sync": "off", @@ -421,11 +274,6 @@ module.exports = { // throw new Error("error")). "no-throw-literal": "error", - // Disallow use of undeclared variables unless mentioned in a /* global */ - // block. Note that globals from head.js are automatically imported in tests - // by the import-headjs-globals rule form the mozilla eslint plugin. - "no-undef": "error", - // Allow dangling underscores in identifiers (for privates). "no-underscore-dangle": "off", @@ -456,9 +304,6 @@ module.exports = { // Don't require quotes around object literal property names. "quote-props": "off", - // Double quotes should be used. - "quotes": ["warn", "double", {"avoidEscape": true, "allowTemplateLiterals": true}], - // Require use of the second argument for parseInt(). "radix": "error", @@ -494,9 +339,6 @@ module.exports = { // Disallow function or variable declarations in nested blocks "no-inner-declarations": "error", - // Disallow usage of __iterator__ property - "no-iterator": "error", - // Disallow labels that share a name with a variable "no-label-var": "error", diff --git a/toolkit/components/extensions/ExtensionTabs.jsm b/toolkit/components/extensions/ExtensionTabs.jsm index 3d1454e196de..c377cdd97036 100644 --- a/toolkit/components/extensions/ExtensionTabs.jsm +++ b/toolkit/components/extensions/ExtensionTabs.jsm @@ -461,7 +461,6 @@ class TabBase { id: this.id, index: this.index, windowId: this.windowId, - selected: this.selected, highlighted: this.selected, active: this.selected, pinned: this.pinned, diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index e895c4939198..f341d8dc16bc 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -5207,30 +5207,6 @@ "n_buckets": 50, "description": "Firefox: Time taken to run permitUnload on a browser during tab close to see whether or not we're allowed to close the tab (ms)." }, - "FX_TAB_ANIM_OPEN_PREVIEW_FRAME_INTERVAL_MS": { - "expires_in_version": "never", - "kind": "exponential", - "low": 7, - "high": 500, - "n_buckets": 50, - "description": "Average frame interval during tab open animation of about:newtab (preview=on), when other tabs are unaffected" - }, - "FX_TAB_ANIM_OPEN_FRAME_INTERVAL_MS": { - "expires_in_version": "never", - "kind": "exponential", - "low": 7, - "high": 500, - "n_buckets": 50, - "description": "Average frame interval during tab open animation of about:newtab (preview=off), when other tabs are unaffected" - }, - "FX_TAB_ANIM_ANY_FRAME_INTERVAL_MS": { - "expires_in_version": "never", - "kind": "exponential", - "low": 7, - "high": 500, - "n_buckets": 50, - "description": "Average frame interval during any tab open/close animation (excluding tabstrip scroll)" - }, "FX_REFRESH_DRIVER_CHROME_FRAME_DELAY_MS": { "alert_emails": ["perf-telemetry-alerts@mozilla.com"], "expires_in_version": "never", @@ -11348,5 +11324,77 @@ "kind": "enumerated", "n_values": 99, "description": "Count of which display items are being used by type id" + }, + "TIME_TO_DOM_LOADING_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to domLoading." + }, + "TIME_TO_DOM_INTERACTIVE_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to domInteractive." + }, + "TIME_TO_DOM_CONTENT_LOADED_START_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to domContentLoadedEventStart." + }, + "TIME_TO_DOM_CONTENT_LOADED_END_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to domContentLoadedEventEnd." + }, + "TIME_TO_DOM_COMPLETE_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to domComplete." + }, + "TIME_TO_LOAD_EVENT_START_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to loadEventStart." + }, + "TIME_TO_LOAD_EVENT_END_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to loadEventEnd." + }, + "TIME_TO_RESPONSE_START_MS": { + "alert_emails": ["wpan@mozilla.com"], + "expires_in_version": "60", + "kind": "exponential", + "high": 50000, + "n_buckets": 100, + "bug_numbers": [1344893], + "description": "Time in milliseconds from navigationStart to responseStart." } } diff --git a/toolkit/components/telemetry/TelemetryEnvironment.jsm b/toolkit/components/telemetry/TelemetryEnvironment.jsm index 6a3bdf7fecae..57f974ef17fe 100644 --- a/toolkit/components/telemetry/TelemetryEnvironment.jsm +++ b/toolkit/components/telemetry/TelemetryEnvironment.jsm @@ -178,7 +178,7 @@ const DEFAULT_ENVIRONMENT_PREFS = new Map([ ["browser.search.suggest.enabled", {what: RECORD_PREF_VALUE}], ["browser.startup.homepage", {what: RECORD_PREF_STATE}], ["browser.startup.page", {what: RECORD_PREF_VALUE}], - ["browser.tabs.animate", {what: RECORD_PREF_VALUE}], + ["toolkit.cosmeticAnimations.enabled", {what: RECORD_PREF_VALUE}], ["browser.urlbar.suggest.searches", {what: RECORD_PREF_VALUE}], ["browser.urlbar.userMadeSearchSuggestionsChoice", {what: RECORD_PREF_VALUE}], ["devtools.chrome.enabled", {what: RECORD_PREF_VALUE}], @@ -624,6 +624,7 @@ EnvironmentAddonBuilder.prototype = { updateDay: Utils.millisecondsToDays(updateDate.getTime()), signedState: addon.signedState, isSystem: addon.isSystem, + isWebExtension: addon.isWebExtension, }; if (addon.signedState !== undefined) diff --git a/toolkit/components/telemetry/TelemetryHistogram.cpp b/toolkit/components/telemetry/TelemetryHistogram.cpp index a2d703b49a7a..3327c659c6d2 100644 --- a/toolkit/components/telemetry/TelemetryHistogram.cpp +++ b/toolkit/components/telemetry/TelemetryHistogram.cpp @@ -570,12 +570,10 @@ GetProcessFromName(const std::string& aString) } Histogram* -internal_GetSubsessionHistogram(Histogram& existing) +internal_GetSubsessionHistogram(mozilla::Telemetry::HistogramID id, + Histogram& existing) { - mozilla::Telemetry::HistogramID id; - nsresult rv - = internal_GetHistogramEnumId(existing.histogram_name().c_str(), &id); - if (NS_FAILED(rv) || gHistograms[id].keyed) { + if (gHistograms[id].keyed) { return nullptr; } @@ -618,10 +616,23 @@ internal_GetSubsessionHistogram(Histogram& existing) cache[id] = clone; return clone; } + +Histogram* +internal_GetSubsessionHistogram(Histogram& existing) +{ + mozilla::Telemetry::HistogramID id; + nsresult rv + = internal_GetHistogramEnumId(existing.histogram_name().c_str(), &id); + if (NS_FAILED(rv)) { + return nullptr; + } + return internal_GetSubsessionHistogram(id, existing); +} #endif nsresult -internal_HistogramAdd(Histogram& histogram, int32_t value, uint32_t dataset) +internal_HistogramAdd(mozilla::Telemetry::HistogramID id, + Histogram& histogram, int32_t value, uint32_t dataset) { // Check if we are allowed to record the data. bool canRecordDataset = CanRecordDataset(dataset, @@ -632,7 +643,7 @@ internal_HistogramAdd(Histogram& histogram, int32_t value, uint32_t dataset) } #if !defined(MOZ_WIDGET_ANDROID) - if (Histogram* subsession = internal_GetSubsessionHistogram(histogram)) { + if (Histogram* subsession = internal_GetSubsessionHistogram(id, histogram)) { subsession->Add(value); } #endif @@ -645,24 +656,17 @@ internal_HistogramAdd(Histogram& histogram, int32_t value, uint32_t dataset) } nsresult -internal_HistogramAdd(Histogram& histogram, int32_t value) +internal_HistogramAdd(mozilla::Telemetry::HistogramID id, + Histogram& histogram, int32_t value) { uint32_t dataset = nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN; // We only really care about the dataset of the histogram if we are not recording // extended telemetry. Otherwise, we always record histogram data. if (!internal_CanRecordExtended()) { - mozilla::Telemetry::HistogramID id; - nsresult rv - = internal_GetHistogramEnumId(histogram.histogram_name().c_str(), &id); - if (NS_FAILED(rv)) { - // If we can't look up the dataset, it might be because the histogram was added - // at runtime. Since we're not recording extended telemetry, bail out. - return NS_OK; - } dataset = gHistograms[id].dataset; } - return internal_HistogramAdd(histogram, value, dataset); + return internal_HistogramAdd(id, histogram, value, dataset); } void @@ -1200,7 +1204,7 @@ void internal_Accumulate(mozilla::Telemetry::HistogramID aHistogram, uint32_t aS Histogram *h; nsresult rv = internal_GetHistogramByEnumId(aHistogram, &h, GeckoProcessType_Default); if (NS_SUCCEEDED(rv)) { - internal_HistogramAdd(*h, aSample, gHistograms[aHistogram].dataset); + internal_HistogramAdd(aHistogram, *h, aSample, gHistograms[aHistogram].dataset); } } @@ -1222,14 +1226,14 @@ internal_Accumulate(mozilla::Telemetry::HistogramID aID, void internal_Accumulate(Histogram& aHistogram, uint32_t aSample) { - if (XRE_IsParentProcess()) { - internal_HistogramAdd(aHistogram, aSample); - return; - } - mozilla::Telemetry::HistogramID id; nsresult rv = internal_GetHistogramEnumId(aHistogram.histogram_name().c_str(), &id); if (NS_SUCCEEDED(rv)) { + if (XRE_IsParentProcess()) { + internal_HistogramAdd(id, aHistogram, aSample); + return; + } + internal_RemoteAccumulate(id, aSample); } } @@ -1258,7 +1262,7 @@ internal_AccumulateChild(GeckoProcessType aProcessType, mozilla::Telemetry::Hist Histogram* h; nsresult rv = internal_GetHistogramByEnumId(aId, &h, aProcessType); if (NS_SUCCEEDED(rv)) { - internal_HistogramAdd(*h, aSample, gHistograms[aId].dataset); + internal_HistogramAdd(aId, *h, aSample, gHistograms[aId].dataset); } else { NS_WARNING("NS_FAILED GetHistogramByEnumId for CHILD"); } diff --git a/toolkit/components/telemetry/TelemetrySend.jsm b/toolkit/components/telemetry/TelemetrySend.jsm index 10778e95b374..2c0268019c05 100644 --- a/toolkit/components/telemetry/TelemetrySend.jsm +++ b/toolkit/components/telemetry/TelemetrySend.jsm @@ -805,10 +805,8 @@ var TelemetrySendImpl = { TelemetryReportingPolicy.canUpload() && AppConstants.platform != "android") { const url = this._buildSubmissionURL(ping); - // Serialize the ping to the disk and spawn the PingSender. - let savePromise = savePing(ping); - savePromise.then(() => this._sendWithPingSender(ping.id, url)); - return savePromise; + // Serialize the ping to the disk and then spawn the PingSender. + return savePing(ping).then(() => this._sendWithPingSender(ping.id, url)); } if (!this.canSendNow) { diff --git a/toolkit/components/telemetry/TelemetrySession.jsm b/toolkit/components/telemetry/TelemetrySession.jsm index e2887115c3e9..6c11de666b37 100644 --- a/toolkit/components/telemetry/TelemetrySession.jsm +++ b/toolkit/components/telemetry/TelemetrySession.jsm @@ -1773,7 +1773,9 @@ var Impl = { // Only send the shutdown ping using the pingsender from the second // browsing session on, to mitigate issues with "bot" profiles (see bug 1354482). - let sendWithPingsender = Preferences.get(PREF_SHUTDOWN_PINGSENDER, true) && + // Note: sending the "shutdown" ping using the pingsender is currently disabled + // due to a crash happening on OSX platforms. See bug 1357745 for context. + let sendWithPingsender = Preferences.get(PREF_SHUTDOWN_PINGSENDER, false) && !TelemetryReportingPolicy.isFirstRun(); let options = { diff --git a/toolkit/components/telemetry/TelemetryStopwatch.jsm b/toolkit/components/telemetry/TelemetryStopwatch.jsm index 299b70a5d58e..4fed4528d354 100644 --- a/toolkit/components/telemetry/TelemetryStopwatch.jsm +++ b/toolkit/components/telemetry/TelemetryStopwatch.jsm @@ -136,13 +136,32 @@ this.TelemetryStopwatch = { return TelemetryStopwatchImpl.start(aHistogram, aObj, null); }, + /** + * Returns whether a timer associated with a telemetry histogram is currently + * running. The timer can be directly associated with a histogram, or with a + * pair of a histogram and an object. + * + * @param {String} aHistogram - a string which must be a valid histogram name. + * + * @param {Object} aObj - Optional parameter. If specified, the timer is + * associated with this object, meaning that multiple + * timers for the same histogram may be run + * concurrently, as long as they are associated with + * different objects. + * + * @returns {Boolean} True if the timer exists and is currently running. + */ + running(aHistogram, aObj) { + return TelemetryStopwatchImpl.running(aHistogram, aObj, null); + }, + /** * Deletes the timer associated with a telemetry histogram. The timer can be * directly associated with a histogram, or with a pair of a histogram and * an object. Important: Only use this method when a legitimate cancellation * should be done. * - * @param {String} aHistogram - a string which must be a valid histogram name. + * @param {String} aHistogram - a string which must be a valid histogram name. * * @param {Object} aObj - Optional parameter. If specified, the timer is * associated with this object, meaning that multiple @@ -229,6 +248,28 @@ this.TelemetryStopwatch = { return TelemetryStopwatchImpl.start(aHistogram, aObj, aKey); }, + /** + * Returns whether a timer associated with a telemetry histogram is currently + * running. Similarly to @see{TelemetryStopwatch.running} the timer and its + * key can be associated with an object. Each key may have multiple associated + * objects and each object can be associated with multiple keys. + * + * @param {String} aHistogram - a string which must be a valid histogram name. + * + * @param {String} aKey - a string which must be a valid histgram key. + * + * @param {Object} aObj - Optional parameter. If specified, the timer is + * associated with this object, meaning that multiple + * timers for the same histogram may be run + * concurrently, as long as they are associated with + * different objects. + * + * @returns {Boolean} True if the timer exists and is currently running. + */ + runningKeyed(aHistogram, aKey, aObj) { + return TelemetryStopwatchImpl.running(aHistogram, aObj, aKey); + }, + /** * Deletes the timer associated with a keyed histogram. Important: Only use * this method when a legitimate cancellation should be done. @@ -304,6 +345,10 @@ this.TelemetryStopwatchImpl = { return Timers.put(histogram, object, key, Components.utils.now()); }, + running(histogram, object, key) { + return Timers.has(histogram, object, key); + }, + cancel(histogram, object, key) { return Timers.delete(histogram, object, key); }, diff --git a/toolkit/components/telemetry/docs/collection/measuring-time.rst b/toolkit/components/telemetry/docs/collection/measuring-time.rst index 6d27e8318bbb..0a4edb789aa8 100644 --- a/toolkit/components/telemetry/docs/collection/measuring-time.rst +++ b/toolkit/components/telemetry/docs/collection/measuring-time.rst @@ -16,16 +16,20 @@ API: .. code-block:: js TelemetryStopwatch = { - // Start, cancel & finish recording elapsed time into a histogram. + // Start, check if running, cancel & finish recording elapsed time into a + // histogram. // |aObject| is optional. If specificied, the timer is associated with this // object, so multiple time measurements can be done concurrently. start(histogramId, aObject); + running(histogramId, aObject); cancel(histogramId, aObject); finish(histogramId, aObject); - // Start, cancel & finished recording elapsed time into a keyed histogram. + // Start, check if running, cancel & finish recording elapsed time into a + // keyed histogram. // |key| specificies the key to record into. // |aObject| is optional and used as above. startKeyed(histogramId, key, aObject); + runningKeyed(histogramId, key, aObject); cancelKeyed(histogramId, key, aObject); finishKeyed(histogramId, key, aObject); }; @@ -44,6 +48,12 @@ Example: // ... do more work. TelemetryStopwatch.finish("SAMPLE_FILE_LOAD_TIME_MS"); + // Another loading attempt? Start stopwatch again if + // not already running. + if (!TelemetryStopwatch.running("SAMPLE_FILE_LOAD_TIME_MS")) { + TelemetryStopwatch.start("SAMPLE_FILE_LOAD_TIME_MS"); + } + // Periodically, it's necessary to attempt to finish a // TelemetryStopwatch that's already been canceled or // finished. Normally, that throws a warning to the diff --git a/toolkit/components/telemetry/docs/data/environment.rst b/toolkit/components/telemetry/docs/data/environment.rst index a3522f6523ae..a9b0a49a4345 100644 --- a/toolkit/components/telemetry/docs/data/environment.rst +++ b/toolkit/components/telemetry/docs/data/environment.rst @@ -213,6 +213,7 @@ Structure: updateDay: , // days since UNIX epoch, 0 on failure signedState: , // whether the add-on is signed by AMO, only present for extensions isSystem: , // true if this is a System Add-on + isWebExtension: , // true if this is a WebExtension }, ... }, diff --git a/toolkit/components/telemetry/docs/data/sync-ping.rst b/toolkit/components/telemetry/docs/data/sync-ping.rst index d2cfd6ecd5a4..7cdc61277c21 100644 --- a/toolkit/components/telemetry/docs/data/sync-ping.rst +++ b/toolkit/components/telemetry/docs/data/sync-ping.rst @@ -191,6 +191,14 @@ Events in the "sync" ping The sync ping includes events in the same format as they are included in the main ping, see :ref:`eventtelemetry`. +All events submitted as part of the sync ping which already include the "extra" +object (the 6th parameter of the event array described in the event telemetry +documentation) may also include a "serverTime" parameter, which the most recent +unix timestamp sent from the sync server (as a string). This arrives in the +``X-Weave-Timestamp`` HTTP header, and may be omitted in cases where the client +has not yet made a request to the server, or doesn't have it for any other +reason. It is included to improve flow analysis across multiple clients. + Every event recorded in this ping will have a category of ``sync``. The following events are defined, categorized by the event method. @@ -207,6 +215,7 @@ client, or opening a new URL. - deviceID: A GUID which identifies the device the command is being sent to. - flowID: A GUID which uniquely identifies this command invocation. + - serverTime: (optional) Most recent server timestamp, as described above. processcommand ~~~~~~~~~~~~~~ @@ -222,3 +231,4 @@ client. This is logically the "other end" of ``sendcommand``. - flowID: A GUID which uniquely identifies this command invocation. The value for this GUID will be the same as the flowID sent to the client via ``sendcommand``. + - serverTime: (optional) Most recent server timestamp, as described above. diff --git a/toolkit/components/telemetry/histogram-whitelists.json b/toolkit/components/telemetry/histogram-whitelists.json index 27eb416b2da5..1fb6becbf747 100644 --- a/toolkit/components/telemetry/histogram-whitelists.json +++ b/toolkit/components/telemetry/histogram-whitelists.json @@ -262,9 +262,6 @@ "FX_SESSION_RESTORE_NUMBER_OF_TABS_RESTORED", "FX_SESSION_RESTORE_NUMBER_OF_WINDOWS_RESTORED", "FX_TABLETMODE_PAGE_LOAD", - "FX_TAB_ANIM_ANY_FRAME_INTERVAL_MS", - "FX_TAB_ANIM_OPEN_FRAME_INTERVAL_MS", - "FX_TAB_ANIM_OPEN_PREVIEW_FRAME_INTERVAL_MS", "FX_TAB_CLICK_MS", "FX_TAB_SWITCH_SPINNER_VISIBLE_MS", "FX_TAB_SWITCH_TOTAL_E10S_MS", @@ -968,9 +965,6 @@ "FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS", "FX_SESSION_RESTORE_WRITE_FILE_MS", "FX_TABLETMODE_PAGE_LOAD", - "FX_TAB_ANIM_ANY_FRAME_INTERVAL_MS", - "FX_TAB_ANIM_OPEN_FRAME_INTERVAL_MS", - "FX_TAB_ANIM_OPEN_PREVIEW_FRAME_INTERVAL_MS", "FX_TAB_CLICK_MS", "FX_TAB_SWITCH_SPINNER_VISIBLE_MS", "FX_TAB_SWITCH_TOTAL_E10S_MS", diff --git a/toolkit/components/telemetry/tests/marionette/harness/__init__.py b/toolkit/components/telemetry/tests/marionette/harness/__init__.py old mode 100755 new mode 100644 diff --git a/toolkit/components/telemetry/tests/marionette/harness/resources/easyscreenshot.xpi b/toolkit/components/telemetry/tests/marionette/harness/resources/easyscreenshot.xpi new file mode 100644 index 000000000000..bf196cc51f5a Binary files /dev/null and b/toolkit/components/telemetry/tests/marionette/harness/resources/easyscreenshot.xpi differ diff --git a/toolkit/components/telemetry/tests/marionette/harness/setup.py b/toolkit/components/telemetry/tests/marionette/harness/setup.py index b87607f264d7..a29d4033ab7a 100755 --- a/toolkit/components/telemetry/tests/marionette/harness/setup.py +++ b/toolkit/components/telemetry/tests/marionette/harness/setup.py @@ -31,7 +31,7 @@ specific Marionette tests."""), keywords='mozilla', author='Firefox Test Engineering Team', author_email='firefox-test-engineering@mozilla.org', - url='https://hg.mozilla.org/mozilla-central/toolkit/telemetry/tests', + url='https://developer.mozilla.org/en-US/docs/Mozilla/QA/telemetry_harness', license='MPL 2.0', packages=find_packages(), zip_safe=False, diff --git a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py index aba9370e5a6b..90af2f62092f 100755 --- a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py +++ b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py @@ -7,13 +7,18 @@ import re import simplejson as json import zlib +from multiprocessing import Process + from firefox_puppeteer import PuppeteerMixin +from marionette_driver.addons import Addons +from marionette_driver.errors import MarionetteException +from marionette_driver.wait import Wait from marionette_harness import MarionetteTestCase from marionette_harness.runner import httpd - here = os.path.abspath(os.path.dirname(__file__)) doc_root = os.path.join(os.path.dirname(here), "www") +resources_dir = os.path.join(os.path.dirname(here), "resources") class TelemetryTestCase(PuppeteerMixin, MarionetteTestCase): @@ -31,19 +36,65 @@ class TelemetryTestCase(PuppeteerMixin, MarionetteTestCase): self.ping_server_url = '{}pings'.format(self.httpd.get_url('/')) telemetry_prefs = { - 'toolkit.telemetry.send.overrideOfficialCheck': True, 'toolkit.telemetry.server': self.ping_server_url, - 'toolkit.telemetry.initDelay': '1', + 'toolkit.telemetry.initDelay': 1, + 'toolkit.telemetry.minSubsessionLength': 0, 'datareporting.healthreport.uploadEnabled': True, 'datareporting.policy.dataSubmissionEnabled': True, 'datareporting.policy.dataSubmissionPolicyBypassNotification': True, 'toolkit.telemetry.log.level': 0, - 'toolkit.telemetry.log.dump': True + 'toolkit.telemetry.log.dump': True, + 'toolkit.telemetry.send.overrideOfficialCheck': True } # Firefox will be forced to restart with the prefs enforced. self.marionette.enforce_gecko_prefs(telemetry_prefs) + def wait_for_ping(self): + if len(self.ping_list) == 0: + try: + Wait(self.marionette, 60).until(lambda t: len(self.ping_list) > 0) + except Exception as e: + self.fail('Error generating ping: {}'.format(e.message)) + return self.ping_list.pop() + + def toggle_update_pref(self): + value = self.marionette.get_pref('app.update.enabled') + self.marionette.enforce_gecko_prefs({'app.update.enabled': not value}) + + def restart_browser(self): + """Restarts browser while maintaining the same profile and session.""" + self.marionette.restart(clean=False, in_app=True) + + def install_addon(self): + trigger = Process(target=self._install_addon) + trigger.start() + + def _install_addon(self): + # The addon that gets installed here is the easyscreenshot addon taken from AMO. + # It has high compatibility with firefox and doesn't cause any adverse side affects that + # could affect our tests like tabs opening, etc. + # Developed by: MozillaOnline + # Addon URL: https://addons.mozilla.org/en-US/firefox/addon/easyscreenshot/ + try: + addon_path = os.path.join(resources_dir, 'easyscreenshot.xpi') + addons = Addons(self.marionette) + addons.install(addon_path) + except MarionetteException as e: + self.fail('{} - Error installing addon: {} - '.format(e.cause, e.message)) + + @property + def client_id(self): + return self.marionette.execute_script('Cu.import("resource://gre/modules/ClientID.jsm");' + 'return ClientID.getCachedClientID();') + + @property + def subsession_id(self): + ping_data = self.marionette.execute_script( + 'Cu.import("resource://gre/modules/TelemetryController.jsm");' + 'return TelemetryController.getCurrentPingData(true);') + return ping_data[u'payload'][u'info'][u'subsessionId'] + def tearDown(self, *args, **kwargs): self.httpd.stop() super(TelemetryTestCase, self).tearDown() diff --git a/toolkit/components/telemetry/tests/marionette/tests/client/manifest.ini b/toolkit/components/telemetry/tests/marionette/tests/client/manifest.ini new file mode 100644 index 000000000000..2cd6999d1e5f --- /dev/null +++ b/toolkit/components/telemetry/tests/marionette/tests/client/manifest.ini @@ -0,0 +1,4 @@ +[DEFAULT] +tags = client + +[test_main_ping_addon_install_tab_window_scalars.py] \ No newline at end of file diff --git a/toolkit/components/telemetry/tests/marionette/tests/client/test_main_tab_scalars.py b/toolkit/components/telemetry/tests/marionette/tests/client/test_main_tab_scalars.py new file mode 100644 index 000000000000..f8224b5b6db8 --- /dev/null +++ b/toolkit/components/telemetry/tests/marionette/tests/client/test_main_tab_scalars.py @@ -0,0 +1,25 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +from telemetry_harness.testcase import TelemetryTestCase + + +class TestMainTabScalars(TelemetryTestCase): + + def test_main_tab_scalars(self): + with self.marionette.using_context(self.marionette.CONTEXT_CHROME): + tab2 = self.browser.tabbar.open_tab() + self.browser.tabbar.switch_to(tab2) + tab3 = self.browser.tabbar.open_tab() + self.browser.tabbar.switch_to(tab3) + self.browser.tabbar.close_tab(tab3, force=True) + self.browser.tabbar.close_tab(tab2, force=True) + self.install_addon() + ping = self.wait_for_ping() + assert ping['type'] == 'main' + assert ping['clientId'] == self.client_id + scalars = ping['payload']['processes']['parent']['scalars'] + assert scalars['browser.engagement.max_concurrent_tab_count'] == 3 + assert scalars['browser.engagement.tab_open_event_count'] == 2 + assert scalars['browser.engagement.max_concurrent_window_count'] == 1 diff --git a/toolkit/components/telemetry/tests/marionette/tests/manifest.ini b/toolkit/components/telemetry/tests/marionette/tests/manifest.ini index 006e94db329a..5192f5245044 100644 --- a/toolkit/components/telemetry/tests/marionette/tests/manifest.ini +++ b/toolkit/components/telemetry/tests/marionette/tests/manifest.ini @@ -1 +1,2 @@ -[include:unit/manifest.ini] \ No newline at end of file +[include:unit/manifest.ini] +[include:client/manifest.ini] \ No newline at end of file diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js index e215f6153f41..51b865413959 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js @@ -22,6 +22,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", XPCOMUtils.defineLazyModuleGetter(this, "ProfileAge", "resource://gre/modules/ProfileAge.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils", + "resource://testing-common/ExtensionXPCShellUtils.jsm"); + // The webserver hosting the addons. var gHttpServer = null; // The URL of the webserver root. @@ -672,6 +675,7 @@ function checkActiveAddon(data) { updateDay: "number", signedState, isSystem: "boolean", + isWebExtension: "boolean", }; for (let f in EXPECTED_ADDON_FIELDS_TYPES) { @@ -1126,6 +1130,7 @@ add_task(function* test_addonsAndPlugins() { updateDay: ADDON_INSTALL_DATE, signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED, isSystem: false, + isWebExtension: false, }; const SYSTEM_ADDON_ID = "tel-system-xpi@tests.mozilla.org"; const EXPECTED_SYSTEM_ADDON_DATA = { @@ -1143,6 +1148,27 @@ add_task(function* test_addonsAndPlugins() { updateDay: truncateToDays(SYSTEM_ADDON_INSTALL_DATE), signedState: undefined, isSystem: true, + isWebExtension: false, + }; + + const WEBEXTENSION_ADDON_ID = "tel-webextension-xpi@tests.mozilla.org"; + const WEBEXTENSION_ADDON_INSTALL_DATE = truncateToDays(Date.now()); + const EXPECTED_WEBEXTENSION_ADDON_DATA = { + blocklisted: false, + description: "A webextension addon.", + name: "XPI Telemetry WebExtension Add-on Test", + userDisabled: false, + appDisabled: false, + version: "1.0", + scope: 1, + type: "extension", + foreignInstall: false, + hasBinaryComponents: false, + installDay: WEBEXTENSION_ADDON_INSTALL_DATE, + updateDay: WEBEXTENSION_ADDON_INSTALL_DATE, + signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED, + isSystem: false, + isWebExtension: true, }; const EXPECTED_PLUGIN_DATA = { @@ -1154,9 +1180,38 @@ add_task(function* test_addonsAndPlugins() { clicktoplay: true, }; - // Install an addon so we have some data. + let deferred = PromiseUtils.defer(); + TelemetryEnvironment.registerChangeListener("test_WebExtension", + (reason, data) => { + Assert.equal(reason, "addons-changed"); + deferred.resolve(); + } + ); + + // Install an add-on so we have some data. yield AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL); + // Install a webextension as well. + ExtensionTestUtils.init(this); + + let webextension = ExtensionTestUtils.loadExtension({ + useAddonManager: "permanent", + manifest: { + "name": "XPI Telemetry WebExtension Add-on Test", + "description": "A webextension addon.", + "version": "1.0", + "applications": { + "gecko": { + "id": WEBEXTENSION_ADDON_ID, + }, + }, + }, + }); + + yield webextension.startup(); + yield deferred.promise; + TelemetryEnvironment.unregisterChangeListener("test_WebExtension"); + let data = TelemetryEnvironment.currentEnvironment; checkEnvironmentData(data); @@ -1174,6 +1229,15 @@ add_task(function* test_addonsAndPlugins() { Assert.equal(targetSystemAddon[f], EXPECTED_SYSTEM_ADDON_DATA[f], f + " must have the correct value."); } + // Check webextension add-on data. + Assert.ok(WEBEXTENSION_ADDON_ID in data.addons.activeAddons, "We must have one active webextension addon."); + let targetWebExtensionAddon = data.addons.activeAddons[WEBEXTENSION_ADDON_ID]; + for (let f in EXPECTED_WEBEXTENSION_ADDON_DATA) { + Assert.equal(targetWebExtensionAddon[f], EXPECTED_WEBEXTENSION_ADDON_DATA[f], f + " must have the correct value."); + } + + yield webextension.unload(); + // Check theme data. let theme = data.addons.theme; Assert.equal(theme.id, (PERSONA_ID + PERSONA_ID_SUFFIX)); diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js b/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js index f90b2f5ac685..d3f8daaee2d8 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js @@ -52,6 +52,13 @@ function run_test() { do_check_true(TelemetryStopwatch.start("NON-EXISTENT_HISTOGRAM", refObj)); do_check_false(TelemetryStopwatch.finish("NON-EXISTENT_HISTOGRAM", refObj)); + do_check_false(TelemetryStopwatch.running(HIST_NAME)); + do_check_false(TelemetryStopwatch.running(HIST_NAME2)); + do_check_false(TelemetryStopwatch.running(HIST_NAME, refObj)); + do_check_false(TelemetryStopwatch.running(HIST_NAME2, refObj)); + do_check_false(TelemetryStopwatch.running(HIST_NAME, refObj2)); + do_check_false(TelemetryStopwatch.running(HIST_NAME2, refObj2)); + do_check_true(TelemetryStopwatch.start(HIST_NAME)); do_check_true(TelemetryStopwatch.start(HIST_NAME2)); do_check_true(TelemetryStopwatch.start(HIST_NAME, refObj)); @@ -59,6 +66,14 @@ function run_test() { do_check_true(TelemetryStopwatch.start(HIST_NAME, refObj2)); do_check_true(TelemetryStopwatch.start(HIST_NAME2, refObj2)); + do_check_true(TelemetryStopwatch.running(HIST_NAME)); + do_check_true(TelemetryStopwatch.running(HIST_NAME)); + do_check_true(TelemetryStopwatch.running(HIST_NAME2)); + do_check_true(TelemetryStopwatch.running(HIST_NAME, refObj)); + do_check_true(TelemetryStopwatch.running(HIST_NAME2, refObj)); + do_check_true(TelemetryStopwatch.running(HIST_NAME, refObj2)); + do_check_true(TelemetryStopwatch.running(HIST_NAME2, refObj2)); + do_check_true(TelemetryStopwatch.finish(HIST_NAME)); do_check_true(TelemetryStopwatch.finish(HIST_NAME2)); do_check_true(TelemetryStopwatch.finish(HIST_NAME, refObj)); @@ -66,6 +81,14 @@ function run_test() { do_check_true(TelemetryStopwatch.finish(HIST_NAME, refObj2)); do_check_true(TelemetryStopwatch.finish(HIST_NAME2, refObj2)); + do_check_false(TelemetryStopwatch.running(HIST_NAME)); + do_check_false(TelemetryStopwatch.running(HIST_NAME)); + do_check_false(TelemetryStopwatch.running(HIST_NAME2)); + do_check_false(TelemetryStopwatch.running(HIST_NAME, refObj)); + do_check_false(TelemetryStopwatch.running(HIST_NAME2, refObj)); + do_check_false(TelemetryStopwatch.running(HIST_NAME, refObj2)); + do_check_false(TelemetryStopwatch.running(HIST_NAME2, refObj2)); + // Verify that TS.finish deleted the timers do_check_false(TelemetryStopwatch.finish(HIST_NAME)); do_check_false(TelemetryStopwatch.finish(HIST_NAME, refObj)); @@ -81,8 +104,12 @@ function run_test() { do_check_false(TelemetryStopwatch.finish(HIST_NAME, {})); // Known mark on unknown object // Test cancel + do_check_false(TelemetryStopwatch.running(HIST_NAME)); + do_check_false(TelemetryStopwatch.running(HIST_NAME, refObj)); do_check_true(TelemetryStopwatch.start(HIST_NAME)); do_check_true(TelemetryStopwatch.start(HIST_NAME, refObj)); + do_check_true(TelemetryStopwatch.running(HIST_NAME)); + do_check_true(TelemetryStopwatch.running(HIST_NAME, refObj)); do_check_true(TelemetryStopwatch.cancel(HIST_NAME)); do_check_true(TelemetryStopwatch.cancel(HIST_NAME, refObj)); @@ -91,6 +118,8 @@ function run_test() { do_check_false(TelemetryStopwatch.cancel(HIST_NAME, refObj)); // Verify that cancel removes the timers + do_check_false(TelemetryStopwatch.running(HIST_NAME)); + do_check_false(TelemetryStopwatch.running(HIST_NAME, refObj)); do_check_false(TelemetryStopwatch.finish(HIST_NAME)); do_check_false(TelemetryStopwatch.finish(HIST_NAME, refObj)); @@ -100,11 +129,21 @@ function run_test() { } // Verify that keyed histograms can be started. + do_check_false(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY1")); + do_check_false(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY2")); + do_check_false(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY1", refObj)); + do_check_false(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY2", refObj)); + do_check_true(TelemetryStopwatch.startKeyed("HISTOGRAM", "KEY1")); do_check_true(TelemetryStopwatch.startKeyed("HISTOGRAM", "KEY2")); do_check_true(TelemetryStopwatch.startKeyed("HISTOGRAM", "KEY1", refObj)); do_check_true(TelemetryStopwatch.startKeyed("HISTOGRAM", "KEY2", refObj)); + do_check_true(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY1")); + do_check_true(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY2")); + do_check_true(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY1", refObj)); + do_check_true(TelemetryStopwatch.runningKeyed("HISTOGRAM", "KEY2", refObj)); + // Restarting keyed histograms should fail. do_check_false(TelemetryStopwatch.startKeyed("HISTOGRAM", "KEY1")); do_check_false(TelemetryStopwatch.startKeyed("HISTOGRAM", "KEY1", refObj)); @@ -117,7 +156,7 @@ function run_test() { do_check_true(TelemetryStopwatch.startKeyed(KEYED_HIST.id, KEYED_HIST.key)); do_check_true(TelemetryStopwatch.finishKeyed(KEYED_HIST.id, KEYED_HIST.key)); // Verify that TS.finish deleted the timers - do_check_false(TelemetryStopwatch.finishKeyed(KEYED_HIST.id, KEYED_HIST.key)); + do_check_false(TelemetryStopwatch.runningKeyed(KEYED_HIST.id, KEYED_HIST.key)); // Verify that they can be used again do_check_true(TelemetryStopwatch.startKeyed(KEYED_HIST.id, KEYED_HIST.key)); diff --git a/toolkit/components/url-classifier/content/listmanager.js b/toolkit/components/url-classifier/content/listmanager.js index 68325bec8fca..7f52b1ca9cf9 100644 --- a/toolkit/components/url-classifier/content/listmanager.js +++ b/toolkit/components/url-classifier/content/listmanager.js @@ -132,6 +132,13 @@ PROT_ListManager.prototype.getGethashUrl = function(tableName) { return ""; } +PROT_ListManager.prototype.getUpdateUrl = function(tableName) { + if (this.tablesData[tableName] && this.tablesData[tableName].updateUrl) { + return this.tablesData[tableName].updateUrl; + } + return ""; +} + /** * Enable updates for some tables * @param tables - an array of table names that need updating @@ -483,6 +490,12 @@ PROT_ListManager.prototype.makeUpdateRequestForEntry_ = function(updateUrl, BindToObject(this.downloadError_, this, tableList, updateUrl))) { // Our alarm gets reset in one of the 3 callbacks. log("pending update, queued request until later"); + } else { + let table = Object.keys(this.tablesData).find(key => { + return this.tablesData[key].updateUrl === updateUrl; + }); + let provider = this.tablesData[table].provider; + Services.obs.notifyObservers(null, "safebrowsing-update-begin", provider); } } @@ -550,6 +563,8 @@ PROT_ListManager.prototype.updateSuccess_ = function(tableList, updateUrl, log("Setting next update of " + provider + " to " + targetTime + " (" + delay + "ms from now)"); this.prefs_.setPref(nextUpdatePref, targetTime.toString()); + + Services.obs.notifyObservers(null, "safebrowsing-update-finished", "success"); } /** @@ -563,6 +578,9 @@ PROT_ListManager.prototype.updateError_ = function(table, updateUrl, result) { this.updateCheckers_[updateUrl] = new G_Alarm(BindToObject(this.checkForUpdates, this, updateUrl), this.updateInterval, false); + + Services.obs.notifyObservers(null, "safebrowsing-update-finished", + "update error(" + result + ")"); } /** @@ -589,6 +607,8 @@ PROT_ListManager.prototype.downloadError_ = function(table, updateUrl, status) { new G_Alarm(BindToObject(this.checkForUpdates, this, updateUrl), delay, false); + Services.obs.notifyObservers(null, "safebrowsing-update-finished", + "download error(" + status + ")"); } PROT_ListManager.prototype.QueryInterface = function(iid) { diff --git a/toolkit/components/url-classifier/nsIUrlListManager.idl b/toolkit/components/url-classifier/nsIUrlListManager.idl index 112c567dcd57..f4b1350e8d8e 100644 --- a/toolkit/components/url-classifier/nsIUrlListManager.idl +++ b/toolkit/components/url-classifier/nsIUrlListManager.idl @@ -26,6 +26,11 @@ interface nsIUrlListManager : nsISupports */ ACString getGethashUrl(in ACString tableName); + /** + * Get the update url for this table + */ + ACString getUpdateUrl(in ACString tableName); + /** * Add a table to the list of tables we are managing. The name is a * string of the format provider_name-semantic_type-table_type. For @@ -64,4 +69,10 @@ interface nsIUrlListManager : nsISupports */ void safeLookup(in nsIPrincipal key, in nsIUrlListManagerCallback cb); + + /** + * This is currently used by about:url-classifier to force an update + * for the update url. Update may still fail because of backoff algorithm. + */ + boolean checkForUpdates(in ACString updateUrl); }; diff --git a/toolkit/content/aboutUrlClassifier.css b/toolkit/content/aboutUrlClassifier.css new file mode 100644 index 000000000000..937a86ac76d5 --- /dev/null +++ b/toolkit/content/aboutUrlClassifier.css @@ -0,0 +1,72 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +html { + --aboutUrlClassifier-table-background: #ebebeb; + background-color: var(--in-content-page-background); +} + +body { + margin: 40px 48px; +} + +.major-section { + margin-top: 2em; + margin-bottom: 1em; + font-size: large; + text-align: start; + font-weight: bold; +} + +table { + background-color: var(--aboutUrlClassifier-table-background); + color: var(--in-content-text-color); + font: message-box; + text-align: start; + width: 100%; + border: 1px solid var(--in-content-border-color); + border-spacing: 0px; +} + +th, td { + border: 1px solid var(--in-content-border-color); + padding: 4px; +} + +thead th { + text-align: center; +} + +th { + text-align: start; + background-color: var(--in-content-table-header-background); + color: var(--in-content-selected-text); +} + +th.column { + white-space: nowrap; + width: 0px; +} + +td { + text-align: start; + border-color: var(--in-content-table-border-dark-color); +} + +#provider-table > tbody > tr > td:last-child { + text-align: center; +} + +#debug-table { + margin-top: 20px; +} + +.options > .toggle-container-with-text { + display: inline-flex; +} + +button { + margin-inline-start: 0; + margin-inline-end: 8px; +} diff --git a/toolkit/content/aboutUrlClassifier.js b/toolkit/content/aboutUrlClassifier.js new file mode 100644 index 000000000000..b542bffea140 --- /dev/null +++ b/toolkit/content/aboutUrlClassifier.js @@ -0,0 +1,335 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var Ci = Components.interfaces; +var Cc = Components.classes; +var Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); + +const bundle = Services.strings.createBundle( + "chrome://global/locale/aboutUrlClassifier.properties"); + +const UPDATE_BEGIN = "safebrowsing-update-begin"; +const UPDATE_FINISH = "safebrowsing-update-finished"; +const JSLOG_PREF = "browser.safebrowsing.debug"; + +const STR_NA = bundle.GetStringFromName("NotAvailable"); + +function unLoad() { + window.removeEventListener("unload", unLoad); + + Provider.uninit(); + Debug.uninit(); +} + +function onLoad() { + window.removeEventListener("load", onLoad); + window.addEventListener("unload", unLoad); + + Provider.init(); + Debug.init(); +} + +/* + * Provider + */ +var Provider = { + providers: null, + + updatingProvider: "", + + init() { + this.providers = new Set(); + let branch = Services.prefs.getBranch("browser.safebrowsing.provider."); + let children = branch.getChildList("", {}); + for (let child of children) { + this.providers.add(child.split(".")[0]); + } + + this.register(); + this.render(); + this.refresh(); + }, + + uninit() { + Services.obs.removeObserver(this.onBeginUpdate, UPDATE_BEGIN); + Services.obs.removeObserver(this.onFinishUpdate, UPDATE_FINISH); + }, + + onBeginUpdate(aSubject, aTopic, aData) { + this.updatingProvider = aData; + let p = this.updatingProvider; + + // Disable update button for the provider while we are doing update. + document.getElementById("update-" + p).disabled = true; + + let elem = document.getElementById(p + "-col-lastupdateresult"); + elem.childNodes[0].nodeValue = bundle.GetStringFromName("Updating"); + }, + + onFinishUpdate(aSubject, aTopic, aData) { + let p = this.updatingProvider; + this.updatingProvider = ""; + + // It is possible that we get update-finished event only because + // about::url-classifier is opened after update-begin event is fired. + if (p === "") { + this.refresh(); + return; + } + + this.refresh([p]); + + document.getElementById("update-" + p).disabled = false; + + let elem = document.getElementById(p + "-col-lastupdateresult"); + elem.childNodes[0].nodeValue = aData; + }, + + register() { + // Handle begin update + this.onBeginUpdate = this.onBeginUpdate.bind(this); + Services.obs.addObserver(this.onBeginUpdate, UPDATE_BEGIN); + + // Handle finish update + this.onFinishUpdate = this.onFinishUpdate.bind(this); + Services.obs.addObserver(this.onFinishUpdate, UPDATE_FINISH); + }, + + // This should only be called once because we assume number of providers + // won't change. + render() { + let tbody = document.getElementById("provider-table-body"); + + for (let provider of this.providers) { + let tr = document.createElement("tr"); + let cols = document.getElementById("provider-head-row").childNodes; + for (let column of cols) { + if (!column.id) { + continue; + } + let td = document.createElement("td"); + td.id = provider + "-" + column.id; + + if (column.id === "col-update") { + let btn = document.createElement("button"); + btn.id = "update-" + provider; + btn.addEventListener("click", () => { this.update(provider); }); + + let str = bundle.GetStringFromName("TriggerUpdate") + btn.appendChild(document.createTextNode(str)); + td.appendChild(btn); + } else { + let str = column.id === "col-lastupdateresult" ? STR_NA : ""; + td.appendChild(document.createTextNode(str)); + } + tr.appendChild(td); + } + tbody.appendChild(tr); + } + }, + + refresh(listProviders = this.providers) { + for (let provider of listProviders) { + let values = {}; + values["col-provider"] = provider; + + let pref = "browser.safebrowsing.provider." + provider + ".lastupdatetime"; + let lut = Services.prefs.getCharPref(pref, ""); + values["col-lastupdatetime"] = lut ? new Date(lut * 1) : STR_NA; + + pref = "browser.safebrowsing.provider." + provider + ".nextupdatetime"; + let nut = Services.prefs.getCharPref(pref, ""); + values["col-nextupdatetime"] = nut ? new Date(nut * 1) : STR_NA; + + for (let key of Object.keys(values)) { + let elem = document.getElementById(provider + "-" + key); + elem.childNodes[0].nodeValue = values[key]; + } + } + }, + + // Call update for the provider. + update(provider) { + let listmanager = Cc["@mozilla.org/url-classifier/listmanager;1"] + .getService(Ci.nsIUrlListManager); + + let pref = "browser.safebrowsing.provider." + provider + ".lists"; + let table = Services.prefs.getCharPref(pref, "").split(",")[0]; + + let updateUrl = listmanager.getUpdateUrl(table); + if (!listmanager.checkForUpdates(updateUrl)) { + // This may because of back-off algorithm. + let elem = document.getElementById(provider + "-col-lastupdateresult"); + elem.childNodes[0].nodeValue = bundle.GetStringFromName("CannotUpdate"); + } + }, + +}; + +/* + * Debug + */ +var Debug = { + // url-classifier NSPR Log modules. + modules: ["UrlClassifierDbService", + "nsChannelClassifier", + "UrlClassifierProtocolParser", + "UrlClassifierStreamUpdater", + "UrlClassifierPrefixSet", + "ApplicationReputation"], + + init() { + this.register(); + this.render(); + this.refresh(); + }, + + uninit() { + Services.prefs.removeObserver(JSLOG_PREF, this.refreshJSDebug); + }, + + register() { + this.refreshJSDebug = this.refreshJSDebug.bind(this); + Services.prefs.addObserver(JSLOG_PREF, this.refreshJSDebug); + }, + + render() { + // This function update the log module text field if we click + // safebrowsing log module check box. + function logModuleUpdate(module) { + let txt = document.getElementById("log-modules"); + let chk = document.getElementById("chk-" + module); + + let dst = chk.checked ? "," + module + ":5" : ""; + let re = new RegExp(",?" + module + ":[0-9]"); + + let str = txt.value.replace(re, dst); + if (chk.checked) { + str = txt.value === str ? str + dst : str; + } + txt.value = str.replace(/^,/, ""); + } + + let setLog = document.getElementById("set-log-modules"); + setLog.addEventListener("click", this.nsprlog); + + let setLogFile = document.getElementById("set-log-file"); + setLogFile.addEventListener("click", this.logfile); + + let setJSLog = document.getElementById("js-log"); + setJSLog.addEventListener("click", this.jslog); + + let modules = document.getElementById("log-modules"); + let sbModules = document.getElementById("sb-log-modules"); + for (let module of this.modules) { + let container = document.createElement("div"); + container.className = "toggle-container-with-text"; + sbModules.appendChild(container); + + let chk = document.createElement("input"); + chk.id = "chk-" + module; + chk.type = "checkbox"; + chk.checked = true; + chk.addEventListener("click", () => { logModuleUpdate(module) }); + container.appendChild(chk, modules); + + let label = document.createElement("label"); + label.for = chk.id; + label.appendChild(document.createTextNode(module)); + container.appendChild(label, modules); + } + + this.modules.map(logModuleUpdate); + + let file = Services.dirsvc.get("TmpD", Ci.nsIFile); + file.append("safebrowsing.log"); + + let logFile = document.getElementById("log-file"); + logFile.value = file.path; + + let curLog = document.getElementById("cur-log-modules"); + curLog.childNodes[0].nodeValue = ""; + + let curLogFile = document.getElementById("cur-log-file"); + curLogFile.childNodes[0].nodeValue = ""; + }, + + refresh() { + this.refreshJSDebug(); + + // Disable configure log modules if log modules are already set + // by environment variable. + let env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + + let logModules = env.get("MOZ_LOG") || + env.get("MOZ_LOG_MODULES") || + env.get("NSPR_LOG_MODULES"); + + if (logModules.length > 0) { + document.getElementById("set-log-modules").disabled = true; + for (let module of this.modules) { + document.getElementById("chk-" + module).disabled = true; + } + + let curLogModules = document.getElementById("cur-log-modules"); + curLogModules.childNodes[0].nodeValue = logModules; + } + + // Disable set log file if log file is already set + // by environment variable. + let logFile = env.get("MOZ_LOG_FILE") || env.get("NSPR_LOG_FILE"); + if (logFile.length > 0) { + document.getElementById("set-log-file").disabled = true; + document.getElementById("log-file").value = logFile; + } + }, + + refreshJSDebug() { + let enabled = Services.prefs.getBoolPref(JSLOG_PREF, false); + + let jsChk = document.getElementById("js-log"); + jsChk.checked = enabled; + + let curJSLog = document.getElementById("cur-js-log"); + curJSLog.childNodes[0].nodeValue = enabled ? + bundle.GetStringFromName("Enabled") : + bundle.GetStringFromName("Disabled"); + }, + + jslog() { + let enabled = Services.prefs.getBoolPref(JSLOG_PREF, false); + Services.prefs.setBoolPref(JSLOG_PREF, !enabled); + }, + + nsprlog() { + // Turn off debugging for all the modules. + let children = Services.prefs.getBranch("logging.").getChildList("", {}); + for (let pref of children) { + if (!pref.startsWith("config.")) { + Services.prefs.clearUserPref(`logging.${pref}`); + } + } + + let value = document.getElementById("log-modules").value; + let logModules = value.split(","); + for (let module of logModules) { + let [key, value] = module.split(":"); + Services.prefs.setIntPref(`logging.${key}`, parseInt(value, 10)); + } + + let curLogModules = document.getElementById("cur-log-modules"); + curLogModules.childNodes[0].nodeValue = value; + }, + + logfile() { + let logFile = document.getElementById("log-file").value.trim(); + Services.prefs.setCharPref("logging.config.LOG_FILE", logFile); + + let curLogFile = document.getElementById("cur-log-file"); + curLogFile.childNodes[0].nodeValue = logFile; + } +}; diff --git a/toolkit/content/aboutUrlClassifier.xhtml b/toolkit/content/aboutUrlClassifier.xhtml new file mode 100644 index 000000000000..f91e791458bf --- /dev/null +++ b/toolkit/content/aboutUrlClassifier.xhtml @@ -0,0 +1,80 @@ + + + + + %htmlDTD; + %globalDTD; + %brandDTD; + %urlClassifierDTD; +]> + + + + + + + + + +

&aboutUrlClassifier.pageTitle;

+
+

&aboutUrlClassifier.providerTitle;

+ + + + + + + + + + + + + +
&aboutUrlClassifier.provider;&aboutUrlClassifier.providerLastUpdateTime;&aboutUrlClassifier.providerNextUpdateTime;&aboutUrlClassifier.providerLastUpdateStatus;&aboutUrlClassifier.providerUpdateBtn;
+
+
+

&aboutUrlClassifier.debugTitle;

+
+ + +

+ + +

+
+ + +
+
+ + + + + + + + + + + + + + + + + + + +
&aboutUrlClassifier.debugSBModules; +
&aboutUrlClassifier.debugModules; +
&aboutUrlClassifier.debugSBJSModules; +
&aboutUrlClassifier.debugFile; +
+
+ + diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index 659a8cf7741b..04a24f98641d 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -33,6 +33,9 @@ toolkit.jar: content/global/aboutTelemetry.js content/global/aboutTelemetry.xhtml content/global/aboutTelemetry.css + content/global/aboutUrlClassifier.js + content/global/aboutUrlClassifier.xhtml + content/global/aboutUrlClassifier.css content/global/directionDetector.html content/global/plugins.html content/global/plugins.css diff --git a/toolkit/content/widgets/scrollbox.xml b/toolkit/content/widgets/scrollbox.xml index 4611cfdeffe5..459467a9d472 100644 --- a/toolkit/content/widgets/scrollbox.xml +++ b/toolkit/content/widgets/scrollbox.xml @@ -758,10 +758,6 @@ // See bug 341047 and comments in overflow handler as to why // try..catch is needed here this._updateScrollButtonsDisabledState(); - - let childNodes = this._getScrollableElements(); - if (childNodes && childNodes.length) - this.ensureElementIsVisible(childNodes[0], false); } catch (e) { this.removeAttribute("notoverflowing"); } diff --git a/toolkit/crashreporter/breakpad-client/linux/moz.build b/toolkit/crashreporter/breakpad-client/linux/moz.build index 73a08eb16e62..d84a33956b3f 100644 --- a/toolkit/crashreporter/breakpad-client/linux/moz.build +++ b/toolkit/crashreporter/breakpad-client/linux/moz.build @@ -37,7 +37,4 @@ if CONFIG['OS_TARGET'] == 'Android' and CONFIG['CPU_ARCH'] == 'x86': # The NDK's user.h defines this struct with a different name. DEFINES['user_fpxregs_struct'] = 'user_fxsr_struct' -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - DEFINES['getcontext'] = 'breakpad_getcontext' - include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build index 79debb3f88e1..191e90ceb09a 100644 --- a/toolkit/library/moz.build +++ b/toolkit/library/moz.build @@ -199,11 +199,6 @@ if CONFIG['OS_ARCH'] == 'WINNT': 'winspool', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - OS_LIBS += [ - 'dbus', - ] - if CONFIG['OS_ARCH'] == 'Linux' and CONFIG['OS_TARGET'] != 'Android': OS_LIBS += [ 'rt', @@ -242,35 +237,6 @@ if CONFIG['MOZ_ALSA']: if CONFIG['HAVE_CLOCK_MONOTONIC']: OS_LIBS += CONFIG['REALTIME_LIBS'] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - OS_LIBS += [ - 'ui', - 'media', - 'hardware_legacy', - 'hardware', - 'utils', - 'cutils', - 'sysutils', - 'camera_client', - 'sensorservice', - 'stagefright', - 'stagefright_foundation', - 'stagefright_omx', - 'binder', - 'gui', - 'mtp', - ] - - if int(CONFIG['ANDROID_VERSION']) >= 17: - OS_LIBS += [ - 'sync', - ] - - if CONFIG['ANDROID_VERSION'] >= '16': - OS_LIBS += [ - 'mdnssd', - ] - if 'rtsp' in CONFIG['NECKO_PROTOCOLS']: OS_LIBS += [ 'stagefright_foundation', diff --git a/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.dtd b/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.dtd new file mode 100644 index 000000000000..9b6906213ab0 --- /dev/null +++ b/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.dtd @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.properties b/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.properties new file mode 100644 index 000000000000..ecb3c29fcd49 --- /dev/null +++ b/toolkit/locales/en-US/chrome/global/aboutUrlClassifier.properties @@ -0,0 +1,19 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +TriggerUpdate = Trigger Update + +NotAvailable = N/A + +DisableSBJSLog = Disable Safe Browsing JS Log + +EnableSBJSLog = Enable Safe Browsing JS Log + +Enabled = Enabled + +Disabled = Disabled + +Updating = updating + +CannotUpdate = cannot update diff --git a/toolkit/locales/jar.mn b/toolkit/locales/jar.mn index f8892b1660e6..7e1d89677c4c 100644 --- a/toolkit/locales/jar.mn +++ b/toolkit/locales/jar.mn @@ -21,6 +21,8 @@ locale/@AB_CD@/global/aboutSupport.properties (%chrome/global/aboutSupport.properties) locale/@AB_CD@/global/aboutTelemetry.dtd (%chrome/global/aboutTelemetry.dtd) locale/@AB_CD@/global/aboutTelemetry.properties (%chrome/global/aboutTelemetry.properties) + locale/@AB_CD@/global/aboutUrlClassifier.dtd (%chrome/global/aboutUrlClassifier.dtd) + locale/@AB_CD@/global/aboutUrlClassifier.properties (%chrome/global/aboutUrlClassifier.properties) locale/@AB_CD@/global/aboutWebrtc.properties (%chrome/global/aboutWebrtc.properties) locale/@AB_CD@/global/autocomplete.properties (%chrome/global/autocomplete.properties) locale/@AB_CD@/global/appPicker.dtd (%chrome/global/appPicker.dtd) diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index ad9d72b3bc90..a3200dd99f62 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -494,7 +494,7 @@ var dataProviders = { // // - let ext = gl.getExtension("MOZ_debug_get"); + let ext = gl.getExtension("MOZ_debug"); // This extension is unconditionally available to chrome. No need to check. let vendor = ext.getParameter(gl.VENDOR); let renderer = ext.getParameter(gl.RENDERER); diff --git a/toolkit/moz.configure b/toolkit/moz.configure index ed6310060d27..d6b0e1062eb0 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -118,7 +118,7 @@ set_config('L10NBASEDIR', l10n_base) # reason. option('--enable-default-toolkit', nargs=1, choices=('cairo-windows', 'cairo-gtk3', 'cairo-gtk3-wayland', - 'cairo-cocoa', 'cairo-uikit', 'cairo-android', 'cairo-gonk'), + 'cairo-cocoa', 'cairo-uikit', 'cairo-android'), help='Select default toolkit') @depends('--enable-default-toolkit', target, '--help') @@ -250,7 +250,7 @@ set_define(gl_provider_define, True) # ============================================================== @depends(toolkit) def pdf_printing(toolkit): - if toolkit in ('windows', 'gtk2', 'gtk3', 'android', 'gonk'): + if toolkit in ('windows', 'gtk2', 'gtk3', 'android'): return True @depends(pdf_printing) @@ -272,8 +272,8 @@ option(env='MOZ_INSTRUMENT_EVENT_LOOP', @depends('MOZ_INSTRUMENT_EVENT_LOOP', toolkit) def instrument_event_loop(value, toolkit): - if value or (toolkit in ('windows', 'gtk2', 'gtk3', 'cocoa', 'android', - 'gonk') and value.origin == 'default'): + if value or (toolkit in ('windows', 'gtk2', 'gtk3', 'cocoa', 'android') and + value.origin == 'default'): return True set_config('MOZ_INSTRUMENT_EVENT_LOOP', instrument_event_loop) @@ -1005,9 +1005,9 @@ set_config('MOZ_MORTAR', True, when='--enable-mortar') # Marionette isn't really a toolkit feature, it's a Gecko engine feature, but # it's enabled based on the toolkit (and target), so here it lives. -@depends(target, toolkit) -def marionette_default(target, toolkit): - # By default, enable Marionette if not Android and not gonk. +@depends(target) +def marionette_default(target): + # By default, enable Marionette if not Android. # # None means "don't set anything", which allows to override with # --enable-marionette. False means --disable-marionette, which @@ -1016,13 +1016,10 @@ def marionette_default(target, toolkit): if target.os == 'Android': return None - if toolkit == 'gonk': - return None - return True imply_option('--enable-marionette', marionette_default, - reason='not Android and not gonk') + reason='not Android') option('--enable-marionette', help='Enable internal Marionette command server') diff --git a/toolkit/mozapps/extensions/internal/AddonRepository.jsm b/toolkit/mozapps/extensions/internal/AddonRepository.jsm index 2f0ce03e9727..6cac732826c2 100644 --- a/toolkit/mozapps/extensions/internal/AddonRepository.jsm +++ b/toolkit/mozapps/extensions/internal/AddonRepository.jsm @@ -121,27 +121,37 @@ function convertHTMLToPlainText(html) { return html; } -function getAddonsToCache(aIds) { +async function getAddonsToCache(aIds) { let types = Preferences.get(PREF_GETADDONS_CACHE_TYPES) || DEFAULT_CACHE_TYPES; types = types.split(","); - return AddonManager.getAddonsByIDs(aIds).then(addons => { - let enabledIds = []; - for (let [i, addon] of addons.entries()) { - var preference = PREF_GETADDONS_CACHE_ID_ENABLED.replace("%ID%", aIds[i]); - // If the preference doesn't exist caching is enabled by default - if (!Preferences.get(preference, true)) - continue; + let addons = await AddonManager.getAddonsByIDs(aIds) + let enabledIds = []; - // The add-ons manager may not know about this ID yet if it is a pending - // install. In that case we'll just cache it regardless - if (!addon || types.includes(addon.type)) - enabledIds.push(aIds[i]); + for (let [i, addon] of addons.entries()) { + var preference = PREF_GETADDONS_CACHE_ID_ENABLED.replace("%ID%", aIds[i]); + // If the preference doesn't exist caching is enabled by default + if (!Preferences.get(preference, true)) + continue; + + // The add-ons manager may not know about this ID yet if it is a pending + // install. In that case we'll just cache it regardless + + // Don't cache add-ons of the wrong types + if (addon && !types.includes(addon.type)) { + continue; } - return enabledIds; - }); + // Don't cache system add-ons + if (addon && addon.isSystem) { + continue; + } + + enabledIds.push(aIds[i]); + } + + return enabledIds; } function AddonSearchResult(aId) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_repository.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_repository.js new file mode 100644 index 000000000000..e2d8e3106b1b --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_repository.js @@ -0,0 +1,52 @@ +// Tests that AddonRepository doesn't download results for system add-ons + +const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled"; + +BootstrapMonitor.init(); + +Components.utils.import("resource://testing-common/httpd.js"); +var gServer = new HttpServer(); +gServer.start(-1); + +// Build the test set +var distroDir = FileUtils.getDir("ProfD", ["sysfeatures"], true); +do_get_file("data/system_addons/system1_1.xpi").copyTo(distroDir, "system1@tests.mozilla.org.xpi"); +do_get_file("data/system_addons/system2_1.xpi").copyTo(distroDir, "system2@tests.mozilla.org.xpi"); +do_get_file("data/system_addons/system3_1.xpi").copyTo(distroDir, "system3@tests.mozilla.org.xpi"); +registerDirectory("XREAppFeat", distroDir); + +createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "0"); + +function getCachedAddon(id) { + return new Promise(resolve => AddonRepository.getCachedAddonByID(id, resolve)); +} + +// Test with a missing features directory +add_task(function* test_app_addons() { + Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true); + Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, `http://localhost:${gServer.identity.primaryPort}/get?%IDS%`); + + gServer.registerPathHandler("/get", (request, response) => { + do_throw("Unexpected request to server."); + }); + + startupManager(); + + yield new Promise((resolve) => { + AddonRepository.cacheAddons(["system1@tests.mozilla.org", + "system2@tests.mozilla.org", + "system3@tests.mozilla.org"], resolve); + }); + + let cached = yield getCachedAddon("system1@tests.mozilla.org"); + do_check_eq(cached, null); + + cached = yield getCachedAddon("system2@tests.mozilla.org"); + do_check_eq(cached, null); + + cached = yield getCachedAddon("system3@tests.mozilla.org"); + do_check_eq(cached, null); + + yield promiseShutdownManager(); + yield new Promise(resolve => gServer.stop(resolve)); +}); diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini index ab116afd1790..f2ca7e60f6d4 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -32,6 +32,7 @@ tags = blocklist [test_shutdown.js] [test_system_update.js] [test_system_update_fail.js] +[test_system_repository.js] [test_system_reset.js] [test_XPIcancel.js] [test_XPIStates.js] diff --git a/toolkit/mozapps/update/UpdateTelemetry.jsm b/toolkit/mozapps/update/UpdateTelemetry.jsm index d64085143499..e25be0960a47 100644 --- a/toolkit/mozapps/update/UpdateTelemetry.jsm +++ b/toolkit/mozapps/update/UpdateTelemetry.jsm @@ -174,7 +174,6 @@ this.AUSTLMY = { DWNLD_RETRY_NET_RESET: 4, DWNLD_ERR_NO_UPDATE: 5, DWNLD_ERR_NO_UPDATE_PATCH: 6, - DWNLD_ERR_NO_PATCH_FILE: 7, DWNLD_ERR_PATCH_SIZE_LARGER: 8, DWNLD_ERR_PATCH_SIZE_NOT_EQUAL: 9, DWNLD_ERR_BINDING_ABORTED: 10, diff --git a/toolkit/mozapps/update/common/errors.h b/toolkit/mozapps/update/common/errors.h index e5134efe26e8..c978d40e1475 100644 --- a/toolkit/mozapps/update/common/errors.h +++ b/toolkit/mozapps/update/common/errors.h @@ -61,7 +61,7 @@ #define UNEXPECTED_MAR_ERROR 40 #define UNEXPECTED_BSPATCH_ERROR 41 #define UNEXPECTED_FILE_OPERATION_ERROR 42 -#define FILESYSTEM_MOUNT_READWRITE_ERROR 43 +// #define FILESYSTEM_MOUNT_READWRITE_ERROR 43 // Removed support for gonk #define DELETE_ERROR_EXPECTED_DIR 46 #define DELETE_ERROR_EXPECTED_FILE 47 #define RENAME_ERROR_EXPECTED_FILE 48 diff --git a/toolkit/mozapps/update/nsIUpdateService.idl b/toolkit/mozapps/update/nsIUpdateService.idl index 817df5a677b4..dffcddaac013 100644 --- a/toolkit/mozapps/update/nsIUpdateService.idl +++ b/toolkit/mozapps/update/nsIUpdateService.idl @@ -183,12 +183,6 @@ interface nsIUpdate : nsISupports */ attribute boolean isSecurityUpdate; - /** - * Whether or not the update being downloaded is an OS update. This is - * generally only possible in Gonk right now. - */ - attribute boolean isOSUpdate; - /** * When the update was installed. */ @@ -386,14 +380,6 @@ interface nsIApplicationUpdateService : nsISupports */ AString downloadUpdate(in nsIUpdate update, in boolean background); - /** - * Apply the OS update which has been downloaded and staged as applied. - * @param update - * The update has been downloaded and staged as applied. - * @throws if the update object is not an OS update. - */ - void applyOsUpdate(in nsIUpdate update); - /** * Get the Active Updates directory * @returns An nsIFile for the active updates directory. diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js index 0fbe5ad864a2..37899f20f375 100644 --- a/toolkit/mozapps/update/nsUpdateService.js +++ b/toolkit/mozapps/update/nsUpdateService.js @@ -60,8 +60,6 @@ const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.proper const KEY_UPDROOT = "UpdRootD"; const KEY_EXECUTABLE = "XREExeF"; -// Gonk only -const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD"; const DIR_UPDATES = "updates"; @@ -83,7 +81,6 @@ const STATE_PENDING_SERVICE = "pending-service"; const STATE_PENDING_ELEVATE = "pending-elevate"; const STATE_APPLYING = "applying"; const STATE_APPLIED = "applied"; -const STATE_APPLIED_OS = "applied-os"; const STATE_APPLIED_SERVICE = "applied-service"; const STATE_SUCCEEDED = "succeeded"; const STATE_DOWNLOAD_FAILED = "download-failed"; @@ -203,17 +200,6 @@ const APPID_TO_TOPIC = { var gUpdateMutexHandle = null; -// Gonk only -var gSDCardMountLock = null; - -// Gonk only -XPCOMUtils.defineLazyGetter(this, "gExtStorage", function aus_gExtStorage() { - if (AppConstants.platform != "gonk") { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - } - return Services.env.get("EXTERNAL_STORAGE"); -}); - XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm"); @@ -568,13 +554,6 @@ function getCanStageUpdates() { return true; } - // For Gonk, the updater will remount the /system partition to move staged - // files into place. - if (AppConstants.platform == "gonk") { - LOG("getCanStageUpdates - able to stage updates because this is gonk"); - return true; - } - if (!hasUpdateMutex()) { LOG("getCanStageUpdates - unable to apply updates because another " + "instance of the application is already handling updates for this " + @@ -799,105 +778,6 @@ function writeVersionFile(dir, version) { writeStringToFile(versionFile, version); } -/** - * Gonk only function that reads the link file specified in the update.link file - * in the specified directory and returns the nsIFile for the corresponding - * file. - * @param dir - * The dir to look for an update.link file in - * @return A nsIFile for the file path specified in the - * update.link file or null if the update.link file - * doesn't exist. - */ -function getFileFromUpdateLink(dir) { - if (AppConstants.platform != "gonk") { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - } - let linkFile = dir.clone(); - linkFile.append(FILE_UPDATE_LINK); - let link = readStringFromFile(linkFile); - LOG("getFileFromUpdateLink linkFile.path: " + linkFile.path + ", link: " + link); - if (!link) { - return null; - } - let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - file.initWithPath(link); - return file; -} - -/** - * Gonk only function to create a link file. This allows the actual patch to - * live in a directory different from the update directory. - * @param dir - * The patch directory where the update.link file - * should be written. - * @param patchFile - * The fully qualified filename of the patchfile. - */ -function writeLinkFile(dir, patchFile) { - if (AppConstants.platform != "gonk") { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - } - let linkFile = dir.clone(); - linkFile.append(FILE_UPDATE_LINK); - writeStringToFile(linkFile, patchFile.path); - if (patchFile.path.indexOf(gExtStorage) == 0) { - // The patchfile is being stored on external storage. Try to lock it - // so that it doesn't get shared with the PC while we're downloading - // to it. - acquireSDCardMountLock(); - } -} - -/** - * Gonk only function to acquire a VolumeMountLock for the sdcard volume. - * - * This prevents the SDCard from being shared with the PC while - * we're downloading the update. - */ -function acquireSDCardMountLock() { - if (AppConstants.platform != "gonk") { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - } - let volsvc = Cc["@mozilla.org/telephony/volume-service;1"]. - getService(Ci.nsIVolumeService); - if (volsvc) { - gSDCardMountLock = volsvc.createMountLock("sdcard"); - } -} - -/** - * Gonk only function that determines if the state corresponds to an - * interrupted update. This could either be because the download was - * interrupted, or because staging the update was interrupted. - * - * @return true if the state corresponds to an interrupted - * update. - */ -function isInterruptedUpdate(status) { - if (AppConstants.platform != "gonk") { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - } - return (status == STATE_DOWNLOADING) || - (status == STATE_PENDING) || - (status == STATE_APPLYING); -} - -/** - * Releases any SDCard mount lock that we might have. - * - * This once again allows the SDCard to be shared with the PC. - */ -function releaseSDCardMountLock() { - if (AppConstants.platform != "gonk") { - throw Cr.NS_ERROR_UNEXPECTED; - } - if (gSDCardMountLock) { - gSDCardMountLock.unlock(); - gSDCardMountLock = null; - } -} - /** * Determines if the service should be used to attempt an update * or not. @@ -1060,15 +940,6 @@ function cleanUpUpdatesDir(aRemovePatchFiles = true) { let dirEntries = updateDir.directoryEntries; while (dirEntries.hasMoreElements()) { let file = dirEntries.getNext().QueryInterface(Ci.nsIFile); - if (AppConstants.platform == "gonk") { - if (file.leafName == FILE_UPDATE_LINK) { - let linkedFile = getFileFromUpdateLink(updateDir); - if (linkedFile && linkedFile.exists()) { - linkedFile.remove(false); - } - } - } - // Now, recursively remove this file. The recursive removal is needed for // Mac OSX because this directory will contain a copy of updater.app, // which is itself a directory and the MozUpdater directory on platforms @@ -1080,9 +951,6 @@ function cleanUpUpdatesDir(aRemovePatchFiles = true) { } } } - if (AppConstants.platform == "gonk") { - releaseSDCardMountLock(); - } } /** @@ -1350,9 +1218,6 @@ function pingStateAndStatusCodes(aUpdate, aStartup, aStatus) { case STATE_APPLIED: stateCode = 7; break; - case STATE_APPLIED_OS: - stateCode = 8; - break; case STATE_APPLIED_SERVICE: stateCode = 9; break; @@ -1830,12 +1695,6 @@ function UpdateService() { LOG("Creating UpdateService"); Services.obs.addObserver(this, "xpcom-shutdown"); Services.prefs.addObserver(PREF_APP_UPDATE_LOG, this); - if (AppConstants.platform == "gonk") { - // PowerManagerService::SyncProfile (which is called for Reboot, PowerOff - // and Restart) sends the profile-change-net-teardown event. We can then - // pause the download in a similar manner to xpcom-shutdown. - Services.obs.addObserver(this, "profile-change-net-teardown"); - } } UpdateService.prototype = { @@ -1917,7 +1776,6 @@ UpdateService.prototype = { gLogEnabled = getPref("getBoolPref", PREF_APP_UPDATE_LOG, false); } break; - case "profile-change-net-teardown": // fall thru case "xpcom-shutdown": Services.obs.removeObserver(this, topic); Services.prefs.removeObserver(PREF_APP_UPDATE_LOG, this); @@ -1983,23 +1841,6 @@ UpdateService.prototype = { return; } - if (AppConstants.platform == "gonk") { - // This code is called very early in the boot process, before we've even - // had a chance to setup the UI so we can give feedback to the user. - // - // Since the download may be occuring over a link which has associated - // cost, we want to require user-consent before resuming the download. - // Also, applying an already downloaded update now is undesireable, - // since the phone will look dead while the update is being applied. - // Applying the update can take several minutes. Instead we wait until - // the UI is initialized so it is possible to give feedback to and get - // consent to update from the user. - if (isInterruptedUpdate(status)) { - LOG("UpdateService:_postUpdateProcessing - interrupted update detected - wait for user consent"); - return; - } - } - if (status == STATE_DOWNLOADING) { LOG("UpdateService:_postUpdateProcessing - patch found in downloading " + "state"); @@ -2041,34 +1882,6 @@ UpdateService.prototype = { return; } - if (AppConstants.platform == "gonk") { - // The update is only applied but not selected to be installed - if (status == STATE_APPLIED && update && update.isOSUpdate) { - LOG("UpdateService:_postUpdateProcessing - update staged as applied found"); - return; - } - - if (status == STATE_APPLIED_OS && update && update.isOSUpdate) { - // In gonk, we need to check for OS update status after startup, since - // the recovery partition won't write to update.status for us - let recoveryService = Cc["@mozilla.org/recovery-service;1"]. - getService(Ci.nsIRecoveryService); - let fotaStatus = recoveryService.getFotaUpdateStatus(); - switch (fotaStatus) { - case Ci.nsIRecoveryService.FOTA_UPDATE_SUCCESS: - status = STATE_SUCCEEDED; - break; - case Ci.nsIRecoveryService.FOTA_UPDATE_FAIL: - status = STATE_FAILED + ": " + FOTA_GENERAL_ERROR; - break; - case Ci.nsIRecoveryService.FOTA_UPDATE_UNKNOWN: - default: - status = STATE_FAILED + ": " + FOTA_UNKNOWN_ERROR; - break; - } - } - } - if (!update) { if (status != STATE_SUCCEEDED) { LOG("UpdateService:_postUpdateProcessing - previous patch failed " + @@ -2527,11 +2340,6 @@ UpdateService.prototype = { var um = Cc["@mozilla.org/updates/update-manager;1"]. getService(Ci.nsIUpdateManager); if (um.activeUpdate) { - if (AppConstants.platform == "gonk") { - // For gonk, the user isn't necessarily aware of the update, so we need - // to show the prompt to make sure. - this._showPrompt(um.activeUpdate); - } AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_HAS_ACTIVEUPDATE); return; } @@ -2734,21 +2542,6 @@ UpdateService.prototype = { } this._downloader.cancel(); } - if (AppConstants.platform == "gonk") { - let um = Cc["@mozilla.org/updates/update-manager;1"]. - getService(Ci.nsIUpdateManager); - let activeUpdate = um.activeUpdate; - if (activeUpdate && - (activeUpdate.appVersion != update.appVersion || - activeUpdate.buildID != update.buildID)) { - // We have an activeUpdate (which presumably was interrupted), and are - // about start downloading a new one. Make sure we remove all traces - // of the active one (otherwise we'll start appending the new update.mar - // the the one that's been partially downloaded). - LOG("UpdateService:downloadUpdate - removing stale active update."); - cleanupActiveUpdate(); - } - } // Set the previous application version prior to downloading the update. update.previousAppVersion = Services.appinfo.version; this._downloader = new Downloader(background, this); @@ -2782,55 +2575,6 @@ UpdateService.prototype = { return this._downloader && this._downloader.isBusy; }, - /** - * See nsIUpdateService.idl - */ - applyOsUpdate: function AUS_applyOsUpdate(aUpdate) { - if (!aUpdate.isOSUpdate || aUpdate.state != STATE_APPLIED) { - aUpdate.statusText = "fota-state-error"; - throw Cr.NS_ERROR_FAILURE; - } - - aUpdate.QueryInterface(Ci.nsIWritablePropertyBag); - let osApplyToDir = aUpdate.getProperty("osApplyToDir"); - - if (!osApplyToDir) { - LOG("UpdateService:applyOsUpdate - Error: osApplyToDir is not defined" + - "in the nsIUpdate!"); - pingStateAndStatusCodes(aUpdate, false, - STATE_FAILED + ": " + FOTA_FILE_OPERATION_ERROR); - handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR); - return; - } - - let updateFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - updateFile.initWithPath(osApplyToDir + "/update.zip"); - if (!updateFile.exists()) { - LOG("UpdateService:applyOsUpdate - Error: OS update is not found at " + - updateFile.path); - pingStateAndStatusCodes(aUpdate, false, - STATE_FAILED + ": " + FOTA_FILE_OPERATION_ERROR); - handleUpdateFailure(aUpdate, FOTA_FILE_OPERATION_ERROR); - return; - } - - writeStatusFile(getUpdatesDir(), aUpdate.state = STATE_APPLIED_OS); - LOG("UpdateService:applyOsUpdate - Rebooting into recovery to apply " + - "FOTA update: " + updateFile.path); - try { - let recoveryService = Cc["@mozilla.org/recovery-service;1"] - .getService(Ci.nsIRecoveryService); - recoveryService.installFotaUpdate(updateFile.path); - } catch (e) { - LOG("UpdateService:applyOsUpdate - Error: Couldn't reboot into recovery" + - " to apply FOTA update " + updateFile.path); - pingStateAndStatusCodes(aUpdate, false, - STATE_FAILED + ": " + FOTA_RECOVERY_ERROR); - writeStatusFile(getUpdatesDir(), aUpdate.state = STATE_APPLIED); - handleUpdateFailure(aUpdate, FOTA_RECOVERY_ERROR); - } - }, - classID: UPDATESERVICE_CID, classInfo: XPCOMUtils.generateCI({classID: UPDATESERVICE_CID, contractID: UPDATESERVICE_CONTRACTID, @@ -3156,21 +2900,6 @@ UpdateManager.prototype = { "the update was staged. topic: update-staged, status: " + update.state); Services.obs.notifyObservers(update, "update-staged", update.state); - if (AppConstants.platform == "gonk") { - // Do this after everything else, since it will likely cause the app to - // shut down. - if (update.state == STATE_APPLIED) { - // Notify the user that an update has been staged and is ready for - // installation (i.e. that they should restart the application). We do - // not notify on failed update attempts. - let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. - createInstance(Ci.nsIUpdatePrompt); - prompter.showUpdateDownloaded(update, true); - } else { - releaseSDCardMountLock(); - } - return; - } // Only prompt when the UI isn't already open. let windowType = getPref("getCharPref", PREF_APP_UPDATE_ALTWINDOWTYPE, null); if (Services.wm.getMostRecentWindow(UPDATE_WINDOW_NAME) || @@ -3522,9 +3251,6 @@ Downloader.prototype = { if (this._request && this._request instanceof Ci.nsIRequest) { this._request.cancel(cancelError); } - if (AppConstants.platform == "gonk") { - releaseSDCardMountLock(); - } }, /** @@ -3653,19 +3379,10 @@ Downloader.prototype = { LOG("Downloader:_selectPatch - resuming download"); return selectedPatch; } - - if (AppConstants.platform == "gonk") { - if (state == STATE_PENDING || state == STATE_APPLYING) { - LOG("Downloader:_selectPatch - resuming interrupted apply"); - return selectedPatch; - } - if (state == STATE_APPLIED) { - LOG("Downloader:_selectPatch - already downloaded and staged"); - return null; - } - } else if (state == STATE_PENDING || state == STATE_PENDING_SERVICE || - state == STATE_PENDING_ELEVATE) { - LOG("Downloader:_selectPatch - already downloaded and staged"); + if (state == STATE_PENDING || state == STATE_PENDING_SERVICE || + state == STATE_PENDING_ELEVATE || state == STATE_APPLIED || + state == STATE_APPLIED_SERVICE) { + LOG("Downloader:_selectPatch - already downloaded"); return null; } @@ -3721,25 +3438,6 @@ Downloader.prototype = { return this._request != null; }, - /** - * Get the nsIFile to use for downloading the active update's selected patch - */ - _getUpdateArchiveFile: function Downloader__getUpdateArchiveFile() { - var updateArchive; - if (AppConstants.platform == "gonk") { - try { - updateArchive = FileUtils.getDir(KEY_UPDATE_ARCHIVE_DIR, [], true); - } catch (e) { - return null; - } - } else { - updateArchive = getUpdatesDir().clone(); - } - - updateArchive.append(FILE_UPDATE_MAR); - return updateArchive; - }, - /** * Download and stage the given update. * @param update @@ -3766,96 +3464,8 @@ Downloader.prototype = { } this.isCompleteUpdate = this._patch.type == "complete"; - let patchFile = null; - - // Only used by gonk - let status = STATE_NONE; - if (AppConstants.platform == "gonk") { - status = readStatusFile(updateDir); - if (isInterruptedUpdate(status)) { - LOG("Downloader:downloadUpdate - interruptted update"); - // The update was interrupted. Try to locate the existing patch file. - // For an interrupted download, this allows a resume rather than a - // re-download. - patchFile = getFileFromUpdateLink(updateDir); - if (!patchFile) { - // No link file. We'll just assume that the update.mar is in the - // update directory. - patchFile = updateDir.clone(); - patchFile.append(FILE_UPDATE_MAR); - } - if (patchFile.exists()) { - LOG("Downloader:downloadUpdate - resuming with patchFile " + patchFile.path); - if (patchFile.fileSize == this._patch.size) { - LOG("Downloader:downloadUpdate - patchFile appears to be fully downloaded"); - // Bump the status along so that we don't try to redownload again. - if (getElevationRequired()) { - status = STATE_PENDING_ELEVATE; - } else { - status = STATE_PENDING; - } - } - } else { - LOG("Downloader:downloadUpdate - patchFile " + patchFile.path + - " doesn't exist - performing full download"); - // The patchfile doesn't exist, we might as well treat this like - // a new download. - patchFile = null; - } - if (patchFile && status != STATE_DOWNLOADING) { - // It looks like the patch was downloaded, but got interrupted while it - // was being verified or applied. So we'll fake the downloading portion. - - if (getElevationRequired()) { - writeStatusFile(updateDir, STATE_PENDING_ELEVATE); - } else { - writeStatusFile(updateDir, STATE_PENDING); - } - - // Since the code expects the onStopRequest callback to happen - // asynchronously (And you have to call AUS_addDownloadListener - // after calling AUS_downloadUpdate) we need to defer this. - - this._downloadTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - this._downloadTimer.initWithCallback(function() { - this._downloadTimer = null; - // Send a fake onStopRequest. Filling in the destination allows - // _verifyDownload to work, and then the update will be applied. - this._request = {destination: patchFile}; - this.onStopRequest(this._request, null, Cr.NS_OK); - }.bind(this), 0, Ci.nsITimer.TYPE_ONE_SHOT); - - // Returning STATE_DOWNLOADING makes UpdatePrompt think we're - // downloading. The onStopRequest that we spoofed above will make it - // look like the download finished. - return STATE_DOWNLOADING; - } - } - } - - if (!patchFile) { - // Find a place to put the patchfile that we're going to download. - patchFile = this._getUpdateArchiveFile(); - } - if (!patchFile) { - AUSTLMY.pingDownloadCode(this.isCompleteUpdate, - AUSTLMY.DWNLD_ERR_NO_PATCH_FILE); - return STATE_NONE; - } - - if (AppConstants.platform == "gonk") { - if (patchFile.path.indexOf(updateDir.path) != 0) { - // The patchFile is in a directory which is different from the - // updateDir, create a link file. - writeLinkFile(updateDir, patchFile); - - if (!isInterruptedUpdate(status) && patchFile.exists()) { - // Remove stale patchFile - patchFile.remove(false); - } - } - } - + let patchFile = getUpdatesDir().clone(); + patchFile.append(FILE_UPDATE_MAR); update.QueryInterface(Ci.nsIPropertyBag); let interval = this.background ? update.getProperty("backgroundInterval") : DOWNLOAD_FOREGROUND_INTERVAL; @@ -4127,13 +3737,6 @@ Downloader.prototype = { this._update.statusText = getStatusTextFromCode(status, Cr.NS_BINDING_FAILED); - if (AppConstants.platform == "gonk") { - // bug891009: On FirefoxOS, manaully retry OTA download will reuse - // the Update object. We need to remove selected patch so that download - // can be triggered again successfully. - this._update.selectedPatch.selected = false; - } - // Destroy the updates directory, since we're done with it. cleanUpUpdatesDir(); @@ -4213,13 +3816,6 @@ Downloader.prototype = { } } - if (AppConstants.platform == "gonk") { - // We always forward errors in B2G, since Gaia controls the update UI - let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. - createInstance(Ci.nsIUpdatePrompt); - prompter.showUpdateError(this._update); - } - // Prevent leaking the update object (bug 454964). this._update = null; } diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 3d40a1b58936..b6bf54d54717 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -57,6 +57,8 @@ #include "mozilla/jni/Utils.h" #endif // defined(MOZ_WIDGET_ANDROID) +#include "mozilla/AbstractThread.h" + #include "mozilla/ipc/BrowserProcessSubThread.h" #include "mozilla/ipc/GeckoChildProcessHost.h" #include "mozilla/ipc/IOThreadChild.h" @@ -419,6 +421,10 @@ XRE_InitChildProcess(int aArgc, PROFILER_LABEL("Startup", "XRE_InitChildProcess", js::ProfileEntry::Category::OTHER); + // Ensure AbstractThread is minimally setup, so async IPC messages + // work properly. + AbstractThread::InitTLS(); + // Complete 'task_t' exchange for Mac OS X. This structure has the same size // regardless of architecture so we don't have any cross-arch issues here. #ifdef XP_MACOSX @@ -773,6 +779,8 @@ XRE_InitParentProcess(int aArgc, // Set main thread before we initialize the profiler NS_SetMainThread(); + mozilla::LogModule::Init(); + char aLocal; GeckoProfilerInitRAII profiler(&aLocal); diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp index 9f2cf2256ee4..41a127e17aa6 100644 --- a/tools/profiler/core/platform.cpp +++ b/tools/profiler/core/platform.cpp @@ -946,6 +946,32 @@ DoNativeBacktrace(PS::LockRef aLock, ProfileBuffer* aBuffer, // assumes that the TaggedUWord holding the stack pointer value is valid, but // it should be, since it was constructed that way in the code just above. + // We could construct |stackImg| so that LUL reads directly from the stack in + // question, rather than from a copy of it. That would reduce overhead and + // space use a bit. However, it gives a problem with dynamic analysis tools + // (ASan, TSan, Valgrind) which is that such tools will report invalid or + // racing memory accesses, and such accesses will be reported deep inside LUL. + // By taking a copy here, we can either sanitise the copy (for Valgrind) or + // copy it using an unchecked memcpy (for ASan, TSan). That way we don't have + // to try and suppress errors inside LUL. + // + // N_STACK_BYTES is set to 160KB. This is big enough to hold all stacks + // observed in some minutes of testing, whilst keeping the size of this + // function (DoNativeBacktrace)'s frame reasonable. Most stacks observed in + // practice are small, 4KB or less, and so the copy costs are insignificant + // compared to other profiler overhead. + // + // |stackImg| is allocated on this (the sampling thread's) stack. That + // implies that the frame for this function is at least N_STACK_BYTES large. + // In general it would be considered unacceptable to have such a large frame + // on a stack, but it only exists for the unwinder thread, and so is not + // expected to be a problem. Allocating it on the heap is troublesome because + // this function runs whilst the sampled thread is suspended, so any heap + // allocation risks deadlock. Allocating it as a global variable is not + // thread safe, which would be a problem if we ever allow multiple sampler + // threads. Hence allocating it on the stack seems to be the least-worst + // option. + lul::StackImage stackImg; { diff --git a/tools/profiler/lul/LulMain.h b/tools/profiler/lul/LulMain.h index 52a25c8521dd..786d12a75d89 100644 --- a/tools/profiler/lul/LulMain.h +++ b/tools/profiler/lul/LulMain.h @@ -158,12 +158,13 @@ struct UnwindRegs { }; -// The maximum number of bytes in a stack snapshot. This can be -// increased if necessary, but larger values cost performance, since a -// stack snapshot needs to be copied between sampling and worker -// threads for each snapshot. In practice 32k seems to be enough -// to get good backtraces. -static const size_t N_STACK_BYTES = 32768; +// The maximum number of bytes in a stack snapshot. This value can be increased +// if necessary, but testing showed that 160k is enough to obtain good +// backtraces on x86_64 Linux. Most backtraces fit comfortably into 4-8k of +// stack space, but we do have some very deep stacks occasionally. Please see +// the comments in DoNativeBacktrace as to why it's OK to have this value be so +// large. +static const size_t N_STACK_BYTES = 160*1024; // The stack chunk image that will be unwound. struct StackImage { diff --git a/tools/profiler/moz.build b/tools/profiler/moz.build index 294a4ac52c80..8485390fa4c2 100644 --- a/tools/profiler/moz.build +++ b/tools/profiler/moz.build @@ -106,9 +106,6 @@ if CONFIG['MOZ_GECKO_PROFILER']: if CONFIG['ENABLE_TESTS']: DIRS += ['tests/gtest'] - if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and (CONFIG['ANDROID_VERSION'] <= '17' or CONFIG['ANDROID_VERSION'] >= '21'): - DEFINES['ELFSIZE'] = 32 - FINAL_LIBRARY = 'xul' IPDL_SOURCES += [ diff --git a/uriloader/exthandler/gonk/nsOSHelperAppService.cpp b/uriloader/exthandler/gonk/nsOSHelperAppService.cpp deleted file mode 100644 index d1342ec18111..000000000000 --- a/uriloader/exthandler/gonk/nsOSHelperAppService.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "nsOSHelperAppService.h" -#include "nsMIMEInfoImpl.h" - -class nsGonkMIMEInfo : public nsMIMEInfoImpl { -public: - nsGonkMIMEInfo(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) { } - -protected: - virtual nsresult LoadUriInternal(nsIURI *aURI) { - return NS_ERROR_NOT_IMPLEMENTED; - } -}; - -nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() -{ -} - -nsOSHelperAppService::~nsOSHelperAppService() -{ -} - -already_AddRefed -nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound) -{ - *aFound = false; - // Even if we return false for aFound, we need to return a working - // nsIMIMEInfo implementation that will be used by the caller. - RefPtr mimeInfo = new nsGonkMIMEInfo(aMIMEType); - return mimeInfo.forget(); -} - -nsresult -nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme, - bool* aExists) -{ - *aExists = false; - return NS_OK; -} diff --git a/uriloader/exthandler/gonk/nsOSHelperAppService.h b/uriloader/exthandler/gonk/nsOSHelperAppService.h deleted file mode 100644 index 99a280bfcc97..000000000000 --- a/uriloader/exthandler/gonk/nsOSHelperAppService.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef nsOSHelperAppService_h -#define nsOSHelperAppService_h - -#include "nsCExternalHandlerService.h" -#include "nsExternalHelperAppService.h" - -class nsOSHelperAppService : public nsExternalHelperAppService -{ -public: - nsOSHelperAppService(); - virtual ~nsOSHelperAppService(); - - virtual already_AddRefed - GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound); - - virtual MOZ_MUST_USE nsresult - OSProtocolHandlerExists(const char* aScheme, - bool* aExists); -}; - -#endif /* nsOSHelperAppService_h */ diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build index d8b874baad09..3349d5006901 100644 --- a/uriloader/exthandler/moz.build +++ b/uriloader/exthandler/moz.build @@ -24,7 +24,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': LOCAL_INCLUDES += ['win'] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': osdir = 'mac' -elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk', 'uikit'): +elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'uikit'): osdir = CONFIG['MOZ_WIDGET_TOOLKIT'] else: osdir = 'unix' diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index b5e4c42fb805..a1a603f8a612 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -2729,14 +2729,12 @@ nsExternalHelperAppService::GetTypeFromExtension(const nsACString& aFileExt, } // Ask OS. - bool found = false; - nsCOMPtr mi = GetMIMEInfoFromOS(EmptyCString(), aFileExt, &found); - if (mi && found) { - return mi->GetMIMEType(aContentType); + if (GetMIMETypeFromOSForExtension(aFileExt, aContentType)) { + return NS_OK; } // Check extras array. - found = GetTypeFromExtras(aFileExt, aContentType); + bool found = GetTypeFromExtras(aFileExt, aContentType); if (found) { return NS_OK; } @@ -2935,3 +2933,11 @@ bool nsExternalHelperAppService::GetTypeFromExtras(const nsACString& aExtension, return false; } + +bool +nsExternalHelperAppService::GetMIMETypeFromOSForExtension(const nsACString& aExtension, nsACString& aMIMEType) +{ + bool found = false; + nsCOMPtr mimeInfo = GetMIMEInfoFromOS(EmptyCString(), aExtension, &found); + return found && mimeInfo && NS_SUCCEEDED(mimeInfo->GetMIMEType(aMIMEType)); +} diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h index ae6d76af39dc..0645b24b01da 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -108,6 +108,15 @@ public: virtual nsresult OSProtocolHandlerExists(const char *aScheme, bool *aExists) = 0; + /** + * Given an extension, get a MIME type string. If not overridden by + * the OS-specific nsOSHelperAppService, will call into GetMIMEInfoFromOS + * with an empty mimetype. + * @return true if we successfully found a mimetype. + */ + virtual bool GetMIMETypeFromOSForExtension(const nsACString& aExtension, + nsACString& aMIMEType); + protected: virtual ~nsExternalHelperAppService(); diff --git a/uriloader/exthandler/win/nsOSHelperAppService.cpp b/uriloader/exthandler/win/nsOSHelperAppService.cpp index c5a8dc039c5b..dedbeb795351 100644 --- a/uriloader/exthandler/win/nsOSHelperAppService.cpp +++ b/uriloader/exthandler/win/nsOSHelperAppService.cpp @@ -395,43 +395,25 @@ already_AddRefed nsOSHelperAppService::GetByExtension(const nsAFl if (aFileExt.IsEmpty()) return nullptr; - // windows registry assumes your file extension is going to include the '.'. - // so make sure it's there... + // Determine the mime type. + nsAutoCString typeToUse; + if (aTypeHint && *aTypeHint) { + typeToUse.Assign(aTypeHint); + } else if (!GetMIMETypeFromOSForExtension(NS_ConvertUTF16toUTF8(aFileExt), typeToUse)) { + return nullptr; + } + + RefPtr mimeInfo = new nsMIMEInfoWin(typeToUse); + + // windows registry assumes your file extension is going to include the '.', + // but our APIs expect it to not be there, so make sure we normalize that bit. nsAutoString fileExtToUse; if (aFileExt.First() != char16_t('.')) fileExtToUse = char16_t('.'); fileExtToUse.Append(aFileExt); - // Try to get an entry from the windows registry. - nsCOMPtr regKey = - do_CreateInstance("@mozilla.org/windows-registry-key;1"); - if (!regKey) - return nullptr; - - nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, - fileExtToUse, - nsIWindowsRegKey::ACCESS_QUERY_VALUE); - if (NS_FAILED(rv)) - return nullptr; - - nsAutoCString typeToUse; - if (aTypeHint && *aTypeHint) { - typeToUse.Assign(aTypeHint); - } - else { - nsAutoString temp; - if (NS_FAILED(regKey->ReadStringValue(NS_LITERAL_STRING("Content Type"), - temp)) || temp.IsEmpty()) { - return nullptr; - } - // Content-Type is always in ASCII - LossyAppendUTF16toASCII(temp, typeToUse); - } - - RefPtr mimeInfo = new nsMIMEInfoWin(typeToUse); - - // don't append the '.' + // don't append the '.' for our APIs. mimeInfo->AppendExtension(NS_ConvertUTF16toUTF8(Substring(fileExtToUse, 1))); mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault); @@ -458,8 +440,17 @@ already_AddRefed nsOSHelperAppService::GetByExtension(const nsAFl } else { - found = NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), - appInfo)); + nsCOMPtr regKey = + do_CreateInstance("@mozilla.org/windows-registry-key;1"); + if (!regKey) + return nullptr; + nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, + fileExtToUse, + nsIWindowsRegKey::ACCESS_QUERY_VALUE); + if (NS_SUCCEEDED(rv)) { + found = NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), + appInfo)); + } } // Bug 358297 - ignore the default handler, force the user to choose app @@ -504,7 +495,8 @@ already_AddRefed nsOSHelperAppService::GetMIMEInfoFromOS(const nsAC * useless.... * We'll do extension-based lookup for this type later in this function. */ - if (!aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM)) { + if (!aMIMEType.IsEmpty() && + !aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM)) { // (1) try to use the windows mime database to see if there is a mapping to a file extension // (2) try to see if we have some left over 4.x registry info we can peek at... GetExtensionFromWindowsMimeDatabase(aMIMEType, fileExtension); @@ -596,3 +588,40 @@ nsOSHelperAppService::GetProtocolHandlerInfoFromOS(const nsACString &aScheme, return NS_OK; } +bool +nsOSHelperAppService::GetMIMETypeFromOSForExtension(const nsACString& aExtension, + nsACString& aMIMEType) +{ + if (aExtension.IsEmpty()) + return false; + + // windows registry assumes your file extension is going to include the '.'. + // so make sure it's there... + nsAutoString fileExtToUse; + if (aExtension.First() != '.') + fileExtToUse = char16_t('.'); + + AppendUTF8toUTF16(aExtension, fileExtToUse); + + // Try to get an entry from the windows registry. + nsCOMPtr regKey = + do_CreateInstance("@mozilla.org/windows-registry-key;1"); + if (!regKey) + return false; + + nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, + fileExtToUse, + nsIWindowsRegKey::ACCESS_QUERY_VALUE); + if (NS_FAILED(rv)) + return false; + + nsAutoString mimeType; + if (NS_FAILED(regKey->ReadStringValue(NS_LITERAL_STRING("Content Type"), + mimeType)) || mimeType.IsEmpty()) { + return false; + } + // Content-Type is always in ASCII + aMIMEType.Truncate(); + LossyAppendUTF16toASCII(mimeType, aMIMEType); + return true; +} diff --git a/uriloader/exthandler/win/nsOSHelperAppService.h b/uriloader/exthandler/win/nsOSHelperAppService.h index c5e707256417..b00529433cc3 100644 --- a/uriloader/exthandler/win/nsOSHelperAppService.h +++ b/uriloader/exthandler/win/nsOSHelperAppService.h @@ -40,6 +40,8 @@ public: NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString &aScheme, bool *found, nsIHandlerInfo **_retval); + virtual bool GetMIMETypeFromOSForExtension(const nsACString& aExtension, + nsACString& aMIMEType) override; /** Get the string value of a registry value and store it in result. * @return true on success, false on failure diff --git a/view/nsView.cpp b/view/nsView.cpp index 33d4f338bc7c..38d2e1d193d8 100644 --- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -116,6 +116,8 @@ nsView::~nsView() // Destroy and release the widget DestroyWidget(); + MOZ_RELEASE_ASSERT(!mFrame); + delete mDirtyRegion; } diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build deleted file mode 100644 index 16a55c714f73..000000000000 --- a/widget/gonk/moz.build +++ /dev/null @@ -1,97 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -with Files("**"): - BUG_COMPONENT = ("Core", "Widget: Gonk") - -EXPORTS += [ - 'GeckoTouchDispatcher.h', - 'GonkPermission.h', -] - -DIRS += ['libdisplay', 'nativewindow'] - -# libui files -SOURCES += ['libui/' + src for src in [ - 'EventHub.cpp', - 'Input.cpp', - 'InputApplication.cpp', - 'InputDevice.cpp', - 'InputDispatcher.cpp', - 'InputListener.cpp', - 'InputReader.cpp', - 'InputTransport.cpp', - 'InputWindow.cpp', - 'Keyboard.cpp', - 'KeyCharacterMap.cpp', - 'KeyLayoutMap.cpp', - 'PointerController.cpp', - 'sha1.c', - 'SpriteController.cpp', - 'Tokenizer.cpp', - 'VelocityControl.cpp', - 'VelocityTracker.cpp', - 'VirtualKeyMap.cpp', -]] - -# HwcHAL files -if CONFIG['ANDROID_VERSION'] >= '17': - SOURCES += [ - 'hwchal/HwcHAL.cpp', - ] - -SOURCES += [ - 'GeckoTouchDispatcher.cpp', - 'GfxInfo.cpp', - 'GonkClipboardData.cpp', - 'GonkMemoryPressureMonitoring.cpp', - 'GonkPermission.cpp', - 'HwcComposer2D.cpp', - 'HwcUtils.cpp', - 'nsAppShell.cpp', - 'nsClipboard.cpp', - 'nsIdleServiceGonk.cpp', - 'nsLookAndFeel.cpp', - 'nsScreenManagerGonk.cpp', - 'nsWidgetFactory.cpp', - 'nsWindow.cpp', - 'ProcessOrientation.cpp', - 'WidgetTraceEvent.cpp' -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/dom/system/android', - '/gfx/skia/skia/include/config', - '/gfx/skia/skia/include/core', - '/image', - '/widget', -] - -DEFINES['HAVE_OFF64_T'] = True -DEFINES['SK_BUILD_FOR_ANDROID_NDK'] = True -DEFINES['HAVE_POSIX_CLOCKS'] = True - -LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/opengl/include', - 'hardware/libhardware/include', - 'hardware/libhardware_legacy/include', - ] -] diff --git a/widget/moz.build b/widget/moz.build index ad8adabe1f57..cb9b5e567ff7 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -30,9 +30,9 @@ with Files("*FontRange*"): toolkit = CONFIG['MOZ_WIDGET_TOOLKIT'] -if toolkit in ('cocoa', 'android', 'gonk', 'uikit'): +if toolkit in ('cocoa', 'android', 'uikit'): DIRS += [toolkit] -if toolkit in ('android', 'cocoa', 'gonk', 'gtk2', 'gtk3'): +if toolkit in ('android', 'cocoa', 'gtk2', 'gtk3'): EXPORTS += ['nsIPrintDialogService.h'] if toolkit == 'windows': @@ -255,7 +255,7 @@ if toolkit in ('cocoa', 'windows'): ] if toolkit in {'gtk2', 'gtk3', 'cocoa', 'windows', - 'android', 'gonk', 'uikit'}: + 'android', 'uikit'}: UNIFIED_SOURCES += [ 'nsBaseFilePicker.cpp', ] diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp index c03d0ad3c77d..0cb36ee61743 100644 --- a/xpcom/base/CycleCollectedJSContext.cpp +++ b/xpcom/base/CycleCollectedJSContext.cpp @@ -4,60 +4,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -// We're dividing JS objects into 3 categories: -// -// 1. "real" roots, held by the JS engine itself or rooted through the root -// and lock JS APIs. Roots from this category are considered black in the -// cycle collector, any cycle they participate in is uncollectable. -// -// 2. certain roots held by C++ objects that are guaranteed to be alive. -// Roots from this category are considered black in the cycle collector, -// and any cycle they participate in is uncollectable. These roots are -// traced from TraceNativeBlackRoots. -// -// 3. all other roots held by C++ objects that participate in cycle -// collection, held by us (see TraceNativeGrayRoots). Roots from this -// category are considered grey in the cycle collector; whether or not -// they are collected depends on the objects that hold them. -// -// Note that if a root is in multiple categories the fact that it is in -// category 1 or 2 that takes precedence, so it will be considered black. -// -// During garbage collection we switch to an additional mark color (gray) -// when tracing inside TraceNativeGrayRoots. This allows us to walk those -// roots later on and add all objects reachable only from them to the -// cycle collector. -// -// Phases: -// -// 1. marking of the roots in category 1 by having the JS GC do its marking -// 2. marking of the roots in category 2 by having the JS GC call us back -// (via JS_SetExtraGCRootsTracer) and running TraceNativeBlackRoots -// 3. marking of the roots in category 3 by TraceNativeGrayRoots using an -// additional color (gray). -// 4. end of GC, GC can sweep its heap -// -// At some later point, when the cycle collector runs: -// -// 5. walk gray objects and add them to the cycle collector, cycle collect -// -// JS objects that are part of cycles the cycle collector breaks will be -// collected by the next JS GC. -// -// If WantAllTraces() is false the cycle collector will not traverse roots -// from category 1 or any JS objects held by them. Any JS objects they hold -// will already be marked by the JS GC and will thus be colored black -// themselves. Any C++ objects they hold will have a missing (untraversed) -// edge from the JS object to the C++ object and so it will be marked black -// too. This decreases the number of objects that the cycle collector has to -// deal with. -// To improve debugging, if WantAllTraces() is true all JS objects are -// traversed. - #include "mozilla/CycleCollectedJSContext.h" #include #include "mozilla/ArrayUtils.h" #include "mozilla/AutoRestore.h" +#include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/Move.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Sprintf.h" @@ -99,412 +50,11 @@ using namespace mozilla::dom; namespace mozilla { -struct DeferredFinalizeFunctionHolder -{ - DeferredFinalizeFunction run; - void* data; -}; - -class IncrementalFinalizeRunnable : public Runnable -{ - typedef AutoTArray DeferredFinalizeArray; - typedef CycleCollectedJSContext::DeferredFinalizerTable DeferredFinalizerTable; - - CycleCollectedJSContext* mContext; - DeferredFinalizeArray mDeferredFinalizeFunctions; - uint32_t mFinalizeFunctionToRun; - bool mReleasing; - - static const PRTime SliceMillis = 5; /* ms */ - -public: - IncrementalFinalizeRunnable(CycleCollectedJSContext* aCx, - DeferredFinalizerTable& aFinalizerTable); - virtual ~IncrementalFinalizeRunnable(); - - void ReleaseNow(bool aLimited); - - NS_DECL_NSIRUNNABLE -}; - -} // namespace mozilla - -struct NoteWeakMapChildrenTracer : public JS::CallbackTracer -{ - NoteWeakMapChildrenTracer(JSContext* aCx, - nsCycleCollectionNoteRootCallback& aCb) - : JS::CallbackTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr), - mKey(nullptr), mKeyDelegate(nullptr) - { - } - void onChild(const JS::GCCellPtr& aThing) override; - nsCycleCollectionNoteRootCallback& mCb; - bool mTracedAny; - JSObject* mMap; - JS::GCCellPtr mKey; - JSObject* mKeyDelegate; -}; - -void -NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing) -{ - if (aThing.is()) { - return; - } - - if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) { - return; - } - - if (AddToCCKind(aThing.kind())) { - mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing); - mTracedAny = true; - } else { - JS::TraceChildren(this, aThing); - } -} - -struct NoteWeakMapsTracer : public js::WeakMapTracer -{ - NoteWeakMapsTracer(JSContext* aCx, nsCycleCollectionNoteRootCallback& aCccb) - : js::WeakMapTracer(aCx), mCb(aCccb), mChildTracer(aCx, aCccb) - { - } - void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override; - nsCycleCollectionNoteRootCallback& mCb; - NoteWeakMapChildrenTracer mChildTracer; -}; - -void -NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey, - JS::GCCellPtr aValue) -{ - // If nothing that could be held alive by this entry is marked gray, return. - if ((!aKey || !JS::GCThingIsMarkedGray(aKey)) && - MOZ_LIKELY(!mCb.WantAllTraces())) { - if (!aValue || !JS::GCThingIsMarkedGray(aValue) || aValue.is()) { - return; - } - } - - // The cycle collector can only properly reason about weak maps if it can - // reason about the liveness of their keys, which in turn requires that - // the key can be represented in the cycle collector graph. All existing - // uses of weak maps use either objects or scripts as keys, which are okay. - MOZ_ASSERT(AddToCCKind(aKey.kind())); - - // As an emergency fallback for non-debug builds, if the key is not - // representable in the cycle collector graph, we treat it as marked. This - // can cause leaks, but is preferable to ignoring the binding, which could - // cause the cycle collector to free live objects. - if (!AddToCCKind(aKey.kind())) { - aKey = nullptr; - } - - JSObject* kdelegate = nullptr; - if (aKey.is()) { - kdelegate = js::GetWeakmapKeyDelegate(&aKey.as()); - } - - if (AddToCCKind(aValue.kind())) { - mCb.NoteWeakMapping(aMap, aKey, kdelegate, aValue); - } else { - mChildTracer.mTracedAny = false; - mChildTracer.mMap = aMap; - mChildTracer.mKey = aKey; - mChildTracer.mKeyDelegate = kdelegate; - - if (!aValue.is()) { - JS::TraceChildren(&mChildTracer, aValue); - } - - // The delegate could hold alive the key, so report something to the CC - // if we haven't already. - if (!mChildTracer.mTracedAny && - aKey && JS::GCThingIsMarkedGray(aKey) && kdelegate) { - mCb.NoteWeakMapping(aMap, aKey, kdelegate, nullptr); - } - } -} - -// Report whether the key or value of a weak mapping entry are gray but need to -// be marked black. -static void -ShouldWeakMappingEntryBeBlack(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue, - bool* aKeyShouldBeBlack, bool* aValueShouldBeBlack) -{ - *aKeyShouldBeBlack = false; - *aValueShouldBeBlack = false; - - // If nothing that could be held alive by this entry is marked gray, return. - bool keyMightNeedMarking = aKey && JS::GCThingIsMarkedGray(aKey); - bool valueMightNeedMarking = aValue && JS::GCThingIsMarkedGray(aValue) && - aValue.kind() != JS::TraceKind::String; - if (!keyMightNeedMarking && !valueMightNeedMarking) { - return; - } - - if (!AddToCCKind(aKey.kind())) { - aKey = nullptr; - } - - if (keyMightNeedMarking && aKey.is()) { - JSObject* kdelegate = js::GetWeakmapKeyDelegate(&aKey.as()); - if (kdelegate && !JS::ObjectIsMarkedGray(kdelegate) && - (!aMap || !JS::ObjectIsMarkedGray(aMap))) - { - *aKeyShouldBeBlack = true; - } - } - - if (aValue && JS::GCThingIsMarkedGray(aValue) && - (!aKey || !JS::GCThingIsMarkedGray(aKey)) && - (!aMap || !JS::ObjectIsMarkedGray(aMap)) && - aValue.kind() != JS::TraceKind::Shape) { - *aValueShouldBeBlack = true; - } -} - -struct FixWeakMappingGrayBitsTracer : public js::WeakMapTracer -{ - explicit FixWeakMappingGrayBitsTracer(JSContext* aCx) - : js::WeakMapTracer(aCx) - { - } - - void - FixAll() - { - do { - mAnyMarked = false; - js::TraceWeakMaps(this); - } while (mAnyMarked); - } - - void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override - { - bool keyShouldBeBlack; - bool valueShouldBeBlack; - ShouldWeakMappingEntryBeBlack(aMap, aKey, aValue, - &keyShouldBeBlack, &valueShouldBeBlack); - if (keyShouldBeBlack && JS::UnmarkGrayGCThingRecursively(aKey)) { - mAnyMarked = true; - } - - if (valueShouldBeBlack && JS::UnmarkGrayGCThingRecursively(aValue)) { - mAnyMarked = true; - } - } - - MOZ_INIT_OUTSIDE_CTOR bool mAnyMarked; -}; - -#ifdef DEBUG -// Check whether weak maps are marked correctly according to the logic above. -struct CheckWeakMappingGrayBitsTracer : public js::WeakMapTracer -{ - explicit CheckWeakMappingGrayBitsTracer(JSContext* aCx) - : js::WeakMapTracer(aCx), mFailed(false) - { - } - - static bool - Check(JSContext* aCx) - { - CheckWeakMappingGrayBitsTracer tracer(aCx); - js::TraceWeakMaps(&tracer); - return !tracer.mFailed; - } - - void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override - { - bool keyShouldBeBlack; - bool valueShouldBeBlack; - ShouldWeakMappingEntryBeBlack(aMap, aKey, aValue, - &keyShouldBeBlack, &valueShouldBeBlack); - - if (keyShouldBeBlack) { - fprintf(stderr, "Weak mapping key %p of map %p should be black\n", - aKey.asCell(), aMap); - mFailed = true; - } - - if (valueShouldBeBlack) { - fprintf(stderr, "Weak mapping value %p of map %p should be black\n", - aValue.asCell(), aMap); - mFailed = true; - } - } - - bool mFailed; -}; -#endif // DEBUG - -static void -CheckParticipatesInCycleCollection(JS::GCCellPtr aThing, const char* aName, - void* aClosure) -{ - bool* cycleCollectionEnabled = static_cast(aClosure); - - if (*cycleCollectionEnabled) { - return; - } - - if (AddToCCKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) { - *cycleCollectionEnabled = true; - } -} - -NS_IMETHODIMP -JSGCThingParticipant::TraverseNative(void* aPtr, - nsCycleCollectionTraversalCallback& aCb) -{ - auto runtime = reinterpret_cast( - reinterpret_cast(this) - offsetof(CycleCollectedJSContext, - mGCThingCycleCollectorGlobal)); - - JS::GCCellPtr cellPtr(aPtr, JS::GCThingTraceKind(aPtr)); - runtime->TraverseGCThing(CycleCollectedJSContext::TRAVERSE_FULL, cellPtr, aCb); - return NS_OK; -} - -// NB: This is only used to initialize the participant in -// CycleCollectedJSContext. It should never be used directly. -static JSGCThingParticipant sGCThingCycleCollectorGlobal; - -NS_IMETHODIMP -JSZoneParticipant::TraverseNative(void* aPtr, - nsCycleCollectionTraversalCallback& aCb) -{ - auto runtime = reinterpret_cast( - reinterpret_cast(this) - offsetof(CycleCollectedJSContext, - mJSZoneCycleCollectorGlobal)); - - MOZ_ASSERT(!aCb.WantAllTraces()); - JS::Zone* zone = static_cast(aPtr); - - runtime->TraverseZone(zone, aCb); - return NS_OK; -} - -struct TraversalTracer : public JS::CallbackTracer -{ - TraversalTracer(JSContext* aCx, nsCycleCollectionTraversalCallback& aCb) - : JS::CallbackTracer(aCx, DoNotTraceWeakMaps), mCb(aCb) - { - } - void onChild(const JS::GCCellPtr& aThing) override; - nsCycleCollectionTraversalCallback& mCb; -}; - -void -TraversalTracer::onChild(const JS::GCCellPtr& aThing) -{ - // Don't traverse non-gray objects, unless we want all traces. - if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) { - return; - } - - /* - * This function needs to be careful to avoid stack overflow. Normally, when - * AddToCCKind is true, the recursion terminates immediately as we just add - * |thing| to the CC graph. So overflow is only possible when there are long - * or cyclic chains of non-AddToCCKind GC things. Places where this can occur - * use special APIs to handle such chains iteratively. - */ - if (AddToCCKind(aThing.kind())) { - if (MOZ_UNLIKELY(mCb.WantDebugInfo())) { - char buffer[200]; - getTracingEdgeName(buffer, sizeof(buffer)); - mCb.NoteNextEdgeName(buffer); - } - mCb.NoteJSChild(aThing); - } else if (aThing.is()) { - // The maximum depth of traversal when tracing a Shape is unbounded, due to - // the parent pointers on the shape. - JS_TraceShapeCycleCollectorChildren(this, aThing); - } else if (aThing.is()) { - // The maximum depth of traversal when tracing an ObjectGroup is unbounded, - // due to information attached to the groups which can lead other groups to - // be traced. - JS_TraceObjectGroupCycleCollectorChildren(this, aThing); - } else if (!aThing.is()) { - JS::TraceChildren(this, aThing); - } -} - -static void -NoteJSChildGrayWrapperShim(void* aData, JS::GCCellPtr aThing) -{ - TraversalTracer* trc = static_cast(aData); - trc->onChild(aThing); -} - -/* - * The cycle collection participant for a Zone is intended to produce the same - * results as if all of the gray GCthings in a zone were merged into a single node, - * except for self-edges. This avoids the overhead of representing all of the GCthings in - * the zone in the cycle collector graph, which should be much faster if many of - * the GCthings in the zone are gray. - * - * Zone merging should not always be used, because it is a conservative - * approximation of the true cycle collector graph that can incorrectly identify some - * garbage objects as being live. For instance, consider two cycles that pass through a - * zone, where one is garbage and the other is live. If we merge the entire - * zone, the cycle collector will think that both are alive. - * - * We don't have to worry about losing track of a garbage cycle, because any such garbage - * cycle incorrectly identified as live must contain at least one C++ to JS edge, and - * XPConnect will always add the C++ object to the CC graph. (This is in contrast to pure - * C++ garbage cycles, which must always be properly identified, because we clear the - * purple buffer during every CC, which may contain the last reference to a garbage - * cycle.) - */ - -// NB: This is only used to initialize the participant in -// CycleCollectedJSContext. It should never be used directly. -static const JSZoneParticipant sJSZoneCycleCollectorGlobal; - -static -void JSObjectsTenuredCb(JSContext* aContext, void* aData) -{ - static_cast(aData)->JSObjectsTenured(); -} - -bool -mozilla::GetBuildId(JS::BuildIdCharVector* aBuildID) -{ - nsCOMPtr info = do_GetService("@mozilla.org/xre/app-info;1"); - if (!info) { - return false; - } - - nsCString buildID; - nsresult rv = info->GetPlatformBuildID(buildID); - NS_ENSURE_SUCCESS(rv, false); - - if (!aBuildID->resize(buildID.Length())) { - return false; - } - - for (size_t i = 0; i < buildID.Length(); i++) { - (*aBuildID)[i] = buildID[i]; - } - - return true; -} - CycleCollectedJSContext::CycleCollectedJSContext() - : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal) - , mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal) + : mRuntime(nullptr) , mJSContext(nullptr) - , mPrevGCSliceCallback(nullptr) - , mPrevGCNurseryCollectionCallback(nullptr) - , mJSHolders(256) , mDoingStableStates(false) , mDisableMicroTaskCheckpoint(false) - , mOutOfMemoryState(OOMState::OK) - , mLargeAllocationFailureState(OOMState::OK) { nsCOMPtr thread = do_GetCurrentThread(); mOwningThread = thread.forget().downcast().take(); @@ -518,7 +68,7 @@ CycleCollectedJSContext::~CycleCollectedJSContext() return; } - MOZ_ASSERT(!mDeferredFinalizerTable.Count()); + mRuntime->Shutdown(); // Last chance to process any events. ProcessMetastableStateQueue(mBaseRecursionDepth); @@ -544,12 +94,9 @@ CycleCollectedJSContext::~CycleCollectedJSContext() mOwningThread->SetScriptObserver(nullptr); NS_RELEASE(mOwningThread); -} -static void -MozCrashWarningReporter(JSContext*, JSErrorReport*) -{ - MOZ_CRASH("Why is someone touching JSAPI without an AutoJSAPI?"); + delete mRuntime; + mRuntime = nullptr; } nsresult @@ -569,43 +116,10 @@ CycleCollectedJSContext::Initialize(JSRuntime* aParentRuntime, return NS_ERROR_OUT_OF_MEMORY; } + mRuntime = CreateRuntime(mJSContext); + NS_GetCurrentThread()->SetCanInvokeJS(true); - if (!JS_AddExtraGCRootsTracer(mJSContext, TraceBlackJS, this)) { - MOZ_CRASH("JS_AddExtraGCRootsTracer failed"); - } - JS_SetGrayGCRootsTracer(mJSContext, TraceGrayJS, this); - JS_SetGCCallback(mJSContext, GCCallback, this); - mPrevGCSliceCallback = JS::SetGCSliceCallback(mJSContext, GCSliceCallback); - - if (NS_IsMainThread()) { - // We would like to support all threads here, but the way timeline consumers - // are set up currently, you can either add a marker for one specific - // docshell, or for every consumer globally. We would like to add a marker - // for every consumer observing anything on this thread, but that is not - // currently possible. For now, add global markers only when we are on the - // main thread, since the UI for this tracing data only displays data - // relevant to the main-thread. - mPrevGCNurseryCollectionCallback = JS::SetGCNurseryCollectionCallback( - mJSContext, GCNurseryCollectionCallback); - } - - JS_SetObjectsTenuredCallback(mJSContext, JSObjectsTenuredCb, this); - JS::SetOutOfMemoryCallback(mJSContext, OutOfMemoryCallback, this); - JS_SetExternalStringSizeofCallback(mJSContext, SizeofExternalStringCallback); - JS::SetBuildIdOp(mJSContext, GetBuildId); - JS::SetWarningReporter(mJSContext, MozCrashWarningReporter); -#ifdef MOZ_CRASHREPORTER - js::AutoEnterOOMUnsafeRegion::setAnnotateOOMAllocationSizeCallback( - CrashReporter::AnnotateOOMAllocationSize); -#endif - - static js::DOMCallbacks DOMcallbacks = { - InstanceClassHasProtoAtDepth - }; - SetDOMCallbacks(mJSContext, &DOMcallbacks); - js::SetScriptEnvironmentPreparer(mJSContext, &mEnvironmentPreparer); - JS::SetGetIncumbentGlobalCallback(mJSContext, GetIncumbentGlobalCallback); JS::SetEnqueuePromiseJobCallback(mJSContext, EnqueuePromiseJobCallback, this); @@ -613,8 +127,6 @@ CycleCollectedJSContext::Initialize(JSRuntime* aParentRuntime, mUncaughtRejections.init(mJSContext, JS::GCVector(js::SystemAllocPolicy())); mConsumedRejections.init(mJSContext, JS::GCVector(js::SystemAllocPolicy())); - JS::dbg::SetDebuggerMallocSizeOf(mJSContext, moz_malloc_size_of); - nsCycleCollector_registerJSContext(this); return NS_OK; @@ -623,370 +135,7 @@ CycleCollectedJSContext::Initialize(JSRuntime* aParentRuntime, size_t CycleCollectedJSContext::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { - size_t n = 0; - - // We're deliberately not measuring anything hanging off the entries in - // mJSHolders. - n += mJSHolders.ShallowSizeOfExcludingThis(aMallocSizeOf); - - return n; -} - -void -CycleCollectedJSContext::UnmarkSkippableJSHolders() -{ - for (auto iter = mJSHolders.Iter(); !iter.Done(); iter.Next()) { - void* holder = iter.Key(); - nsScriptObjectTracer*& tracer = iter.Data(); - tracer->CanSkip(holder, true); - } -} - -void -CycleCollectedJSContext::DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) const -{ - if (!aCb.WantDebugInfo()) { - aCb.DescribeGCedNode(aIsMarked, "JS Object"); - return; - } - - char name[72]; - uint64_t compartmentAddress = 0; - if (aThing.is()) { - JSObject* obj = &aThing.as(); - compartmentAddress = (uint64_t)js::GetObjectCompartment(obj); - const js::Class* clasp = js::GetObjectClass(obj); - - // Give the subclass a chance to do something - if (DescribeCustomObjects(obj, clasp, name)) { - // Nothing else to do! - } else if (js::IsFunctionObject(obj)) { - JSFunction* fun = JS_GetObjectFunction(obj); - JSString* str = JS_GetFunctionDisplayId(fun); - if (str) { - JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(str); - nsAutoString chars; - AssignJSFlatString(chars, flat); - NS_ConvertUTF16toUTF8 fname(chars); - SprintfLiteral(name, "JS Object (Function - %s)", fname.get()); - } else { - SprintfLiteral(name, "JS Object (Function)"); - } - } else { - SprintfLiteral(name, "JS Object (%s)", clasp->name); - } - } else { - SprintfLiteral(name, "JS %s", JS::GCTraceKindToAscii(aThing.kind())); - } - - // Disable printing global for objects while we figure out ObjShrink fallout. - aCb.DescribeGCedNode(aIsMarked, name, compartmentAddress); -} - -void -CycleCollectedJSContext::NoteGCThingJSChildren(JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) const -{ - MOZ_ASSERT(mJSContext); - TraversalTracer trc(mJSContext, aCb); - JS::TraceChildren(&trc, aThing); -} - -void -CycleCollectedJSContext::NoteGCThingXPCOMChildren(const js::Class* aClasp, - JSObject* aObj, - nsCycleCollectionTraversalCallback& aCb) const -{ - MOZ_ASSERT(aClasp); - MOZ_ASSERT(aClasp == js::GetObjectClass(aObj)); - - if (NoteCustomGCThingXPCOMChildren(aClasp, aObj, aCb)) { - // Nothing else to do! - return; - } - // XXX This test does seem fragile, we should probably whitelist classes - // that do hold a strong reference, but that might not be possible. - else if (aClasp->flags & JSCLASS_HAS_PRIVATE && - aClasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "js::GetObjectPrivate(obj)"); - aCb.NoteXPCOMChild(static_cast(js::GetObjectPrivate(aObj))); - } else { - const DOMJSClass* domClass = GetDOMClass(aObj); - if (domClass) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "UnwrapDOMObject(obj)"); - // It's possible that our object is an unforgeable holder object, in - // which case it doesn't actually have a C++ DOM object associated with - // it. Use UnwrapPossiblyNotInitializedDOMObject, which produces null in - // that case, since NoteXPCOMChild/NoteNativeChild are null-safe. - if (domClass->mDOMObjectIsISupports) { - aCb.NoteXPCOMChild(UnwrapPossiblyNotInitializedDOMObject(aObj)); - } else if (domClass->mParticipant) { - aCb.NoteNativeChild(UnwrapPossiblyNotInitializedDOMObject(aObj), - domClass->mParticipant); - } - } - } -} - -void -CycleCollectedJSContext::TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) -{ - bool isMarkedGray = JS::GCThingIsMarkedGray(aThing); - - if (aTs == TRAVERSE_FULL) { - DescribeGCThing(!isMarkedGray, aThing, aCb); - } - - // If this object is alive, then all of its children are alive. For JS objects, - // the black-gray invariant ensures the children are also marked black. For C++ - // objects, the ref count from this object will keep them alive. Thus we don't - // need to trace our children, unless we are debugging using WantAllTraces. - if (!isMarkedGray && !aCb.WantAllTraces()) { - return; - } - - if (aTs == TRAVERSE_FULL) { - NoteGCThingJSChildren(aThing, aCb); - } - - if (aThing.is()) { - JSObject* obj = &aThing.as(); - NoteGCThingXPCOMChildren(js::GetObjectClass(obj), obj, aCb); - } -} - -struct TraverseObjectShimClosure -{ - nsCycleCollectionTraversalCallback& cb; - CycleCollectedJSContext* self; -}; - -void -CycleCollectedJSContext::TraverseZone(JS::Zone* aZone, - nsCycleCollectionTraversalCallback& aCb) -{ - MOZ_ASSERT(mJSContext); - - /* - * We treat the zone as being gray. We handle non-gray GCthings in the - * zone by not reporting their children to the CC. The black-gray invariant - * ensures that any JS children will also be non-gray, and thus don't need to be - * added to the graph. For C++ children, not representing the edge from the - * non-gray JS GCthings to the C++ object will keep the child alive. - * - * We don't allow zone merging in a WantAllTraces CC, because then these - * assumptions don't hold. - */ - aCb.DescribeGCedNode(false, "JS Zone"); - - /* - * Every JS child of everything in the zone is either in the zone - * or is a cross-compartment wrapper. In the former case, we don't need to - * represent these edges in the CC graph because JS objects are not ref counted. - * In the latter case, the JS engine keeps a map of these wrappers, which we - * iterate over. Edges between compartments in the same zone will add - * unnecessary loop edges to the graph (bug 842137). - */ - TraversalTracer trc(mJSContext, aCb); - js::VisitGrayWrapperTargets(aZone, NoteJSChildGrayWrapperShim, &trc); - - /* - * To find C++ children of things in the zone, we scan every JS Object in - * the zone. Only JS Objects can have C++ children. - */ - TraverseObjectShimClosure closure = { aCb, this }; - js::IterateGrayObjects(aZone, TraverseObjectShim, &closure); -} - -/* static */ void -CycleCollectedJSContext::TraverseObjectShim(void* aData, JS::GCCellPtr aThing) -{ - TraverseObjectShimClosure* closure = - static_cast(aData); - - MOZ_ASSERT(aThing.is()); - closure->self->TraverseGCThing(CycleCollectedJSContext::TRAVERSE_CPP, - aThing, closure->cb); -} - -void -CycleCollectedJSContext::TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb) -{ - // NB: This is here just to preserve the existing XPConnect order. I doubt it - // would hurt to do this after the JS holders. - TraverseAdditionalNativeRoots(aCb); - - for (auto iter = mJSHolders.Iter(); !iter.Done(); iter.Next()) { - void* holder = iter.Key(); - nsScriptObjectTracer*& tracer = iter.Data(); - - bool noteRoot = false; - if (MOZ_UNLIKELY(aCb.WantAllTraces())) { - noteRoot = true; - } else { - tracer->Trace(holder, - TraceCallbackFunc(CheckParticipatesInCycleCollection), - ¬eRoot); - } - - if (noteRoot) { - aCb.NoteNativeRoot(holder, tracer); - } - } -} - -/* static */ void -CycleCollectedJSContext::TraceBlackJS(JSTracer* aTracer, void* aData) -{ - CycleCollectedJSContext* self = static_cast(aData); - - self->TraceNativeBlackRoots(aTracer); -} - -/* static */ void -CycleCollectedJSContext::TraceGrayJS(JSTracer* aTracer, void* aData) -{ - CycleCollectedJSContext* self = static_cast(aData); - - // Mark these roots as gray so the CC can walk them later. - self->TraceNativeGrayRoots(aTracer); -} - -/* static */ void -CycleCollectedJSContext::GCCallback(JSContext* aContext, - JSGCStatus aStatus, - void* aData) -{ - CycleCollectedJSContext* self = static_cast(aData); - - MOZ_ASSERT(aContext == self->Context()); - - self->OnGC(aStatus); -} - -/* static */ void -CycleCollectedJSContext::GCSliceCallback(JSContext* aContext, - JS::GCProgress aProgress, - const JS::GCDescription& aDesc) -{ - CycleCollectedJSContext* self = CycleCollectedJSContext::Get(); - MOZ_ASSERT(self->Context() == aContext); - - if (aProgress == JS::GC_CYCLE_END) { - JS::gcreason::Reason reason = aDesc.reason_; - Unused << - NS_WARN_IF(NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) && - reason != JS::gcreason::SHUTDOWN_CC && - reason != JS::gcreason::DESTROY_RUNTIME && - reason != JS::gcreason::XPCONNECT_SHUTDOWN); - } - - if (self->mPrevGCSliceCallback) { - self->mPrevGCSliceCallback(aContext, aProgress, aDesc); - } -} - -class MinorGCMarker : public TimelineMarker -{ -private: - JS::gcreason::Reason mReason; - -public: - MinorGCMarker(MarkerTracingType aTracingType, - JS::gcreason::Reason aReason) - : TimelineMarker("MinorGC", - aTracingType, - MarkerStackRequest::NO_STACK) - , mReason(aReason) - { - MOZ_ASSERT(aTracingType == MarkerTracingType::START || - aTracingType == MarkerTracingType::END); - } - - MinorGCMarker(JS::GCNurseryProgress aProgress, - JS::gcreason::Reason aReason) - : TimelineMarker("MinorGC", - aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START - ? MarkerTracingType::START - : MarkerTracingType::END, - MarkerStackRequest::NO_STACK) - , mReason(aReason) - { } - - virtual void - AddDetails(JSContext* aCx, - dom::ProfileTimelineMarker& aMarker) override - { - TimelineMarker::AddDetails(aCx, aMarker); - - if (GetTracingType() == MarkerTracingType::START) { - auto reason = JS::gcreason::ExplainReason(mReason); - aMarker.mCauseName.Construct(NS_ConvertUTF8toUTF16(reason)); - } - } - - virtual UniquePtr - Clone() override - { - auto clone = MakeUnique(GetTracingType(), mReason); - clone->SetCustomTime(GetTime()); - return UniquePtr(Move(clone)); - } -}; - -/* static */ void -CycleCollectedJSContext::GCNurseryCollectionCallback(JSContext* aContext, - JS::GCNurseryProgress aProgress, - JS::gcreason::Reason aReason) -{ - CycleCollectedJSContext* self = CycleCollectedJSContext::Get(); - MOZ_ASSERT(self->Context() == aContext); - MOZ_ASSERT(NS_IsMainThread()); - - RefPtr timelines = TimelineConsumers::Get(); - if (timelines && !timelines->IsEmpty()) { - UniquePtr abstractMarker( - MakeUnique(aProgress, aReason)); - timelines->AddMarkerForAllObservedDocShells(abstractMarker); - } - - if (self->mPrevGCNurseryCollectionCallback) { - self->mPrevGCNurseryCollectionCallback(aContext, aProgress, aReason); - } -} - - -/* static */ void -CycleCollectedJSContext::OutOfMemoryCallback(JSContext* aContext, - void* aData) -{ - CycleCollectedJSContext* self = static_cast(aData); - - MOZ_ASSERT(aContext == self->Context()); - - self->OnOutOfMemory(); -} - -/* static */ size_t -CycleCollectedJSContext::SizeofExternalStringCallback(JSString* aStr, - MallocSizeOf aMallocSizeOf) -{ - // We promised the JS engine we would not GC. Enforce that: - JS::AutoCheckCannotGC autoCannotGC; - - if (!XPCStringConvert::IsDOMString(aStr)) { - // Might be a literal or something we don't understand. Just claim 0. - return 0; - } - - const char16_t* chars = JS_GetTwoByteExternalStringChars(aStr); - const nsStringBuffer* buf = nsStringBuffer::FromData((void*)chars); - // We want sizeof including this, because the entire string buffer is owned by - // the external string. But only report here if we're unshared; if we're - // shared then we don't know who really owns this data. - return buf->SizeOfIncludingThisIfUnshared(aMallocSizeOf); + return 0; } class PromiseJobRunnable final : public Runnable @@ -1070,164 +219,6 @@ CycleCollectedJSContext::PromiseRejectionTrackerCallback(JSContext* aCx, } } -struct JsGcTracer : public TraceCallbacks -{ - virtual void Trace(JS::Heap* aPtr, const char* aName, - void* aClosure) const override - { - JS::TraceEdge(static_cast(aClosure), aPtr, aName); - } - virtual void Trace(JS::Heap* aPtr, const char* aName, - void* aClosure) const override - { - JS::TraceEdge(static_cast(aClosure), aPtr, aName); - } - virtual void Trace(JS::Heap* aPtr, const char* aName, - void* aClosure) const override - { - JS::TraceEdge(static_cast(aClosure), aPtr, aName); - } - virtual void Trace(JSObject** aPtr, const char* aName, - void* aClosure) const override - { - js::UnsafeTraceManuallyBarrieredEdge(static_cast(aClosure), aPtr, aName); - } - virtual void Trace(JS::TenuredHeap* aPtr, const char* aName, - void* aClosure) const override - { - JS::TraceEdge(static_cast(aClosure), aPtr, aName); - } - virtual void Trace(JS::Heap* aPtr, const char* aName, - void* aClosure) const override - { - JS::TraceEdge(static_cast(aClosure), aPtr, aName); - } - virtual void Trace(JS::Heap* aPtr, const char* aName, - void* aClosure) const override - { - JS::TraceEdge(static_cast(aClosure), aPtr, aName); - } - virtual void Trace(JS::Heap* aPtr, const char* aName, - void* aClosure) const override - { - JS::TraceEdge(static_cast(aClosure), aPtr, aName); - } -}; - -void -mozilla::TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer) -{ - nsXPCOMCycleCollectionParticipant* participant = nullptr; - CallQueryInterface(aHolder, &participant); - participant->Trace(aHolder, JsGcTracer(), aTracer); -} - -void -CycleCollectedJSContext::TraceNativeGrayRoots(JSTracer* aTracer) -{ - MOZ_ASSERT(mJSContext); - - // NB: This is here just to preserve the existing XPConnect order. I doubt it - // would hurt to do this after the JS holders. - TraceAdditionalNativeGrayRoots(aTracer); - - for (auto iter = mJSHolders.Iter(); !iter.Done(); iter.Next()) { - void* holder = iter.Key(); - nsScriptObjectTracer*& tracer = iter.Data(); - tracer->Trace(holder, JsGcTracer(), aTracer); - } -} - -void -CycleCollectedJSContext::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer) -{ - MOZ_ASSERT(mJSContext); - mJSHolders.Put(aHolder, aTracer); -} - -struct ClearJSHolder : public TraceCallbacks -{ - virtual void Trace(JS::Heap* aPtr, const char*, void*) const override - { - aPtr->setUndefined(); - } - - virtual void Trace(JS::Heap* aPtr, const char*, void*) const override - { - *aPtr = JSID_VOID; - } - - virtual void Trace(JS::Heap* aPtr, const char*, void*) const override - { - *aPtr = nullptr; - } - - virtual void Trace(JSObject** aPtr, const char* aName, - void* aClosure) const override - { - *aPtr = nullptr; - } - - virtual void Trace(JS::TenuredHeap* aPtr, const char*, void*) const override - { - *aPtr = nullptr; - } - - virtual void Trace(JS::Heap* aPtr, const char*, void*) const override - { - *aPtr = nullptr; - } - - virtual void Trace(JS::Heap* aPtr, const char*, void*) const override - { - *aPtr = nullptr; - } - - virtual void Trace(JS::Heap* aPtr, const char*, void*) const override - { - *aPtr = nullptr; - } -}; - -void -CycleCollectedJSContext::RemoveJSHolder(void* aHolder) -{ - MOZ_ASSERT(mJSContext); - - nsScriptObjectTracer* tracer = mJSHolders.Get(aHolder); - if (!tracer) { - return; - } - tracer->Trace(aHolder, ClearJSHolder(), nullptr); - mJSHolders.Remove(aHolder); -} - -#ifdef DEBUG -bool -CycleCollectedJSContext::IsJSHolder(void* aHolder) -{ - MOZ_ASSERT(mJSContext); - return mJSHolders.Get(aHolder, nullptr); -} - -static void -AssertNoGcThing(JS::GCCellPtr aGCThing, const char* aName, void* aClosure) -{ - MOZ_ASSERT(!aGCThing); -} - -void -CycleCollectedJSContext::AssertNoObjectsToTrace(void* aPossibleJSHolder) -{ - MOZ_ASSERT(mJSContext); - - nsScriptObjectTracer* tracer = mJSHolders.Get(aPossibleJSHolder); - if (tracer) { - tracer->Trace(aPossibleJSHolder, TraceCallbackFunc(AssertNoGcThing), nullptr); - } -} -#endif - already_AddRefed CycleCollectedJSContext::GetPendingException() const { @@ -1258,162 +249,6 @@ CycleCollectedJSContext::GetDebuggerPromiseMicroTaskQueue() return mDebuggerPromiseMicroTaskQueue; } -nsCycleCollectionParticipant* -CycleCollectedJSContext::GCThingParticipant() -{ - MOZ_ASSERT(mJSContext); - return &mGCThingCycleCollectorGlobal; -} - -nsCycleCollectionParticipant* -CycleCollectedJSContext::ZoneParticipant() -{ - MOZ_ASSERT(mJSContext); - return &mJSZoneCycleCollectorGlobal; -} - -nsresult -CycleCollectedJSContext::TraverseRoots(nsCycleCollectionNoteRootCallback& aCb) -{ - MOZ_ASSERT(mJSContext); - - TraverseNativeRoots(aCb); - - NoteWeakMapsTracer trc(mJSContext, aCb); - js::TraceWeakMaps(&trc); - - return NS_OK; -} - -bool -CycleCollectedJSContext::UsefulToMergeZones() const -{ - return false; -} - -void -CycleCollectedJSContext::FixWeakMappingGrayBits() const -{ - MOZ_ASSERT(mJSContext); - MOZ_ASSERT(!JS::IsIncrementalGCInProgress(mJSContext), - "Don't call FixWeakMappingGrayBits during a GC."); - FixWeakMappingGrayBitsTracer fixer(mJSContext); - fixer.FixAll(); -} - -void -CycleCollectedJSContext::CheckGrayBits() const -{ - MOZ_ASSERT(mJSContext); - MOZ_ASSERT(!JS::IsIncrementalGCInProgress(mJSContext), - "Don't call CheckGrayBits during a GC."); - -#ifndef ANDROID - // Bug 1346874 - The gray state check is expensive. Android tests are already - // slow enough that this check can easily push them over the threshold to a - // timeout. - - MOZ_ASSERT(js::CheckGrayMarkingState(mJSContext)); - MOZ_ASSERT(CheckWeakMappingGrayBitsTracer::Check(mJSContext)); -#endif -} - -bool -CycleCollectedJSContext::AreGCGrayBitsValid() const -{ - MOZ_ASSERT(mJSContext); - return js::AreGCGrayBitsValid(mJSContext); -} - -void -CycleCollectedJSContext::GarbageCollect(uint32_t aReason) const -{ - MOZ_ASSERT(mJSContext); - - MOZ_ASSERT(aReason < JS::gcreason::NUM_REASONS); - JS::gcreason::Reason gcreason = static_cast(aReason); - - JS::PrepareForFullGC(mJSContext); - JS::GCForReason(mJSContext, GC_NORMAL, gcreason); -} - -void -CycleCollectedJSContext::JSObjectsTenured() -{ - MOZ_ASSERT(mJSContext); - - for (auto iter = mNurseryObjects.Iter(); !iter.Done(); iter.Next()) { - nsWrapperCache* cache = iter.Get(); - JSObject* wrapper = cache->GetWrapperPreserveColor(); - MOZ_DIAGNOSTIC_ASSERT(wrapper); - if (!JS::ObjectIsTenured(wrapper)) { - MOZ_ASSERT(!cache->PreservingWrapper()); - const JSClass* jsClass = js::GetObjectJSClass(wrapper); - jsClass->doFinalize(nullptr, wrapper); - } - } - -#ifdef DEBUG -for (auto iter = mPreservedNurseryObjects.Iter(); !iter.Done(); iter.Next()) { - MOZ_ASSERT(JS::ObjectIsTenured(iter.Get().get())); -} -#endif - - mNurseryObjects.Clear(); - mPreservedNurseryObjects.Clear(); -} - -void -CycleCollectedJSContext::NurseryWrapperAdded(nsWrapperCache* aCache) -{ - MOZ_ASSERT(mJSContext); - MOZ_ASSERT(aCache); - MOZ_ASSERT(aCache->GetWrapperPreserveColor()); - MOZ_ASSERT(!JS::ObjectIsTenured(aCache->GetWrapperPreserveColor())); - mNurseryObjects.InfallibleAppend(aCache); -} - -void -CycleCollectedJSContext::NurseryWrapperPreserved(JSObject* aWrapper) -{ - MOZ_ASSERT(mJSContext); - - mPreservedNurseryObjects.InfallibleAppend( - JS::PersistentRooted(mJSContext, aWrapper)); -} - -void -CycleCollectedJSContext::DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, - DeferredFinalizeFunction aFunc, - void* aThing) -{ - MOZ_ASSERT(mJSContext); - - void* thingArray = nullptr; - bool hadThingArray = mDeferredFinalizerTable.Get(aFunc, &thingArray); - - thingArray = aAppendFunc(thingArray, aThing); - if (!hadThingArray) { - mDeferredFinalizerTable.Put(aFunc, thingArray); - } -} - -void -CycleCollectedJSContext::DeferredFinalize(nsISupports* aSupports) -{ - MOZ_ASSERT(mJSContext); - - typedef DeferredFinalizerImpl Impl; - DeferredFinalize(Impl::AppendDeferredFinalizePointer, Impl::DeferredFinalize, - aSupports); -} - -void -CycleCollectedJSContext::DumpJSHeap(FILE* aFile) -{ - js::DumpHeap(Context(), aFile, js::CollectNurseryBeforeDump); -} - void CycleCollectedJSContext::ProcessStableStateQueue() { @@ -1542,229 +377,6 @@ CycleCollectedJSContext::RunInMetastableState(already_AddRefed&& aR mMetastableStateEvents.AppendElement(Move(data)); } -IncrementalFinalizeRunnable::IncrementalFinalizeRunnable(CycleCollectedJSContext* aCx, - DeferredFinalizerTable& aFinalizers) - : Runnable("IncrementalFinalizeRunnable") - , mContext(aCx) - , mFinalizeFunctionToRun(0) - , mReleasing(false) -{ - for (auto iter = aFinalizers.Iter(); !iter.Done(); iter.Next()) { - DeferredFinalizeFunction& function = iter.Key(); - void*& data = iter.Data(); - - DeferredFinalizeFunctionHolder* holder = - mDeferredFinalizeFunctions.AppendElement(); - holder->run = function; - holder->data = data; - - iter.Remove(); - } -} - -IncrementalFinalizeRunnable::~IncrementalFinalizeRunnable() -{ - MOZ_ASSERT(this != mContext->mFinalizeRunnable); -} - -void -IncrementalFinalizeRunnable::ReleaseNow(bool aLimited) -{ - if (mReleasing) { - NS_WARNING("Re-entering ReleaseNow"); - return; - } - { - mozilla::AutoRestore ar(mReleasing); - mReleasing = true; - MOZ_ASSERT(mDeferredFinalizeFunctions.Length() != 0, - "We should have at least ReleaseSliceNow to run"); - MOZ_ASSERT(mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length(), - "No more finalizers to run?"); - - TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis); - TimeStamp started = TimeStamp::Now(); - bool timeout = false; - do { - const DeferredFinalizeFunctionHolder& function = - mDeferredFinalizeFunctions[mFinalizeFunctionToRun]; - if (aLimited) { - bool done = false; - while (!timeout && !done) { - /* - * We don't want to read the clock too often, so we try to - * release slices of 100 items. - */ - done = function.run(100, function.data); - timeout = TimeStamp::Now() - started >= sliceTime; - } - if (done) { - ++mFinalizeFunctionToRun; - } - if (timeout) { - break; - } - } else { - while (!function.run(UINT32_MAX, function.data)); - ++mFinalizeFunctionToRun; - } - } while (mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length()); - } - - if (mFinalizeFunctionToRun == mDeferredFinalizeFunctions.Length()) { - MOZ_ASSERT(mContext->mFinalizeRunnable == this); - mDeferredFinalizeFunctions.Clear(); - // NB: This may delete this! - mContext->mFinalizeRunnable = nullptr; - } -} - -NS_IMETHODIMP -IncrementalFinalizeRunnable::Run() -{ - if (mContext->mFinalizeRunnable != this) { - /* These items were already processed synchronously in JSGC_END. */ - MOZ_ASSERT(!mDeferredFinalizeFunctions.Length()); - return NS_OK; - } - - TimeStamp start = TimeStamp::Now(); - ReleaseNow(true); - - if (mDeferredFinalizeFunctions.Length()) { - nsresult rv = NS_DispatchToCurrentThread(this); - if (NS_FAILED(rv)) { - ReleaseNow(false); - } - } - - uint32_t duration = (uint32_t)((TimeStamp::Now() - start).ToMilliseconds()); - Telemetry::Accumulate(Telemetry::DEFERRED_FINALIZE_ASYNC, duration); - - return NS_OK; -} - -void -CycleCollectedJSContext::FinalizeDeferredThings(DeferredFinalizeType aType) -{ - MOZ_ASSERT(mJSContext); - - /* - * If the previous GC created a runnable to finalize objects - * incrementally, and if it hasn't finished yet, finish it now. We - * don't want these to build up. We also don't want to allow any - * existing incremental finalize runnables to run after a - * non-incremental GC, since they are often used to detect leaks. - */ - if (mFinalizeRunnable) { - mFinalizeRunnable->ReleaseNow(false); - if (mFinalizeRunnable) { - // If we re-entered ReleaseNow, we couldn't delete mFinalizeRunnable and - // we need to just continue processing it. - return; - } - } - - if (mDeferredFinalizerTable.Count() == 0) { - return; - } - - mFinalizeRunnable = new IncrementalFinalizeRunnable(this, - mDeferredFinalizerTable); - - // Everything should be gone now. - MOZ_ASSERT(mDeferredFinalizerTable.Count() == 0); - - if (aType == FinalizeIncrementally) { - NS_DispatchToCurrentThread(mFinalizeRunnable); - } else { - mFinalizeRunnable->ReleaseNow(false); - MOZ_ASSERT(!mFinalizeRunnable); - } -} - -void -CycleCollectedJSContext::AnnotateAndSetOutOfMemory(OOMState* aStatePtr, - OOMState aNewState) -{ - MOZ_ASSERT(mJSContext); - - *aStatePtr = aNewState; -#ifdef MOZ_CRASHREPORTER - CrashReporter::AnnotateCrashReport(aStatePtr == &mOutOfMemoryState - ? NS_LITERAL_CSTRING("JSOutOfMemory") - : NS_LITERAL_CSTRING("JSLargeAllocationFailure"), - aNewState == OOMState::Reporting - ? NS_LITERAL_CSTRING("Reporting") - : aNewState == OOMState::Reported - ? NS_LITERAL_CSTRING("Reported") - : NS_LITERAL_CSTRING("Recovered")); -#endif -} - -void -CycleCollectedJSContext::OnGC(JSGCStatus aStatus) -{ - MOZ_ASSERT(mJSContext); - - switch (aStatus) { - case JSGC_BEGIN: - nsCycleCollector_prepareForGarbageCollection(); - mZonesWaitingForGC.Clear(); - break; - case JSGC_END: { -#ifdef MOZ_CRASHREPORTER - if (mOutOfMemoryState == OOMState::Reported) { - AnnotateAndSetOutOfMemory(&mOutOfMemoryState, OOMState::Recovered); - } - if (mLargeAllocationFailureState == OOMState::Reported) { - AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Recovered); - } -#endif - - // Do any deferred finalization of native objects. - FinalizeDeferredThings(JS::WasIncrementalGC(mJSContext) ? FinalizeIncrementally : - FinalizeNow); - break; - } - default: - MOZ_CRASH(); - } - - CustomGCCallback(aStatus); -} - -void -CycleCollectedJSContext::OnOutOfMemory() -{ - MOZ_ASSERT(mJSContext); - - AnnotateAndSetOutOfMemory(&mOutOfMemoryState, OOMState::Reporting); - CustomOutOfMemoryCallback(); - AnnotateAndSetOutOfMemory(&mOutOfMemoryState, OOMState::Reported); -} - -void -CycleCollectedJSContext::SetLargeAllocationFailure(OOMState aNewState) -{ - MOZ_ASSERT(mJSContext); - - AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, aNewState); -} - -void -CycleCollectedJSContext::PrepareWaitingZonesForGC() -{ - if (mZonesWaitingForGC.Count() == 0) { - JS::PrepareForFullGC(Context()); - } else { - for (auto iter = mZonesWaitingForGC.Iter(); !iter.Done(); iter.Next()) { - JS::PrepareZoneForGC(iter.Get()->GetKey()); - } - mZonesWaitingForGC.Clear(); - } -} - void CycleCollectedJSContext::DispatchToMicroTask(already_AddRefed aRunnable) { @@ -1776,23 +388,154 @@ CycleCollectedJSContext::DispatchToMicroTask(already_AddRefed aRunn mPromiseMicroTaskQueue.push(runnable.forget()); } +// All these functions just delegate to the runtime. + void -CycleCollectedJSContext::EnvironmentPreparer::invoke(JS::HandleObject scope, - js::ScriptEnvironmentPreparer::Closure& closure) +CycleCollectedJSContext::FinalizeDeferredThings(DeferredFinalizeType aType) { - nsIGlobalObject* global = xpc::NativeGlobal(scope); - - // Not much we can do if we simply don't have a usable global here... - NS_ENSURE_TRUE_VOID(global && global->GetGlobalJSObject()); - - AutoEntryScript aes(global, "JS-engine-initiated execution"); - - MOZ_ASSERT(!JS_IsExceptionPending(aes.cx())); - - DebugOnly ok = closure(aes.cx()); - - MOZ_ASSERT_IF(ok, !JS_IsExceptionPending(aes.cx())); - - // The AutoEntryScript will check for JS_IsExceptionPending on the - // JSContext and report it as needed as it comes off the stack. + Runtime()->FinalizeDeferredThings(aType); } + +void +CycleCollectedJSContext::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer) +{ + Runtime()->AddJSHolder(aHolder, aTracer); +} + +void +CycleCollectedJSContext::RemoveJSHolder(void* aHolder) +{ + Runtime()->RemoveJSHolder(aHolder); +} + +#ifdef DEBUG +bool +CycleCollectedJSContext::IsJSHolder(void* aHolder) +{ + return Runtime()->IsJSHolder(aHolder); +} + +void +CycleCollectedJSContext::AssertNoObjectsToTrace(void* aPossibleJSHolder) +{ + Runtime()->AssertNoObjectsToTrace(aPossibleJSHolder); +} +#endif + +nsCycleCollectionParticipant* +CycleCollectedJSContext::GCThingParticipant() +{ + return Runtime()->GCThingParticipant(); +} + +nsCycleCollectionParticipant* +CycleCollectedJSContext::ZoneParticipant() +{ + return Runtime()->ZoneParticipant(); +} + +nsresult +CycleCollectedJSContext::TraverseRoots(nsCycleCollectionNoteRootCallback& aCb) +{ + return Runtime()->TraverseRoots(aCb); +} + +bool +CycleCollectedJSContext::UsefulToMergeZones() const +{ + return Runtime()->UsefulToMergeZones(); +} + +void +CycleCollectedJSContext::FixWeakMappingGrayBits() const +{ + Runtime()->FixWeakMappingGrayBits(); +} + +bool +CycleCollectedJSContext::AreGCGrayBitsValid() const +{ + return Runtime()->AreGCGrayBitsValid(); +} + +void +CycleCollectedJSContext::GarbageCollect(uint32_t aReason) const +{ + Runtime()->GarbageCollect(aReason); +} + +void +CycleCollectedJSContext::NurseryWrapperAdded(nsWrapperCache* aCache) +{ + Runtime()->NurseryWrapperAdded(aCache); +} + +void +CycleCollectedJSContext::NurseryWrapperPreserved(JSObject* aWrapper) +{ + Runtime()->NurseryWrapperPreserved(aWrapper); +} + +void +CycleCollectedJSContext::JSObjectsTenured() +{ + Runtime()->JSObjectsTenured(); +} + +void +CycleCollectedJSContext::DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, + DeferredFinalizeFunction aFunc, + void* aThing) +{ + Runtime()->DeferredFinalize(aAppendFunc, aFunc, aThing); +} + +void +CycleCollectedJSContext::DeferredFinalize(nsISupports* aSupports) +{ + Runtime()->DeferredFinalize(aSupports); +} + +void +CycleCollectedJSContext::DumpJSHeap(FILE* aFile) +{ + Runtime()->DumpJSHeap(aFile); +} + +void +CycleCollectedJSContext::AddZoneWaitingForGC(JS::Zone* aZone) +{ + Runtime()->AddZoneWaitingForGC(aZone); +} + +void +CycleCollectedJSContext::PrepareWaitingZonesForGC() +{ + Runtime()->PrepareWaitingZonesForGC(); +} + +void +CycleCollectedJSContext::PrepareForForgetSkippable() +{ + Runtime()->PrepareForForgetSkippable(); +} + +void +CycleCollectedJSContext::BeginCycleCollectionCallback() +{ + Runtime()->BeginCycleCollectionCallback(); +} + +void +CycleCollectedJSContext::EndCycleCollectionCallback(CycleCollectorResults& aResults) +{ + Runtime()->EndCycleCollectionCallback(aResults); +} + +void +CycleCollectedJSContext::DispatchDeferredDeletion(bool aContinuation, bool aPurge) +{ + Runtime()->DispatchDeferredDeletion(aContinuation, aPurge); +} + +} // namespace mozilla diff --git a/xpcom/base/CycleCollectedJSContext.h b/xpcom/base/CycleCollectedJSContext.h index fec84cf13bfc..9773a93ee659 100644 --- a/xpcom/base/CycleCollectedJSContext.h +++ b/xpcom/base/CycleCollectedJSContext.h @@ -4,23 +4,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef mozilla_CycleCollectedJSContext_h__ -#define mozilla_CycleCollectedJSContext_h__ +#ifndef mozilla_CycleCollectedJSContext_h +#define mozilla_CycleCollectedJSContext_h #include #include "mozilla/DeferredFinalize.h" #include "mozilla/mozalloc.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/SegmentedVector.h" #include "jsapi.h" #include "jsfriendapi.h" +#include "nsCOMPtr.h" #include "nsCycleCollectionParticipant.h" -#include "nsDataHashtable.h" -#include "nsHashKeys.h" #include "nsTArray.h" -#include "nsTHashtable.h" class nsCycleCollectionNoteRootCallback; class nsIException; @@ -28,78 +25,9 @@ class nsIRunnable; class nsThread; class nsWrapperCache; -namespace js { -struct Class; -} // namespace js - namespace mozilla { -class JSGCThingParticipant: public nsCycleCollectionParticipant -{ -public: - constexpr JSGCThingParticipant() - : nsCycleCollectionParticipant(false) {} - - NS_IMETHOD_(void) Root(void*) override - { - MOZ_ASSERT(false, "Don't call Root on GC things"); - } - - NS_IMETHOD_(void) Unlink(void*) override - { - MOZ_ASSERT(false, "Don't call Unlink on GC things, as they may be dead"); - } - - NS_IMETHOD_(void) Unroot(void*) override - { - MOZ_ASSERT(false, "Don't call Unroot on GC things, as they may be dead"); - } - - NS_IMETHOD_(void) DeleteCycleCollectable(void* aPtr) override - { - MOZ_ASSERT(false, "Can't directly delete a cycle collectable GC thing"); - } - - NS_IMETHOD TraverseNative(void* aPtr, nsCycleCollectionTraversalCallback& aCb) - override; - - NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(JSGCThingParticipant) -}; - -class JSZoneParticipant : public nsCycleCollectionParticipant -{ -public: - constexpr JSZoneParticipant(): nsCycleCollectionParticipant(false) - { - } - - NS_IMETHOD_(void) Root(void*) override - { - MOZ_ASSERT(false, "Don't call Root on GC things"); - } - - NS_IMETHOD_(void) Unlink(void*) override - { - MOZ_ASSERT(false, "Don't call Unlink on GC things, as they may be dead"); - } - - NS_IMETHOD_(void) Unroot(void*) override - { - MOZ_ASSERT(false, "Don't call Unroot on GC things, as they may be dead"); - } - - NS_IMETHOD_(void) DeleteCycleCollectable(void*) override - { - MOZ_ASSERT(false, "Can't directly delete a cycle collectable GC thing"); - } - - NS_IMETHOD TraverseNative(void* aPtr, nsCycleCollectionTraversalCallback& aCb) - override; - - NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(JSZoneParticipant) -}; - -class IncrementalFinalizeRunnable; +class CycleCollectedJSRuntime; // Contains various stats about the cycle collection. struct CycleCollectorResults @@ -139,9 +67,8 @@ struct CycleCollectorResults class CycleCollectedJSContext { - friend class JSGCThingParticipant; - friend class JSZoneParticipant; - friend class IncrementalFinalizeRunnable; + friend class CycleCollectedJSRuntime; + protected: CycleCollectedJSContext(); virtual ~CycleCollectedJSContext(); @@ -151,80 +78,14 @@ protected: uint32_t aMaxBytes, uint32_t aMaxNurseryBytes); + virtual CycleCollectedJSRuntime* CreateRuntime(JSContext* aCx) = 0; + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; - void UnmarkSkippableJSHolders(); - - virtual void - TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& aCb) {} - virtual void TraceAdditionalNativeGrayRoots(JSTracer* aTracer) {} - - virtual void CustomGCCallback(JSGCStatus aStatus) {} - virtual void CustomOutOfMemoryCallback() {} std::queue> mPromiseMicroTaskQueue; std::queue> mDebuggerPromiseMicroTaskQueue; private: - void - DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) const; - - virtual bool - DescribeCustomObjects(JSObject* aObject, const js::Class* aClasp, - char (&aName)[72]) const - { - return false; // We did nothing. - } - - void - NoteGCThingJSChildren(JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb) const; - - void - NoteGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj, - nsCycleCollectionTraversalCallback& aCb) const; - - virtual bool - NoteCustomGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj, - nsCycleCollectionTraversalCallback& aCb) const - { - return false; // We did nothing. - } - - enum TraverseSelect { - TRAVERSE_CPP, - TRAVERSE_FULL - }; - - void - TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThing, - nsCycleCollectionTraversalCallback& aCb); - - void - TraverseZone(JS::Zone* aZone, nsCycleCollectionTraversalCallback& aCb); - - static void - TraverseObjectShim(void* aData, JS::GCCellPtr aThing); - - void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb); - - static void TraceBlackJS(JSTracer* aTracer, void* aData); - static void TraceGrayJS(JSTracer* aTracer, void* aData); - static void GCCallback(JSContext* aContext, JSGCStatus aStatus, void* aData); - static void GCSliceCallback(JSContext* aContext, JS::GCProgress aProgress, - const JS::GCDescription& aDesc); - static void GCNurseryCollectionCallback(JSContext* aContext, - JS::GCNurseryProgress aProgress, - JS::gcreason::Reason aReason); - static void OutOfMemoryCallback(JSContext* aContext, void* aData); - /** - * Callback for reporting external string memory. - */ - static size_t SizeofExternalStringCallback(JSString* aStr, - mozilla::MallocSizeOf aMallocSizeOf); - - static bool ContextCallback(JSContext* aCx, unsigned aOperation, - void* aData); static JSObject* GetIncumbentGlobalCallback(JSContext* aCx); static bool EnqueuePromiseJobCallback(JSContext* aCx, JS::HandleObject aJob, @@ -236,9 +97,6 @@ private: PromiseRejectionHandlingState state, void* aData); - virtual void TraceNativeBlackRoots(JSTracer* aTracer) { }; - void TraceNativeGrayRoots(JSTracer* aTracer); - void AfterProcessMicrotask(uint32_t aRecursionDepth); public: void ProcessStableStateQueue(); @@ -253,52 +111,12 @@ public: void FinalizeDeferredThings(DeferredFinalizeType aType); - // Two conditions, JSOutOfMemory and JSLargeAllocationFailure, are noted in - // crash reports. Here are the values that can appear in the reports: - enum class OOMState : uint32_t { - // The condition has never happened. No entry appears in the crash report. - OK, - - // We are currently reporting the given condition. - // - // Suppose a crash report contains "JSLargeAllocationFailure: - // Reporting". This means we crashed while executing memory-pressure - // observers, trying to shake loose some memory. The large allocation in - // question did not return null: it is still on the stack. Had we not - // crashed, it would have been retried. - Reporting, - - // The condition has been reported since the last GC. - // - // If a crash report contains "JSOutOfMemory: Reported", that means a small - // allocation failed, and then we crashed, probably due to buggy - // error-handling code that ran after allocation returned null. - // - // This contrasts with "Reporting" which means that no error-handling code - // had executed yet. - Reported, - - // The condition has happened, but a GC cycle ended since then. - // - // GC is taken as a proxy for "we've been banging on the heap a good bit - // now and haven't crashed; the OOM was probably handled correctly". - Recovered - }; - - void SetLargeAllocationFailure(OOMState aNewState); - -private: - void AnnotateAndSetOutOfMemory(OOMState* aStatePtr, OOMState aNewState); - void OnGC(JSGCStatus aStatus); - void OnOutOfMemory(); - public: - void AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer); - void RemoveJSHolder(void* aHolder); -#ifdef DEBUG - bool IsJSHolder(void* aHolder); - void AssertNoObjectsToTrace(void* aPossibleJSHolder); -#endif + CycleCollectedJSRuntime* Runtime() const + { + MOZ_ASSERT(mRuntime); + return mRuntime; + } already_AddRefed GetPendingException() const; void SetPendingException(nsIException* aException); @@ -306,31 +124,10 @@ public: std::queue>& GetPromiseMicroTaskQueue(); std::queue>& GetDebuggerPromiseMicroTaskQueue(); - nsCycleCollectionParticipant* GCThingParticipant(); - nsCycleCollectionParticipant* ZoneParticipant(); - - nsresult TraverseRoots(nsCycleCollectionNoteRootCallback& aCb); - virtual bool UsefulToMergeZones() const; - void FixWeakMappingGrayBits() const; - void CheckGrayBits() const; - bool AreGCGrayBitsValid() const; - void GarbageCollect(uint32_t aReason) const; - - void NurseryWrapperAdded(nsWrapperCache* aCache); - void NurseryWrapperPreserved(JSObject* aWrapper); - void JSObjectsTenured(); - - void DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, - DeferredFinalizeFunction aFunc, - void* aThing); - void DeferredFinalize(nsISupports* aSupports); - - void DumpJSHeap(FILE* aFile); - - virtual void PrepareForForgetSkippable() = 0; - virtual void BeginCycleCollectionCallback() = 0; - virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults) = 0; - virtual void DispatchDeferredDeletion(bool aContinuation, bool aPurge = false) = 0; + void PrepareForForgetSkippable(); + void BeginCycleCollectionCallback(); + void EndCycleCollectionCallback(CycleCollectorResults& aResults); + void DispatchDeferredDeletion(bool aContinuation, bool aPurge = false); JSContext* Context() const { @@ -373,6 +170,42 @@ public: bool mOldValue; }; + void AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer); + void RemoveJSHolder(void* aHolder); +#ifdef DEBUG + bool IsJSHolder(void* aHolder); + void AssertNoObjectsToTrace(void* aPossibleJSHolder); +#endif + + nsCycleCollectionParticipant* GCThingParticipant(); + nsCycleCollectionParticipant* ZoneParticipant(); + + nsresult TraverseRoots(nsCycleCollectionNoteRootCallback& aCb); + virtual bool UsefulToMergeZones() const; + void FixWeakMappingGrayBits() const; + bool AreGCGrayBitsValid() const; + void GarbageCollect(uint32_t aReason) const; + + void NurseryWrapperAdded(nsWrapperCache* aCache); + void NurseryWrapperPreserved(JSObject* aWrapper); + void JSObjectsTenured(); + + void DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, + DeferredFinalizeFunction aFunc, + void* aThing); + void DeferredFinalize(nsISupports* aSupports); + + void DumpJSHeap(FILE* aFile); + + // Add aZone to the set of zones waiting for a GC. + void AddZoneWaitingForGC(JS::Zone* aZone); + + // Prepare any zones for GC that have been passed to AddZoneWaitingForGC() + // since the last GC or since the last call to PrepareWaitingZonesForGC(), + // whichever was most recent. If there were no such zones, prepare for a + // full GC. + void PrepareWaitingZonesForGC(); + protected: JSContext* MaybeContext() const { return mJSContext; } @@ -396,18 +229,6 @@ public: // isn't one. static CycleCollectedJSContext* Get(); - // Add aZone to the set of zones waiting for a GC. - void AddZoneWaitingForGC(JS::Zone* aZone) - { - mZonesWaitingForGC.PutEntry(aZone); - } - - // Prepare any zones for GC that have been passed to AddZoneWaitingForGC() - // since the last GC or since the last call to PrepareWaitingZonesForGC(), - // whichever was most recent. If there were no such zones, prepare for a - // full GC. - void PrepareWaitingZonesForGC(); - // Queue an async microtask to the current main or worker thread. virtual void DispatchToMicroTask(already_AddRefed aRunnable); @@ -426,23 +247,10 @@ public: nsTArray> mUncaughtRejectionObservers; private: - JSGCThingParticipant mGCThingCycleCollectorGlobal; - - JSZoneParticipant mJSZoneCycleCollectorGlobal; + CycleCollectedJSRuntime* mRuntime; JSContext* mJSContext; - JS::GCSliceCallback mPrevGCSliceCallback; - JS::GCNurseryCollectionCallback mPrevGCNurseryCollectionCallback; - - nsDataHashtable, nsScriptObjectTracer*> mJSHolders; - - typedef nsDataHashtable, void*> - DeferredFinalizerTable; - DeferredFinalizerTable mDeferredFinalizerTable; - - RefPtr mFinalizeRunnable; - nsCOMPtr mPendingException; nsThread* mOwningThread; // Manual refcounting to avoid include hell. @@ -458,39 +266,8 @@ private: bool mDoingStableStates; bool mDisableMicroTaskCheckpoint; - - OOMState mOutOfMemoryState; - OOMState mLargeAllocationFailureState; - - static const size_t kSegmentSize = 512; - SegmentedVector - mNurseryObjects; - SegmentedVector, kSegmentSize, - InfallibleAllocPolicy> - mPreservedNurseryObjects; - - nsTHashtable> mZonesWaitingForGC; - - struct EnvironmentPreparer : public js::ScriptEnvironmentPreparer { - void invoke(JS::HandleObject scope, Closure& closure) override; - }; - EnvironmentPreparer mEnvironmentPreparer; }; -void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer); - -// Returns true if the JS::TraceKind is one the cycle collector cares about. -inline bool AddToCCKind(JS::TraceKind aKind) -{ - return aKind == JS::TraceKind::Object || - aKind == JS::TraceKind::Script || - aKind == JS::TraceKind::Scope || - aKind == JS::TraceKind::RegExpShared; -} - -bool -GetBuildId(JS::BuildIdCharVector* aBuildID); - } // namespace mozilla -#endif // mozilla_CycleCollectedJSContext_h__ +#endif // mozilla_CycleCollectedJSContext_h diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp new file mode 100644 index 000000000000..e306ffc9073a --- /dev/null +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -0,0 +1,1507 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// We're dividing JS objects into 3 categories: +// +// 1. "real" roots, held by the JS engine itself or rooted through the root +// and lock JS APIs. Roots from this category are considered black in the +// cycle collector, any cycle they participate in is uncollectable. +// +// 2. certain roots held by C++ objects that are guaranteed to be alive. +// Roots from this category are considered black in the cycle collector, +// and any cycle they participate in is uncollectable. These roots are +// traced from TraceNativeBlackRoots. +// +// 3. all other roots held by C++ objects that participate in cycle +// collection, held by us (see TraceNativeGrayRoots). Roots from this +// category are considered grey in the cycle collector; whether or not +// they are collected depends on the objects that hold them. +// +// Note that if a root is in multiple categories the fact that it is in +// category 1 or 2 that takes precedence, so it will be considered black. +// +// During garbage collection we switch to an additional mark color (gray) +// when tracing inside TraceNativeGrayRoots. This allows us to walk those +// roots later on and add all objects reachable only from them to the +// cycle collector. +// +// Phases: +// +// 1. marking of the roots in category 1 by having the JS GC do its marking +// 2. marking of the roots in category 2 by having the JS GC call us back +// (via JS_SetExtraGCRootsTracer) and running TraceNativeBlackRoots +// 3. marking of the roots in category 3 by TraceNativeGrayRoots using an +// additional color (gray). +// 4. end of GC, GC can sweep its heap +// +// At some later point, when the cycle collector runs: +// +// 5. walk gray objects and add them to the cycle collector, cycle collect +// +// JS objects that are part of cycles the cycle collector breaks will be +// collected by the next JS GC. +// +// If WantAllTraces() is false the cycle collector will not traverse roots +// from category 1 or any JS objects held by them. Any JS objects they hold +// will already be marked by the JS GC and will thus be colored black +// themselves. Any C++ objects they hold will have a missing (untraversed) +// edge from the JS object to the C++ object and so it will be marked black +// too. This decreases the number of objects that the cycle collector has to +// deal with. +// To improve debugging, if WantAllTraces() is true all JS objects are +// traversed. + +#include "mozilla/CycleCollectedJSRuntime.h" +#include +#include "mozilla/ArrayUtils.h" +#include "mozilla/AutoRestore.h" +#include "mozilla/CycleCollectedJSContext.h" +#include "mozilla/Move.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/Sprintf.h" +#include "mozilla/Telemetry.h" +#include "mozilla/TimelineConsumers.h" +#include "mozilla/TimelineMarker.h" +#include "mozilla/Unused.h" +#include "mozilla/DebuggerOnGCRunnable.h" +#include "mozilla/dom/DOMJSClass.h" +#include "mozilla/dom/ProfileTimelineMarkerBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/PromiseBinding.h" +#include "mozilla/dom/PromiseDebugging.h" +#include "mozilla/dom/ScriptSettings.h" +#include "jsprf.h" +#include "js/Debug.h" +#include "js/GCAPI.h" +#include "nsContentUtils.h" +#include "nsCycleCollectionNoteRootCallback.h" +#include "nsCycleCollectionParticipant.h" +#include "nsCycleCollector.h" +#include "nsDOMJSUtils.h" +#include "nsJSUtils.h" +#include "nsWrapperCache.h" +#include "nsStringBuffer.h" + +#ifdef MOZ_CRASHREPORTER +#include "nsExceptionHandler.h" +#endif + +#include "nsIException.h" +#include "nsIPlatformInfo.h" +#include "nsThread.h" +#include "nsThreadUtils.h" +#include "xpcpublic.h" + +using namespace mozilla; +using namespace mozilla::dom; + +namespace mozilla { + +struct DeferredFinalizeFunctionHolder +{ + DeferredFinalizeFunction run; + void* data; +}; + +class IncrementalFinalizeRunnable : public Runnable +{ + typedef AutoTArray DeferredFinalizeArray; + typedef CycleCollectedJSRuntime::DeferredFinalizerTable DeferredFinalizerTable; + + CycleCollectedJSRuntime* mRuntime; + DeferredFinalizeArray mDeferredFinalizeFunctions; + uint32_t mFinalizeFunctionToRun; + bool mReleasing; + + static const PRTime SliceMillis = 5; /* ms */ + +public: + IncrementalFinalizeRunnable(CycleCollectedJSRuntime* aRt, + DeferredFinalizerTable& aFinalizerTable); + virtual ~IncrementalFinalizeRunnable(); + + void ReleaseNow(bool aLimited); + + NS_DECL_NSIRUNNABLE +}; + +} // namespace mozilla + +struct NoteWeakMapChildrenTracer : public JS::CallbackTracer +{ + NoteWeakMapChildrenTracer(JSContext* aCx, + nsCycleCollectionNoteRootCallback& aCb) + : JS::CallbackTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr), + mKey(nullptr), mKeyDelegate(nullptr) + { + } + void onChild(const JS::GCCellPtr& aThing) override; + nsCycleCollectionNoteRootCallback& mCb; + bool mTracedAny; + JSObject* mMap; + JS::GCCellPtr mKey; + JSObject* mKeyDelegate; +}; + +void +NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing) +{ + if (aThing.is()) { + return; + } + + if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) { + return; + } + + if (AddToCCKind(aThing.kind())) { + mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing); + mTracedAny = true; + } else { + JS::TraceChildren(this, aThing); + } +} + +struct NoteWeakMapsTracer : public js::WeakMapTracer +{ + NoteWeakMapsTracer(JSContext* aCx, nsCycleCollectionNoteRootCallback& aCccb) + : js::WeakMapTracer(aCx), mCb(aCccb), mChildTracer(aCx, aCccb) + { + } + void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override; + nsCycleCollectionNoteRootCallback& mCb; + NoteWeakMapChildrenTracer mChildTracer; +}; + +void +NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey, + JS::GCCellPtr aValue) +{ + // If nothing that could be held alive by this entry is marked gray, return. + if ((!aKey || !JS::GCThingIsMarkedGray(aKey)) && + MOZ_LIKELY(!mCb.WantAllTraces())) { + if (!aValue || !JS::GCThingIsMarkedGray(aValue) || aValue.is()) { + return; + } + } + + // The cycle collector can only properly reason about weak maps if it can + // reason about the liveness of their keys, which in turn requires that + // the key can be represented in the cycle collector graph. All existing + // uses of weak maps use either objects or scripts as keys, which are okay. + MOZ_ASSERT(AddToCCKind(aKey.kind())); + + // As an emergency fallback for non-debug builds, if the key is not + // representable in the cycle collector graph, we treat it as marked. This + // can cause leaks, but is preferable to ignoring the binding, which could + // cause the cycle collector to free live objects. + if (!AddToCCKind(aKey.kind())) { + aKey = nullptr; + } + + JSObject* kdelegate = nullptr; + if (aKey.is()) { + kdelegate = js::GetWeakmapKeyDelegate(&aKey.as()); + } + + if (AddToCCKind(aValue.kind())) { + mCb.NoteWeakMapping(aMap, aKey, kdelegate, aValue); + } else { + mChildTracer.mTracedAny = false; + mChildTracer.mMap = aMap; + mChildTracer.mKey = aKey; + mChildTracer.mKeyDelegate = kdelegate; + + if (!aValue.is()) { + JS::TraceChildren(&mChildTracer, aValue); + } + + // The delegate could hold alive the key, so report something to the CC + // if we haven't already. + if (!mChildTracer.mTracedAny && + aKey && JS::GCThingIsMarkedGray(aKey) && kdelegate) { + mCb.NoteWeakMapping(aMap, aKey, kdelegate, nullptr); + } + } +} + +// Report whether the key or value of a weak mapping entry are gray but need to +// be marked black. +static void +ShouldWeakMappingEntryBeBlack(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue, + bool* aKeyShouldBeBlack, bool* aValueShouldBeBlack) +{ + *aKeyShouldBeBlack = false; + *aValueShouldBeBlack = false; + + // If nothing that could be held alive by this entry is marked gray, return. + bool keyMightNeedMarking = aKey && JS::GCThingIsMarkedGray(aKey); + bool valueMightNeedMarking = aValue && JS::GCThingIsMarkedGray(aValue) && + aValue.kind() != JS::TraceKind::String; + if (!keyMightNeedMarking && !valueMightNeedMarking) { + return; + } + + if (!AddToCCKind(aKey.kind())) { + aKey = nullptr; + } + + if (keyMightNeedMarking && aKey.is()) { + JSObject* kdelegate = js::GetWeakmapKeyDelegate(&aKey.as()); + if (kdelegate && !JS::ObjectIsMarkedGray(kdelegate) && + (!aMap || !JS::ObjectIsMarkedGray(aMap))) + { + *aKeyShouldBeBlack = true; + } + } + + if (aValue && JS::GCThingIsMarkedGray(aValue) && + (!aKey || !JS::GCThingIsMarkedGray(aKey)) && + (!aMap || !JS::ObjectIsMarkedGray(aMap)) && + aValue.kind() != JS::TraceKind::Shape) { + *aValueShouldBeBlack = true; + } +} + +struct FixWeakMappingGrayBitsTracer : public js::WeakMapTracer +{ + explicit FixWeakMappingGrayBitsTracer(JSContext* aCx) + : js::WeakMapTracer(aCx) + { + } + + void + FixAll() + { + do { + mAnyMarked = false; + js::TraceWeakMaps(this); + } while (mAnyMarked); + } + + void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override + { + bool keyShouldBeBlack; + bool valueShouldBeBlack; + ShouldWeakMappingEntryBeBlack(aMap, aKey, aValue, + &keyShouldBeBlack, &valueShouldBeBlack); + if (keyShouldBeBlack && JS::UnmarkGrayGCThingRecursively(aKey)) { + mAnyMarked = true; + } + + if (valueShouldBeBlack && JS::UnmarkGrayGCThingRecursively(aValue)) { + mAnyMarked = true; + } + } + + MOZ_INIT_OUTSIDE_CTOR bool mAnyMarked; +}; + +#ifdef DEBUG +// Check whether weak maps are marked correctly according to the logic above. +struct CheckWeakMappingGrayBitsTracer : public js::WeakMapTracer +{ + explicit CheckWeakMappingGrayBitsTracer(JSContext* aCx) + : js::WeakMapTracer(aCx), mFailed(false) + { + } + + static bool + Check(JSContext* aCx) + { + CheckWeakMappingGrayBitsTracer tracer(aCx); + js::TraceWeakMaps(&tracer); + return !tracer.mFailed; + } + + void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override + { + bool keyShouldBeBlack; + bool valueShouldBeBlack; + ShouldWeakMappingEntryBeBlack(aMap, aKey, aValue, + &keyShouldBeBlack, &valueShouldBeBlack); + + if (keyShouldBeBlack) { + fprintf(stderr, "Weak mapping key %p of map %p should be black\n", + aKey.asCell(), aMap); + mFailed = true; + } + + if (valueShouldBeBlack) { + fprintf(stderr, "Weak mapping value %p of map %p should be black\n", + aValue.asCell(), aMap); + mFailed = true; + } + } + + bool mFailed; +}; +#endif // DEBUG + +static void +CheckParticipatesInCycleCollection(JS::GCCellPtr aThing, const char* aName, + void* aClosure) +{ + bool* cycleCollectionEnabled = static_cast(aClosure); + + if (*cycleCollectionEnabled) { + return; + } + + if (AddToCCKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) { + *cycleCollectionEnabled = true; + } +} + +NS_IMETHODIMP +JSGCThingParticipant::TraverseNative(void* aPtr, + nsCycleCollectionTraversalCallback& aCb) +{ + auto runtime = reinterpret_cast( + reinterpret_cast(this) - offsetof(CycleCollectedJSRuntime, + mGCThingCycleCollectorGlobal)); + + JS::GCCellPtr cellPtr(aPtr, JS::GCThingTraceKind(aPtr)); + runtime->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_FULL, cellPtr, aCb); + return NS_OK; +} + +// NB: This is only used to initialize the participant in +// CycleCollectedJSRuntime. It should never be used directly. +static JSGCThingParticipant sGCThingCycleCollectorGlobal; + +NS_IMETHODIMP +JSZoneParticipant::TraverseNative(void* aPtr, + nsCycleCollectionTraversalCallback& aCb) +{ + auto runtime = reinterpret_cast( + reinterpret_cast(this) - offsetof(CycleCollectedJSRuntime, + mJSZoneCycleCollectorGlobal)); + + MOZ_ASSERT(!aCb.WantAllTraces()); + JS::Zone* zone = static_cast(aPtr); + + runtime->TraverseZone(zone, aCb); + return NS_OK; +} + +struct TraversalTracer : public JS::CallbackTracer +{ + TraversalTracer(JSContext* aCx, nsCycleCollectionTraversalCallback& aCb) + : JS::CallbackTracer(aCx, DoNotTraceWeakMaps), mCb(aCb) + { + } + void onChild(const JS::GCCellPtr& aThing) override; + nsCycleCollectionTraversalCallback& mCb; +}; + +void +TraversalTracer::onChild(const JS::GCCellPtr& aThing) +{ + // Don't traverse non-gray objects, unless we want all traces. + if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) { + return; + } + + /* + * This function needs to be careful to avoid stack overflow. Normally, when + * AddToCCKind is true, the recursion terminates immediately as we just add + * |thing| to the CC graph. So overflow is only possible when there are long + * or cyclic chains of non-AddToCCKind GC things. Places where this can occur + * use special APIs to handle such chains iteratively. + */ + if (AddToCCKind(aThing.kind())) { + if (MOZ_UNLIKELY(mCb.WantDebugInfo())) { + char buffer[200]; + getTracingEdgeName(buffer, sizeof(buffer)); + mCb.NoteNextEdgeName(buffer); + } + mCb.NoteJSChild(aThing); + } else if (aThing.is()) { + // The maximum depth of traversal when tracing a Shape is unbounded, due to + // the parent pointers on the shape. + JS_TraceShapeCycleCollectorChildren(this, aThing); + } else if (aThing.is()) { + // The maximum depth of traversal when tracing an ObjectGroup is unbounded, + // due to information attached to the groups which can lead other groups to + // be traced. + JS_TraceObjectGroupCycleCollectorChildren(this, aThing); + } else if (!aThing.is()) { + JS::TraceChildren(this, aThing); + } +} + +static void +NoteJSChildGrayWrapperShim(void* aData, JS::GCCellPtr aThing) +{ + TraversalTracer* trc = static_cast(aData); + trc->onChild(aThing); +} + +/* + * The cycle collection participant for a Zone is intended to produce the same + * results as if all of the gray GCthings in a zone were merged into a single node, + * except for self-edges. This avoids the overhead of representing all of the GCthings in + * the zone in the cycle collector graph, which should be much faster if many of + * the GCthings in the zone are gray. + * + * Zone merging should not always be used, because it is a conservative + * approximation of the true cycle collector graph that can incorrectly identify some + * garbage objects as being live. For instance, consider two cycles that pass through a + * zone, where one is garbage and the other is live. If we merge the entire + * zone, the cycle collector will think that both are alive. + * + * We don't have to worry about losing track of a garbage cycle, because any such garbage + * cycle incorrectly identified as live must contain at least one C++ to JS edge, and + * XPConnect will always add the C++ object to the CC graph. (This is in contrast to pure + * C++ garbage cycles, which must always be properly identified, because we clear the + * purple buffer during every CC, which may contain the last reference to a garbage + * cycle.) + */ + +// NB: This is only used to initialize the participant in +// CycleCollectedJSRuntime. It should never be used directly. +static const JSZoneParticipant sJSZoneCycleCollectorGlobal; + +static +void JSObjectsTenuredCb(JSContext* aContext, void* aData) +{ + static_cast(aData)->JSObjectsTenured(); +} + +bool +mozilla::GetBuildId(JS::BuildIdCharVector* aBuildID) +{ + nsCOMPtr info = do_GetService("@mozilla.org/xre/app-info;1"); + if (!info) { + return false; + } + + nsCString buildID; + nsresult rv = info->GetPlatformBuildID(buildID); + NS_ENSURE_SUCCESS(rv, false); + + if (!aBuildID->resize(buildID.Length())) { + return false; + } + + for (size_t i = 0; i < buildID.Length(); i++) { + (*aBuildID)[i] = buildID[i]; + } + + return true; +} + +static void +MozCrashWarningReporter(JSContext*, JSErrorReport*) +{ + MOZ_CRASH("Why is someone touching JSAPI without an AutoJSAPI?"); +} + +CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSContext* aMainContext) + : mGCThingCycleCollectorGlobal(sGCThingCycleCollectorGlobal) + , mJSZoneCycleCollectorGlobal(sJSZoneCycleCollectorGlobal) + , mJSContext(aMainContext) + , mPrevGCSliceCallback(nullptr) + , mPrevGCNurseryCollectionCallback(nullptr) + , mJSHolders(256) + , mOutOfMemoryState(OOMState::OK) + , mLargeAllocationFailureState(OOMState::OK) +{ + if (!JS_AddExtraGCRootsTracer(mJSContext, TraceBlackJS, this)) { + MOZ_CRASH("JS_AddExtraGCRootsTracer failed"); + } + JS_SetGrayGCRootsTracer(mJSContext, TraceGrayJS, this); + JS_SetGCCallback(mJSContext, GCCallback, this); + mPrevGCSliceCallback = JS::SetGCSliceCallback(mJSContext, GCSliceCallback); + + if (NS_IsMainThread()) { + // We would like to support all threads here, but the way timeline consumers + // are set up currently, you can either add a marker for one specific + // docshell, or for every consumer globally. We would like to add a marker + // for every consumer observing anything on this thread, but that is not + // currently possible. For now, add global markers only when we are on the + // main thread, since the UI for this tracing data only displays data + // relevant to the main-thread. + mPrevGCNurseryCollectionCallback = JS::SetGCNurseryCollectionCallback( + mJSContext, GCNurseryCollectionCallback); + } + + JS_SetObjectsTenuredCallback(mJSContext, JSObjectsTenuredCb, this); + JS::SetOutOfMemoryCallback(mJSContext, OutOfMemoryCallback, this); + JS_SetExternalStringSizeofCallback(mJSContext, SizeofExternalStringCallback); + JS::SetBuildIdOp(mJSContext, GetBuildId); + JS::SetWarningReporter(mJSContext, MozCrashWarningReporter); +#ifdef MOZ_CRASHREPORTER + js::AutoEnterOOMUnsafeRegion::setAnnotateOOMAllocationSizeCallback( + CrashReporter::AnnotateOOMAllocationSize); +#endif + + static js::DOMCallbacks DOMcallbacks = { + InstanceClassHasProtoAtDepth + }; + SetDOMCallbacks(mJSContext, &DOMcallbacks); + js::SetScriptEnvironmentPreparer(mJSContext, &mEnvironmentPreparer); + + JS::dbg::SetDebuggerMallocSizeOf(mJSContext, moz_malloc_size_of); +} + +void +CycleCollectedJSRuntime::Shutdown() +{ +} + +CycleCollectedJSRuntime::~CycleCollectedJSRuntime() +{ + // If the allocation failed, here we are. + if (!mJSContext) { + return; + } + + MOZ_ASSERT(!mDeferredFinalizerTable.Count()); + + mJSContext = nullptr; +} + +size_t +CycleCollectedJSRuntime::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + size_t n = 0; + + // We're deliberately not measuring anything hanging off the entries in + // mJSHolders. + n += mJSHolders.ShallowSizeOfExcludingThis(aMallocSizeOf); + + return n; +} + +void +CycleCollectedJSRuntime::UnmarkSkippableJSHolders() +{ + for (auto iter = mJSHolders.Iter(); !iter.Done(); iter.Next()) { + void* holder = iter.Key(); + nsScriptObjectTracer*& tracer = iter.Data(); + tracer->CanSkip(holder, true); + } +} + +void +CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing, + nsCycleCollectionTraversalCallback& aCb) const +{ + if (!aCb.WantDebugInfo()) { + aCb.DescribeGCedNode(aIsMarked, "JS Object"); + return; + } + + char name[72]; + uint64_t compartmentAddress = 0; + if (aThing.is()) { + JSObject* obj = &aThing.as(); + compartmentAddress = (uint64_t)js::GetObjectCompartment(obj); + const js::Class* clasp = js::GetObjectClass(obj); + + // Give the subclass a chance to do something + if (DescribeCustomObjects(obj, clasp, name)) { + // Nothing else to do! + } else if (js::IsFunctionObject(obj)) { + JSFunction* fun = JS_GetObjectFunction(obj); + JSString* str = JS_GetFunctionDisplayId(fun); + if (str) { + JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(str); + nsAutoString chars; + AssignJSFlatString(chars, flat); + NS_ConvertUTF16toUTF8 fname(chars); + SprintfLiteral(name, "JS Object (Function - %s)", fname.get()); + } else { + SprintfLiteral(name, "JS Object (Function)"); + } + } else { + SprintfLiteral(name, "JS Object (%s)", clasp->name); + } + } else { + SprintfLiteral(name, "JS %s", JS::GCTraceKindToAscii(aThing.kind())); + } + + // Disable printing global for objects while we figure out ObjShrink fallout. + aCb.DescribeGCedNode(aIsMarked, name, compartmentAddress); +} + +void +CycleCollectedJSRuntime::NoteGCThingJSChildren(JS::GCCellPtr aThing, + nsCycleCollectionTraversalCallback& aCb) const +{ + MOZ_ASSERT(mJSContext); + TraversalTracer trc(mJSContext, aCb); + JS::TraceChildren(&trc, aThing); +} + +void +CycleCollectedJSRuntime::NoteGCThingXPCOMChildren(const js::Class* aClasp, + JSObject* aObj, + nsCycleCollectionTraversalCallback& aCb) const +{ + MOZ_ASSERT(aClasp); + MOZ_ASSERT(aClasp == js::GetObjectClass(aObj)); + + if (NoteCustomGCThingXPCOMChildren(aClasp, aObj, aCb)) { + // Nothing else to do! + return; + } + // XXX This test does seem fragile, we should probably whitelist classes + // that do hold a strong reference, but that might not be possible. + else if (aClasp->flags & JSCLASS_HAS_PRIVATE && + aClasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "js::GetObjectPrivate(obj)"); + aCb.NoteXPCOMChild(static_cast(js::GetObjectPrivate(aObj))); + } else { + const DOMJSClass* domClass = GetDOMClass(aObj); + if (domClass) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "UnwrapDOMObject(obj)"); + // It's possible that our object is an unforgeable holder object, in + // which case it doesn't actually have a C++ DOM object associated with + // it. Use UnwrapPossiblyNotInitializedDOMObject, which produces null in + // that case, since NoteXPCOMChild/NoteNativeChild are null-safe. + if (domClass->mDOMObjectIsISupports) { + aCb.NoteXPCOMChild(UnwrapPossiblyNotInitializedDOMObject(aObj)); + } else if (domClass->mParticipant) { + aCb.NoteNativeChild(UnwrapPossiblyNotInitializedDOMObject(aObj), + domClass->mParticipant); + } + } + } +} + +void +CycleCollectedJSRuntime::TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThing, + nsCycleCollectionTraversalCallback& aCb) +{ + bool isMarkedGray = JS::GCThingIsMarkedGray(aThing); + + if (aTs == TRAVERSE_FULL) { + DescribeGCThing(!isMarkedGray, aThing, aCb); + } + + // If this object is alive, then all of its children are alive. For JS objects, + // the black-gray invariant ensures the children are also marked black. For C++ + // objects, the ref count from this object will keep them alive. Thus we don't + // need to trace our children, unless we are debugging using WantAllTraces. + if (!isMarkedGray && !aCb.WantAllTraces()) { + return; + } + + if (aTs == TRAVERSE_FULL) { + NoteGCThingJSChildren(aThing, aCb); + } + + if (aThing.is()) { + JSObject* obj = &aThing.as(); + NoteGCThingXPCOMChildren(js::GetObjectClass(obj), obj, aCb); + } +} + +struct TraverseObjectShimClosure +{ + nsCycleCollectionTraversalCallback& cb; + CycleCollectedJSRuntime* self; +}; + +void +CycleCollectedJSRuntime::TraverseZone(JS::Zone* aZone, + nsCycleCollectionTraversalCallback& aCb) +{ + MOZ_ASSERT(mJSContext); + + /* + * We treat the zone as being gray. We handle non-gray GCthings in the + * zone by not reporting their children to the CC. The black-gray invariant + * ensures that any JS children will also be non-gray, and thus don't need to be + * added to the graph. For C++ children, not representing the edge from the + * non-gray JS GCthings to the C++ object will keep the child alive. + * + * We don't allow zone merging in a WantAllTraces CC, because then these + * assumptions don't hold. + */ + aCb.DescribeGCedNode(false, "JS Zone"); + + /* + * Every JS child of everything in the zone is either in the zone + * or is a cross-compartment wrapper. In the former case, we don't need to + * represent these edges in the CC graph because JS objects are not ref counted. + * In the latter case, the JS engine keeps a map of these wrappers, which we + * iterate over. Edges between compartments in the same zone will add + * unnecessary loop edges to the graph (bug 842137). + */ + TraversalTracer trc(mJSContext, aCb); + js::VisitGrayWrapperTargets(aZone, NoteJSChildGrayWrapperShim, &trc); + + /* + * To find C++ children of things in the zone, we scan every JS Object in + * the zone. Only JS Objects can have C++ children. + */ + TraverseObjectShimClosure closure = { aCb, this }; + js::IterateGrayObjects(aZone, TraverseObjectShim, &closure); +} + +/* static */ void +CycleCollectedJSRuntime::TraverseObjectShim(void* aData, JS::GCCellPtr aThing) +{ + TraverseObjectShimClosure* closure = + static_cast(aData); + + MOZ_ASSERT(aThing.is()); + closure->self->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_CPP, + aThing, closure->cb); +} + +void +CycleCollectedJSRuntime::TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb) +{ + // NB: This is here just to preserve the existing XPConnect order. I doubt it + // would hurt to do this after the JS holders. + TraverseAdditionalNativeRoots(aCb); + + for (auto iter = mJSHolders.Iter(); !iter.Done(); iter.Next()) { + void* holder = iter.Key(); + nsScriptObjectTracer*& tracer = iter.Data(); + + bool noteRoot = false; + if (MOZ_UNLIKELY(aCb.WantAllTraces())) { + noteRoot = true; + } else { + tracer->Trace(holder, + TraceCallbackFunc(CheckParticipatesInCycleCollection), + ¬eRoot); + } + + if (noteRoot) { + aCb.NoteNativeRoot(holder, tracer); + } + } +} + +/* static */ void +CycleCollectedJSRuntime::TraceBlackJS(JSTracer* aTracer, void* aData) +{ + CycleCollectedJSRuntime* self = static_cast(aData); + + self->TraceNativeBlackRoots(aTracer); +} + +/* static */ void +CycleCollectedJSRuntime::TraceGrayJS(JSTracer* aTracer, void* aData) +{ + CycleCollectedJSRuntime* self = static_cast(aData); + + // Mark these roots as gray so the CC can walk them later. + self->TraceNativeGrayRoots(aTracer); +} + +/* static */ void +CycleCollectedJSRuntime::GCCallback(JSContext* aContext, + JSGCStatus aStatus, + void* aData) +{ + CycleCollectedJSRuntime* self = static_cast(aData); + + MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext); + MOZ_ASSERT(CycleCollectedJSContext::Get()->Runtime() == self); + + self->OnGC(aStatus); +} + +/* static */ void +CycleCollectedJSRuntime::GCSliceCallback(JSContext* aContext, + JS::GCProgress aProgress, + const JS::GCDescription& aDesc) +{ + CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get(); + MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext); + + if (aProgress == JS::GC_CYCLE_END) { + JS::gcreason::Reason reason = aDesc.reason_; + Unused << + NS_WARN_IF(NS_FAILED(DebuggerOnGCRunnable::Enqueue(aContext, aDesc)) && + reason != JS::gcreason::SHUTDOWN_CC && + reason != JS::gcreason::DESTROY_RUNTIME && + reason != JS::gcreason::XPCONNECT_SHUTDOWN); + } + + if (self->mPrevGCSliceCallback) { + self->mPrevGCSliceCallback(aContext, aProgress, aDesc); + } +} + +class MinorGCMarker : public TimelineMarker +{ +private: + JS::gcreason::Reason mReason; + +public: + MinorGCMarker(MarkerTracingType aTracingType, + JS::gcreason::Reason aReason) + : TimelineMarker("MinorGC", + aTracingType, + MarkerStackRequest::NO_STACK) + , mReason(aReason) + { + MOZ_ASSERT(aTracingType == MarkerTracingType::START || + aTracingType == MarkerTracingType::END); + } + + MinorGCMarker(JS::GCNurseryProgress aProgress, + JS::gcreason::Reason aReason) + : TimelineMarker("MinorGC", + aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START + ? MarkerTracingType::START + : MarkerTracingType::END, + MarkerStackRequest::NO_STACK) + , mReason(aReason) + { } + + virtual void + AddDetails(JSContext* aCx, + dom::ProfileTimelineMarker& aMarker) override + { + TimelineMarker::AddDetails(aCx, aMarker); + + if (GetTracingType() == MarkerTracingType::START) { + auto reason = JS::gcreason::ExplainReason(mReason); + aMarker.mCauseName.Construct(NS_ConvertUTF8toUTF16(reason)); + } + } + + virtual UniquePtr + Clone() override + { + auto clone = MakeUnique(GetTracingType(), mReason); + clone->SetCustomTime(GetTime()); + return UniquePtr(Move(clone)); + } +}; + +/* static */ void +CycleCollectedJSRuntime::GCNurseryCollectionCallback(JSContext* aContext, + JS::GCNurseryProgress aProgress, + JS::gcreason::Reason aReason) +{ + CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get(); + MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext); + MOZ_ASSERT(NS_IsMainThread()); + + RefPtr timelines = TimelineConsumers::Get(); + if (timelines && !timelines->IsEmpty()) { + UniquePtr abstractMarker( + MakeUnique(aProgress, aReason)); + timelines->AddMarkerForAllObservedDocShells(abstractMarker); + } + + if (self->mPrevGCNurseryCollectionCallback) { + self->mPrevGCNurseryCollectionCallback(aContext, aProgress, aReason); + } +} + + +/* static */ void +CycleCollectedJSRuntime::OutOfMemoryCallback(JSContext* aContext, + void* aData) +{ + CycleCollectedJSRuntime* self = static_cast(aData); + + MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext); + MOZ_ASSERT(CycleCollectedJSContext::Get()->Runtime() == self); + + self->OnOutOfMemory(); +} + +/* static */ size_t +CycleCollectedJSRuntime::SizeofExternalStringCallback(JSString* aStr, + MallocSizeOf aMallocSizeOf) +{ + // We promised the JS engine we would not GC. Enforce that: + JS::AutoCheckCannotGC autoCannotGC; + + if (!XPCStringConvert::IsDOMString(aStr)) { + // Might be a literal or something we don't understand. Just claim 0. + return 0; + } + + const char16_t* chars = JS_GetTwoByteExternalStringChars(aStr); + const nsStringBuffer* buf = nsStringBuffer::FromData((void*)chars); + // We want sizeof including this, because the entire string buffer is owned by + // the external string. But only report here if we're unshared; if we're + // shared then we don't know who really owns this data. + return buf->SizeOfIncludingThisIfUnshared(aMallocSizeOf); +} + +struct JsGcTracer : public TraceCallbacks +{ + virtual void Trace(JS::Heap* aPtr, const char* aName, + void* aClosure) const override + { + JS::TraceEdge(static_cast(aClosure), aPtr, aName); + } + virtual void Trace(JS::Heap* aPtr, const char* aName, + void* aClosure) const override + { + JS::TraceEdge(static_cast(aClosure), aPtr, aName); + } + virtual void Trace(JS::Heap* aPtr, const char* aName, + void* aClosure) const override + { + JS::TraceEdge(static_cast(aClosure), aPtr, aName); + } + virtual void Trace(JSObject** aPtr, const char* aName, + void* aClosure) const override + { + js::UnsafeTraceManuallyBarrieredEdge(static_cast(aClosure), aPtr, aName); + } + virtual void Trace(JS::TenuredHeap* aPtr, const char* aName, + void* aClosure) const override + { + JS::TraceEdge(static_cast(aClosure), aPtr, aName); + } + virtual void Trace(JS::Heap* aPtr, const char* aName, + void* aClosure) const override + { + JS::TraceEdge(static_cast(aClosure), aPtr, aName); + } + virtual void Trace(JS::Heap* aPtr, const char* aName, + void* aClosure) const override + { + JS::TraceEdge(static_cast(aClosure), aPtr, aName); + } + virtual void Trace(JS::Heap* aPtr, const char* aName, + void* aClosure) const override + { + JS::TraceEdge(static_cast(aClosure), aPtr, aName); + } +}; + +void +mozilla::TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer) +{ + nsXPCOMCycleCollectionParticipant* participant = nullptr; + CallQueryInterface(aHolder, &participant); + participant->Trace(aHolder, JsGcTracer(), aTracer); +} + +void +CycleCollectedJSRuntime::TraceNativeGrayRoots(JSTracer* aTracer) +{ + MOZ_ASSERT(mJSContext); + + // NB: This is here just to preserve the existing XPConnect order. I doubt it + // would hurt to do this after the JS holders. + TraceAdditionalNativeGrayRoots(aTracer); + + for (auto iter = mJSHolders.Iter(); !iter.Done(); iter.Next()) { + void* holder = iter.Key(); + nsScriptObjectTracer*& tracer = iter.Data(); + tracer->Trace(holder, JsGcTracer(), aTracer); + } +} + +void +CycleCollectedJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer) +{ + MOZ_ASSERT(mJSContext); + mJSHolders.Put(aHolder, aTracer); +} + +struct ClearJSHolder : public TraceCallbacks +{ + virtual void Trace(JS::Heap* aPtr, const char*, void*) const override + { + aPtr->setUndefined(); + } + + virtual void Trace(JS::Heap* aPtr, const char*, void*) const override + { + *aPtr = JSID_VOID; + } + + virtual void Trace(JS::Heap* aPtr, const char*, void*) const override + { + *aPtr = nullptr; + } + + virtual void Trace(JSObject** aPtr, const char* aName, + void* aClosure) const override + { + *aPtr = nullptr; + } + + virtual void Trace(JS::TenuredHeap* aPtr, const char*, void*) const override + { + *aPtr = nullptr; + } + + virtual void Trace(JS::Heap* aPtr, const char*, void*) const override + { + *aPtr = nullptr; + } + + virtual void Trace(JS::Heap* aPtr, const char*, void*) const override + { + *aPtr = nullptr; + } + + virtual void Trace(JS::Heap* aPtr, const char*, void*) const override + { + *aPtr = nullptr; + } +}; + +void +CycleCollectedJSRuntime::RemoveJSHolder(void* aHolder) +{ + MOZ_ASSERT(mJSContext); + + nsScriptObjectTracer* tracer = mJSHolders.Get(aHolder); + if (!tracer) { + return; + } + tracer->Trace(aHolder, ClearJSHolder(), nullptr); + mJSHolders.Remove(aHolder); +} + +#ifdef DEBUG +bool +CycleCollectedJSRuntime::IsJSHolder(void* aHolder) +{ + MOZ_ASSERT(mJSContext); + return mJSHolders.Get(aHolder, nullptr); +} + +static void +AssertNoGcThing(JS::GCCellPtr aGCThing, const char* aName, void* aClosure) +{ + MOZ_ASSERT(!aGCThing); +} + +void +CycleCollectedJSRuntime::AssertNoObjectsToTrace(void* aPossibleJSHolder) +{ + MOZ_ASSERT(mJSContext); + + nsScriptObjectTracer* tracer = mJSHolders.Get(aPossibleJSHolder); + if (tracer) { + tracer->Trace(aPossibleJSHolder, TraceCallbackFunc(AssertNoGcThing), nullptr); + } +} +#endif + +nsCycleCollectionParticipant* +CycleCollectedJSRuntime::GCThingParticipant() +{ + MOZ_ASSERT(mJSContext); + return &mGCThingCycleCollectorGlobal; +} + +nsCycleCollectionParticipant* +CycleCollectedJSRuntime::ZoneParticipant() +{ + MOZ_ASSERT(mJSContext); + return &mJSZoneCycleCollectorGlobal; +} + +nsresult +CycleCollectedJSRuntime::TraverseRoots(nsCycleCollectionNoteRootCallback& aCb) +{ + MOZ_ASSERT(mJSContext); + + TraverseNativeRoots(aCb); + + NoteWeakMapsTracer trc(mJSContext, aCb); + js::TraceWeakMaps(&trc); + + return NS_OK; +} + +bool +CycleCollectedJSRuntime::UsefulToMergeZones() const +{ + return false; +} + +void +CycleCollectedJSRuntime::FixWeakMappingGrayBits() const +{ + MOZ_ASSERT(mJSContext); + MOZ_ASSERT(!JS::IsIncrementalGCInProgress(mJSContext), + "Don't call FixWeakMappingGrayBits during a GC."); + FixWeakMappingGrayBitsTracer fixer(mJSContext); + fixer.FixAll(); +} + +void +CycleCollectedJSRuntime::CheckGrayBits() const +{ + MOZ_ASSERT(mJSContext); + MOZ_ASSERT(!JS::IsIncrementalGCInProgress(mJSContext), + "Don't call CheckGrayBits during a GC."); + +#ifndef ANDROID + // Bug 1346874 - The gray state check is expensive. Android tests are already + // slow enough that this check can easily push them over the threshold to a + // timeout. + + MOZ_ASSERT(js::CheckGrayMarkingState(mJSContext)); + MOZ_ASSERT(CheckWeakMappingGrayBitsTracer::Check(mJSContext)); +#endif +} + +bool +CycleCollectedJSRuntime::AreGCGrayBitsValid() const +{ + MOZ_ASSERT(mJSContext); + return js::AreGCGrayBitsValid(mJSContext); +} + +void +CycleCollectedJSRuntime::GarbageCollect(uint32_t aReason) const +{ + MOZ_ASSERT(mJSContext); + + MOZ_ASSERT(aReason < JS::gcreason::NUM_REASONS); + JS::gcreason::Reason gcreason = static_cast(aReason); + + JS::PrepareForFullGC(mJSContext); + JS::GCForReason(mJSContext, GC_NORMAL, gcreason); +} + +void +CycleCollectedJSRuntime::JSObjectsTenured() +{ + MOZ_ASSERT(mJSContext); + + for (auto iter = mNurseryObjects.Iter(); !iter.Done(); iter.Next()) { + nsWrapperCache* cache = iter.Get(); + JSObject* wrapper = cache->GetWrapperPreserveColor(); + MOZ_DIAGNOSTIC_ASSERT(wrapper); + if (!JS::ObjectIsTenured(wrapper)) { + MOZ_ASSERT(!cache->PreservingWrapper()); + const JSClass* jsClass = js::GetObjectJSClass(wrapper); + jsClass->doFinalize(nullptr, wrapper); + } + } + +#ifdef DEBUG +for (auto iter = mPreservedNurseryObjects.Iter(); !iter.Done(); iter.Next()) { + MOZ_ASSERT(JS::ObjectIsTenured(iter.Get().get())); +} +#endif + + mNurseryObjects.Clear(); + mPreservedNurseryObjects.Clear(); +} + +void +CycleCollectedJSRuntime::NurseryWrapperAdded(nsWrapperCache* aCache) +{ + MOZ_ASSERT(mJSContext); + MOZ_ASSERT(aCache); + MOZ_ASSERT(aCache->GetWrapperPreserveColor()); + MOZ_ASSERT(!JS::ObjectIsTenured(aCache->GetWrapperPreserveColor())); + mNurseryObjects.InfallibleAppend(aCache); +} + +void +CycleCollectedJSRuntime::NurseryWrapperPreserved(JSObject* aWrapper) +{ + MOZ_ASSERT(mJSContext); + + mPreservedNurseryObjects.InfallibleAppend( + JS::PersistentRooted(mJSContext, aWrapper)); +} + +void +CycleCollectedJSRuntime::DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, + DeferredFinalizeFunction aFunc, + void* aThing) +{ + MOZ_ASSERT(mJSContext); + + void* thingArray = nullptr; + bool hadThingArray = mDeferredFinalizerTable.Get(aFunc, &thingArray); + + thingArray = aAppendFunc(thingArray, aThing); + if (!hadThingArray) { + mDeferredFinalizerTable.Put(aFunc, thingArray); + } +} + +void +CycleCollectedJSRuntime::DeferredFinalize(nsISupports* aSupports) +{ + MOZ_ASSERT(mJSContext); + + typedef DeferredFinalizerImpl Impl; + DeferredFinalize(Impl::AppendDeferredFinalizePointer, Impl::DeferredFinalize, + aSupports); +} + +void +CycleCollectedJSRuntime::DumpJSHeap(FILE* aFile) +{ + js::DumpHeap(MainContext(), aFile, js::CollectNurseryBeforeDump); +} + +IncrementalFinalizeRunnable::IncrementalFinalizeRunnable(CycleCollectedJSRuntime* aRt, + DeferredFinalizerTable& aFinalizers) + : Runnable("IncrementalFinalizeRunnable") + , mRuntime(aRt) + , mFinalizeFunctionToRun(0) + , mReleasing(false) +{ + for (auto iter = aFinalizers.Iter(); !iter.Done(); iter.Next()) { + DeferredFinalizeFunction& function = iter.Key(); + void*& data = iter.Data(); + + DeferredFinalizeFunctionHolder* holder = + mDeferredFinalizeFunctions.AppendElement(); + holder->run = function; + holder->data = data; + + iter.Remove(); + } +} + +IncrementalFinalizeRunnable::~IncrementalFinalizeRunnable() +{ + MOZ_ASSERT(this != mRuntime->mFinalizeRunnable); +} + +void +IncrementalFinalizeRunnable::ReleaseNow(bool aLimited) +{ + if (mReleasing) { + NS_WARNING("Re-entering ReleaseNow"); + return; + } + { + mozilla::AutoRestore ar(mReleasing); + mReleasing = true; + MOZ_ASSERT(mDeferredFinalizeFunctions.Length() != 0, + "We should have at least ReleaseSliceNow to run"); + MOZ_ASSERT(mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length(), + "No more finalizers to run?"); + + TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis); + TimeStamp started = TimeStamp::Now(); + bool timeout = false; + do { + const DeferredFinalizeFunctionHolder& function = + mDeferredFinalizeFunctions[mFinalizeFunctionToRun]; + if (aLimited) { + bool done = false; + while (!timeout && !done) { + /* + * We don't want to read the clock too often, so we try to + * release slices of 100 items. + */ + done = function.run(100, function.data); + timeout = TimeStamp::Now() - started >= sliceTime; + } + if (done) { + ++mFinalizeFunctionToRun; + } + if (timeout) { + break; + } + } else { + while (!function.run(UINT32_MAX, function.data)); + ++mFinalizeFunctionToRun; + } + } while (mFinalizeFunctionToRun < mDeferredFinalizeFunctions.Length()); + } + + if (mFinalizeFunctionToRun == mDeferredFinalizeFunctions.Length()) { + MOZ_ASSERT(mRuntime->mFinalizeRunnable == this); + mDeferredFinalizeFunctions.Clear(); + // NB: This may delete this! + mRuntime->mFinalizeRunnable = nullptr; + } +} + +NS_IMETHODIMP +IncrementalFinalizeRunnable::Run() +{ + if (mRuntime->mFinalizeRunnable != this) { + /* These items were already processed synchronously in JSGC_END. */ + MOZ_ASSERT(!mDeferredFinalizeFunctions.Length()); + return NS_OK; + } + + TimeStamp start = TimeStamp::Now(); + ReleaseNow(true); + + if (mDeferredFinalizeFunctions.Length()) { + nsresult rv = NS_DispatchToCurrentThread(this); + if (NS_FAILED(rv)) { + ReleaseNow(false); + } + } + + uint32_t duration = (uint32_t)((TimeStamp::Now() - start).ToMilliseconds()); + Telemetry::Accumulate(Telemetry::DEFERRED_FINALIZE_ASYNC, duration); + + return NS_OK; +} + +void +CycleCollectedJSRuntime::FinalizeDeferredThings(CycleCollectedJSContext::DeferredFinalizeType aType) +{ + MOZ_ASSERT(mJSContext); + + /* + * If the previous GC created a runnable to finalize objects + * incrementally, and if it hasn't finished yet, finish it now. We + * don't want these to build up. We also don't want to allow any + * existing incremental finalize runnables to run after a + * non-incremental GC, since they are often used to detect leaks. + */ + if (mFinalizeRunnable) { + mFinalizeRunnable->ReleaseNow(false); + if (mFinalizeRunnable) { + // If we re-entered ReleaseNow, we couldn't delete mFinalizeRunnable and + // we need to just continue processing it. + return; + } + } + + if (mDeferredFinalizerTable.Count() == 0) { + return; + } + + mFinalizeRunnable = new IncrementalFinalizeRunnable(this, + mDeferredFinalizerTable); + + // Everything should be gone now. + MOZ_ASSERT(mDeferredFinalizerTable.Count() == 0); + + if (aType == CycleCollectedJSContext::FinalizeIncrementally) { + NS_DispatchToCurrentThread(mFinalizeRunnable); + } else { + mFinalizeRunnable->ReleaseNow(false); + MOZ_ASSERT(!mFinalizeRunnable); + } +} + +void +CycleCollectedJSRuntime::AnnotateAndSetOutOfMemory(OOMState* aStatePtr, + OOMState aNewState) +{ + MOZ_ASSERT(mJSContext); + + *aStatePtr = aNewState; +#ifdef MOZ_CRASHREPORTER + CrashReporter::AnnotateCrashReport(aStatePtr == &mOutOfMemoryState + ? NS_LITERAL_CSTRING("JSOutOfMemory") + : NS_LITERAL_CSTRING("JSLargeAllocationFailure"), + aNewState == OOMState::Reporting + ? NS_LITERAL_CSTRING("Reporting") + : aNewState == OOMState::Reported + ? NS_LITERAL_CSTRING("Reported") + : NS_LITERAL_CSTRING("Recovered")); +#endif +} + +void +CycleCollectedJSRuntime::OnGC(JSGCStatus aStatus) +{ + MOZ_ASSERT(mJSContext); + + switch (aStatus) { + case JSGC_BEGIN: + nsCycleCollector_prepareForGarbageCollection(); + mZonesWaitingForGC.Clear(); + break; + case JSGC_END: { +#ifdef MOZ_CRASHREPORTER + if (mOutOfMemoryState == OOMState::Reported) { + AnnotateAndSetOutOfMemory(&mOutOfMemoryState, OOMState::Recovered); + } + if (mLargeAllocationFailureState == OOMState::Reported) { + AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Recovered); + } +#endif + + // Do any deferred finalization of native objects. + FinalizeDeferredThings(JS::WasIncrementalGC(mJSContext) + ? CycleCollectedJSContext::FinalizeIncrementally + : CycleCollectedJSContext::FinalizeNow); + break; + } + default: + MOZ_CRASH(); + } + + CustomGCCallback(aStatus); +} + +void +CycleCollectedJSRuntime::OnOutOfMemory() +{ + MOZ_ASSERT(mJSContext); + + AnnotateAndSetOutOfMemory(&mOutOfMemoryState, OOMState::Reporting); + CustomOutOfMemoryCallback(); + AnnotateAndSetOutOfMemory(&mOutOfMemoryState, OOMState::Reported); +} + +void +CycleCollectedJSRuntime::SetLargeAllocationFailure(OOMState aNewState) +{ + MOZ_ASSERT(mJSContext); + + AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, aNewState); +} + +void +CycleCollectedJSRuntime::PrepareWaitingZonesForGC() +{ + if (mZonesWaitingForGC.Count() == 0) { + JS::PrepareForFullGC(MainContext()); + } else { + for (auto iter = mZonesWaitingForGC.Iter(); !iter.Done(); iter.Next()) { + JS::PrepareZoneForGC(iter.Get()->GetKey()); + } + mZonesWaitingForGC.Clear(); + } +} + +void +CycleCollectedJSRuntime::EnvironmentPreparer::invoke(JS::HandleObject scope, + js::ScriptEnvironmentPreparer::Closure& closure) +{ + nsIGlobalObject* global = xpc::NativeGlobal(scope); + + // Not much we can do if we simply don't have a usable global here... + NS_ENSURE_TRUE_VOID(global && global->GetGlobalJSObject()); + + AutoEntryScript aes(global, "JS-engine-initiated execution"); + + MOZ_ASSERT(!JS_IsExceptionPending(aes.cx())); + + DebugOnly ok = closure(aes.cx()); + + MOZ_ASSERT_IF(ok, !JS_IsExceptionPending(aes.cx())); + + // The AutoEntryScript will check for JS_IsExceptionPending on the + // JSContext and report it as needed as it comes off the stack. +} + +/* static */ CycleCollectedJSRuntime* +CycleCollectedJSRuntime::Get() +{ + auto context = CycleCollectedJSContext::Get(); + if (context) { + return context->Runtime(); + } + return nullptr; +} diff --git a/xpcom/base/CycleCollectedJSRuntime.h b/xpcom/base/CycleCollectedJSRuntime.h new file mode 100644 index 000000000000..0e794c79e54b --- /dev/null +++ b/xpcom/base/CycleCollectedJSRuntime.h @@ -0,0 +1,342 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_CycleCollectedJSRuntime_h +#define mozilla_CycleCollectedJSRuntime_h + +#include + +#include "mozilla/CycleCollectedJSContext.h" +#include "mozilla/DeferredFinalize.h" +#include "mozilla/mozalloc.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/SegmentedVector.h" +#include "jsapi.h" +#include "jsfriendapi.h" + +#include "nsCycleCollectionParticipant.h" +#include "nsDataHashtable.h" +#include "nsHashKeys.h" +#include "nsTHashtable.h" + +class nsCycleCollectionNoteRootCallback; +class nsIException; +class nsIRunnable; +class nsWrapperCache; + +namespace js { +struct Class; +} // namespace js + +namespace mozilla { + +class JSGCThingParticipant: public nsCycleCollectionParticipant +{ +public: + constexpr JSGCThingParticipant() + : nsCycleCollectionParticipant(false) {} + + NS_IMETHOD_(void) Root(void*) override + { + MOZ_ASSERT(false, "Don't call Root on GC things"); + } + + NS_IMETHOD_(void) Unlink(void*) override + { + MOZ_ASSERT(false, "Don't call Unlink on GC things, as they may be dead"); + } + + NS_IMETHOD_(void) Unroot(void*) override + { + MOZ_ASSERT(false, "Don't call Unroot on GC things, as they may be dead"); + } + + NS_IMETHOD_(void) DeleteCycleCollectable(void* aPtr) override + { + MOZ_ASSERT(false, "Can't directly delete a cycle collectable GC thing"); + } + + NS_IMETHOD TraverseNative(void* aPtr, nsCycleCollectionTraversalCallback& aCb) + override; + + NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(JSGCThingParticipant) +}; + +class JSZoneParticipant : public nsCycleCollectionParticipant +{ +public: + constexpr JSZoneParticipant(): nsCycleCollectionParticipant(false) + { + } + + NS_IMETHOD_(void) Root(void*) override + { + MOZ_ASSERT(false, "Don't call Root on GC things"); + } + + NS_IMETHOD_(void) Unlink(void*) override + { + MOZ_ASSERT(false, "Don't call Unlink on GC things, as they may be dead"); + } + + NS_IMETHOD_(void) Unroot(void*) override + { + MOZ_ASSERT(false, "Don't call Unroot on GC things, as they may be dead"); + } + + NS_IMETHOD_(void) DeleteCycleCollectable(void*) override + { + MOZ_ASSERT(false, "Can't directly delete a cycle collectable GC thing"); + } + + NS_IMETHOD TraverseNative(void* aPtr, nsCycleCollectionTraversalCallback& aCb) + override; + + NS_DECL_CYCLE_COLLECTION_CLASS_NAME_METHOD(JSZoneParticipant) +}; + +class IncrementalFinalizeRunnable; + +class CycleCollectedJSRuntime +{ + friend class JSGCThingParticipant; + friend class JSZoneParticipant; + friend class IncrementalFinalizeRunnable; + friend class CycleCollectedJSContext; +protected: + CycleCollectedJSRuntime(JSContext* aMainContext); + virtual ~CycleCollectedJSRuntime(); + + virtual void Shutdown(); + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + void UnmarkSkippableJSHolders(); + + virtual void + TraverseAdditionalNativeRoots(nsCycleCollectionNoteRootCallback& aCb) {} + virtual void TraceAdditionalNativeGrayRoots(JSTracer* aTracer) {} + + virtual void CustomGCCallback(JSGCStatus aStatus) {} + virtual void CustomOutOfMemoryCallback() {} + +private: + void + DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing, + nsCycleCollectionTraversalCallback& aCb) const; + + virtual bool + DescribeCustomObjects(JSObject* aObject, const js::Class* aClasp, + char (&aName)[72]) const + { + return false; // We did nothing. + } + + void + NoteGCThingJSChildren(JS::GCCellPtr aThing, + nsCycleCollectionTraversalCallback& aCb) const; + + void + NoteGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj, + nsCycleCollectionTraversalCallback& aCb) const; + + virtual bool + NoteCustomGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj, + nsCycleCollectionTraversalCallback& aCb) const + { + return false; // We did nothing. + } + + enum TraverseSelect { + TRAVERSE_CPP, + TRAVERSE_FULL + }; + + void + TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThing, + nsCycleCollectionTraversalCallback& aCb); + + void + TraverseZone(JS::Zone* aZone, nsCycleCollectionTraversalCallback& aCb); + + static void + TraverseObjectShim(void* aData, JS::GCCellPtr aThing); + + void TraverseNativeRoots(nsCycleCollectionNoteRootCallback& aCb); + + static void TraceBlackJS(JSTracer* aTracer, void* aData); + static void TraceGrayJS(JSTracer* aTracer, void* aData); + static void GCCallback(JSContext* aContext, JSGCStatus aStatus, void* aData); + static void GCSliceCallback(JSContext* aContext, JS::GCProgress aProgress, + const JS::GCDescription& aDesc); + static void GCNurseryCollectionCallback(JSContext* aContext, + JS::GCNurseryProgress aProgress, + JS::gcreason::Reason aReason); + static void OutOfMemoryCallback(JSContext* aContext, void* aData); + /** + * Callback for reporting external string memory. + */ + static size_t SizeofExternalStringCallback(JSString* aStr, + mozilla::MallocSizeOf aMallocSizeOf); + + static bool ContextCallback(JSContext* aCx, unsigned aOperation, + void* aData); + + virtual void TraceNativeBlackRoots(JSTracer* aTracer) { }; + void TraceNativeGrayRoots(JSTracer* aTracer); + +public: + void FinalizeDeferredThings(CycleCollectedJSContext::DeferredFinalizeType aType); + + virtual void PrepareForForgetSkippable() = 0; + virtual void BeginCycleCollectionCallback() = 0; + virtual void EndCycleCollectionCallback(CycleCollectorResults& aResults) = 0; + virtual void DispatchDeferredDeletion(bool aContinuation, bool aPurge = false) = 0; + + // Two conditions, JSOutOfMemory and JSLargeAllocationFailure, are noted in + // crash reports. Here are the values that can appear in the reports: + enum class OOMState : uint32_t { + // The condition has never happened. No entry appears in the crash report. + OK, + + // We are currently reporting the given condition. + // + // Suppose a crash report contains "JSLargeAllocationFailure: + // Reporting". This means we crashed while executing memory-pressure + // observers, trying to shake loose some memory. The large allocation in + // question did not return null: it is still on the stack. Had we not + // crashed, it would have been retried. + Reporting, + + // The condition has been reported since the last GC. + // + // If a crash report contains "JSOutOfMemory: Reported", that means a small + // allocation failed, and then we crashed, probably due to buggy + // error-handling code that ran after allocation returned null. + // + // This contrasts with "Reporting" which means that no error-handling code + // had executed yet. + Reported, + + // The condition has happened, but a GC cycle ended since then. + // + // GC is taken as a proxy for "we've been banging on the heap a good bit + // now and haven't crashed; the OOM was probably handled correctly". + Recovered + }; + + void SetLargeAllocationFailure(OOMState aNewState); + + void AnnotateAndSetOutOfMemory(OOMState* aStatePtr, OOMState aNewState); + void OnGC(JSGCStatus aStatus); + void OnOutOfMemory(); + void OnLargeAllocationFailure(); + +public: + void AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer); + void RemoveJSHolder(void* aHolder); +#ifdef DEBUG + bool IsJSHolder(void* aHolder); + void AssertNoObjectsToTrace(void* aPossibleJSHolder); +#endif + + nsCycleCollectionParticipant* GCThingParticipant(); + nsCycleCollectionParticipant* ZoneParticipant(); + + nsresult TraverseRoots(nsCycleCollectionNoteRootCallback& aCb); + virtual bool UsefulToMergeZones() const; + void FixWeakMappingGrayBits() const; + void CheckGrayBits() const; + bool AreGCGrayBitsValid() const; + void GarbageCollect(uint32_t aReason) const; + + void NurseryWrapperAdded(nsWrapperCache* aCache); + void NurseryWrapperPreserved(JSObject* aWrapper); + void JSObjectsTenured(); + + void DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, + DeferredFinalizeFunction aFunc, + void* aThing); + void DeferredFinalize(nsISupports* aSupports); + + void DumpJSHeap(FILE* aFile); + + // Add aZone to the set of zones waiting for a GC. + void AddZoneWaitingForGC(JS::Zone* aZone) + { + mZonesWaitingForGC.PutEntry(aZone); + } + + // Prepare any zones for GC that have been passed to AddZoneWaitingForGC() + // since the last GC or since the last call to PrepareWaitingZonesForGC(), + // whichever was most recent. If there were no such zones, prepare for a + // full GC. + void PrepareWaitingZonesForGC(); + + // The main context is the first one created in the runtime and the last one + // destroyed. + JSContext* MainContext() const + { + MOZ_ASSERT(mJSContext); + return mJSContext; + } + + // Get the current thread's CycleCollectedJSRuntime. Returns null if there + // isn't one. + static CycleCollectedJSRuntime* Get(); + +private: + JSGCThingParticipant mGCThingCycleCollectorGlobal; + + JSZoneParticipant mJSZoneCycleCollectorGlobal; + + JSContext* mJSContext; + + JS::GCSliceCallback mPrevGCSliceCallback; + JS::GCNurseryCollectionCallback mPrevGCNurseryCollectionCallback; + + nsDataHashtable, nsScriptObjectTracer*> mJSHolders; + + typedef nsDataHashtable, void*> + DeferredFinalizerTable; + DeferredFinalizerTable mDeferredFinalizerTable; + + RefPtr mFinalizeRunnable; + + OOMState mOutOfMemoryState; + OOMState mLargeAllocationFailureState; + + static const size_t kSegmentSize = 512; + SegmentedVector + mNurseryObjects; + SegmentedVector, kSegmentSize, + InfallibleAllocPolicy> + mPreservedNurseryObjects; + + nsTHashtable> mZonesWaitingForGC; + + struct EnvironmentPreparer : public js::ScriptEnvironmentPreparer { + void invoke(JS::HandleObject scope, Closure& closure) override; + }; + EnvironmentPreparer mEnvironmentPreparer; +}; + +void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer); + +// Returns true if the JS::TraceKind is one the cycle collector cares about. +inline bool AddToCCKind(JS::TraceKind aKind) +{ + return aKind == JS::TraceKind::Object || + aKind == JS::TraceKind::Script || + aKind == JS::TraceKind::Scope || + aKind == JS::TraceKind::RegExpShared; +} + +bool +GetBuildId(JS::BuildIdCharVector* aBuildID); + +} // namespace mozilla + +#endif // mozilla_CycleCollectedJSRuntime_h diff --git a/xpcom/base/moz.build b/xpcom/base/moz.build index 69156f40d869..ce737a2b2aea 100644 --- a/xpcom/base/moz.build +++ b/xpcom/base/moz.build @@ -96,6 +96,7 @@ EXPORTS.mozilla += [ 'ClearOnShutdown.h', 'CountingAllocatorBase.h', 'CycleCollectedJSContext.h', + 'CycleCollectedJSRuntime.h', 'Debug.h', 'DebuggerOnGCRunnable.h', 'DeferredFinalize.h', @@ -126,6 +127,7 @@ UNIFIED_SOURCES += [ 'AvailableMemoryTracker.cpp', 'ClearOnShutdown.cpp', 'CycleCollectedJSContext.cpp', + 'CycleCollectedJSRuntime.cpp', 'Debug.cpp', 'DebuggerOnGCRunnable.cpp', 'DeferredFinalize.cpp', diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index bc16f4a192a9..1890efd3d37f 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -155,6 +155,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/AutoRestore.h" #include "mozilla/CycleCollectedJSContext.h" +#include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/DebugOnly.h" #include "mozilla/HoldDropJSObjects.h" /* This must occur *after* base/process_util.h to avoid typedefs conflicts. */ @@ -3833,7 +3834,7 @@ nsCycleCollector::BeginCollection(ccType aCCType, FixGrayBits(forceGC, timeLog); if (mJSContext) { - mJSContext->CheckGrayBits(); + mJSContext->Runtime()->CheckGrayBits(); } FreeSnowWhite(true); diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 495224c879e6..25ea57e082a7 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1712,8 +1712,8 @@ nsMemoryReporterManager::StartGettingReports() s->mAnonymize, parentDMDFile, s->mFinishReporting, s->mFinishReportingData); - nsTArray childWeakRefs; - ContentParent::GetAll(childWeakRefs); + nsTArray childWeakRefs; + dom::ContentParent::GetAll(childWeakRefs); if (!childWeakRefs.IsEmpty()) { // Request memory reports from child processes. This happens // after the parent report so that the parent's main thread will diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 69ba7fa0cd25..4cf2ecaa5829 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -8,6 +8,7 @@ #define nsMemoryReporterManager_h__ #include "mozilla/Mutex.h" +#include "nsDataHashtable.h" #include "nsHashKeys.h" #include "nsIMemoryReporter.h" #include "nsITimer.h" diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index c147e56e6f30..056376082dcf 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -6,7 +6,6 @@ #include "base/basictypes.h" -#include "mozilla/AbstractThread.h" #include "mozilla/Atomics.h" #include "mozilla/Poison.h" #include "mozilla/SharedThreadPool.h" @@ -681,9 +680,6 @@ NS_InitXPCOM2(nsIServiceManager** aResult, } sInitializedJS = true; - // Init AbstractThread. - AbstractThread::InitStatics(); - rv = nsComponentManagerImpl::gComponentManager->Init(); if (NS_FAILED(rv)) { NS_RELEASE(nsComponentManagerImpl::gComponentManager); @@ -791,7 +787,6 @@ NS_InitMinimalXPCOM() return NS_ERROR_UNEXPECTED; } - AbstractThread::InitStatics(); SharedThreadPool::InitStatics(); mozilla::Telemetry::Init(); mozilla::HangMonitor::Startup(); diff --git a/xpcom/threads/AbstractThread.cpp b/xpcom/threads/AbstractThread.cpp index 3a134a7d1951..17f1e17d89f7 100644 --- a/xpcom/threads/AbstractThread.cpp +++ b/xpcom/threads/AbstractThread.cpp @@ -251,7 +251,15 @@ AbstractThread::MainThread() } void -AbstractThread::InitStatics() +AbstractThread::InitTLS() +{ + if (!sCurrentThreadTLS.init()) { + MOZ_CRASH(); + } +} + +void +AbstractThread::InitMainThread() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!sMainThread); diff --git a/xpcom/threads/AbstractThread.h b/xpcom/threads/AbstractThread.h index 34c67dc05c85..03721164d7b5 100644 --- a/xpcom/threads/AbstractThread.h +++ b/xpcom/threads/AbstractThread.h @@ -95,7 +95,8 @@ public: static AbstractThread* MainThread(); // Must be called exactly once during startup. - static void InitStatics(); + static void InitTLS(); + static void InitMainThread(); void DispatchStateChange(already_AddRefed aRunnable); diff --git a/xpcom/threads/moz.build b/xpcom/threads/moz.build index 3192efc4a4dd..79725e7f5a4d 100644 --- a/xpcom/threads/moz.build +++ b/xpcom/threads/moz.build @@ -94,11 +94,9 @@ LOCAL_INCLUDES += [ # BHR disabled for Release builds because of bug 965392. # BHR disabled for debug builds because of bug 979069. -# BHR disabled on gonk because of bug 1180533 # BHR disabled for TSan builds because of bug 1121216. if CONFIG['MOZ_UPDATE_CHANNEL'] not in ('release') and \ not CONFIG['MOZ_DEBUG'] and \ - not CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and \ not CONFIG['MOZ_TSAN']: DEFINES['MOZ_ENABLE_BACKGROUND_HANG_MONITOR'] = 1 diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 9e85d748eb75..59e57bfbdcb2 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -10,6 +10,7 @@ #include "nsIClassInfoImpl.h" #include "nsTArray.h" #include "nsAutoPtr.h" +#include "mozilla/AbstractThread.h" #include "mozilla/ThreadLocal.h" #ifdef MOZ_CANARY #include @@ -110,6 +111,10 @@ nsThreadManager::Init() // GetIsMainThread calls that occur post-Shutdown. mMainThread->GetPRThread(&mMainPRThread); + // Init AbstractThread. + AbstractThread::InitTLS(); + AbstractThread::InitMainThread(); + mInitialized = true; return NS_OK; }