From f429287e6d12c50e4457b20893d386a6cb32c3a5 Mon Sep 17 00:00:00 2001 From: Tareq Khandaker Date: Wed, 25 Sep 2013 09:48:20 -0400 Subject: [PATCH 01/62] Bug 869613 - Make mach build some/deeper/path do dependencies for some and some/deeper. r=jdm --- python/mozbuild/dumbmake/dumbmake.py | 41 ++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/python/mozbuild/dumbmake/dumbmake.py b/python/mozbuild/dumbmake/dumbmake.py index f4b2c2e19411..5a083a35b38e 100644 --- a/python/mozbuild/dumbmake/dumbmake.py +++ b/python/mozbuild/dumbmake/dumbmake.py @@ -7,6 +7,7 @@ from __future__ import unicode_literals from collections import OrderedDict from itertools import groupby from operator import itemgetter +from os.path import dirname WHITESPACE_CHARACTERS = ' \t' @@ -61,7 +62,6 @@ def all_dependencies(*targets, **kwargs): all_targets = OrderedDict() # Used as an ordered set. for target in targets: - all_targets[target] = True if target in dm: for dependency in dm[target]: # Move element back in the ordered set. @@ -71,6 +71,18 @@ def all_dependencies(*targets, **kwargs): return all_targets.keys() +def get_components(path): + """Take a path and return all the components of the path.""" + paths = [path] + while True: + parent = dirname(paths[-1]) + if parent == "": + break + paths.append(parent) + + paths.reverse() + return paths + def add_extra_dependencies(target_pairs, dependency_map): """Take a list [(make_dir, make_target)] and expand (make_dir, None) entries with extra make dependencies from |dependency_map|. @@ -78,16 +90,33 @@ def add_extra_dependencies(target_pairs, dependency_map): Returns an iterator of pairs (make_dir, make_target). """ + all_targets = OrderedDict() # Used as an ordered set. + make_dirs = OrderedDict() # Used as an ordered set. + for make_target, group in groupby(target_pairs, itemgetter(1)): # Return non-simple directory targets untouched. if make_target is not None: for pair in group: - yield pair + # Generate dependencies for all components of a path. + # Given path a/b/c, examine a, a/b, and a/b/c in that order. + paths = get_components(pair[1]) + # For each component of a path, find and add all dependencies + # to the final target list. + for target in paths: + if target not in all_targets: + yield pair[0], target + all_targets[target] = True continue # Add extra dumbmake dependencies to simple directory targets. - make_dirs = [make_dir for make_dir, _ in group] - new_make_dirs = all_dependencies(*make_dirs, dependency_map=dependency_map) + for make_dir, _ in group: + make_dirs[make_dir] = True - for make_dir in new_make_dirs: - yield make_dir, None + all_components = [] + for make_dir in make_dirs.iterkeys(): + all_components.extend(get_components(make_dir)) + yield make_dir, None + + for i in all_dependencies(*all_components, dependency_map=dependency_map): + if i not in make_dirs: + yield i, None From 2f82a6a0774afa8fe609518fc645efce75b48ea4 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Wed, 25 Sep 2013 09:48:20 -0400 Subject: [PATCH 02/62] Bug 906852 - Make layout/style/nsFontFaceLoader.* pointer notation follow layout code style. r=mats --- layout/style/nsFontFaceLoader.cpp | 88 +++++++++++++++---------------- layout/style/nsFontFaceLoader.h | 56 ++++++++++---------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp index 06ffa5e3e6f3..9e3a2e15a854 100644 --- a/layout/style/nsFontFaceLoader.cpp +++ b/layout/style/nsFontFaceLoader.cpp @@ -38,10 +38,10 @@ using namespace mozilla; #ifdef PR_LOGGING -static PRLogModuleInfo * +static PRLogModuleInfo* GetFontDownloaderLog() { - static PRLogModuleInfo *sLog; + static PRLogModuleInfo* sLog; if (!sLog) sLog = PR_NewLogModule("fontdownloader"); return sLog; @@ -52,11 +52,11 @@ GetFontDownloaderLog() #define LOG_ENABLED() PR_LOG_TEST(GetFontDownloaderLog(), PR_LOG_DEBUG) -nsFontFaceLoader::nsFontFaceLoader(gfxMixedFontFamily *aFontFamily, - gfxProxyFontEntry *aProxy, - nsIURI *aFontURI, - nsUserFontSet *aFontSet, - nsIChannel *aChannel) +nsFontFaceLoader::nsFontFaceLoader(gfxMixedFontFamily* aFontFamily, + gfxProxyFontEntry* aProxy, + nsIURI* aFontURI, + nsUserFontSet* aFontSet, + nsIChannel* aChannel) : mFontFamily(aFontFamily), mFontEntry(aProxy), mFontURI(aFontURI), @@ -80,7 +80,7 @@ nsFontFaceLoader::~nsFontFaceLoader() } void -nsFontFaceLoader::StartedLoading(nsIStreamLoader *aStreamLoader) +nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader) { int32_t loadTimeout = Preferences::GetInt("gfx.downloadable_fonts.fallback_delay", 3000); @@ -99,16 +99,16 @@ nsFontFaceLoader::StartedLoading(nsIStreamLoader *aStreamLoader) } void -nsFontFaceLoader::LoadTimerCallback(nsITimer *aTimer, void *aClosure) +nsFontFaceLoader::LoadTimerCallback(nsITimer* aTimer, void* aClosure) { - nsFontFaceLoader *loader = static_cast(aClosure); + nsFontFaceLoader* loader = static_cast(aClosure); if (!loader->mFontSet) { // We've been canceled return; } - gfxProxyFontEntry *pe = loader->mFontEntry.get(); + gfxProxyFontEntry* pe = loader->mFontEntry.get(); bool updateUserFontSet = true; // If the entry is loading, check whether it's >75% done; if so, @@ -142,8 +142,8 @@ nsFontFaceLoader::LoadTimerCallback(nsITimer *aTimer, void *aClosure) // font will be used in the meantime, and tell the context to refresh. if (updateUserFontSet) { pe->mLoadingState = gfxProxyFontEntry::LOADING_SLOWLY; - gfxUserFontSet *fontSet = loader->mFontSet; - nsPresContext *ctx = loader->mFontSet->GetPresContext(); + gfxUserFontSet* fontSet = loader->mFontSet; + nsPresContext* ctx = loader->mFontSet->GetPresContext(); NS_ASSERTION(ctx, "userfontset doesn't have a presContext?"); if (ctx) { fontSet->IncrementGeneration(); @@ -183,7 +183,7 @@ nsFontFaceLoader::OnStreamComplete(nsIStreamLoader* aLoader, } #endif - nsPresContext *ctx = mFontSet->GetPresContext(); + nsPresContext* ctx = mFontSet->GetPresContext(); NS_ASSERTION(ctx && !ctx->PresShell()->IsDestroying(), "We should have been canceled already"); @@ -257,7 +257,7 @@ nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal, return NS_OK; // check with the security manager - nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager(); + nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); rv = secMan->CheckLoadURIWithPrincipal(aSourcePrincipal, aTargetURI, nsIScriptSecurityManager::STANDARD); if (NS_FAILED(rv)) { @@ -283,7 +283,7 @@ nsFontFaceLoader::CheckLoadAllowed(nsIPrincipal* aSourcePrincipal, return NS_OK; } -nsUserFontSet::nsUserFontSet(nsPresContext *aContext) +nsUserFontSet::nsUserFontSet(nsPresContext* aContext) : mPresContext(aContext) { NS_ASSERTION(mPresContext, "null context passed to nsUserFontSet"); @@ -310,19 +310,19 @@ nsUserFontSet::Destroy() } void -nsUserFontSet::RemoveLoader(nsFontFaceLoader *aLoader) +nsUserFontSet::RemoveLoader(nsFontFaceLoader* aLoader) { mLoaders.RemoveEntry(aLoader); } nsresult -nsUserFontSet::StartLoad(gfxMixedFontFamily *aFamily, - gfxProxyFontEntry *aProxy, - const gfxFontFaceSrc *aFontFaceSrc) +nsUserFontSet::StartLoad(gfxMixedFontFamily* aFamily, + gfxProxyFontEntry* aProxy, + const gfxFontFaceSrc* aFontFaceSrc) { nsresult rv; - nsIPresShell *ps = mPresContext->PresShell(); + nsIPresShell* ps = mPresContext->PresShell(); if (!ps) return NS_ERROR_FAILURE; @@ -461,12 +461,12 @@ nsUserFontSet::UpdateRules(const nsTArray& aRules) // even after the oldRules array is deleted. size_t count = oldRules.Length(); for (size_t i = 0; i < count; ++i) { - gfxFontEntry *fe = oldRules[i].mFontEntry; + gfxFontEntry* fe = oldRules[i].mFontEntry; if (!fe->mIsProxy) { continue; } - gfxProxyFontEntry *proxy = static_cast(fe); - nsFontFaceLoader *loader = proxy->mLoader; + gfxProxyFontEntry* proxy = static_cast(fe); + nsFontFaceLoader* loader = proxy->mLoader; if (loader) { loader->Cancel(); RemoveLoader(loader); @@ -482,7 +482,7 @@ nsUserFontSet::UpdateRules(const nsTArray& aRules) } void -nsUserFontSet::InsertRule(nsCSSFontFaceRule *aRule, uint8_t aSheetType, +nsUserFontSet::InsertRule(nsCSSFontFaceRule* aRule, uint8_t aSheetType, nsTArray& aOldRules, bool& aFontSetModified) { @@ -600,13 +600,13 @@ nsUserFontSet::InsertRule(nsCSSFontFaceRule *aRule, uint8_t aSheetType, aRule->GetDesc(eCSSFontDesc_Src, val); unit = val.GetUnit(); if (unit == eCSSUnit_Array) { - nsCSSValue::Array *srcArr = val.GetArrayValue(); + nsCSSValue::Array* srcArr = val.GetArrayValue(); size_t numSrc = srcArr->Count(); for (size_t i = 0; i < numSrc; i++) { val = srcArr->Item(i); unit = val.GetUnit(); - gfxFontFaceSrc *face = srcArray.AppendElements(1); + gfxFontFaceSrc* face = srcArray.AppendElements(1); if (!face) return; @@ -689,9 +689,9 @@ nsUserFontSet::InsertRule(nsCSSFontFaceRule *aRule, uint8_t aSheetType, } void -nsUserFontSet::ReplaceFontEntry(gfxMixedFontFamily *aFamily, - gfxProxyFontEntry *aProxy, - gfxFontEntry *aFontEntry) +nsUserFontSet::ReplaceFontEntry(gfxMixedFontFamily* aFamily, + gfxProxyFontEntry* aProxy, + gfxFontEntry* aFontEntry) { // aProxy is being supplanted by the "real" font aFontEntry, so we need to // update any rules that refer to it. Note that there may be multiple rules @@ -706,7 +706,7 @@ nsUserFontSet::ReplaceFontEntry(gfxMixedFontFamily *aFamily, } nsCSSFontFaceRule* -nsUserFontSet::FindRuleForEntry(gfxFontEntry *aFontEntry) +nsUserFontSet::FindRuleForEntry(gfxFontEntry* aFontEntry) { for (uint32_t i = 0; i < mRules.Length(); ++i) { if (mRules[i].mFontEntry == aFontEntry) { @@ -717,9 +717,9 @@ nsUserFontSet::FindRuleForEntry(gfxFontEntry *aFontEntry) } nsresult -nsUserFontSet::LogMessage(gfxMixedFontFamily *aFamily, - gfxProxyFontEntry *aProxy, - const char *aMessage, +nsUserFontSet::LogMessage(gfxMixedFontFamily* aFamily, + gfxProxyFontEntry* aProxy, + const char* aMessage, uint32_t aFlags, nsresult aStatus) { @@ -742,7 +742,7 @@ nsUserFontSet::LogMessage(gfxMixedFontFamily *aFamily, } char weightKeywordBuf[8]; // plenty to sprintf() a uint16_t - const char *weightKeyword; + const char* weightKeyword; const nsAFlatCString& weightKeywordString = nsCSSProps::ValueToKeyword(aProxy->Weight(), nsCSSProps::kFontWeightKTable); @@ -830,12 +830,12 @@ nsUserFontSet::LogMessage(gfxMixedFontFamily *aFamily, } nsresult -nsUserFontSet::CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc, - nsIPrincipal **aPrincipal, - bool *aBypassCache) +nsUserFontSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc, + nsIPrincipal** aPrincipal, + bool* aBypassCache) { // check same-site origin - nsIPresShell *ps = mPresContext->PresShell(); + nsIPresShell* ps = mPresContext->PresShell(); if (!ps) return NS_ERROR_FAILURE; @@ -881,10 +881,10 @@ nsUserFontSet::CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc, } nsresult -nsUserFontSet::SyncLoadFontData(gfxProxyFontEntry *aFontToLoad, - const gfxFontFaceSrc *aFontFaceSrc, - uint8_t* &aBuffer, - uint32_t &aBufferLength) +nsUserFontSet::SyncLoadFontData(gfxProxyFontEntry* aFontToLoad, + const gfxFontFaceSrc* aFontFaceSrc, + uint8_t*& aBuffer, + uint32_t& aBufferLength) { nsresult rv; @@ -965,7 +965,7 @@ nsUserFontSet::SyncLoadFontData(gfxProxyFontEntry *aFontToLoad, bool nsUserFontSet::GetPrivateBrowsing() { - nsIPresShell *ps = mPresContext->PresShell(); + nsIPresShell* ps = mPresContext->PresShell(); if (!ps) { return false; } diff --git a/layout/style/nsFontFaceLoader.h b/layout/style/nsFontFaceLoader.h index 502dbf4c2069..198f1d47a97a 100644 --- a/layout/style/nsFontFaceLoader.h +++ b/layout/style/nsFontFaceLoader.h @@ -26,7 +26,7 @@ class nsFontFaceLoader; class nsUserFontSet : public gfxUserFontSet { public: - nsUserFontSet(nsPresContext *aContext); + nsUserFontSet(nsPresContext* aContext); ~nsUserFontSet(); // Called when this font set is no longer associated with a presentation. @@ -34,23 +34,23 @@ public: // starts loading process, creating and initializing a nsFontFaceLoader obj // returns whether load process successfully started or not - nsresult StartLoad(gfxMixedFontFamily *aFamily, - gfxProxyFontEntry *aFontToLoad, - const gfxFontFaceSrc *aFontFaceSrc); + nsresult StartLoad(gfxMixedFontFamily* aFamily, + gfxProxyFontEntry* aFontToLoad, + const gfxFontFaceSrc* aFontFaceSrc); // Called by nsFontFaceLoader when the loader has completed normally. // It's removed from the mLoaders set. - void RemoveLoader(nsFontFaceLoader *aLoader); + void RemoveLoader(nsFontFaceLoader* aLoader); bool UpdateRules(const nsTArray& aRules); - nsPresContext *GetPresContext() { return mPresContext; } + nsPresContext* GetPresContext() { return mPresContext; } - virtual void ReplaceFontEntry(gfxMixedFontFamily *aFamily, - gfxProxyFontEntry *aProxy, - gfxFontEntry *aFontEntry); + virtual void ReplaceFontEntry(gfxMixedFontFamily* aFamily, + gfxProxyFontEntry* aProxy, + gfxFontEntry* aFontEntry); - nsCSSFontFaceRule *FindRuleForEntry(gfxFontEntry *aFontEntry); + nsCSSFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry); protected: // The font-set keeps track of the collection of rules, and their @@ -62,28 +62,28 @@ protected: nsFontFaceRuleContainer mContainer; }; - void InsertRule(nsCSSFontFaceRule *aRule, uint8_t aSheetType, + void InsertRule(nsCSSFontFaceRule* aRule, uint8_t aSheetType, nsTArray& oldRules, bool& aFontSetModified); - virtual nsresult LogMessage(gfxMixedFontFamily *aFamily, - gfxProxyFontEntry *aProxy, - const char *aMessage, + virtual nsresult LogMessage(gfxMixedFontFamily* aFamily, + gfxProxyFontEntry* aProxy, + const char* aMessage, uint32_t aFlags = nsIScriptError::errorFlag, nsresult aStatus = NS_OK); - virtual nsresult CheckFontLoad(const gfxFontFaceSrc *aFontFaceSrc, - nsIPrincipal **aPrincipal, - bool *aBypassCache); + virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc, + nsIPrincipal** aPrincipal, + bool* aBypassCache); - virtual nsresult SyncLoadFontData(gfxProxyFontEntry *aFontToLoad, - const gfxFontFaceSrc *aFontFaceSrc, - uint8_t* &aBuffer, - uint32_t &aBufferLength); + virtual nsresult SyncLoadFontData(gfxProxyFontEntry* aFontToLoad, + const gfxFontFaceSrc* aFontFaceSrc, + uint8_t*& aBuffer, + uint32_t& aBufferLength); virtual bool GetPrivateBrowsing() MOZ_OVERRIDE; - nsPresContext *mPresContext; // weak reference + nsPresContext* mPresContext; // weak reference // Set of all loaders pointing to us. These are not strong pointers, // but that's OK because nsFontFaceLoader always calls RemoveLoader on @@ -96,9 +96,9 @@ protected: class nsFontFaceLoader : public nsIStreamLoaderObserver { public: - nsFontFaceLoader(gfxMixedFontFamily *aFontFamily, - gfxProxyFontEntry *aFontToLoad, nsIURI *aFontURI, - nsUserFontSet *aFontSet, nsIChannel *aChannel); + nsFontFaceLoader(gfxMixedFontFamily* aFontFamily, + gfxProxyFontEntry* aFontToLoad, nsIURI* aFontURI, + nsUserFontSet* aFontSet, nsIChannel* aChannel); virtual ~nsFontFaceLoader(); @@ -112,9 +112,9 @@ public: void DropChannel() { mChannel = nullptr; } - void StartedLoading(nsIStreamLoader *aStreamLoader); + void StartedLoading(nsIStreamLoader* aStreamLoader); - static void LoadTimerCallback(nsITimer *aTimer, void *aClosure); + static void LoadTimerCallback(nsITimer* aTimer, void* aClosure); static nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal, nsIURI* aTargetURI, @@ -128,7 +128,7 @@ private: nsCOMPtr mChannel; nsCOMPtr mLoadTimer; - nsIStreamLoader *mStreamLoader; + nsIStreamLoader* mStreamLoader; }; #endif /* !defined(nsFontFaceLoader_h_) */ From 5ce7dfc55044a885f9d16a89d015c51ea705dcab Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Tue, 24 Sep 2013 10:05:00 -0500 Subject: [PATCH 03/62] Bug 918884 - Implement a method to get the DOM element that owns a docshell. r=bz --- dom/base/nsDOMWindowUtils.cpp | 17 ++++ dom/interfaces/base/nsIDOMWindowUtils.idl | 8 +- dom/tests/browser/Makefile.in | 4 +- dom/tests/browser/browser_frame_elements.html | 15 ++++ dom/tests/browser/browser_frame_elements.js | 87 +++++++++++++++++++ 5 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 dom/tests/browser/browser_frame_elements.html create mode 100644 dom/tests/browser/browser_frame_elements.js diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index d33b0b03a555..4310a03ef415 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -2538,6 +2538,23 @@ nsDOMWindowUtils::GetOuterWindowWithId(uint64_t aWindowID, return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::GetContainerElement(nsIDOMElement** aResult) +{ + if (!nsContentUtils::IsCallerChrome()) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsCOMPtr window = do_QueryReferent(mWindow); + NS_ENSURE_STATE(window); + + nsCOMPtr element = + do_QueryInterface(window->GetFrameElementInternal()); + + element.forget(aResult); + return NS_OK; +} + NS_IMETHODIMP nsDOMWindowUtils::WrapDOMFile(nsIFile *aFile, nsIDOMFile **aDOMFile) diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index c9cbff8272f8..013bb86e3445 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -43,7 +43,7 @@ interface nsIDOMEventTarget; interface nsIRunnable; interface nsICompositionStringSynthesizer; -[scriptable, uuid(a1383ae5-e828-4c9a-929d-5293e61beb64)] +[scriptable, uuid(750a47b6-8bdb-4cad-ba2c-b7d3e66d8021)] interface nsIDOMWindowUtils : nsISupports { /** @@ -1087,6 +1087,12 @@ interface nsIDOMWindowUtils : nsISupports { */ nsIDOMWindow getOuterWindowWithId(in unsigned long long aOuterWindowID); + /** + * Return this window's frame element. + * Ignores all chrome/content or mozbrowser boundaries. + */ + readonly attribute nsIDOMElement containerElement; + [noscript] void RenderDocument(in nsConstRect aRect, in uint32_t aFlags, in nscolor aBackgroundColor, diff --git a/dom/tests/browser/Makefile.in b/dom/tests/browser/Makefile.in index 5857ff42dda9..c0e4e1967432 100644 --- a/dom/tests/browser/Makefile.in +++ b/dom/tests/browser/Makefile.in @@ -17,7 +17,9 @@ MOCHITEST_BROWSER_FILES := \ browser_geolocation_privatebrowsing_perwindowpb.js \ browser_localStorage_privatestorageevent.js \ network_geolocation.sjs \ - page_privatestorageevent.html + page_privatestorageevent.html \ + browser_frame_elements.js \ + browser_frame_elements.html $(NULL) ifdef MOZ_B2G diff --git a/dom/tests/browser/browser_frame_elements.html b/dom/tests/browser/browser_frame_elements.html new file mode 100644 index 000000000000..4843173f5742 --- /dev/null +++ b/dom/tests/browser/browser_frame_elements.html @@ -0,0 +1,15 @@ + + + + Frame Element Tests + + +

Frame Element Tests

+ + + + + + + + diff --git a/dom/tests/browser/browser_frame_elements.js b/dom/tests/browser/browser_frame_elements.js new file mode 100644 index 000000000000..11b1ba8e0b02 --- /dev/null +++ b/dom/tests/browser/browser_frame_elements.js @@ -0,0 +1,87 @@ +/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=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/. */ + +const TEST_URI = "http://example.com/browser/dom/tests/browser/browser_frame_elements.html"; +let gWindow; + +function test() { + waitForExplicitFinish(); + + var tab = gBrowser.addTab(TEST_URI); + gBrowser.selectedTab = tab; + var browser = gBrowser.selectedBrowser; + + registerCleanupFunction(function () { + gBrowser.removeTab(tab); + gWindow = null; + }); + + browser.addEventListener("DOMContentLoaded", function onLoad(event) { + browser.removeEventListener("DOMContentLoaded", onLoad, false); + executeSoon(function test_executeSoon() { + gWindow = browser.contentWindow; + startTests(); + }); + }, false); +} + +function startTests() { + info("Frame tests started"); + + info("Checking top window"); + let windowUtils = getWindowUtils(gWindow); + is (windowUtils.containerElement, gBrowser.selectedBrowser, "Container element for main window is xul:browser"); + is (gWindow.top, gWindow, "gWindow is top"); + is (gWindow.parent, gWindow, "gWindow is parent"); + + info("Checking about:blank iframe"); + let iframeBlank = gWindow.document.querySelector("#iframe-blank"); + ok (iframeBlank, "Iframe exists on page"); + let iframeBlankUtils = getWindowUtils(iframeBlank.contentWindow); + is (iframeBlankUtils.containerElement, iframeBlank, "Container element for iframe window is iframe"); + is (iframeBlank.contentWindow.top, gWindow, "gWindow is top"); + is (iframeBlank.contentWindow.parent, gWindow, "gWindow is parent"); + + info("Checking iframe with data url src"); + let iframeDataUrl = gWindow.document.querySelector("#iframe-data-url"); + ok (iframeDataUrl, "Iframe exists on page"); + let iframeDataUrlUtils = getWindowUtils(iframeDataUrl.contentWindow); + is (iframeDataUrlUtils.containerElement, iframeDataUrl, "Container element for iframe window is iframe"); + is (iframeDataUrl.contentWindow.top, gWindow, "gWindow is top"); + is (iframeDataUrl.contentWindow.parent, gWindow, "gWindow is parent"); + + info("Checking object with data url data attribute"); + let objectDataUrl = gWindow.document.querySelector("#object-data-url"); + ok (objectDataUrl, "Object exists on page"); + let objectDataUrlUtils = getWindowUtils(objectDataUrl.contentWindow); + is (objectDataUrlUtils.containerElement, objectDataUrl, "Container element for object window is the object"); + is (objectDataUrl.contentWindow.top, gWindow, "gWindow is top"); + is (objectDataUrl.contentWindow.parent, gWindow, "gWindow is parent"); + + info("Granting special powers for mozbrowser"); + SpecialPowers.addPermission("browser", true, gWindow.document); + SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true); + + info("Checking mozbrowser iframe"); + let mozBrowserFrame = gWindow.document.createElement("iframe"); + mozBrowserFrame.setAttribute("mozbrowser", ""); + gWindow.document.body.appendChild(mozBrowserFrame); + is (mozBrowserFrame.contentWindow.top, mozBrowserFrame.contentWindow, "Mozbrowser top == iframe window"); + is (mozBrowserFrame.contentWindow.parent, mozBrowserFrame.contentWindow, "Mozbrowser parent == iframe window"); + + info("Revoking special powers for mozbrowser"); + SpecialPowers.clearUserPref('dom.mozBrowserFramesEnabled') + SpecialPowers.removePermission("browser", gWindow.document); + + finish(); +} + +function getWindowUtils(window) +{ + return window. + QueryInterface(Components.interfaces.nsIInterfaceRequestor). + getInterface(Components.interfaces.nsIDOMWindowUtils); +} From 64f8d6e459e86c48315da63e21e4dcf522578431 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Wed, 25 Sep 2013 09:48:20 -0400 Subject: [PATCH 04/62] Bug 919729 - Remove unnecessary MOZILLA_INTERNAL_API checks from nsIFrame.h. r=bz --- layout/generic/nsFrame.cpp | 2 +- layout/generic/nsIFrame.h | 26 +------------------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 30d7587d2370..9c57329e9354 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -345,7 +345,7 @@ NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary) } void -nsWeakFrame::InitInternal(nsIFrame* aFrame) +nsWeakFrame::Init(nsIFrame* aFrame) { Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr); mFrame = aFrame; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 9d9c58f8b84c..7b3c21279c09 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -806,11 +806,9 @@ public: #include "nsStyleStructList.h" #undef STYLE_STRUCT -#ifdef MOZILLA_INTERNAL_API /** Also forward GetVisitedDependentColor to the style context */ nscolor GetVisitedDependentColor(nsCSSProperty aProperty) { return mStyleContext->GetVisitedDependentColor(aProperty); } -#endif /** * These methods are to access any additional style contexts that @@ -3249,29 +3247,7 @@ public: Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr); } private: - void InitInternal(nsIFrame* aFrame); - - void InitExternal(nsIFrame* aFrame) { - Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr); - mFrame = aFrame; - if (mFrame) { - nsIPresShell* shell = mFrame->PresContext()->GetPresShell(); - NS_WARN_IF_FALSE(shell, "Null PresShell in nsWeakFrame!"); - if (shell) { - shell->AddWeakFrame(this); - } else { - mFrame = nullptr; - } - } - } - - void Init(nsIFrame* aFrame) { -#ifdef MOZILLA_INTERNAL_API - InitInternal(aFrame); -#else - InitExternal(aFrame); -#endif - } + void Init(nsIFrame* aFrame); nsWeakFrame* mPrev; nsIFrame* mFrame; From 2cb201396b1e13c6314622b3aa83606ab2de03df Mon Sep 17 00:00:00 2001 From: Ryo ONODERA Date: Wed, 25 Sep 2013 09:48:21 -0400 Subject: [PATCH 05/62] Bug 919968 - Fix AsmJS build errors on Solaris/i386 and NetBSD/amd64. r=luke --- js/src/jit/AsmJSSignalHandlers.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/jit/AsmJSSignalHandlers.cpp b/js/src/jit/AsmJSSignalHandlers.cpp index e2c0ac1b22bb..5994845e1895 100644 --- a/js/src/jit/AsmJSSignalHandlers.cpp +++ b/js/src/jit/AsmJSSignalHandlers.cpp @@ -58,10 +58,11 @@ using JS::GenericNaN; #elif defined(__linux__) || defined(SOLARIS) # if defined(__linux__) # define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i]) +# define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP]) # else # define XMM_sig(p,i) ((p)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[i]) +# define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_PC]) # endif -# define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP]) # define RIP_sig(p) ((p)->uc_mcontext.gregs[REG_RIP]) # define PC_sig(p) ((p)->uc_mcontext.arm_pc) # define RAX_sig(p) ((p)->uc_mcontext.gregs[REG_RAX]) @@ -310,7 +311,8 @@ LookupHeapAccess(const AsmJSModule &module, uint8_t *pc) #if defined(JS_CPU_X64) # if defined(__DragonFly__) # include // for union savefpu -# elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) +# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || defined(__OpenBSD__) # include // for struct savefpu/fxsave64 # endif #endif From 646f853649ea2326ee088c9f82d0db6f7c1f2b43 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Wed, 25 Sep 2013 09:48:21 -0400 Subject: [PATCH 06/62] Bug 919968 - Simplify ContextToPC() and make it work on non-Linux ARM. r=luke --- js/src/jit/AsmJSSignalHandlers.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/js/src/jit/AsmJSSignalHandlers.cpp b/js/src/jit/AsmJSSignalHandlers.cpp index 5994845e1895..fdf7c7b0f3ab 100644 --- a/js/src/jit/AsmJSSignalHandlers.cpp +++ b/js/src/jit/AsmJSSignalHandlers.cpp @@ -64,7 +64,6 @@ using JS::GenericNaN; # define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_PC]) # endif # define RIP_sig(p) ((p)->uc_mcontext.gregs[REG_RIP]) -# define PC_sig(p) ((p)->uc_mcontext.arm_pc) # define RAX_sig(p) ((p)->uc_mcontext.gregs[REG_RAX]) # define RCX_sig(p) ((p)->uc_mcontext.gregs[REG_RCX]) # define RDX_sig(p) ((p)->uc_mcontext.gregs[REG_RDX]) @@ -80,7 +79,11 @@ using JS::GenericNaN; # define R12_sig(p) ((p)->uc_mcontext.gregs[REG_R12]) # define R13_sig(p) ((p)->uc_mcontext.gregs[REG_R13]) # define R14_sig(p) ((p)->uc_mcontext.gregs[REG_R14]) -# define R15_sig(p) ((p)->uc_mcontext.gregs[REG_R15]) +# if defined(__linux__) && defined(__arm__) +# define R15_sig(p) ((p)->uc_mcontext.arm_pc) +# else +# define R15_sig(p) ((p)->uc_mcontext.gregs[REG_R15]) +# endif #elif defined(__NetBSD__) # define XMM_sig(p,i) (((struct fxsave64 *)(p)->uc_mcontext.__fpregs)->fx_xmm[i]) # define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP]) @@ -124,7 +127,11 @@ using JS::GenericNaN; # define R12_sig(p) ((p)->uc_mcontext.mc_r12) # define R13_sig(p) ((p)->uc_mcontext.mc_r13) # define R14_sig(p) ((p)->uc_mcontext.mc_r14) -# define R15_sig(p) ((p)->uc_mcontext.mc_r15) +# if defined(__FreeBSD__) && defined(__arm__) +# define R15_sig(p) ((p)->uc_mcontext.__gregs[_REG_R15]) +# else +# define R15_sig(p) ((p)->uc_mcontext.mc_r15) +# endif #elif defined(XP_MACOSX) // Mach requires special treatment. #else @@ -381,20 +388,20 @@ static bool IsSignalHandlingBroken() { return false; } # define CONTEXT ucontext_t #endif +#if defined(JS_CPU_X64) +# define PC_sig(p) RIP_sig(p) +#elif defined(JS_CPU_X86) +# define PC_sig(p) EIP_sig(p) +#elif defined(JS_CPU_ARM) +# define PC_sig(p) R15_sig(p) +#endif + #if !defined(XP_MACOSX) static uint8_t ** ContextToPC(CONTEXT *context) { -# if defined(JS_CPU_X64) - JS_STATIC_ASSERT(sizeof(RIP_sig(context)) == sizeof(void*)); - return reinterpret_cast(&RIP_sig(context)); -# elif defined(JS_CPU_X86) - JS_STATIC_ASSERT(sizeof(EIP_sig(context)) == sizeof(void*)); - return reinterpret_cast(&EIP_sig(context)); -# elif defined(JS_CPU_ARM) JS_STATIC_ASSERT(sizeof(PC_sig(context)) == sizeof(void*)); return reinterpret_cast(&PC_sig(context)); -# endif } # if defined(JS_CPU_X64) From 8e6e0a7c889a6159cf920e63c44f1e1ea984e842 Mon Sep 17 00:00:00 2001 From: Monica Chew Date: Wed, 25 Sep 2013 07:03:31 -0700 Subject: [PATCH 07/62] Bug 842828: Check local list to suppress remote lookups (r=paolo) --- toolkit/components/build/nsToolkitCompsCID.h | 6 - .../components/build/nsToolkitCompsModule.cpp | 4 - .../downloads/ApplicationReputation.cpp | 368 ++++++++++-------- .../downloads/ApplicationReputation.h | 68 +--- .../downloads/test/unit/data/digest.chunk | 2 + .../downloads/test/unit/test_app_rep.js | 180 +++++++-- toolkit/components/url-classifier/moz.build | 6 + 7 files changed, 375 insertions(+), 259 deletions(-) create mode 100644 toolkit/components/downloads/test/unit/data/digest.chunk diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index 9b25877e58f6..b0b12f44f978 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -175,12 +175,6 @@ { 0xf3dcf644, 0x79e8, 0x4f59, { 0xa1, 0xbb, 0x87, 0x84, 0x54, 0x48, 0x8e, 0xf9 } } #endif -#define NS_APPLICATION_REPUTATION_QUERY_CONTRACTID \ - "@mozilla.org/downloads/application-reputation-query;1" - -#define NS_APPLICATION_REPUTATION_QUERY_CID \ -{ 0x857da2c0, 0xcfe5, 0x11e2, { 0x8b, 0x8b, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } } - #define NS_APPLICATION_REPUTATION_SERVICE_CONTRACTID \ "@mozilla.org/downloads/application-reputation-service;1" diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index eb77441573f0..ebeb8af008cc 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -79,7 +79,6 @@ nsUrlClassifierDBServiceConstructor(nsISupports *aOuter, REFNSIID aIID, } #endif -NS_GENERIC_FACTORY_CONSTRUCTOR(ApplicationReputationQuery) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ApplicationReputationService, ApplicationReputationService::GetSingleton) NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserStatusFilter) @@ -87,7 +86,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserStatusFilter) NS_GENERIC_FACTORY_CONSTRUCTOR(nsUpdateProcessor) #endif -NS_DEFINE_NAMED_CID(NS_APPLICATION_REPUTATION_QUERY_CID); NS_DEFINE_NAMED_CID(NS_APPLICATION_REPUTATION_SERVICE_CID); NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID); NS_DEFINE_NAMED_CID(NS_USERINFO_CID); @@ -113,7 +111,6 @@ NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID); #endif static const mozilla::Module::CIDEntry kToolkitCIDs[] = { - { &kNS_APPLICATION_REPUTATION_QUERY_CID, false, NULL, ApplicationReputationQueryConstructor }, { &kNS_APPLICATION_REPUTATION_SERVICE_CID, false, NULL, ApplicationReputationServiceConstructor }, { &kNS_TOOLKIT_APPSTARTUP_CID, false, NULL, nsAppStartupConstructor }, { &kNS_USERINFO_CID, false, NULL, nsUserInfoConstructor }, @@ -141,7 +138,6 @@ static const mozilla::Module::CIDEntry kToolkitCIDs[] = { }; static const mozilla::Module::ContractIDEntry kToolkitContracts[] = { - { NS_APPLICATION_REPUTATION_QUERY_CONTRACTID, &kNS_APPLICATION_REPUTATION_QUERY_CID }, { NS_APPLICATION_REPUTATION_SERVICE_CONTRACTID, &kNS_APPLICATION_REPUTATION_SERVICE_CID }, { NS_APPSTARTUP_CONTRACTID, &kNS_TOOLKIT_APPSTARTUP_CID }, { NS_USERINFO_CONTRACTID, &kNS_USERINFO_CID }, diff --git a/toolkit/components/downloads/ApplicationReputation.cpp b/toolkit/components/downloads/ApplicationReputation.cpp index 99c743f9ea72..6dc936c321e2 100644 --- a/toolkit/components/downloads/ApplicationReputation.cpp +++ b/toolkit/components/downloads/ApplicationReputation.cpp @@ -11,8 +11,8 @@ #include "nsIChannel.h" #include "nsIHttpChannel.h" #include "nsIIOService.h" -#include "nsIObserverService.h" #include "nsIPrefService.h" +#include "nsIScriptSecurityManager.h" #include "nsIStreamListener.h" #include "nsIStringStream.h" #include "nsIUploadChannel2.h" @@ -25,6 +25,7 @@ #include "nsDebug.h" #include "nsError.h" #include "nsNetCID.h" +#include "nsReadableUtils.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsThreadUtils.h" @@ -38,79 +39,117 @@ using mozilla::Preferences; #define PREF_SB_APP_REP_URL "browser.safebrowsing.appRepURL" #define PREF_SB_MALWARE_ENABLED "browser.safebrowsing.malware.enabled" #define PREF_GENERAL_LOCALE "general.useragent.locale" +#define PREF_DOWNLOAD_BLOCK_TABLE "urlclassifier.download_block_table" +#define PREF_DOWNLOAD_ALLOW_TABLE "urlclassifier.download_allow_table" -NS_IMPL_ISUPPORTS1(ApplicationReputationService, nsIApplicationReputationService) +/** + * Keep track of pending lookups. Once the ApplicationReputationService creates + * this, it is guaranteed to call mCallback. This class is private to + * ApplicationReputationService. + */ +class PendingLookup MOZ_FINAL : + public nsIStreamListener, + public nsIUrlClassifierCallback { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIURLCLASSIFIERCALLBACK + PendingLookup(nsIApplicationReputationQuery* aQuery, + nsIApplicationReputationCallback* aCallback); + ~PendingLookup(); -ApplicationReputationService* ApplicationReputationService::gApplicationReputationService = nullptr; +private: + nsCOMPtr mQuery; + nsCOMPtr mCallback; + /** + * The response from the application reputation query. This is read in chunks + * as part of our nsIStreamListener implementation and may contain embedded + * NULLs. + */ + nsCString mResponse; + /** + * Clean up and call the callback. PendingLookup must not be used after this + * function is called. + */ + nsresult OnComplete(bool shouldBlock, nsresult rv); + /** + * Wrapper function for nsIStreamListener.onStopRequest to make it easy to + * guarantee calling the callback + */ + nsresult OnStopRequestInternal(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aResult, + bool* aShouldBlock); + /** + * Sends a query to the remote application reputation service. Returns NS_OK + * on success. + */ + nsresult SendRemoteQuery(); +}; -ApplicationReputationService * -ApplicationReputationService::GetSingleton() -{ - if (gApplicationReputationService) { - NS_ADDREF(gApplicationReputationService); - return gApplicationReputationService; - } +NS_IMPL_ISUPPORTS3(PendingLookup, + nsIStreamListener, + nsIRequestObserver, + nsIUrlClassifierCallback) - gApplicationReputationService = new ApplicationReputationService(); - if (gApplicationReputationService) { - NS_ADDREF(gApplicationReputationService); - } - - return gApplicationReputationService; +PendingLookup::PendingLookup(nsIApplicationReputationQuery* aQuery, + nsIApplicationReputationCallback* aCallback) : + mQuery(aQuery), + mCallback(aCallback) { } -ApplicationReputationService::ApplicationReputationService() { } -ApplicationReputationService::~ApplicationReputationService() { } +PendingLookup::~PendingLookup() { +} +nsresult +PendingLookup::OnComplete(bool shouldBlock, nsresult rv) { + nsresult res = mCallback->OnComplete(shouldBlock, rv); + return res; +} + +//////////////////////////////////////////////////////////////////////////////// +//// nsIUrlClassifierCallback NS_IMETHODIMP -ApplicationReputationService::QueryReputation( - nsIApplicationReputationQuery* aQuery, - nsIApplicationReputationCallback* aCallback) { - NS_ENSURE_ARG_POINTER(aQuery); - NS_ENSURE_ARG_POINTER(aCallback); +PendingLookup::HandleEvent(const nsACString& tables) { + // HandleEvent is guaranteed to call the callback if either the URL can be + // classified locally, or if there is an error sending the remote lookup. + // Allow listing trumps block listing. + nsCString allow_list; + Preferences::GetCString(PREF_DOWNLOAD_ALLOW_TABLE, &allow_list); + if (FindInReadable(tables, allow_list)) { + return OnComplete(false, NS_OK); + } - nsresult rv = QueryReputationInternal(aQuery, aCallback); + nsCString block_list; + Preferences::GetCString(PREF_DOWNLOAD_BLOCK_TABLE, &block_list); + if (FindInReadable(tables, block_list)) { + return OnComplete(true, NS_OK); + } + + nsresult rv = SendRemoteQuery(); if (NS_FAILED(rv)) { - aCallback->OnComplete(false, rv); - aCallback = nullptr; + return OnComplete(false, rv); } return NS_OK; } nsresult -ApplicationReputationService::QueryReputationInternal( - nsIApplicationReputationQuery* aQuery, - nsIApplicationReputationCallback* aCallback) { - nsresult rv; - aQuery->SetCallback(aCallback); - - // If malware checks aren't enabled, don't query application reputation. - if (!Preferences::GetBool(PREF_SB_MALWARE_ENABLED, false)) { - return NS_ERROR_NOT_AVAILABLE; - } - - // If there is no service URL for querying application reputation, abort. - nsCString serviceUrl; - NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_SB_APP_REP_URL, &serviceUrl), - NS_ERROR_NOT_AVAILABLE); - if (serviceUrl.EqualsLiteral("")) { - return NS_ERROR_NOT_AVAILABLE; - } - +PendingLookup::SendRemoteQuery() { + // We did not find a local result, so fire off the query to the application + // reputation service. safe_browsing::ClientDownloadRequest req; - + nsCOMPtr uri; + nsresult rv; + rv = mQuery->GetSourceURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); nsCString spec; - nsCOMPtr aURI; - rv = aQuery->GetSourceURI(getter_AddRefs(aURI)); + rv = uri->GetSpec(spec); NS_ENSURE_SUCCESS(rv, rv); - // If the URI hasn't been set, bail - NS_ENSURE_STATE(aURI); - rv = aURI->GetSpec(spec); - NS_ENSURE_SUCCESS(rv, rv); - req.set_url(spec.get()); + uint32_t fileSize; - rv = aQuery->GetFileSize(&fileSize); + rv = mQuery->GetFileSize(&fileSize); NS_ENSURE_SUCCESS(rv, rv); req.set_length(fileSize); // We have no way of knowing whether or not a user initiated the download. @@ -121,11 +160,11 @@ ApplicationReputationService::QueryReputationInternal( NS_ERROR_NOT_AVAILABLE); req.set_locale(locale.get()); nsCString sha256Hash; - rv = aQuery->GetSha256Hash(sha256Hash); + rv = mQuery->GetSha256Hash(sha256Hash); NS_ENSURE_SUCCESS(rv, rv); req.mutable_digests()->set_sha256(sha256Hash.Data()); nsString fileName; - rv = aQuery->GetSuggestedFileName(fileName); + rv = mQuery->GetSuggestedFileName(fileName); NS_ENSURE_SUCCESS(rv, rv); req.set_file_basename(NS_ConvertUTF16toUTF8(fileName).get()); @@ -150,6 +189,9 @@ ApplicationReputationService::QueryReputationInternal( // Set up the channel to transmit the request to the service. nsCOMPtr channel; + nsCString serviceUrl; + NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_SB_APP_REP_URL, &serviceUrl), + NS_ERROR_NOT_AVAILABLE); rv = ios->NewChannel(serviceUrl, nullptr, nullptr, getter_AddRefs(channel)); NS_ENSURE_SUCCESS(rv, rv); @@ -171,96 +213,14 @@ ApplicationReputationService::QueryReputationInternal( NS_LITERAL_CSTRING("POST"), false); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr listener = do_QueryInterface(aQuery, &rv); - NS_ENSURE_SUCCESS(rv, rv); - rv = channel->AsyncOpen(listener, nullptr); + rv = channel->AsyncOpen(this, nullptr); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } -NS_IMPL_ISUPPORTS3(ApplicationReputationQuery, - nsIApplicationReputationQuery, - nsIStreamListener, - nsIRequestObserver) - -ApplicationReputationQuery::ApplicationReputationQuery() : - mURI(nullptr), - mFileSize(0), - mCallback(nullptr) { -} - -ApplicationReputationQuery::~ApplicationReputationQuery() { -} - -NS_IMETHODIMP -ApplicationReputationQuery::GetSourceURI(nsIURI** aURI) { - *aURI = mURI; - NS_IF_ADDREF(*aURI); - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::SetSourceURI(nsIURI* aURI) { - mURI = aURI; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::GetSuggestedFileName( - nsAString& aSuggestedFileName) { - aSuggestedFileName = mSuggestedFileName; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::SetSuggestedFileName( - const nsAString& aSuggestedFileName) { - mSuggestedFileName = aSuggestedFileName; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::GetFileSize(uint32_t* aFileSize) { - *aFileSize = mFileSize; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::SetFileSize(uint32_t aFileSize) { - mFileSize = aFileSize; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::GetSha256Hash(nsACString& aSha256Hash) { - aSha256Hash = mSha256Hash; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::SetSha256Hash(const nsACString& aSha256Hash) { - mSha256Hash = aSha256Hash; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::GetCallback( - nsIApplicationReputationCallback** aCallback) { - *aCallback = mCallback; - return NS_OK; -} - -NS_IMETHODIMP -ApplicationReputationQuery::SetCallback( - nsIApplicationReputationCallback* aCallback) { - mCallback = aCallback; - return NS_OK; -} - //////////////////////////////////////////////////////////////////////////////// //// nsIStreamListener - static NS_METHOD AppendSegmentToString(nsIInputStream* inputStream, void *closure, @@ -275,40 +235,39 @@ AppendSegmentToString(nsIInputStream* inputStream, } NS_IMETHODIMP -ApplicationReputationQuery::OnDataAvailable(nsIRequest *aRequest, - nsISupports *aContext, - nsIInputStream *aStream, - uint64_t offset, - uint32_t count) { +PendingLookup::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aStream, + uint64_t offset, + uint32_t count) { uint32_t read; return aStream->ReadSegments(AppendSegmentToString, &mResponse, count, &read); } NS_IMETHODIMP -ApplicationReputationQuery::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) { +PendingLookup::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) { return NS_OK; } NS_IMETHODIMP -ApplicationReputationQuery::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aResult) { +PendingLookup::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aResult) { NS_ENSURE_STATE(mCallback); bool shouldBlock = false; nsresult rv = OnStopRequestInternal(aRequest, aContext, aResult, &shouldBlock); - mCallback->OnComplete(shouldBlock, rv); - mCallback = nullptr; + OnComplete(shouldBlock, rv); return rv; } nsresult -ApplicationReputationQuery::OnStopRequestInternal(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aResult, - bool* aShouldBlock) { +PendingLookup::OnStopRequestInternal(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aResult, + bool* aShouldBlock) { *aShouldBlock = false; nsresult rv; nsCOMPtr channel = do_QueryInterface(aRequest, &rv); @@ -337,3 +296,102 @@ ApplicationReputationQuery::OnStopRequestInternal(nsIRequest *aRequest, return NS_OK; } + +NS_IMPL_ISUPPORTS1(ApplicationReputationService, + nsIApplicationReputationService) + +ApplicationReputationService* + ApplicationReputationService::gApplicationReputationService = nullptr; + +ApplicationReputationService* +ApplicationReputationService::GetSingleton() +{ + if (gApplicationReputationService) { + NS_ADDREF(gApplicationReputationService); + return gApplicationReputationService; + } + + // We're not initialized yet. + gApplicationReputationService = new ApplicationReputationService(); + if (gApplicationReputationService) { + NS_ADDREF(gApplicationReputationService); + } + + return gApplicationReputationService; +} + +ApplicationReputationService::ApplicationReputationService() : + mDBService(nullptr), + mSecurityManager(nullptr) { +} + +ApplicationReputationService::~ApplicationReputationService() { +} + +NS_IMETHODIMP +ApplicationReputationService::QueryReputation( + nsIApplicationReputationQuery* aQuery, + nsIApplicationReputationCallback* aCallback) { + NS_ENSURE_ARG_POINTER(aQuery); + NS_ENSURE_ARG_POINTER(aCallback); + + nsresult rv = QueryReputationInternal(aQuery, aCallback); + if (NS_FAILED(rv)) { + aCallback->OnComplete(false, rv); + } + return NS_OK; +} + +nsresult ApplicationReputationService::QueryReputationInternal( + nsIApplicationReputationQuery* aQuery, + nsIApplicationReputationCallback* aCallback) { + // Lazily instantiate mDBService and mSecurityManager + nsresult rv; + if (!mDBService) { + mDBService = do_GetService(NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + if (!mSecurityManager) { + mSecurityManager = do_GetService("@mozilla.org/scriptsecuritymanager;1", + &rv); + NS_ENSURE_SUCCESS(rv, rv); + } + // If malware checks aren't enabled, don't query application reputation. + if (!Preferences::GetBool(PREF_SB_MALWARE_ENABLED, false)) { + return NS_ERROR_NOT_AVAILABLE; + } + + // If there is no service URL for querying application reputation, abort. + nsCString serviceUrl; + NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_SB_APP_REP_URL, &serviceUrl), + NS_ERROR_NOT_AVAILABLE); + if (serviceUrl.EqualsLiteral("")) { + return NS_ERROR_NOT_AVAILABLE; + } + + // We must be able to create a principal and query local lists. + NS_ENSURE_STATE(mDBService); + NS_ENSURE_STATE(mSecurityManager); + + // Create a new pending lookup. + nsRefPtr lookup(new PendingLookup(aQuery, aCallback)); + NS_ENSURE_STATE(lookup); + + nsCOMPtr uri; + rv = aQuery->GetSourceURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + // If the URI hasn't been set, bail + NS_ENSURE_STATE(uri); + nsCOMPtr principal; + // In nsIUrlClassifierDBService.lookup, the only use of the principal is to + // wrap the URI. nsISecurityManager.getNoAppCodebasePrincipal is the easiest + // way to wrap a URI inside a principal, since principals can't be + // constructed. + rv = mSecurityManager->GetNoAppCodebasePrincipal(uri, + getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + // Check local lists to see if the URI has already been whitelisted or + // blacklisted. + return mDBService->Lookup(principal, lookup); +} diff --git a/toolkit/components/downloads/ApplicationReputation.h b/toolkit/components/downloads/ApplicationReputation.h index 775cf2fcda25..c6774fb1f882 100644 --- a/toolkit/components/downloads/ApplicationReputation.h +++ b/toolkit/components/downloads/ApplicationReputation.h @@ -11,15 +11,16 @@ #include "nsIRequestObserver.h" #include "nsIStreamListener.h" #include "nsISupports.h" +#include "nsIUrlClassifierDBService.h" +#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsString.h" -class nsIApplicationReputationListener; -class nsIChannel; -class nsIObserverService; class nsIRequest; -class PRLogModuleInfo; +class nsIUrlClassifierDBService; +class nsIScriptSecurityManager; +class PendingLookup; class ApplicationReputationService MOZ_FINAL : public nsIApplicationReputationService { @@ -35,10 +36,16 @@ private: * Global singleton object for holding this factory service. */ static ApplicationReputationService* gApplicationReputationService; - + /** + * Keeps track of services used to query the local database of URLs. + */ + nsCOMPtr mDBService; + nsCOMPtr mSecurityManager; + /** + * This is a singleton, so disallow construction. + */ ApplicationReputationService(); ~ApplicationReputationService(); - /** * Wrapper function for QueryReputation that makes it easier to ensure the * callback is called. @@ -46,53 +53,4 @@ private: nsresult QueryReputationInternal(nsIApplicationReputationQuery* aQuery, nsIApplicationReputationCallback* aCallback); }; - -/** - * This class implements nsIApplicationReputation. See the - * nsIApplicationReputation.idl for details. ApplicationReputation also - * implements nsIStreamListener because it calls nsIChannel->AsyncOpen. - */ -class ApplicationReputationQuery MOZ_FINAL : - public nsIApplicationReputationQuery, - public nsIStreamListener { -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIAPPLICATIONREPUTATIONQUERY - - ApplicationReputationQuery(); - ~ApplicationReputationQuery(); - -private: - /** - * Corresponding member variables for the attributes in the IDL. - */ - nsString mSuggestedFileName; - nsCOMPtr mURI; - uint32_t mFileSize; - nsCString mSha256Hash; - - /** - * The callback for the request. - */ - nsCOMPtr mCallback; - - /** - * The response from the application reputation query. This is read in chunks - * as part of our nsIStreamListener implementation and may contain embedded - * NULLs. - */ - nsCString mResponse; - - /** - * Wrapper function for nsIStreamListener.onStopRequest to make it easy to - * guarantee calling the callback - */ - nsresult OnStopRequestInternal(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aResult, - bool* aShouldBlock); -}; - #endif /* ApplicationReputation_h__ */ diff --git a/toolkit/components/downloads/test/unit/data/digest.chunk b/toolkit/components/downloads/test/unit/data/digest.chunk new file mode 100644 index 000000000000..738c96f6ba17 --- /dev/null +++ b/toolkit/components/downloads/test/unit/data/digest.chunk @@ -0,0 +1,2 @@ +a:5:32:32 +“Ê_Há^˜aÍ7ÂÙ]´=#ÌnmåÃøún‹æo—ÌQ‰ \ No newline at end of file diff --git a/toolkit/components/downloads/test/unit/test_app_rep.js b/toolkit/components/downloads/test/unit/test_app_rep.js index a77a75202e1d..c7155c339bf2 100644 --- a/toolkit/components/downloads/test/unit/test_app_rep.js +++ b/toolkit/components/downloads/test/unit/test_app_rep.js @@ -7,13 +7,47 @@ Cu.import('resource://gre/modules/NetUtil.jsm'); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -const ApplicationReputationQuery = Components.Constructor( - "@mozilla.org/downloads/application-reputation-query;1", - "nsIApplicationReputationQuery"); - const gAppRep = Cc["@mozilla.org/downloads/application-reputation-service;1"]. getService(Ci.nsIApplicationReputationService); let gHttpServ = null; +let gTables = {}; + +function readFileToString(aFilename) { + let f = do_get_file(aFilename); + let stream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + stream.init(f, -1, 0, 0); + let buf = NetUtil.readInputStreamToString(stream, stream.available()); + return buf; +} + +// Registers a table for which to serve update chunks. Returns a promise that +// resolves when that chunk has been downloaded. +function registerTableUpdate(aTable, aFilename) { + // If we haven't been given an update for this table yet, add it to the map + if (!(aTable in gTables)) { + gTables[aTable] = []; + } + + // The number of chunks associated with this table. + let numChunks = gTables[aTable].length + 1; + let redirectPath = "/" + aTable + "-" + numChunks; + let redirectUrl = "localhost:4444" + redirectPath; + + // Store redirect url for that table so we can return it later when we + // process an update request. + gTables[aTable].push(redirectUrl); + + gHttpServ.registerPathHandler(redirectPath, function(request, response) { + do_print("Mock safebrowsing server handling request for " + redirectPath); + let contents = readFileToString(aFilename); + do_print("Length of " + aFilename + ": " + contents.length); + response.setHeader("Content-Type", + "application/vnd.google.safebrowsing-update", false); + response.setStatusLine(request.httpVersion, 200, "OK"); + response.bodyOutputStream.write(contents, contents.length); + }); +} function run_test() { // Set up a local HTTP server to return bad verdicts. @@ -49,13 +83,16 @@ function run_test() { request.bodyInputStream, request.bodyInputStream.available()); do_print("Request length: " + buf.length); - // A garbage response. + // A garbage response. By default this produces NS_CANNOT_CONVERT_DATA as + // the callback status. let blob = "this is not a serialized protocol buffer"; // We can't actually parse the protocol buffer here, so just switch on the // length instead of inspecting the contents. if (buf.length == 35) { + // evil.com blob = createVerdict(true); } else if (buf.length == 38) { + // mozilla.com blob = createVerdict(false); } response.bodyOutputStream.write(blob, blob.length); @@ -67,11 +104,10 @@ function run_test() { } add_test(function test_shouldBlock() { - let query = new ApplicationReputationQuery(); - query.sourceURI = createURI("http://evil.com"); - query.fileSize = 12; - - gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { + gAppRep.queryReputation({ + sourceURI: createURI("http://evil.com"), + fileSize: 12, + }, function onComplete(aShouldBlock, aStatus) { do_check_true(aShouldBlock); do_check_eq(Cr.NS_OK, aStatus); run_next_test(); @@ -79,35 +115,21 @@ add_test(function test_shouldBlock() { }); add_test(function test_shouldNotBlock() { - let query = new ApplicationReputationQuery(); - query.sourceURI = createURI("http://mozilla.com"); - query.fileSize = 12; - - gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { + gAppRep.queryReputation({ + sourceURI: createURI("http://mozilla.com"), + fileSize: 12, + }, function onComplete(aShouldBlock, aStatus) { do_check_eq(Cr.NS_OK, aStatus); do_check_false(aShouldBlock); run_next_test(); }); }); -add_test(function test_garbage() { - let query = new ApplicationReputationQuery(); - query.sourceURI = createURI("http://thisisagarbageurl.com"); - query.fileSize = 12; - - gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { - // We should be getting the garbage response. - do_check_eq(Cr.NS_ERROR_CANNOT_CONVERT_DATA, aStatus); - do_check_false(aShouldBlock); - run_next_test(); - }); -}); - add_test(function test_nullSourceURI() { - let query = new ApplicationReputationQuery(); - query.fileSize = 12; - // No source URI - gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { + gAppRep.queryReputation({ + // No source URI + fileSize: 12, + }, function onComplete(aShouldBlock, aStatus) { do_check_eq(Cr.NS_ERROR_UNEXPECTED, aStatus); do_check_false(aShouldBlock); run_next_test(); @@ -115,10 +137,11 @@ add_test(function test_nullSourceURI() { }); add_test(function test_nullCallback() { - let query = new ApplicationReputationQuery(); - query.fileSize = 12; try { - gAppRep.queryReputation(query, null); + gAppRep.queryReputation({ + sourceURI: createURI("http://example.com"), + fileSize: 12, + }, null); do_throw("Callback cannot be null"); } catch (ex if ex.result == Cr.NS_ERROR_INVALID_POINTER) { run_next_test(); @@ -127,13 +150,92 @@ add_test(function test_nullCallback() { add_test(function test_disabled() { Services.prefs.setCharPref("browser.safebrowsing.appRepURL", ""); - let query = new ApplicationReputationQuery(); - query.sourceURI = createURI("http://example.com"); - query.fileSize = 12; - gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { + gAppRep.queryReputation({ + sourceURI: createURI("http://example.com"), + fileSize: 12, + }, function onComplete(aShouldBlock, aStatus) { // We should be getting NS_ERROR_NOT_AVAILABLE if the service is disabled do_check_eq(Cr.NS_ERROR_NOT_AVAILABLE, aStatus); do_check_false(aShouldBlock); run_next_test(); }); }); + +add_test(function test_garbage() { + Services.prefs.setCharPref("browser.safebrowsing.appRepURL", + "http://localhost:4444/download"); + gAppRep.queryReputation({ + sourceURI: createURI("http://whitelisted.com"), + fileSize: 12, + }, function onComplete(aShouldBlock, aStatus) { + // We should be getting the garbage response. + do_check_eq(Cr.NS_ERROR_CANNOT_CONVERT_DATA, aStatus); + do_check_false(aShouldBlock); + run_next_test(); + }); +}); + +// Set up the local whitelist. +add_test(function test_local_list() { + // Construct a response with redirect urls. + function processUpdateRequest() { + let response = "n:1000\n"; + for (let table in gTables) { + response += "i:" + table + "\n"; + for (let i = 0; i < gTables[table].length; ++i) { + response += "u:" + gTables[table][i] + "\n"; + } + } + do_print("Returning update response: " + response); + return response; + } + gHttpServ.registerPathHandler("/downloads", function(request, response) { + let buf = NetUtil.readInputStreamToString(request.bodyInputStream, + request.bodyInputStream.available()); + let blob = processUpdateRequest(); + response.setHeader("Content-Type", + "application/vnd.google.safebrowsing-update", false); + response.setStatusLine(request.httpVersion, 200, "OK"); + response.bodyOutputStream.write(blob, blob.length); + }); + + let streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"] + .getService(Ci.nsIUrlClassifierStreamUpdater); + streamUpdater.updateUrl = "http://localhost:4444/downloads"; + + // Load up some update chunks for the safebrowsing server to serve. This + // particular chunk contains the hash of whitelisted.com/. + registerTableUpdate("goog-downloadwhite-digest256", "data/digest.chunk"); + + // Download some updates, and don't continue until the downloads are done. + function updateSuccess(aEvent) { + // Timeout of n:1000 is constructed in processUpdateRequest above and + // passed back in the callback in nsIUrlClassifierStreamUpdater on success. + do_check_eq("1000", aEvent); + do_print("All data processed"); + run_next_test(); + } + // Just throw if we ever get an update or download error. + function handleError(aEvent) { + do_throw("We didn't download or update correctly: " + aEvent); + } + streamUpdater.downloadUpdates( + "goog-downloadwhite-digest256", + "goog-downloadwhite-digest256;\n", "", + updateSuccess, handleError, handleError); +}); + +// After being whitelisted, we shouldn't throw. +add_test(function test_local_whitelist() { + Services.prefs.setCharPref("browser.safebrowsing.appRepURL", + "http://localhost:4444/download"); + gAppRep.queryReputation({ + sourceURI: createURI("http://whitelisted.com"), + fileSize: 12, + }, function onComplete(aShouldBlock, aStatus) { + // We would get garbage if this query made it to the remote server. + do_check_eq(Cr.NS_OK, aStatus); + do_check_false(aShouldBlock); + run_next_test(); + }); +}); diff --git a/toolkit/components/url-classifier/moz.build b/toolkit/components/url-classifier/moz.build index 4112828827f8..07ca62105681 100644 --- a/toolkit/components/url-classifier/moz.build +++ b/toolkit/components/url-classifier/moz.build @@ -48,6 +48,12 @@ EXTRA_JS_MODULES += [ 'SafeBrowsing.jsm', ] +EXPORTS += [ + 'Entries.h', + 'LookupCache.h', + 'nsUrlClassifierPrefixSet.h' +] + FAIL_ON_WARNINGS = True LIBXUL_LIBRARY = True From 7fdbdee9beb6b77a9d7fb5d367c16d41d754cde7 Mon Sep 17 00:00:00 2001 From: Monica Chew Date: Wed, 25 Sep 2013 07:03:42 -0700 Subject: [PATCH 08/62] Bug 842828: Mark attributes of nsIApplicationReputationQuery as readonly, remove unused field (r=mossop) --- .../downloads/nsIApplicationReputation.idl | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/toolkit/components/downloads/nsIApplicationReputation.idl b/toolkit/components/downloads/nsIApplicationReputation.idl index b947de9fecb3..b346a8f49416 100644 --- a/toolkit/components/downloads/nsIApplicationReputation.idl +++ b/toolkit/components/downloads/nsIApplicationReputation.idl @@ -43,12 +43,12 @@ interface nsIApplicationReputationService : nsISupports { * downloaded file. nsIApplicationReputationService.Start() may only be called * once with a single query. */ -[scriptable, uuid(857da2c0-cfe5-11e2-8b8b-0800200c9a66)] +[scriptable, uuid(5a054991-e489-4a1c-a0aa-ea7c69b20e3d)] interface nsIApplicationReputationQuery : nsISupports { /* * The nsIURI from which the file was downloaded. This may not be null. */ - attribute nsIURI sourceURI; + readonly attribute nsIURI sourceURI; /* * The target filename for the downloaded file, as inferred from the source @@ -56,24 +56,19 @@ interface nsIApplicationReputationQuery : nsISupports { * is not set by the caller, it will be passed as an empty string but the * query won't produce any useful information. */ - attribute AString suggestedFileName; + readonly attribute AString suggestedFileName; /* * The size of the downloaded file in bytes. */ - attribute unsigned long fileSize; + readonly attribute unsigned long fileSize; /* * The SHA256 hash of the downloaded file in raw bytes. If this is not set by * the caller, it will be passed as an empty string but the query won't * produce any useful information. */ - attribute ACString sha256Hash; - - /** - * The callback object listening to this query. - */ - attribute nsIApplicationReputationCallback callback; + readonly attribute ACString sha256Hash; }; [scriptable, function, uuid(9a228470-cfe5-11e2-8b8b-0800200c9a66)] From 3d2a39baf6afb4186e3275378e0123afed6e66e6 Mon Sep 17 00:00:00 2001 From: Monica Chew Date: Wed, 25 Sep 2013 07:03:45 -0700 Subject: [PATCH 09/62] Bug 842828: Clean up urlclassifier.gethashtables preferences (r=gcp) --- b2g/app/b2g.js | 3 - browser/app/profile/firefox.js | 3 - browser/metro/profile/metro.js | 3 - mobile/android/app/mobile.js | 3 - modules/libpref/src/init/all.js | 6 + .../url-classifier/SafeBrowsing.jsm | 10 +- .../nsUrlClassifierDBService.cpp | 105 +++++++++--------- .../url-classifier/nsUrlClassifierDBService.h | 2 +- 8 files changed, 68 insertions(+), 67 deletions(-) diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 8c528941c8ca..1a5666467b53 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -330,9 +330,6 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); -// The list of tables that use the gethash request to confirm partial results. -pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); - // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 4b9ebbc6ac3a..f13caa8e32f8 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -803,9 +803,6 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); -// The list of tables that use the gethash request to confirm partial results. -pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); - // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/browser/metro/profile/metro.js b/browser/metro/profile/metro.js index c87617f0ca29..346f8a3ef7de 100644 --- a/browser/metro/profile/metro.js +++ b/browser/metro/profile/metro.js @@ -607,9 +607,6 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); -// The list of tables that use the gethash request to confirm partial results. -pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); - // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 000e442e88da..c68a7f9eb4f8 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -600,9 +600,6 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); -// The list of tables that use the gethash request to confirm partial results. -pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); - // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index c5d986b9c736..feca2a6d015b 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -4428,3 +4428,9 @@ pref("dom.telephony.enabled", false); // DOM Inter-App Communication API. pref("dom.inter-app-communication-api.enabled", false); + +// The tables used for Safebrowsing phishing and malware checks. +pref("urlclassifier.malware_table", "goog-malware-shavar"); +pref("urlclassifier.phish_table", "goog-phish-shavar"); +pref("urlclassifier.download_block_table", "goog-badbinurl-shavar"); +pref("urlclassifier.download_allow_table", "goog-downloadwhite-digest256"); diff --git a/toolkit/components/url-classifier/SafeBrowsing.jsm b/toolkit/components/url-classifier/SafeBrowsing.jsm index 099d38da0f62..5f6df334eeb4 100644 --- a/toolkit/components/url-classifier/SafeBrowsing.jsm +++ b/toolkit/components/url-classifier/SafeBrowsing.jsm @@ -10,8 +10,12 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); -const [phishingList, malwareList] = - Services.prefs.getCharPref("urlclassifier.gethashtables").split(",").map(function(value) value.trim()); +const phishingList = Services.prefs.getCharPref("urlclassifier.phish_table"); +const malwareList = Services.prefs.getCharPref("urlclassifier.malware_table"); +const downloadBlockList = + Services.prefs.getCharPref("urlclassifier.download_block_table"); +const downloadAllowList = + Services.prefs.getCharPref("urlclassifier.download_allow_table"); var debug = false; function log(...stuff) { @@ -39,6 +43,8 @@ this.SafeBrowsing = { getService(Ci.nsIUrlListManager); listManager.registerTable(phishingList, false); listManager.registerTable(malwareList, false); + listManager.registerTable(downloadBlockList, false); + listManager.registerTable(downloadAllowList, false); this.addMozEntries(); this.controlUpdateChecking(); diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index fbda1291ff16..e970a9b62849 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -33,6 +33,7 @@ #include "mozilla/Atomics.h" #include "mozilla/DebugOnly.h" #include "mozilla/Mutex.h" +#include "mozilla/Preferences.h" #include "mozilla/TimeStamp.h" #include "mozilla/Telemetry.h" #include "prlog.h" @@ -68,7 +69,10 @@ PRLogModuleInfo *gUrlClassifierDbServiceLog = nullptr; #define GETHASH_NOISE_PREF "urlclassifier.gethashnoise" #define GETHASH_NOISE_DEFAULT 4 -#define GETHASH_TABLES_PREF "urlclassifier.gethashtables" +#define MALWARE_TABLE_PREF "urlclassifier.malware_table" +#define PHISH_TABLE_PREF "urlclassifier.phish_table" +#define DOWNLOAD_BLOCK_TABLE_PREF "urlclassifier.download_block_table" +#define DOWNLOAD_ALLOW_TABLE_PREF "urlclassifier.download_allow_table" #define CONFIRM_AGE_PREF "urlclassifier.max-complete-age" #define CONFIRM_AGE_DEFAULT_SEC (45 * 60) @@ -1115,43 +1119,34 @@ nsUrlClassifierDBService::Init() gUrlClassifierDbServiceLog = PR_NewLogModule("UrlClassifierDbService"); #endif - nsresult rv; + // Retrieve all the preferences. + mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF, + CHECK_MALWARE_DEFAULT); + mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF, + CHECK_PHISHING_DEFAULT); + uint32_t gethashNoise = Preferences::GetUint(GETHASH_NOISE_PREF, + GETHASH_NOISE_DEFAULT); + gFreshnessGuarantee = Preferences::GetInt(CONFIRM_AGE_PREF, + CONFIRM_AGE_DEFAULT_SEC); + mGethashTables.AppendElement(Preferences::GetCString(PHISH_TABLE_PREF)); + mGethashTables.AppendElement(Preferences::GetCString(MALWARE_TABLE_PREF)); + mGethashTables.AppendElement(Preferences::GetCString( + DOWNLOAD_BLOCK_TABLE_PREF)); + mGethashTables.AppendElement(Preferences::GetCString( + DOWNLOAD_ALLOW_TABLE_PREF)); - // Should we check document loads for malware URIs? - nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); - - uint32_t gethashNoise = 0; - if (prefs) { - bool tmpbool; - rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool); - mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT; - - prefs->AddObserver(CHECK_MALWARE_PREF, this, false); - - rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool); - mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT; - - prefs->AddObserver(CHECK_PHISHING_PREF, this, false); - - int32_t tmpint; - rv = prefs->GetIntPref(GETHASH_NOISE_PREF, &tmpint); - gethashNoise = (NS_SUCCEEDED(rv) && tmpint >= 0) ? - static_cast(tmpint) : GETHASH_NOISE_DEFAULT; - - nsXPIDLCString tmpstr; - if (NS_SUCCEEDED(prefs->GetCharPref(GETHASH_TABLES_PREF, getter_Copies(tmpstr)))) { - SplitTables(tmpstr, mGethashWhitelist); - } - - prefs->AddObserver(GETHASH_TABLES_PREF, this, false); - - rv = prefs->GetIntPref(CONFIRM_AGE_PREF, &tmpint); - gFreshnessGuarantee = NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC; - - prefs->AddObserver(CONFIRM_AGE_PREF, this, false); - } + // Do we *really* need to be able to change all of these at runtime? + Preferences::AddStrongObserver(this, CHECK_MALWARE_PREF); + Preferences::AddStrongObserver(this, CHECK_PHISHING_PREF); + Preferences::AddStrongObserver(this, GETHASH_NOISE_PREF); + Preferences::AddStrongObserver(this, CONFIRM_AGE_PREF); + Preferences::AddStrongObserver(this, PHISH_TABLE_PREF); + Preferences::AddStrongObserver(this, MALWARE_TABLE_PREF); + Preferences::AddStrongObserver(this, DOWNLOAD_BLOCK_TABLE_PREF); + Preferences::AddStrongObserver(this, DOWNLOAD_ALLOW_TABLE_PREF); // Force PSM loading on main thread + nsresult rv; nsCOMPtr acryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -1429,7 +1424,7 @@ nsUrlClassifierDBService::GetCompleter(const nsACString &tableName, return true; } - if (!mGethashWhitelist.Contains(tableName)) { + if (!mGethashTables.Contains(tableName)) { return false; } @@ -1446,23 +1441,26 @@ nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic, nsCOMPtr prefs(do_QueryInterface(aSubject, &rv)); NS_ENSURE_SUCCESS(rv, rv); if (NS_LITERAL_STRING(CHECK_MALWARE_PREF).Equals(aData)) { - bool tmpbool; - rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool); - mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT; + mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF, + CHECK_MALWARE_DEFAULT); } else if (NS_LITERAL_STRING(CHECK_PHISHING_PREF).Equals(aData)) { - bool tmpbool; - rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool); - mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT; - } else if (NS_LITERAL_STRING(GETHASH_TABLES_PREF).Equals(aData)) { - mGethashWhitelist.Clear(); - nsXPIDLCString val; - if (NS_SUCCEEDED(prefs->GetCharPref(GETHASH_TABLES_PREF, getter_Copies(val)))) { - SplitTables(val, mGethashWhitelist); - } + mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF, + CHECK_PHISHING_DEFAULT); + } else if (NS_LITERAL_STRING(PHISH_TABLE_PREF).Equals(aData) || + NS_LITERAL_STRING(MALWARE_TABLE_PREF).Equals(aData) || + NS_LITERAL_STRING(DOWNLOAD_BLOCK_TABLE_PREF).Equals(aData) || + NS_LITERAL_STRING(DOWNLOAD_ALLOW_TABLE_PREF).Equals(aData)) { + // Just read everything again. + mGethashTables.Clear(); + mGethashTables.AppendElement(Preferences::GetCString(PHISH_TABLE_PREF)); + mGethashTables.AppendElement(Preferences::GetCString(MALWARE_TABLE_PREF)); + mGethashTables.AppendElement(Preferences::GetCString( + DOWNLOAD_BLOCK_TABLE_PREF)); + mGethashTables.AppendElement(Preferences::GetCString( + DOWNLOAD_ALLOW_TABLE_PREF)); } else if (NS_LITERAL_STRING(CONFIRM_AGE_PREF).Equals(aData)) { - int32_t tmpint; - rv = prefs->GetIntPref(CONFIRM_AGE_PREF, &tmpint); - gFreshnessGuarantee = NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC; + gFreshnessGuarantee = Preferences::GetInt(CONFIRM_AGE_PREF, + CONFIRM_AGE_DEFAULT_SEC); } } else if (!strcmp(aTopic, "profile-before-change") || !strcmp(aTopic, "xpcom-shutdown-threads")) { @@ -1489,7 +1487,10 @@ nsUrlClassifierDBService::Shutdown() if (prefs) { prefs->RemoveObserver(CHECK_MALWARE_PREF, this); prefs->RemoveObserver(CHECK_PHISHING_PREF, this); - prefs->RemoveObserver(GETHASH_TABLES_PREF, this); + prefs->RemoveObserver(PHISH_TABLE_PREF, this); + prefs->RemoveObserver(MALWARE_TABLE_PREF, this); + prefs->RemoveObserver(DOWNLOAD_BLOCK_TABLE_PREF, this); + prefs->RemoveObserver(DOWNLOAD_ALLOW_TABLE_PREF, this); prefs->RemoveObserver(CONFIRM_AGE_PREF, this); } diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.h b/toolkit/components/url-classifier/nsUrlClassifierDBService.h index f3f6a63cda42..a951b2ee4d91 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h @@ -101,7 +101,7 @@ private: bool mInUpdate; // The list of tables that can use the default hash completer object. - nsTArray mGethashWhitelist; + nsTArray mGethashTables; // Thread that we do the updates on. static nsIThread* gDbBackgroundThread; From bba34e47da5228cf3bffd03e63056d63c2181845 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Wed, 25 Sep 2013 16:42:16 +0200 Subject: [PATCH 10/62] Bug 919468 - build issue in CacheStorageService.cpp with logging off, r=michal --- netwerk/cache2/CacheStorageService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index 054950867227..826d322019eb 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -1040,7 +1040,7 @@ CacheStorageService::PurgeOverMemoryLimit() LOG(("CacheStorageService::PurgeOverMemoryLimit")); -#ifdef MOZ_LOGGING +#ifdef PR_LOG TimeStamp start(TimeStamp::Now()); #endif From ef102a8dbff37e367455712dc7abc26e5d30e82b Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Wed, 25 Sep 2013 16:42:17 +0200 Subject: [PATCH 11/62] Bug 919087 - Intermittent TEST-UNEXPECTED-FAIL | test_cache2-22-anon-visit.js, r=michal --- netwerk/test/unit/test_cache2-11-evict-memory.js | 2 +- netwerk/test/unit/test_cache2-12-evict-disk.js | 2 +- netwerk/test/unit/test_cache2-22-anon-visit.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/netwerk/test/unit/test_cache2-11-evict-memory.js b/netwerk/test/unit/test_cache2-11-evict-memory.js index b4ea8f0eef87..c1234a0a3ccf 100644 --- a/netwerk/test/unit/test_cache2-11-evict-memory.js +++ b/netwerk/test/unit/test_cache2-11-evict-memory.js @@ -20,7 +20,7 @@ function run_test() ); }) ); - }); + }, !newCacheBackEndUsed()); asyncOpenCacheEntry("http://mem1/", "memory", Ci.nsICacheStorage.OPEN_NORMALLY, null, new OpenCallback(NEW, "m2m", "m2d", function(entry) { diff --git a/netwerk/test/unit/test_cache2-12-evict-disk.js b/netwerk/test/unit/test_cache2-12-evict-disk.js index d24b7e949575..f7fc468b6481 100644 --- a/netwerk/test/unit/test_cache2-12-evict-disk.js +++ b/netwerk/test/unit/test_cache2-12-evict-disk.js @@ -25,7 +25,7 @@ function run_test() ); }) ); - }); + }, !newCacheBackEndUsed()); asyncOpenCacheEntry("http://mem1/", "memory", Ci.nsICacheStorage.OPEN_NORMALLY, null, new OpenCallback(NEW, "m2m", "m2d", function(entry) { diff --git a/netwerk/test/unit/test_cache2-22-anon-visit.js b/netwerk/test/unit/test_cache2-22-anon-visit.js index d26166ad9150..204ae05f49c2 100644 --- a/netwerk/test/unit/test_cache2-22-anon-visit.js +++ b/netwerk/test/unit/test_cache2-22-anon-visit.js @@ -40,7 +40,7 @@ function run_test() }); } - var mc = new MultipleCallbacks(2, newCacheBackEndUsed() ? checkNewBackEnd : checkOldBackEnd); + var mc = new MultipleCallbacks(2, newCacheBackEndUsed() ? checkNewBackEnd : checkOldBackEnd, !newCacheBackEndUsed()); asyncOpenCacheEntry("http://an2/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, LoadContextInfo.default, new OpenCallback(NEW|WAITFORWRITE, "an2", "an2", function(entry) { From bb2e5fbc55a94e844b276ecf29f5175fababcd7f Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 25 Sep 2013 10:56:57 -0400 Subject: [PATCH 12/62] Backed out changeset 0d924e17bba4 (bug 869613) for checktest failures. --- python/mozbuild/dumbmake/dumbmake.py | 41 ++++------------------------ 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/python/mozbuild/dumbmake/dumbmake.py b/python/mozbuild/dumbmake/dumbmake.py index 5a083a35b38e..f4b2c2e19411 100644 --- a/python/mozbuild/dumbmake/dumbmake.py +++ b/python/mozbuild/dumbmake/dumbmake.py @@ -7,7 +7,6 @@ from __future__ import unicode_literals from collections import OrderedDict from itertools import groupby from operator import itemgetter -from os.path import dirname WHITESPACE_CHARACTERS = ' \t' @@ -62,6 +61,7 @@ def all_dependencies(*targets, **kwargs): all_targets = OrderedDict() # Used as an ordered set. for target in targets: + all_targets[target] = True if target in dm: for dependency in dm[target]: # Move element back in the ordered set. @@ -71,18 +71,6 @@ def all_dependencies(*targets, **kwargs): return all_targets.keys() -def get_components(path): - """Take a path and return all the components of the path.""" - paths = [path] - while True: - parent = dirname(paths[-1]) - if parent == "": - break - paths.append(parent) - - paths.reverse() - return paths - def add_extra_dependencies(target_pairs, dependency_map): """Take a list [(make_dir, make_target)] and expand (make_dir, None) entries with extra make dependencies from |dependency_map|. @@ -90,33 +78,16 @@ def add_extra_dependencies(target_pairs, dependency_map): Returns an iterator of pairs (make_dir, make_target). """ - all_targets = OrderedDict() # Used as an ordered set. - make_dirs = OrderedDict() # Used as an ordered set. - for make_target, group in groupby(target_pairs, itemgetter(1)): # Return non-simple directory targets untouched. if make_target is not None: for pair in group: - # Generate dependencies for all components of a path. - # Given path a/b/c, examine a, a/b, and a/b/c in that order. - paths = get_components(pair[1]) - # For each component of a path, find and add all dependencies - # to the final target list. - for target in paths: - if target not in all_targets: - yield pair[0], target - all_targets[target] = True + yield pair continue # Add extra dumbmake dependencies to simple directory targets. - for make_dir, _ in group: - make_dirs[make_dir] = True + make_dirs = [make_dir for make_dir, _ in group] + new_make_dirs = all_dependencies(*make_dirs, dependency_map=dependency_map) - all_components = [] - for make_dir in make_dirs.iterkeys(): - all_components.extend(get_components(make_dir)) - yield make_dir, None - - for i in all_dependencies(*all_components, dependency_map=dependency_map): - if i not in make_dirs: - yield i, None + for make_dir in new_make_dirs: + yield make_dir, None From 94467d9098dcb267fbae00d23ac5daade9a2c7e1 Mon Sep 17 00:00:00 2001 From: John Hopkins Date: Wed, 25 Sep 2013 11:24:01 -0400 Subject: [PATCH 13/62] Bug 918414 - look for gapi.data on c: then e:. r=catlee --- browser/config/mozconfigs/win32/common-opt | 8 +++++++- browser/config/mozconfigs/win64/common-opt | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/browser/config/mozconfigs/win32/common-opt b/browser/config/mozconfigs/win32/common-opt index d38a0a5bb3e9..e1684a8aae1c 100644 --- a/browser/config/mozconfigs/win32/common-opt +++ b/browser/config/mozconfigs/win32/common-opt @@ -5,7 +5,13 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-jemalloc -ac_add_options --with-google-api-keyfile=/e/builds/gapi.data +if [ -f /c/builds/gapi.data ]; then + _gapi_keyfile=/c/builds/gapi.data +else + _gapi_keyfile=/e/builds/gapi.data +fi +ac_add_options --with-google-api-keyfile=${_gapi_keyfile} + # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 diff --git a/browser/config/mozconfigs/win64/common-opt b/browser/config/mozconfigs/win64/common-opt index 743bc703b2b4..d81e366f4999 100644 --- a/browser/config/mozconfigs/win64/common-opt +++ b/browser/config/mozconfigs/win64/common-opt @@ -5,7 +5,12 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-jemalloc -ac_add_options --with-google-api-keyfile=/e/builds/gapi.data +if [ -f /c/builds/gapi.data ]; then + _gapi_keyfile=/c/builds/gapi.data +else + _gapi_keyfile=/e/builds/gapi.data +fi +ac_add_options --with-google-api-keyfile=${_gapi_keyfile} # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 From fcc11b2aa90369b68be4965db0cfb774223c3f34 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 20 Sep 2013 12:57:30 -0400 Subject: [PATCH 14/62] Bug 919635 - Add manifests for Steeplechase tests to moz.build. r=gps --HG-- extra : rebase_source : 9e0ac924da517d78d0d21e01730a1593ee917b31 --- dom/media/tests/mochitest/moz.build | 1 + dom/media/tests/mochitest/steeplechase.ini | 8 ++++++++ python/mozbuild/mozbuild/frontend/emitter.py | 1 + python/mozbuild/mozbuild/frontend/sandbox_symbols.py | 4 ++++ 4 files changed, 14 insertions(+) create mode 100644 dom/media/tests/mochitest/steeplechase.ini diff --git a/dom/media/tests/mochitest/moz.build b/dom/media/tests/mochitest/moz.build index 895d11993cfb..1a1b43d64b87 100644 --- a/dom/media/tests/mochitest/moz.build +++ b/dom/media/tests/mochitest/moz.build @@ -4,3 +4,4 @@ # 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/. +WEBRTC_SIGNALLING_TEST_MANIFESTS += ['steeplechase.ini'] diff --git a/dom/media/tests/mochitest/steeplechase.ini b/dom/media/tests/mochitest/steeplechase.ini new file mode 100644 index 000000000000..5c8ab931387b --- /dev/null +++ b/dom/media/tests/mochitest/steeplechase.ini @@ -0,0 +1,8 @@ +[DEFAULT] +support-files = + head.js + mediaStreamPlayback.js + pc.js + templates.js + +[test_peerConnection_basicAudio.html] diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index b9747c0f3ed4..b0a9428062ea 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -221,6 +221,7 @@ class TreeMetadataEmitter(LoggingMixin): BROWSER_CHROME=('browser-chrome', 'testing/mochitest/browser', True), MOCHITEST=('mochitest', 'testing/mochitest/tests', True), MOCHITEST_CHROME=('chrome', 'testing/mochitest/chrome', True), + WEBRTC_SIGNALLING_TEST=('steeplechase', 'steeplechase', True), XPCSHELL_TESTS=('xpcshell', 'xpcshell', False), ) diff --git a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py index 3d87b1f3c93d..667b4f3f39e0 100644 --- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py +++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py @@ -467,6 +467,10 @@ VARIABLES = { """List of manifest files defining mochitest chrome tests. """), + 'WEBRTC_SIGNALLING_TEST_MANIFESTS': (StrictOrderingOnAppendList, list, [], + """List of manifest files defining WebRTC signalling tests. + """), + 'XPCSHELL_TESTS_MANIFESTS': (StrictOrderingOnAppendList, list, [], """List of manifest files defining xpcshell tests. """), From 3d318d39acac2ae4a87b6846609966b3296e7628 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 25 Sep 2013 06:57:34 -0400 Subject: [PATCH 15/62] bug 919635 - package Steeplechase tests and extra bits in test package. r=gps --HG-- extra : rebase_source : b0030545c25da1f27c601363c84362470a32aee6 --- testing/testsuite-targets.mk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index c59d865f2371..88a5f2f4702f 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -406,6 +406,7 @@ package-tests: \ stage-marionette \ stage-cppunittests \ stage-jittest \ + stage-steeplechase \ $(NULL) else # This staging area has been built for us by universal/flight.mk @@ -513,6 +514,12 @@ stage-jittest: cp -RL $(topsrcdir)/js/src/tests/ecma_6 $(PKG_STAGE)/jit-test/tests/ecma_6 cp -RL $(topsrcdir)/js/src/tests/lib $(PKG_STAGE)/jit-test/tests/lib +stage-steeplechase: + $(NSINSTALL) -D $(PKG_STAGE)/steeplechase/ + cp -RL $(DEPTH)/_tests/steeplechase $(PKG_STAGE)/steeplechase/tests + cp -RL $(DIST)/xpi-stage/specialpowers $(PKG_STAGE)/steeplechase + cp -RL $(topsrcdir)/testing/profiles/prefs_general.js $(PKG_STAGE)/steeplechase + MARIONETTE_DIR=$(PKG_STAGE)/marionette stage-marionette: make-stage-dir $(NSINSTALL) -D $(MARIONETTE_DIR)/tests @@ -551,5 +558,6 @@ stage-mozbase: make-stage-dir stage-tps \ stage-modules \ stage-marionette \ + stage-steeplechase \ $(NULL) From cfa371035b87f325fe7d4528358c9b87ba348144 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 25 Sep 2013 08:25:46 -0700 Subject: [PATCH 16/62] Bug 917841 - Use overflow-resistant arithmetic in binary searches. r=luke --- js/src/frontend/TokenStream.cpp | 2 +- js/src/jit/BaselineJIT.cpp | 8 ++++---- js/src/jsinferinlines.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 56a590146567..863943dda9ab 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -216,7 +216,7 @@ TokenStream::SourceCoords::lineIndexOf(uint32_t offset) const // want one before that. iMax = lineStartOffsets_.length() - 2; while (iMax > iMin) { - iMid = (iMin + iMax) / 2; + iMid = iMin + (iMax - iMin) / 2; if (offset >= lineStartOffsets_[iMid + 1]) iMin = iMid + 1; // offset is above lineStartOffsets_[iMid] else diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 6c4ef80807b3..bf6056da0b66 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -467,14 +467,14 @@ BaselineScript::maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset) { size_t bottom = 0; size_t top = numICEntries(); - size_t mid = (bottom + top) / 2; + size_t mid = bottom + (top - bottom) / 2; while (mid < top) { ICEntry &midEntry = icEntry(mid); if (midEntry.returnOffset().offset() < returnOffset.offset()) bottom = mid + 1; else // if (midEntry.returnOffset().offset() >= returnOffset.offset()) top = mid; - mid = (bottom + top) / 2; + mid = bottom + (top - bottom) / 2; } if (mid >= numICEntries()) return NULL; @@ -506,7 +506,7 @@ BaselineScript::icEntryFromPCOffset(uint32_t pcOffset) // those which have isForOp() set. size_t bottom = 0; size_t top = numICEntries(); - size_t mid = (bottom + top) / 2; + size_t mid = bottom + (top - bottom) / 2; while (mid < top) { ICEntry &midEntry = icEntry(mid); if (midEntry.pcOffset() < pcOffset) @@ -515,7 +515,7 @@ BaselineScript::icEntryFromPCOffset(uint32_t pcOffset) top = mid; else break; - mid = (bottom + top) / 2; + mid = bottom + (top - bottom) / 2; } // Found an IC entry with a matching PC offset. Search backward, and then // forward from this IC entry, looking for one with the same PC offset which diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index af6791dba80b..edd99090ce9a 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -720,7 +720,7 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc) // Fall back to a binary search. size_t bottom = 0; size_t top = script->nTypeSets - 1; - size_t mid = (bottom + top) / 2; + size_t mid = bottom + (top - bottom) / 2; while (mid < top) { if (bytecodeMap[mid] < offset) bottom = mid + 1; @@ -728,7 +728,7 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc) top = mid; else break; - mid = (bottom + top) / 2; + mid = bottom + (top - bottom) / 2; } // We should have have zeroed in on either the exact offset, unless there From cfa94dca53a78e5277575c4f51f31258c6a31157 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 25 Sep 2013 09:28:34 -0600 Subject: [PATCH 17/62] Bug 867757, Part 2: Gives SPS the ability to immediately sample the current thread's stack and annotate it. r=BenWa --- tools/profiler/BreakpadSampler.cpp | 139 +-- tools/profiler/EHABIStackWalk.h | 7 +- tools/profiler/GeckoProfiler.h | 9 + tools/profiler/GeckoProfilerFunc.h | 5 + tools/profiler/GeckoProfilerImpl.h | 26 +- tools/profiler/Makefile.in | 7 + tools/profiler/ProfileEntry.cpp | 26 +- tools/profiler/ProfileEntry.h | 15 +- tools/profiler/ProfilerBacktrace.cpp | 39 + tools/profiler/ProfilerBacktrace.h | 29 + .../profiler/ProfilerIOInterposeObserver.cpp | 8 +- tools/profiler/ProfilerMarkers.cpp | 79 +- tools/profiler/ProfilerMarkers.h | 49 +- tools/profiler/PseudoStack.h | 111 ++- tools/profiler/SyncProfile.cpp | 65 ++ tools/profiler/SyncProfile.h | 45 + tools/profiler/TableTicker.cpp | 162 +++- tools/profiler/TableTicker.h | 3 + tools/profiler/UnwinderThread2.cpp | 794 ++++++++++-------- tools/profiler/UnwinderThread2.h | 17 + tools/profiler/android-signal-defs.h | 36 - tools/profiler/moz.build | 2 + tools/profiler/platform-linux.cc | 94 ++- tools/profiler/platform-macos.cc | 40 + tools/profiler/platform-win32.cc | 37 +- tools/profiler/platform.cpp | 82 +- tools/profiler/platform.h | 22 +- 27 files changed, 1375 insertions(+), 573 deletions(-) create mode 100644 tools/profiler/ProfilerBacktrace.cpp create mode 100644 tools/profiler/ProfilerBacktrace.h create mode 100644 tools/profiler/SyncProfile.cpp create mode 100644 tools/profiler/SyncProfile.h delete mode 100644 tools/profiler/android-signal-defs.h diff --git a/tools/profiler/BreakpadSampler.cpp b/tools/profiler/BreakpadSampler.cpp index 2b2e515a02df..3cef1cde15e1 100644 --- a/tools/profiler/BreakpadSampler.cpp +++ b/tools/profiler/BreakpadSampler.cpp @@ -10,9 +10,6 @@ #include #include #include -#if defined(ANDROID) -# include "android-signal-defs.h" -#endif // Profiler #include "PlatformMacros.h" @@ -24,6 +21,7 @@ #include "shared-libraries.h" #include "mozilla/StackWalk.h" #include "ProfileEntry.h" +#include "SyncProfile.h" #include "SaveProfileTask.h" #include "UnwinderThread2.h" #include "TableTicker.h" @@ -157,57 +155,53 @@ void genPseudoBacktraceEntries(/*MODIFIED*/UnwinderThreadBuffer* utb, } // RUNS IN SIGHANDLER CONTEXT -void TableTicker::UnwinderTick(TickSample* sample) +static +void populateBuffer(UnwinderThreadBuffer* utb, TickSample* sample, + UTB_RELEASE_FUNC releaseFunction, bool jankOnly) { - if (!sample->threadProfile) { - // Platform doesn't support multithread, so use the main thread profile we created - sample->threadProfile = GetPrimaryThreadProfile(); - } - - ThreadProfile& currThreadProfile = *sample->threadProfile; - - /* Get hold of an empty inter-thread buffer into which to park - the ProfileEntries for this sample. */ - UnwinderThreadBuffer* utb = uwt__acquire_empty_buffer(); - - /* This could fail, if no buffers are currently available, in which - case we must give up right away. We cannot wait for a buffer to - become available, as that risks deadlock. */ - if (!utb) - return; + ThreadProfile& sampledThreadProfile = *sample->threadProfile; + PseudoStack* stack = sampledThreadProfile.GetPseudoStack(); /* Manufacture the ProfileEntries that we will give to the unwinder thread, and park them in |utb|. */ - - // Marker(s) come before the sample - PseudoStack* stack = currThreadProfile.GetPseudoStack(); - ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers(); - while (pendingMarkersList && pendingMarkersList->peek()) { - ProfilerMarker* marker = pendingMarkersList->popHead(); - stack->addStoredMarker(marker); - utb__addEntry( utb, ProfileEntry('m', marker) ); - } - stack->updateGeneration(currThreadProfile.GetGenerationID()); - bool recordSample = true; - if (mJankOnly) { - // if we are on a different event we can discard any temporary samples - // we've kept around - if (sLastSampledEventGeneration != sCurrentEventGeneration) { - // XXX: we also probably want to add an entry to the profile to help - // distinguish which samples are part of the same event. That, or record - // the event generation in each sample - currThreadProfile.erase(); - } - sLastSampledEventGeneration = sCurrentEventGeneration; - recordSample = false; - // only record the events when we have a we haven't seen a tracer - // event for 100ms - if (!sLastTracerEvent.IsNull()) { - TimeDuration delta = sample->timestamp - sLastTracerEvent; - if (delta.ToMilliseconds() > 100.0) { - recordSample = true; + /* Don't process the PeudoStack's markers or honour jankOnly if we're + immediately sampling the current thread. */ + if (!sample->isSamplingCurrentThread) { + // LinkedUWTBuffers before markers + UWTBufferLinkedList* syncBufs = stack->getLinkedUWTBuffers(); + while (syncBufs && syncBufs->peek()) { + LinkedUWTBuffer* syncBuf = syncBufs->popHead(); + utb__addEntry(utb, ProfileEntry('B', syncBuf->GetBuffer())); + } + // Marker(s) come before the sample + ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers(); + while (pendingMarkersList && pendingMarkersList->peek()) { + ProfilerMarker* marker = pendingMarkersList->popHead(); + stack->addStoredMarker(marker); + utb__addEntry( utb, ProfileEntry('m', marker) ); + } + stack->updateGeneration(sampledThreadProfile.GetGenerationID()); + if (jankOnly) { + // if we are on a different event we can discard any temporary samples + // we've kept around + if (sLastSampledEventGeneration != sCurrentEventGeneration) { + // XXX: we also probably want to add an entry to the profile to help + // distinguish which samples are part of the same event. That, or record + // the event generation in each sample + sampledThreadProfile.erase(); + } + sLastSampledEventGeneration = sCurrentEventGeneration; + + recordSample = false; + // only record the events when we have a we haven't seen a tracer + // event for 100ms + if (!sLastTracerEvent.IsNull()) { + TimeDuration delta = sample->timestamp - sLastTracerEvent; + if (delta.ToMilliseconds() > 100.0) { + recordSample = true; + } } } } @@ -304,12 +298,57 @@ void TableTicker::UnwinderTick(TickSample* sample) # else # error "Unsupported platform" # endif - uwt__release_full_buffer(&currThreadProfile, utb, ucV); + releaseFunction(&sampledThreadProfile, utb, ucV); } else { - uwt__release_full_buffer(&currThreadProfile, utb, NULL); + releaseFunction(&sampledThreadProfile, utb, NULL); } } +static +void sampleCurrent(TickSample* sample) +{ + // This variant requires sample->threadProfile to be set + MOZ_ASSERT(sample->threadProfile); + LinkedUWTBuffer* syncBuf = utb__acquire_sync_buffer(tlsStackTop.get()); + if (!syncBuf) { + return; + } + SyncProfile* syncProfile = sample->threadProfile->AsSyncProfile(); + MOZ_ASSERT(syncProfile); + if (!syncProfile->SetUWTBuffer(syncBuf)) { + utb__release_sync_buffer(syncBuf); + return; + } + UnwinderThreadBuffer* utb = syncBuf->GetBuffer(); + populateBuffer(utb, sample, &utb__finish_sync_buffer, false); +} + +// RUNS IN SIGHANDLER CONTEXT +void TableTicker::UnwinderTick(TickSample* sample) +{ + if (sample->isSamplingCurrentThread) { + sampleCurrent(sample); + return; + } + + if (!sample->threadProfile) { + // Platform doesn't support multithread, so use the main thread profile we created + sample->threadProfile = GetPrimaryThreadProfile(); + } + + /* Get hold of an empty inter-thread buffer into which to park + the ProfileEntries for this sample. */ + UnwinderThreadBuffer* utb = uwt__acquire_empty_buffer(); + + /* This could fail, if no buffers are currently available, in which + case we must give up right away. We cannot wait for a buffer to + become available, as that risks deadlock. */ + if (!utb) + return; + + populateBuffer(utb, sample, &uwt__release_full_buffer, mJankOnly); +} + // END take samples //////////////////////////////////////////////////////////////////////// diff --git a/tools/profiler/EHABIStackWalk.h b/tools/profiler/EHABIStackWalk.h index 0bcc29d2e041..5529d9511f94 100644 --- a/tools/profiler/EHABIStackWalk.h +++ b/tools/profiler/EHABIStackWalk.h @@ -14,12 +14,7 @@ #define mozilla_EHABIStackWalk_h__ #include - -#ifdef ANDROID -# include "android-signal-defs.h" -#else -# include -#endif +#include namespace mozilla { diff --git a/tools/profiler/GeckoProfiler.h b/tools/profiler/GeckoProfiler.h index 220e85671b04..3981239c64a3 100644 --- a/tools/profiler/GeckoProfiler.h +++ b/tools/profiler/GeckoProfiler.h @@ -108,6 +108,14 @@ static inline void profiler_start(int aProfileEntries, double aInterval, // to retrieve the profile. static inline void profiler_stop() {} +class ProfilerBacktrace; + +// Immediately capture the current thread's call stack and return it +static inline ProfilerBacktrace* profiler_get_backtrace() { return nullptr; } + +// Free a ProfilerBacktrace returned by profiler_get_backtrace() +static inline void profiler_free_backtrace(ProfilerBacktrace* aBacktrace) {} + static inline bool profiler_is_active() { return false; } // Internal-only. Used by the event tracer. @@ -150,6 +158,7 @@ static inline void profiler_unregister_thread() {} static inline void profiler_js_operation_callback() {} static inline double profiler_time() { return 0; } +static inline double profiler_time(const mozilla::TimeStamp& aTime) { return 0; } static inline bool profiler_in_privacy_mode() { return false; } diff --git a/tools/profiler/GeckoProfilerFunc.h b/tools/profiler/GeckoProfilerFunc.h index 2cdca492e5a5..97bb88a9df85 100644 --- a/tools/profiler/GeckoProfilerFunc.h +++ b/tools/profiler/GeckoProfilerFunc.h @@ -18,6 +18,7 @@ class TimeStamp; using mozilla::TimeStamp; using mozilla::TimeDuration; +class ProfilerBacktrace; class ProfilerMarkerPayload; // Returns a handle to pass on exit. This can check that we are popping the @@ -33,6 +34,9 @@ void mozilla_sampler_start(int aEntries, double aInterval, void mozilla_sampler_stop(); +ProfilerBacktrace* mozilla_sampler_get_backtrace(); +void mozilla_sampler_free_backtrace(ProfilerBacktrace* aBacktrace); + bool mozilla_sampler_is_active(); void mozilla_sampler_responsiveness(const TimeStamp& time); @@ -69,6 +73,7 @@ bool mozilla_sampler_register_thread(const char* name, void* stackTop); void mozilla_sampler_unregister_thread(); double mozilla_sampler_time(); +double mozilla_sampler_time(const TimeStamp& aTime); /* Returns true if env var SPS_NEW is set to anything, else false. */ extern bool sps_version2(); diff --git a/tools/profiler/GeckoProfilerImpl.h b/tools/profiler/GeckoProfilerImpl.h index de9716eb5a38..823a0708cbe1 100644 --- a/tools/profiler/GeckoProfilerImpl.h +++ b/tools/profiler/GeckoProfilerImpl.h @@ -32,7 +32,6 @@ #undef min #endif -struct PseudoStack; class TableTicker; class JSCustomObject; @@ -42,6 +41,7 @@ class TimeStamp; extern mozilla::ThreadLocal tlsPseudoStack; extern mozilla::ThreadLocal tlsTicker; +extern mozilla::ThreadLocal tlsStackTop; extern bool stack_key_initialized; #ifndef SAMPLE_FUNCTION_NAME @@ -80,6 +80,18 @@ void profiler_stop() mozilla_sampler_stop(); } +static inline +ProfilerBacktrace* profiler_get_backtrace() +{ + return mozilla_sampler_get_backtrace(); +} + +static inline +void profiler_free_backtrace(ProfilerBacktrace* aBacktrace) +{ + mozilla_sampler_free_backtrace(aBacktrace); +} + static inline bool profiler_is_active() { @@ -87,7 +99,7 @@ bool profiler_is_active() } static inline -void profiler_responsiveness(const TimeStamp& aTime) +void profiler_responsiveness(const mozilla::TimeStamp& aTime) { mozilla_sampler_responsiveness(aTime); } @@ -173,6 +185,12 @@ double profiler_time() return mozilla_sampler_time(); } +static inline +double profiler_time(const mozilla::TimeStamp& aTime) +{ + return mozilla_sampler_time(aTime); +} + static inline bool profiler_in_privacy_mode() { @@ -212,6 +230,10 @@ bool profiler_in_privacy_mode() # define PROFILE_DEFAULT_ENTRY 100000 #endif +// In the case of profiler_get_backtrace we know that we only need enough space +// for a single backtrace. +#define GET_BACKTRACE_DEFAULT_ENTRY 1000 + #if defined(PLATFORM_LIKELY_MEMORY_CONSTRAINED) /* A 1ms sampling interval has been shown to be a large perf hit * (10fps) on memory-contrained (low-end) platforms, and additionally diff --git a/tools/profiler/Makefile.in b/tools/profiler/Makefile.in index 1fa86f9c1194..9434ff95d7af 100644 --- a/tools/profiler/Makefile.in +++ b/tools/profiler/Makefile.in @@ -12,6 +12,13 @@ LOCAL_INCLUDES += \ -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src \ $(NULL) +# We need access to Breakpad's getcontext(3) which is suitable for Android +ifeq ($(OS_TARGET),Android) +LOCAL_INCLUDES += \ + -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src/common/android/include \ + $(NULL) +endif + ifneq (,$(filter armeabi,$(ANDROID_CPU_ARCH))) DEFINES += -DARCH_ARMV6 endif diff --git a/tools/profiler/ProfileEntry.cpp b/tools/profiler/ProfileEntry.cpp index 25c99037a73a..0f933d1dd012 100644 --- a/tools/profiler/ProfileEntry.cpp +++ b/tools/profiler/ProfileEntry.cpp @@ -91,8 +91,9 @@ void ProfileEntry::log() // There is no compiler enforced mapping between tag chars // and union variant fields, so the following was derived // by looking through all the use points of TableTicker.cpp. - // mTagData (const char*) m,c,s - // mTagPtr (void*) d,l,L, S(start-of-stack) + // mTagMarker (ProfilerMarker*) m + // mTagData (const char*) c,s + // mTagPtr (void*) d,l,L,B (immediate backtrace), S(start-of-stack) // mTagLine (int) n,f // mTagChar (char) h // mTagFloat (double) r,t @@ -101,7 +102,7 @@ void ProfileEntry::log() LOGF("%c \"%s\"", mTagName, mTagMarker->GetMarkerName()); break; case 'c': case 's': LOGF("%c \"%s\"", mTagName, mTagData); break; - case 'd': case 'l': case 'L': case 'S': + case 'd': case 'l': case 'L': case 'B': case 'S': LOGF("%c %p", mTagName, mTagPtr); break; case 'n': case 'f': LOGF("%c %d", mTagName, mTagLine); break; @@ -143,7 +144,7 @@ std::ostream& operator<<(std::ostream& stream, const ProfileEntry& entry) #define DYNAMIC_MAX_STRING 512 ThreadProfile::ThreadProfile(const char* aName, int aEntrySize, - PseudoStack *aStack, int aThreadId, + PseudoStack *aStack, Thread::tid_t aThreadId, PlatformData* aPlatform, bool aIsMainThread, void *aStackTop) : mWritePos(0) @@ -323,8 +324,9 @@ JSObject* ThreadProfile::ToJSObject(JSContext *aCx) } template -void ThreadProfile::BuildJSObject(Builder& b, typename Builder::ObjectHandle profile) { - +void ThreadProfile::BuildJSObject(Builder& b, + typename Builder::ObjectHandle profile) +{ // Thread meta data if (XRE_GetProcessType() == GeckoProcessType_Plugin) { // TODO Add the proper plugin name @@ -333,7 +335,7 @@ void ThreadProfile::BuildJSObject(Builder& b, typename Builder::ObjectHandle pro b.DefineProperty(profile, "name", mName); } - b.DefineProperty(profile, "tid", mThreadId); + b.DefineProperty(profile, "tid", static_cast(mThreadId)); typename Builder::RootedArray samples(b.context(), b.CreateArray()); b.DefineProperty(profile, "samples", samples); @@ -442,6 +444,16 @@ PseudoStack* ThreadProfile::GetPseudoStack() return mPseudoStack; } +void ThreadProfile::BeginUnwind() +{ + mMutex.Lock(); +} + +void ThreadProfile::EndUnwind() +{ + mMutex.Unlock(); +} + mozilla::Mutex* ThreadProfile::GetMutex() { return &mMutex; diff --git a/tools/profiler/ProfileEntry.h b/tools/profiler/ProfileEntry.h index 0a53cdac827f..c43c0e27a36e 100644 --- a/tools/profiler/ProfileEntry.h +++ b/tools/profiler/ProfileEntry.h @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; 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/. */ @@ -9,6 +10,7 @@ #include #include "GeckoProfilerImpl.h" #include "platform.h" +#include "ProfilerBacktrace.h" #include "mozilla/Mutex.h" class ThreadProfile; @@ -62,9 +64,9 @@ class ThreadProfile { public: ThreadProfile(const char* aName, int aEntrySize, PseudoStack *aStack, - int aThreadId, PlatformData* aPlatformData, + Thread::tid_t aThreadId, PlatformData* aPlatformData, bool aIsMainThread, void *aStackTop); - ~ThreadProfile(); + virtual ~ThreadProfile(); void addTag(ProfileEntry aTag); void flush(); void erase(); @@ -77,10 +79,13 @@ public: PseudoStack* GetPseudoStack(); mozilla::Mutex* GetMutex(); template void BuildJSObject(Builder& b, typename Builder::ObjectHandle profile); + void BeginUnwind(); + virtual void EndUnwind(); + virtual SyncProfile* AsSyncProfile() { return nullptr; } bool IsMainThread() const { return mIsMainThread; } const char* Name() const { return mName; } - int ThreadId() const { return mThreadId; } + Thread::tid_t ThreadId() const { return mThreadId; } PlatformData* GetPlatformData() { return mPlatformData; } int GetGenerationID() const { return mGeneration; } @@ -91,7 +96,7 @@ public: private: // Circular buffer 'Keep One Slot Open' implementation // for simplicity - ProfileEntry* mEntries; + ProfileEntry* mEntries; int mWritePos; // points to the next entry we will write to int mLastFlushPos; // points to the next entry since the last flush() int mReadPos; // points to the next entry we will read to @@ -99,7 +104,7 @@ private: PseudoStack* mPseudoStack; mozilla::Mutex mMutex; char* mName; - int mThreadId; + Thread::tid_t mThreadId; bool mIsMainThread; PlatformData* mPlatformData; // Platform specific data. int mGeneration; diff --git a/tools/profiler/ProfilerBacktrace.cpp b/tools/profiler/ProfilerBacktrace.cpp new file mode 100644 index 000000000000..b3c9b8d53963 --- /dev/null +++ b/tools/profiler/ProfilerBacktrace.cpp @@ -0,0 +1,39 @@ +/* -*- 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/. */ + +#include "JSCustomObjectBuilder.h" +#include "JSObjectBuilder.h" +#include "ProfilerBacktrace.h" +#include "SyncProfile.h" + +ProfilerBacktrace::ProfilerBacktrace(SyncProfile* aProfile) + : mProfile(aProfile) +{ + MOZ_ASSERT(aProfile); +} + +ProfilerBacktrace::~ProfilerBacktrace() +{ + if (mProfile->ShouldDestroy()) { + delete mProfile; + } +} + +template void +ProfilerBacktrace::BuildJSObject(Builder& aObjBuilder, + typename Builder::ObjectHandle aScope) +{ + mozilla::MutexAutoLock lock(*mProfile->GetMutex()); + mProfile->BuildJSObject(aObjBuilder, aScope); +} + +template void +ProfilerBacktrace::BuildJSObject( + JSCustomObjectBuilder& aObjBuilder, + JSCustomObjectBuilder::ObjectHandle aScope); +template void +ProfilerBacktrace::BuildJSObject(JSObjectBuilder& aObjBuilder, + JSObjectBuilder::ObjectHandle aScope); diff --git a/tools/profiler/ProfilerBacktrace.h b/tools/profiler/ProfilerBacktrace.h new file mode 100644 index 000000000000..8e5c8c4d3aaf --- /dev/null +++ b/tools/profiler/ProfilerBacktrace.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 2; 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 __PROFILER_BACKTRACE_H +#define __PROFILER_BACKTRACE_H + +class SyncProfile; + +class ProfilerBacktrace +{ +public: + ProfilerBacktrace(SyncProfile* aProfile); + ~ProfilerBacktrace(); + + template void + BuildJSObject(Builder& aObjBuilder, typename Builder::ObjectHandle aScope); + +private: + ProfilerBacktrace(const ProfilerBacktrace&); + ProfilerBacktrace& operator=(const ProfilerBacktrace&); + + SyncProfile* mProfile; +}; + +#endif // __PROFILER_BACKTRACE_H + diff --git a/tools/profiler/ProfilerIOInterposeObserver.cpp b/tools/profiler/ProfilerIOInterposeObserver.cpp index 825fe6b6f935..ebd97a979f26 100644 --- a/tools/profiler/ProfilerIOInterposeObserver.cpp +++ b/tools/profiler/ProfilerIOInterposeObserver.cpp @@ -4,6 +4,7 @@ #include "GeckoProfiler.h" #include "ProfilerIOInterposeObserver.h" +#include "ProfilerMarkers.h" using namespace mozilla; @@ -13,6 +14,11 @@ void ProfilerIOInterposeObserver::Observe(Observation& aObservation) // well as noting what files or references causes the IO. if (NS_IsMainThread()) { const char* ops[] = {"none", "read", "write", "invalid", "fsync"}; - PROFILER_MARKER(ops[aObservation.ObservedOperation()]); + ProfilerBacktrace* stack = profiler_get_backtrace(); + IOMarkerPayload* markerPayload = new IOMarkerPayload(aObservation.Reference(), + aObservation.Start(), + aObservation.End(), + stack); + PROFILER_MARKER_PAYLOAD(ops[aObservation.ObservedOperation()], markerPayload); } } diff --git a/tools/profiler/ProfilerMarkers.cpp b/tools/profiler/ProfilerMarkers.cpp index 8df1af44a596..a865455af68b 100644 --- a/tools/profiler/ProfilerMarkers.cpp +++ b/tools/profiler/ProfilerMarkers.cpp @@ -3,8 +3,60 @@ * 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 "GeckoProfiler.h" +#include "ProfilerBacktrace.h" #include "ProfilerMarkers.h" #include "gfxASurface.h" +#include "SyncProfile.h" + +ProfilerMarkerPayload::ProfilerMarkerPayload(ProfilerBacktrace* aStack) + : mStack(aStack) +{} + +ProfilerMarkerPayload::ProfilerMarkerPayload(const mozilla::TimeStamp& aStartTime, + const mozilla::TimeStamp& aEndTime, + ProfilerBacktrace* aStack) + : mStartTime(aStartTime), + mEndTime(aEndTime), + mStack(aStack) +{} + +ProfilerMarkerPayload::~ProfilerMarkerPayload() +{ + profiler_free_backtrace(mStack); +} + +template void +ProfilerMarkerPayload::prepareCommonProps(const char* aMarkerType, + Builder& aBuilder, + typename Builder::ObjectHandle aObject) +{ + MOZ_ASSERT(aMarkerType); + aBuilder.DefineProperty(aObject, "type", aMarkerType); + if (!mStartTime.IsNull()) { + aBuilder.DefineProperty(aObject, "startTime", profiler_time(mStartTime)); + } + if (!mEndTime.IsNull()) { + aBuilder.DefineProperty(aObject, "endTime", profiler_time(mEndTime)); + } + if (mStack) { + typename Builder::RootedObject stack(aBuilder.context(), + aBuilder.CreateObject()); + aBuilder.DefineProperty(aObject, "stack", stack); + mStack->BuildJSObject(aBuilder, stack); + } +} + +template void +ProfilerMarkerPayload::prepareCommonProps( + const char* aMarkerType, + JSCustomObjectBuilder& b, + JSCustomObjectBuilder::ObjectHandle aObject); +template void +ProfilerMarkerPayload::prepareCommonProps( + const char* aMarkerType, + JSObjectBuilder& b, + JSObjectBuilder::ObjectHandle aObject); ProfilerMarkerImagePayload::ProfilerMarkerImagePayload(gfxASurface *aImg) : mImg(aImg) @@ -15,7 +67,7 @@ typename Builder::Object ProfilerMarkerImagePayload::preparePayloadImp(Builder& b) { typename Builder::RootedObject data(b.context(), b.CreateObject()); - b.DefineProperty(data, "type", "innerHTML"); + prepareCommonProps("innerHTML", b, data); // TODO: Finish me //b.DefineProperty(data, "innerHTML", ""); return data; @@ -26,3 +78,28 @@ ProfilerMarkerImagePayload::preparePayloadImp(JSCustomObj template JSObjectBuilder::Object ProfilerMarkerImagePayload::preparePayloadImp(JSObjectBuilder& b); +IOMarkerPayload::IOMarkerPayload(const char* aSource, + const mozilla::TimeStamp& aStartTime, + const mozilla::TimeStamp& aEndTime, + ProfilerBacktrace* aStack) + : ProfilerMarkerPayload(aStartTime, aEndTime, aStack), + mSource(aSource) +{ + MOZ_ASSERT(aSource); +} + +template typename Builder::Object +IOMarkerPayload::preparePayloadImp(Builder& b) +{ + typename Builder::RootedObject data(b.context(), b.CreateObject()); + prepareCommonProps("io", b, data); + b.DefineProperty(data, "source", mSource); + + return data; +} + +template JSCustomObjectBuilder::Object +IOMarkerPayload::preparePayloadImp(JSCustomObjectBuilder& b); +template JSObjectBuilder::Object +IOMarkerPayload::preparePayloadImp(JSObjectBuilder& b); + diff --git a/tools/profiler/ProfilerMarkers.h b/tools/profiler/ProfilerMarkers.h index bd76dd279b09..f7f5ed04a7e5 100644 --- a/tools/profiler/ProfilerMarkers.h +++ b/tools/profiler/ProfilerMarkers.h @@ -8,6 +8,7 @@ #include "JSCustomObjectBuilder.h" #include "JSObjectBuilder.h" +#include "mozilla/TimeStamp.h" #include "nsAutoPtr.h" /** @@ -22,14 +23,21 @@ * on a particular thread but 'preparePayload' and the destructor * is called from the main thread. */ -class ProfilerMarkerPayload { +class ProfilerMarkerPayload +{ public: - ProfilerMarkerPayload() {} + /** + * ProfilerMarkerPayload takes ownership of aStack + */ + ProfilerMarkerPayload(ProfilerBacktrace* aStack = nullptr); + ProfilerMarkerPayload(const mozilla::TimeStamp& aStartTime, + const mozilla::TimeStamp& aEndTime, + ProfilerBacktrace* aStack = nullptr); /** * Called from the main thread */ - virtual ~ProfilerMarkerPayload() {} + virtual ~ProfilerMarkerPayload(); /** * Called from the main thread @@ -41,6 +49,13 @@ public: } protected: + /** + * Called from the main thread + */ + template + void prepareCommonProps(const char* aMarkerType, Builder& aBuilder, + typename Builder::ObjectHandle aObject); + /** * Called from the main thread */ @@ -52,10 +67,16 @@ protected: */ virtual JSObjectBuilder::Object preparePayload(JSObjectBuilder& b) = 0; + +private: + mozilla::TimeStamp mStartTime; + mozilla::TimeStamp mEndTime; + ProfilerBacktrace* mStack; }; class gfxASurface; -class ProfilerMarkerImagePayload : public ProfilerMarkerPayload { +class ProfilerMarkerImagePayload : public ProfilerMarkerPayload +{ public: ProfilerMarkerImagePayload(gfxASurface *aImg); @@ -72,4 +93,24 @@ private: nsRefPtr mImg; }; +class IOMarkerPayload : public ProfilerMarkerPayload +{ +public: + IOMarkerPayload(const char* aSource, const mozilla::TimeStamp& aStartTime, + const mozilla::TimeStamp& aEndTime, + ProfilerBacktrace* aStack); + +protected: + virtual JSCustomObjectBuilder::Object + preparePayload(JSCustomObjectBuilder& b) { return preparePayloadImp(b); } + virtual JSObjectBuilder::Object + preparePayload(JSObjectBuilder& b) { return preparePayloadImp(b); } + +private: + template + typename Builder::Object preparePayloadImp(Builder& b); + + const char* mSource; +}; + #endif // PROFILER_MARKERS_H diff --git a/tools/profiler/PseudoStack.h b/tools/profiler/PseudoStack.h index 24a2b24be139..6e271c080ca2 100644 --- a/tools/profiler/PseudoStack.h +++ b/tools/profiler/PseudoStack.h @@ -101,12 +101,13 @@ public: }; class ProfilerMarkerPayload; -class ProfilerMarkerLinkedList; +template +class ProfilerLinkedList; class JSAObjectBuilder; class JSCustomArray; class ThreadProfile; class ProfilerMarker { - friend class ProfilerMarkerLinkedList; + friend class ProfilerLinkedList; public: ProfilerMarker(const char* aMarkerName, ProfilerMarkerPayload* aPayload = nullptr); @@ -133,25 +134,73 @@ private: int mGenID; }; -class ProfilerMarkerLinkedList { +// Foward declaration +typedef struct _UnwinderThreadBuffer UnwinderThreadBuffer; + +/** + * This struct is used to add a mNext field to UnwinderThreadBuffer objects for + * use with ProfilerLinkedList. It is done this way so that UnwinderThreadBuffer + * may continue to be opaque with respect to code outside of UnwinderThread2.cpp + */ +struct LinkedUWTBuffer +{ + LinkedUWTBuffer() + :mNext(nullptr) + {} + virtual ~LinkedUWTBuffer() {} + virtual UnwinderThreadBuffer* GetBuffer() = 0; + LinkedUWTBuffer* mNext; +}; + +template +class ProfilerLinkedList { public: - ProfilerMarkerLinkedList() + ProfilerLinkedList() : mHead(nullptr) , mTail(nullptr) {} - void insert(ProfilerMarker* elem); - ProfilerMarker* popHead(); + void insert(T* elem) + { + if (!mTail) { + mHead = elem; + mTail = elem; + } else { + mTail->mNext = elem; + mTail = elem; + } + elem->mNext = nullptr; + } - const ProfilerMarker* peek() { + T* popHead() + { + if (!mHead) { + MOZ_ASSERT(false); + return nullptr; + } + + T* head = mHead; + + mHead = head->mNext; + if (!mHead) { + mTail = nullptr; + } + + return head; + } + + const T* peek() { return mHead; } private: - ProfilerMarker* mHead; - ProfilerMarker* mTail; + T* mHead; + T* mTail; }; +typedef ProfilerLinkedList ProfilerMarkerLinkedList; +typedef ProfilerLinkedList UWTBufferLinkedList; + class PendingMarkers { public: PendingMarkers() @@ -206,6 +255,38 @@ private: volatile mozilla::sig_safe_t mGenID; }; +class PendingUWTBuffers +{ +public: + PendingUWTBuffers() + : mSignalLock(false) + { + } + + void addLinkedUWTBuffer(LinkedUWTBuffer* aBuff) + { + MOZ_ASSERT(aBuff); + mSignalLock = true; + STORE_SEQUENCER(); + mPendingUWTBuffers.insert(aBuff); + STORE_SEQUENCER(); + mSignalLock = false; + } + + // called within signal. Function must be reentrant + UWTBufferLinkedList* getLinkedUWTBuffers() + { + if (mSignalLock) { + return nullptr; + } + return &mPendingUWTBuffers; + } + +private: + UWTBufferLinkedList mPendingUWTBuffers; + volatile bool mSignalLock; +}; + // the PseudoStack members are read by signal // handlers, so the mutation of them needs to be signal-safe. struct PseudoStack @@ -228,6 +309,16 @@ public: } } + void addLinkedUWTBuffer(LinkedUWTBuffer* aBuff) + { + mPendingUWTBuffers.addLinkedUWTBuffer(aBuff); + } + + UWTBufferLinkedList* getLinkedUWTBuffers() + { + return mPendingUWTBuffers.getLinkedUWTBuffers(); + } + void addMarker(const char *aMarkerStr, ProfilerMarkerPayload *aPayload) { ProfilerMarker* marker = new ProfilerMarker(aMarkerStr, aPayload); @@ -322,6 +413,8 @@ public: // Keep a list of pending markers that must be moved // to the circular buffer PendingMarkers mPendingMarkers; + // List of LinkedUWTBuffers that must be processed on the next tick + PendingUWTBuffers mPendingUWTBuffers; // This may exceed the length of mStack, so instead use the stackSize() method // to determine the number of valid samples in mStack mozilla::sig_safe_t mStackPointer; diff --git a/tools/profiler/SyncProfile.cpp b/tools/profiler/SyncProfile.cpp new file mode 100644 index 000000000000..96d5d4d57c72 --- /dev/null +++ b/tools/profiler/SyncProfile.cpp @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "SyncProfile.h" +#include "UnwinderThread2.h" + +SyncProfile::SyncProfile(const char* aName, int aEntrySize, PseudoStack *aStack, + Thread::tid_t aThreadId, bool aIsMainThread) + : ThreadProfile(aName, aEntrySize, aStack, aThreadId, + Sampler::AllocPlatformData(aThreadId), aIsMainThread, + tlsStackTop.get()), + mOwnerState(REFERENCED), + mUtb(nullptr) +{ +} + +SyncProfile::~SyncProfile() +{ + if (mUtb) { + utb__release_sync_buffer(mUtb); + } + Sampler::FreePlatformData(GetPlatformData()); +} + +bool +SyncProfile::SetUWTBuffer(LinkedUWTBuffer* aBuff) +{ + MOZ_ASSERT(aBuff); + mUtb = aBuff; + return true; +} + +bool +SyncProfile::ShouldDestroy() +{ + GetMutex()->AssertNotCurrentThreadOwns(); + mozilla::MutexAutoLock lock(*GetMutex()); + if (mOwnerState == OWNED) { + mOwnerState = OWNER_DESTROYING; + return true; + } + mOwnerState = ORPHANED; + return false; +} + +void +SyncProfile::EndUnwind() +{ + // Mutex must be held when this is called + GetMutex()->AssertCurrentThreadOwns(); + if (mOwnerState != ORPHANED) { + flush(); + mOwnerState = OWNED; + } + // Save mOwnerState before we release the mutex + OwnerState ownerState = mOwnerState; + ThreadProfile::EndUnwind(); + if (ownerState == ORPHANED) { + delete this; + } +} + diff --git a/tools/profiler/SyncProfile.h b/tools/profiler/SyncProfile.h new file mode 100644 index 000000000000..bb1585be8a7e --- /dev/null +++ b/tools/profiler/SyncProfile.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; 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 __SYNCPROFILE_H +#define __SYNCPROFILE_H + +#include "ProfileEntry.h" + +struct LinkedUWTBuffer; + +class SyncProfile : public ThreadProfile +{ +public: + SyncProfile(const char* aName, int aEntrySize, PseudoStack *aStack, + Thread::tid_t aThreadId, bool aIsMainThread); + ~SyncProfile(); + + bool SetUWTBuffer(LinkedUWTBuffer* aBuff); + LinkedUWTBuffer* GetUWTBuffer() { return mUtb; } + + virtual void EndUnwind(); + virtual SyncProfile* AsSyncProfile() { return this; } + +private: + friend class ProfilerBacktrace; + + enum OwnerState + { + REFERENCED, // ProfilerBacktrace has a pointer to this but doesn't own + OWNED, // ProfilerBacktrace is responsible for destroying this + OWNER_DESTROYING, // ProfilerBacktrace owns this and is destroying + ORPHANED // No owner, we must destroy ourselves + }; + + bool ShouldDestroy(); + + OwnerState mOwnerState; + LinkedUWTBuffer* mUtb; +}; + +#endif // __SYNCPROFILE_H + diff --git a/tools/profiler/TableTicker.cpp b/tools/profiler/TableTicker.cpp index 493ad2866a00..c7efe291af72 100644 --- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -10,6 +10,7 @@ #include "GeckoProfilerImpl.h" #include "SaveProfileTask.h" #include "ProfileEntry.h" +#include "SyncProfile.h" #include "platform.h" #include "nsThreadUtils.h" #include "prenv.h" @@ -50,6 +51,18 @@ #include "nsStackWalk.h" #endif +#if defined(XP_WIN) +typedef CONTEXT tickcontext_t; +#elif defined(LINUX) +#include +typedef ucontext_t tickcontext_t; +#endif + +#if defined(LINUX) || defined(XP_MACOSX) +#include +pid_t gettid(); +#endif + #if defined(SPS_ARCH_arm) && defined(MOZ_WIDGET_GONK) // Should also work on other Android and ARM Linux, but not tested there yet. #define USE_EHABI_STACKWALK @@ -416,6 +429,27 @@ void StackWalkCallback(void* aPC, void* aSP, void* aClosure) void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample) { +#ifdef XP_WIN + /* For the purpose of SPS it is currently too expensive to call NS_StackWalk() + on itself on Windows. For each call to NS_StackWalk(), we currently have to + use another thread to suspend the calling thread, obtain its context, and + walk its stack. We shouldn't do that every time we need a thread to obtain + its own backtrace in SPS.*/ + if (aSample->isSamplingCurrentThread) { + void* ptrs[100]; + USHORT count = RtlCaptureStackBackTrace(0, 100, ptrs, nullptr); + aProfile.addTag(ProfileEntry('s', "(root)")); + if (count) { + USHORT i = count; + do { + --i; + aProfile.addTag(ProfileEntry('l', ptrs[i])); + } while (i != 0); + } + return; + } +#endif + #ifndef XP_MACOSX uintptr_t thread = GetThreadHandle(aSample->threadProfile->GetPlatformData()); MOZ_ASSERT(thread); @@ -510,34 +544,39 @@ void TableTicker::InplaceTick(TickSample* sample) { ThreadProfile& currThreadProfile = *sample->threadProfile; - // Marker(s) come before the sample PseudoStack* stack = currThreadProfile.GetPseudoStack(); - ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers(); - while (pendingMarkersList && pendingMarkersList->peek()) { - ProfilerMarker* marker = pendingMarkersList->popHead(); - stack->addStoredMarker(marker); - currThreadProfile.addTag(ProfileEntry('m', marker)); - } - stack->updateGeneration(currThreadProfile.GetGenerationID()); - bool recordSample = true; - if (mJankOnly) { - // if we are on a different event we can discard any temporary samples - // we've kept around - if (sLastSampledEventGeneration != sCurrentEventGeneration) { - // XXX: we also probably want to add an entry to the profile to help - // distinguish which samples are part of the same event. That, or record - // the event generation in each sample - currThreadProfile.erase(); - } - sLastSampledEventGeneration = sCurrentEventGeneration; - recordSample = false; - // only record the events when we have a we haven't seen a tracer event for 100ms - if (!sLastTracerEvent.IsNull()) { - TimeDuration delta = sample->timestamp - sLastTracerEvent; - if (delta.ToMilliseconds() > 100.0) { - recordSample = true; + /* Don't process the PeudoStack's markers or honour jankOnly if we're + immediately sampling the current thread. */ + if (!sample->isSamplingCurrentThread) { + // Marker(s) come before the sample + ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers(); + while (pendingMarkersList && pendingMarkersList->peek()) { + ProfilerMarker* marker = pendingMarkersList->popHead(); + stack->addStoredMarker(marker); + currThreadProfile.addTag(ProfileEntry('m', marker)); + } + stack->updateGeneration(currThreadProfile.GetGenerationID()); + + if (mJankOnly) { + // if we are on a different event we can discard any temporary samples + // we've kept around + if (sLastSampledEventGeneration != sCurrentEventGeneration) { + // XXX: we also probably want to add an entry to the profile to help + // distinguish which samples are part of the same event. That, or record + // the event generation in each sample + currThreadProfile.erase(); + } + sLastSampledEventGeneration = sCurrentEventGeneration; + + recordSample = false; + // only record the events when we have a we haven't seen a tracer event for 100ms + if (!sLastTracerEvent.IsNull()) { + TimeDuration delta = sample->timestamp - sLastTracerEvent; + if (delta.ToMilliseconds() > 100.0) { + recordSample = true; + } } } } @@ -571,7 +610,57 @@ void TableTicker::InplaceTick(TickSample* sample) } } -static void print_callback(const ProfileEntry& entry, const char* tagStringData) { +namespace { + +SyncProfile* NewSyncProfile() +{ + PseudoStack* stack = tlsPseudoStack.get(); + if (!stack) { + MOZ_ASSERT(stack); + return nullptr; + } + Thread::tid_t tid = Thread::GetCurrentId(); + + SyncProfile* profile = new SyncProfile("SyncProfile", + GET_BACKTRACE_DEFAULT_ENTRY, + stack, tid, NS_IsMainThread()); + return profile; +} + +} // anonymous namespace + +SyncProfile* TableTicker::GetBacktrace() +{ + SyncProfile* profile = NewSyncProfile(); + + TickSample sample; + sample.threadProfile = profile; + +#if defined(XP_WIN) || defined(LINUX) + tickcontext_t context; + sample.PopulateContext(&context); +#elif defined(XP_MACOSX) + sample.PopulateContext(nullptr); +#endif + + sample.isSamplingCurrentThread = true; + sample.timestamp = mozilla::TimeStamp::Now(); + + if (!HasUnwinderThread()) { + profile->BeginUnwind(); + } + + Tick(&sample); + + if (!HasUnwinderThread()) { + profile->EndUnwind(); + } + + return profile; +} + +static void print_callback(const ProfileEntry& entry, const char* tagStringData) +{ switch (entry.getTagName()) { case 's': case 'c': @@ -584,25 +673,18 @@ void mozilla_sampler_print_location1() if (!stack_key_initialized) profiler_init(NULL); - PseudoStack *stack = tlsPseudoStack.get(); - if (!stack) { - MOZ_ASSERT(false); + SyncProfile* syncProfile = NewSyncProfile(); + if (!syncProfile) { return; } - // This won't allow unwinding past this function, but it will be safe. - void *stackTop = &stack; - - ThreadProfile threadProfile("Temp", PROFILE_DEFAULT_ENTRY, stack, - 0, Sampler::AllocPlatformData(0), false, - stackTop); - - doSampleStackTrace(stack, threadProfile, NULL); - - threadProfile.flush(); + syncProfile->BeginUnwind(); + doSampleStackTrace(syncProfile->GetPseudoStack(), *syncProfile, NULL); + syncProfile->EndUnwind(); printf_stderr("Backtrace:\n"); - threadProfile.IterateTags(print_callback); + syncProfile->IterateTags(print_callback); + delete syncProfile; } diff --git a/tools/profiler/TableTicker.h b/tools/profiler/TableTicker.h index d71a3ab8f5b1..987a6e3d2073 100644 --- a/tools/profiler/TableTicker.h +++ b/tools/profiler/TableTicker.h @@ -128,6 +128,9 @@ class TableTicker: public Sampler { // Called within a signal. This function must be reentrant virtual void Tick(TickSample* sample); + // Immediately captures the calling thread's call stack and returns it. + virtual SyncProfile* GetBacktrace(); + // Called within a signal. This function must be reentrant virtual void RequestSave() { diff --git a/tools/profiler/UnwinderThread2.cpp b/tools/profiler/UnwinderThread2.cpp index 3a1591911656..82edde9ea232 100644 --- a/tools/profiler/UnwinderThread2.cpp +++ b/tools/profiler/UnwinderThread2.cpp @@ -29,6 +29,7 @@ #include #include "ProfileEntry.h" +#include "SyncProfile.h" #include "UnwinderThread2.h" #if !defined(SPS_OS_windows) @@ -39,8 +40,8 @@ # include #endif -#if defined(SPS_OS_android) -# include "android-signal-defs.h" +#if defined(SPS_OS_android) || defined(SPS_OS_linux) +# include #endif #include "shared-libraries.h" @@ -87,12 +88,29 @@ void uwt__unregister_thread_for_profiling() { } +LinkedUWTBuffer* utb__acquire_sync_buffer(void* stackTop) +{ + return nullptr; +} + // RUNS IN SIGHANDLER CONTEXT UnwinderThreadBuffer* uwt__acquire_empty_buffer() { return NULL; } +void +utb__finish_sync_buffer(ThreadProfile* aProfile, + UnwinderThreadBuffer* utb, + void* /* ucontext_t*, really */ ucV) +{ +} + +void +utb__release_sync_buffer(LinkedUWTBuffer* utb) +{ +} + // RUNS IN SIGHANDLER CONTEXT void uwt__release_full_buffer(ThreadProfile* aProfile, @@ -132,10 +150,20 @@ static void thread_unregister_for_profiling(); // Frees some memory when the unwinder thread is shut down. static void do_breakpad_unwind_Buffer_free_singletons(); +// Allocate a buffer for synchronous unwinding +static LinkedUWTBuffer* acquire_sync_buffer(void* stackTop); + // RUNS IN SIGHANDLER CONTEXT // Acquire an empty buffer and mark it as FILLING static UnwinderThreadBuffer* acquire_empty_buffer(); +static void finish_sync_buffer(ThreadProfile* aProfile, + UnwinderThreadBuffer* utb, + void* /* ucontext_t*, really */ ucV); + +// Release an empty synchronous unwind buffer. +static void release_sync_buffer(LinkedUWTBuffer* utb); + // RUNS IN SIGHANDLER CONTEXT // Put this buffer in the queue of stuff going to the unwinder // thread, and mark it as FULL. Before doing that, fill in stack @@ -188,6 +216,23 @@ void uwt__unregister_thread_for_profiling() thread_unregister_for_profiling(); } +LinkedUWTBuffer* utb__acquire_sync_buffer(void* stackTop) +{ + return acquire_sync_buffer(stackTop); +} + +void utb__finish_sync_buffer(ThreadProfile* profile, + UnwinderThreadBuffer* buff, + void* /* ucontext_t*, really */ ucV) +{ + finish_sync_buffer(profile, buff, ucV); +} + +void utb__release_sync_buffer(LinkedUWTBuffer* buff) +{ + release_sync_buffer(buff); +} + // RUNS IN SIGHANDLER CONTEXT UnwinderThreadBuffer* uwt__acquire_empty_buffer() { @@ -669,6 +714,43 @@ static void show_registered_threads() spinLock_release(&g_spinLock); } +// RUNS IN SIGHANDLER CONTEXT +/* The calling thread owns the buffer, as denoted by its state being + S_FILLING. So we can mess with it without further locking. */ +static void init_empty_buffer(UnwinderThreadBuffer* buff, void* stackTop) +{ + /* Now we own the buffer, initialise it. */ + buff->aProfile = NULL; + buff->entsUsed = 0; + buff->haveNativeInfo = false; + buff->stackImgUsed = 0; + buff->stackImgAddr = 0; + buff->stackMaxSafe = stackTop; /* We will need this in + release_full_buffer() */ + for (size_t i = 0; i < N_PROF_ENT_PAGES; i++) + buff->entsPages[i] = ProfEntsPage_INVALID; +} + +struct SyncUnwinderThreadBuffer : public LinkedUWTBuffer +{ + UnwinderThreadBuffer* GetBuffer() + { + return &mBuff; + } + + UnwinderThreadBuffer mBuff; +}; + +static LinkedUWTBuffer* acquire_sync_buffer(void* stackTop) +{ + MOZ_ASSERT(stackTop); + SyncUnwinderThreadBuffer* buff = new SyncUnwinderThreadBuffer(); + // We can set state without locking here because this thread owns the buffer + // and it is going to fill it itself. + buff->GetBuffer()->state = S_FILLING; + init_empty_buffer(buff->GetBuffer(), stackTop); + return buff; +} // RUNS IN SIGHANDLER CONTEXT static UnwinderThreadBuffer* acquire_empty_buffer() @@ -758,25 +840,16 @@ static UnwinderThreadBuffer* acquire_empty_buffer() spinLock_release(&g_spinLock); /* Now we own the buffer, initialise it. */ - buff->aProfile = NULL; - buff->entsUsed = 0; - buff->haveNativeInfo = false; - buff->stackImgUsed = 0; - buff->stackImgAddr = 0; - buff->stackMaxSafe = myStackTop; /* We will need this in - release_full_buffer() */ - for (i = 0; i < N_PROF_ENT_PAGES; i++) - buff->entsPages[i] = ProfEntsPage_INVALID; + init_empty_buffer(buff, myStackTop); return buff; } - // RUNS IN SIGHANDLER CONTEXT /* The calling thread owns the buffer, as denoted by its state being S_FILLING. So we can mess with it without further locking. */ -static void release_full_buffer(ThreadProfile* aProfile, - UnwinderThreadBuffer* buff, - void* /* ucontext_t*, really */ ucV ) +static void fill_buffer(ThreadProfile* aProfile, + UnwinderThreadBuffer* buff, + void* /* ucontext_t*, really */ ucV) { MOZ_ASSERT(buff->state == S_FILLING); @@ -814,7 +887,7 @@ static void release_full_buffer(ThreadProfile* aProfile, buff->regs.r12 = mc->arm_ip; //gregs[R12]; buff->regs.r11 = mc->arm_fp; //gregs[R11]; buff->regs.r7 = mc->arm_r7; //gregs[R7]; -# elif defined(SPS_PLAT_x86_linux) +# elif defined(SPS_PLAT_x86_linux) || defined(SPS_PLAT_x86_android) ucontext_t* uc = (ucontext_t*)ucV; mcontext_t* mc = &(uc->uc_mcontext); buff->regs.eip = mc->gregs[REG_EIP]; @@ -827,12 +900,6 @@ static void release_full_buffer(ThreadProfile* aProfile, buff->regs.eip = ss->__eip; buff->regs.esp = ss->__esp; buff->regs.ebp = ss->__ebp; -# elif defined(SPS_PLAT_x86_android) - ucontext_t* uc = (ucontext_t*)ucV; - mcontext_t* mc = &(uc->uc_mcontext); - buff->regs.eip = mc->eip; - buff->regs.esp = mc->esp; - buff->regs.ebp = mc->ebp; # else # error "Unknown plat" # endif @@ -875,7 +942,16 @@ static void release_full_buffer(ThreadProfile* aProfile, } /* if (buff->haveNativeInfo) */ // END fill //////////////////////////////////////////////////// +} +// RUNS IN SIGHANDLER CONTEXT +/* The calling thread owns the buffer, as denoted by its state being + S_FILLING. So we can mess with it without further locking. */ +static void release_full_buffer(ThreadProfile* aProfile, + UnwinderThreadBuffer* buff, + void* /* ucontext_t*, really */ ucV ) +{ + fill_buffer(aProfile, buff, ucV); /* And now relinquish ownership of the buff, so that an unwinder thread can pick it up. */ spinLock_acquire(&g_spinLock); @@ -883,7 +959,6 @@ static void release_full_buffer(ThreadProfile* aProfile, spinLock_release(&g_spinLock); } - // RUNS IN SIGHANDLER CONTEXT // Allocate a ProfEntsPage, without using malloc, or return // ProfEntsPage_INVALID if we can't for some reason. @@ -967,6 +1042,345 @@ static ProfileEntry utb_get_profent(UnwinderThreadBuffer* buff, uintptr_t i) } } +/* Copy ProfileEntries presented to us by the sampling thread. + Most of them are copied verbatim into |buff->aProfile|, + except for 'hint' tags, which direct us to do something + different. */ +static void process_buffer(UnwinderThreadBuffer* buff, int oldest_ix) +{ + /* Need to lock |aProfile| so nobody tries to copy out entries + whilst we are putting them in. */ + buff->aProfile->BeginUnwind(); + + /* The buff is a sequence of ProfileEntries (ents). It has + this grammar: + + | --pre-tags-- | (h 'P' .. h 'Q')* | --post-tags-- | + ^ ^ + ix_first_hP ix_last_hQ + + Each (h 'P' .. h 'Q') subsequence represents one pseudostack + entry. These, if present, are in the order + outermost-frame-first, and that is the order that they should + be copied into aProfile. The --pre-tags-- and --post-tags-- + are to be copied into the aProfile verbatim, except that they + may contain the hints "h 'F'" for a flush and "h 'N'" to + indicate that a native unwind is also required, and must be + interleaved with the pseudostack entries. + + The hint tags that bound each pseudostack entry, "h 'P'" and "h + 'Q'", are not to be copied into the aProfile -- they are + present only to make parsing easy here. Also, the pseudostack + entries may contain an "'S' (void*)" entry, which is the stack + pointer value for that entry, and these are also not to be + copied. + */ + /* The first thing to do is therefore to find the pseudostack + entries, if any, and to find out also whether a native unwind + has been requested. */ + const uintptr_t infUW = ~(uintptr_t)0; // infinity + bool need_native_unw = false; + uintptr_t ix_first_hP = infUW; // "not found" + uintptr_t ix_last_hQ = infUW; // "not found" + + uintptr_t k; + for (k = 0; k < buff->entsUsed; k++) { + ProfileEntry ent = utb_get_profent(buff, k); + if (ent.is_ent_hint('N')) { + need_native_unw = true; + } + else if (ent.is_ent_hint('P') && ix_first_hP == ~(uintptr_t)0) { + ix_first_hP = k; + } + else if (ent.is_ent_hint('Q')) { + ix_last_hQ = k; + } + } + + if (0) LOGF("BPUnw: ix_first_hP %llu ix_last_hQ %llu need_native_unw %llu", + (unsigned long long int)ix_first_hP, + (unsigned long long int)ix_last_hQ, + (unsigned long long int)need_native_unw); + + /* There are four possibilities: native-only, pseudostack-only, + combined (both), and neither. We handle all four cases. */ + + MOZ_ASSERT( (ix_first_hP == infUW && ix_last_hQ == infUW) || + (ix_first_hP != infUW && ix_last_hQ != infUW) ); + bool have_P = ix_first_hP != infUW; + if (have_P) { + MOZ_ASSERT(ix_first_hP < ix_last_hQ); + MOZ_ASSERT(ix_last_hQ <= buff->entsUsed); + } + + /* Neither N nor P. This is very unusual but has been observed to happen. + Just copy to the output. */ + if (!need_native_unw && !have_P) { + for (k = 0; k < buff->entsUsed; k++) { + ProfileEntry ent = utb_get_profent(buff, k); + // action flush-hints + if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } + // skip ones we can't copy + if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } + // handle GetBacktrace() + if (ent.is_ent('B')) { + UnwinderThreadBuffer* buff = (UnwinderThreadBuffer*)ent.get_tagPtr(); + process_buffer(buff, -1); + continue; + } + // and copy everything else + buff->aProfile->addTag( ent ); + } + } + else /* Native only-case. */ + if (need_native_unw && !have_P) { + for (k = 0; k < buff->entsUsed; k++) { + ProfileEntry ent = utb_get_profent(buff, k); + // action a native-unwind-now hint + if (ent.is_ent_hint('N')) { + MOZ_ASSERT(buff->haveNativeInfo); + PCandSP* pairs = NULL; + unsigned int nPairs = 0; + do_breakpad_unwind_Buffer(&pairs, &nPairs, buff, oldest_ix); + buff->aProfile->addTag( ProfileEntry('s', "(root)") ); + for (unsigned int i = 0; i < nPairs; i++) { + /* Skip any outermost frames that + do_breakpad_unwind_Buffer didn't give us. See comments + on that function for details. */ + if (pairs[i].pc == 0 && pairs[i].sp == 0) + continue; + buff->aProfile + ->addTag( ProfileEntry('l', reinterpret_cast(pairs[i].pc)) ); + } + if (pairs) + free(pairs); + continue; + } + // action flush-hints + if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } + // skip ones we can't copy + if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } + // handle GetBacktrace() + if (ent.is_ent('B')) { + UnwinderThreadBuffer* buff = (UnwinderThreadBuffer*)ent.get_tagPtr(); + process_buffer(buff, -1); + continue; + } + // and copy everything else + buff->aProfile->addTag( ent ); + } + } + else /* Pseudostack-only case */ + if (!need_native_unw && have_P) { + /* If there's no request for a native stack, it's easy: just + copy the tags verbatim into aProfile, skipping the ones that + can't be copied -- 'h' (hint) tags, and "'S' (void*)" + stack-pointer tags. Except, insert a sample-start tag when + we see the start of the first pseudostack frame. */ + for (k = 0; k < buff->entsUsed; k++) { + ProfileEntry ent = utb_get_profent(buff, k); + // We need to insert a sample-start tag before the first frame + if (k == ix_first_hP) { + buff->aProfile->addTag( ProfileEntry('s', "(root)") ); + } + // action flush-hints + if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } + // skip ones we can't copy + if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } + // handle GetBacktrace() + if (ent.is_ent('B')) { + UnwinderThreadBuffer* buff = (UnwinderThreadBuffer*)ent.get_tagPtr(); + process_buffer(buff, -1); + continue; + } + // and copy everything else + buff->aProfile->addTag( ent ); + } + } + else /* Combined case */ + if (need_native_unw && have_P) + { + /* We need to get a native stacktrace and merge it with the + pseudostack entries. This isn't too simple. First, copy all + the tags up to the start of the pseudostack tags. Then + generate a combined set of tags by native unwind and + pseudostack. Then, copy all the stuff after the pseudostack + tags. */ + MOZ_ASSERT(buff->haveNativeInfo); + + // Get native unwind info + PCandSP* pairs = NULL; + unsigned int n_pairs = 0; + do_breakpad_unwind_Buffer(&pairs, &n_pairs, buff, oldest_ix); + + // Entries before the pseudostack frames + for (k = 0; k < ix_first_hP; k++) { + ProfileEntry ent = utb_get_profent(buff, k); + // action flush-hints + if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } + // skip ones we can't copy + if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } + // handle GetBacktrace() + if (ent.is_ent('B')) { + UnwinderThreadBuffer* buff = (UnwinderThreadBuffer*)ent.get_tagPtr(); + process_buffer(buff, -1); + continue; + } + // and copy everything else + buff->aProfile->addTag( ent ); + } + + // BEGIN merge + buff->aProfile->addTag( ProfileEntry('s', "(root)") ); + unsigned int next_N = 0; // index in pairs[] + unsigned int next_P = ix_first_hP; // index in buff profent array + bool last_was_P = false; + if (0) LOGF("at mergeloop: n_pairs %llu ix_last_hQ %llu", + (unsigned long long int)n_pairs, + (unsigned long long int)ix_last_hQ); + /* Skip any outermost frames that do_breakpad_unwind_Buffer + didn't give us. See comments on that function for + details. */ + while (next_N < n_pairs && pairs[next_N].pc == 0 && pairs[next_N].sp == 0) + next_N++; + + while (true) { + if (next_P <= ix_last_hQ) { + // Assert that next_P points at the start of an P entry + MOZ_ASSERT(utb_get_profent(buff, next_P).is_ent_hint('P')); + } + if (next_N >= n_pairs && next_P > ix_last_hQ) { + // both stacks empty + break; + } + /* Decide which entry to use next: + If N is empty, must use P, and vice versa + else + If the last was P and current P has zero SP, use P + else + we assume that both P and N have valid SP, in which case + use the one with the larger value + */ + bool use_P = true; + if (next_N >= n_pairs) { + // N empty, use P + use_P = true; + if (0) LOG(" P <= no remaining N entries"); + } + else if (next_P > ix_last_hQ) { + // P empty, use N + use_P = false; + if (0) LOG(" N <= no remaining P entries"); + } + else { + // We have at least one N and one P entry available. + // Scan forwards to find the SP of the current P entry + u_int64_t sp_cur_P = 0; + unsigned int m = next_P + 1; + while (1) { + /* This assertion should hold because in a well formed + input, we must eventually find the hint-Q that marks + the end of this frame's entries. */ + MOZ_ASSERT(m < buff->entsUsed); + ProfileEntry ent = utb_get_profent(buff, m); + if (ent.is_ent_hint('Q')) + break; + if (ent.is_ent('S')) { + sp_cur_P = reinterpret_cast(ent.get_tagPtr()); + break; + } + m++; + } + if (last_was_P && sp_cur_P == 0) { + if (0) LOG(" P <= last_was_P && sp_cur_P == 0"); + use_P = true; + } else { + u_int64_t sp_cur_N = pairs[next_N].sp; + use_P = (sp_cur_P > sp_cur_N); + if (0) LOGF(" %s <= sps P %p N %p", + use_P ? "P" : "N", (void*)(intptr_t)sp_cur_P, + (void*)(intptr_t)sp_cur_N); + } + } + /* So, we know which we are going to use. */ + if (use_P) { + unsigned int m = next_P + 1; + while (true) { + MOZ_ASSERT(m < buff->entsUsed); + ProfileEntry ent = utb_get_profent(buff, m); + if (ent.is_ent_hint('Q')) { + next_P = m + 1; + break; + } + // we don't expect a flush-hint here + MOZ_ASSERT(!ent.is_ent_hint('F')); + // skip ones we can't copy + if (ent.is_ent_hint() || ent.is_ent('S')) { m++; continue; } + // and copy everything else + buff->aProfile->addTag( ent ); + m++; + } + } else { + buff->aProfile + ->addTag( ProfileEntry('l', reinterpret_cast(pairs[next_N].pc)) ); + next_N++; + } + /* Remember what we chose, for next time. */ + last_was_P = use_P; + } + + MOZ_ASSERT(next_P == ix_last_hQ + 1); + MOZ_ASSERT(next_N == n_pairs); + // END merge + + // Entries after the pseudostack frames + for (k = ix_last_hQ+1; k < buff->entsUsed; k++) { + ProfileEntry ent = utb_get_profent(buff, k); + // action flush-hints + if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } + // skip ones we can't copy + if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } + // and copy everything else + buff->aProfile->addTag( ent ); + } + + // free native unwind info + if (pairs) + free(pairs); + } + +#if 0 + bool show = true; + if (show) LOG("----------------"); + for (k = 0; k < buff->entsUsed; k++) { + ProfileEntry ent = utb_get_profent(buff, k); + if (show) ent.log(); + if (ent.is_ent_hint('F')) { + /* This is a flush-hint */ + buff->aProfile->flush(); + } + else if (ent.is_ent_hint('N')) { + /* This is a do-a-native-unwind-right-now hint */ + MOZ_ASSERT(buff->haveNativeInfo); + PCandSP* pairs = NULL; + unsigned int nPairs = 0; + do_breakpad_unwind_Buffer(&pairs, &nPairs, buff, oldest_ix); + buff->aProfile->addTag( ProfileEntry('s', "(root)") ); + for (unsigned int i = 0; i < nPairs; i++) { + buff->aProfile + ->addTag( ProfileEntry('l', reinterpret_cast(pairs[i].pc)) ); + } + if (pairs) + free(pairs); + } else { + /* Copy in verbatim */ + buff->aProfile->addTag( ent ); + } + } +#endif + + buff->aProfile->EndUnwind(); +} // Runs in the unwinder thread -- well, this _is_ the unwinder thread. static void* unwind_thr_fn(void* exit_nowV) @@ -1092,319 +1506,7 @@ static void* unwind_thr_fn(void* exit_nowV) if (0) LOGF("BPUnw: unwinder: seqNo %llu: emptying buf %d\n", (unsigned long long int)oldest_seqNo, oldest_ix); - /* Copy ProfileEntries presented to us by the sampling thread. - Most of them are copied verbatim into |buff->aProfile|, - except for 'hint' tags, which direct us to do something - different. */ - - /* Need to lock |aProfile| so nobody tries to copy out entries - whilst we are putting them in. */ - buff->aProfile->GetMutex()->Lock(); - - /* The buff is a sequence of ProfileEntries (ents). It has - this grammar: - - | --pre-tags-- | (h 'P' .. h 'Q')* | --post-tags-- | - ^ ^ - ix_first_hP ix_last_hQ - - Each (h 'P' .. h 'Q') subsequence represents one pseudostack - entry. These, if present, are in the order - outermost-frame-first, and that is the order that they should - be copied into aProfile. The --pre-tags-- and --post-tags-- - are to be copied into the aProfile verbatim, except that they - may contain the hints "h 'F'" for a flush and "h 'N'" to - indicate that a native unwind is also required, and must be - interleaved with the pseudostack entries. - - The hint tags that bound each pseudostack entry, "h 'P'" and "h - 'Q'", are not to be copied into the aProfile -- they are - present only to make parsing easy here. Also, the pseudostack - entries may contain an "'S' (void*)" entry, which is the stack - pointer value for that entry, and these are also not to be - copied. - */ - /* The first thing to do is therefore to find the pseudostack - entries, if any, and to find out also whether a native unwind - has been requested. */ - const uintptr_t infUW = ~(uintptr_t)0; // infinity - bool need_native_unw = false; - uintptr_t ix_first_hP = infUW; // "not found" - uintptr_t ix_last_hQ = infUW; // "not found" - - uintptr_t k; - for (k = 0; k < buff->entsUsed; k++) { - ProfileEntry ent = utb_get_profent(buff, k); - if (ent.is_ent_hint('N')) { - need_native_unw = true; - } - else if (ent.is_ent_hint('P') && ix_first_hP == ~(uintptr_t)0) { - ix_first_hP = k; - } - else if (ent.is_ent_hint('Q')) { - ix_last_hQ = k; - } - } - - if (0) LOGF("BPUnw: ix_first_hP %llu ix_last_hQ %llu need_native_unw %llu", - (unsigned long long int)ix_first_hP, - (unsigned long long int)ix_last_hQ, - (unsigned long long int)need_native_unw); - - /* There are four possibilities: native-only, pseudostack-only, - combined (both), and neither. We handle all four cases. */ - - MOZ_ASSERT( (ix_first_hP == infUW && ix_last_hQ == infUW) || - (ix_first_hP != infUW && ix_last_hQ != infUW) ); - bool have_P = ix_first_hP != infUW; - if (have_P) { - MOZ_ASSERT(ix_first_hP < ix_last_hQ); - MOZ_ASSERT(ix_last_hQ <= buff->entsUsed); - } - - /* Neither N nor P. This is very unusual but has been observed to happen. - Just copy to the output. */ - if (!need_native_unw && !have_P) { - for (k = 0; k < buff->entsUsed; k++) { - ProfileEntry ent = utb_get_profent(buff, k); - // action flush-hints - if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } - // skip ones we can't copy - if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } - // and copy everything else - buff->aProfile->addTag( ent ); - } - } - else /* Native only-case. */ - if (need_native_unw && !have_P) { - for (k = 0; k < buff->entsUsed; k++) { - ProfileEntry ent = utb_get_profent(buff, k); - // action a native-unwind-now hint - if (ent.is_ent_hint('N')) { - MOZ_ASSERT(buff->haveNativeInfo); - PCandSP* pairs = NULL; - unsigned int nPairs = 0; - do_breakpad_unwind_Buffer(&pairs, &nPairs, buff, oldest_ix); - buff->aProfile->addTag( ProfileEntry('s', "(root)") ); - for (unsigned int i = 0; i < nPairs; i++) { - /* Skip any outermost frames that - do_breakpad_unwind_Buffer didn't give us. See comments - on that function for details. */ - if (pairs[i].pc == 0 && pairs[i].sp == 0) - continue; - buff->aProfile - ->addTag( ProfileEntry('l', reinterpret_cast(pairs[i].pc)) ); - } - if (pairs) - free(pairs); - continue; - } - // action flush-hints - if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } - // skip ones we can't copy - if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } - // and copy everything else - buff->aProfile->addTag( ent ); - } - } - else /* Pseudostack-only case */ - if (!need_native_unw && have_P) { - /* If there's no request for a native stack, it's easy: just - copy the tags verbatim into aProfile, skipping the ones that - can't be copied -- 'h' (hint) tags, and "'S' (void*)" - stack-pointer tags. Except, insert a sample-start tag when - we see the start of the first pseudostack frame. */ - for (k = 0; k < buff->entsUsed; k++) { - ProfileEntry ent = utb_get_profent(buff, k); - // We need to insert a sample-start tag before the first frame - if (k == ix_first_hP) { - buff->aProfile->addTag( ProfileEntry('s', "(root)") ); - } - // action flush-hints - if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } - // skip ones we can't copy - if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } - // and copy everything else - buff->aProfile->addTag( ent ); - } - } - else /* Combined case */ - if (need_native_unw && have_P) - { - /* We need to get a native stacktrace and merge it with the - pseudostack entries. This isn't too simple. First, copy all - the tags up to the start of the pseudostack tags. Then - generate a combined set of tags by native unwind and - pseudostack. Then, copy all the stuff after the pseudostack - tags. */ - MOZ_ASSERT(buff->haveNativeInfo); - - // Get native unwind info - PCandSP* pairs = NULL; - unsigned int n_pairs = 0; - do_breakpad_unwind_Buffer(&pairs, &n_pairs, buff, oldest_ix); - - // Entries before the pseudostack frames - for (k = 0; k < ix_first_hP; k++) { - ProfileEntry ent = utb_get_profent(buff, k); - // action flush-hints - if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } - // skip ones we can't copy - if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } - // and copy everything else - buff->aProfile->addTag( ent ); - } - - // BEGIN merge - buff->aProfile->addTag( ProfileEntry('s', "(root)") ); - unsigned int next_N = 0; // index in pairs[] - unsigned int next_P = ix_first_hP; // index in buff profent array - bool last_was_P = false; - if (0) LOGF("at mergeloop: n_pairs %llu ix_last_hQ %llu", - (unsigned long long int)n_pairs, - (unsigned long long int)ix_last_hQ); - /* Skip any outermost frames that do_breakpad_unwind_Buffer - didn't give us. See comments on that function for - details. */ - while (next_N < n_pairs && pairs[next_N].pc == 0 && pairs[next_N].sp == 0) - next_N++; - - while (true) { - if (next_P <= ix_last_hQ) { - // Assert that next_P points at the start of an P entry - MOZ_ASSERT(utb_get_profent(buff, next_P).is_ent_hint('P')); - } - if (next_N >= n_pairs && next_P > ix_last_hQ) { - // both stacks empty - break; - } - /* Decide which entry to use next: - If N is empty, must use P, and vice versa - else - If the last was P and current P has zero SP, use P - else - we assume that both P and N have valid SP, in which case - use the one with the larger value - */ - bool use_P = true; - if (next_N >= n_pairs) { - // N empty, use P - use_P = true; - if (0) LOG(" P <= no remaining N entries"); - } - else if (next_P > ix_last_hQ) { - // P empty, use N - use_P = false; - if (0) LOG(" N <= no remaining P entries"); - } - else { - // We have at least one N and one P entry available. - // Scan forwards to find the SP of the current P entry - u_int64_t sp_cur_P = 0; - unsigned int m = next_P + 1; - while (1) { - /* This assertion should hold because in a well formed - input, we must eventually find the hint-Q that marks - the end of this frame's entries. */ - MOZ_ASSERT(m < buff->entsUsed); - ProfileEntry ent = utb_get_profent(buff, m); - if (ent.is_ent_hint('Q')) - break; - if (ent.is_ent('S')) { - sp_cur_P = reinterpret_cast(ent.get_tagPtr()); - break; - } - m++; - } - if (last_was_P && sp_cur_P == 0) { - if (0) LOG(" P <= last_was_P && sp_cur_P == 0"); - use_P = true; - } else { - u_int64_t sp_cur_N = pairs[next_N].sp; - use_P = (sp_cur_P > sp_cur_N); - if (0) LOGF(" %s <= sps P %p N %p", - use_P ? "P" : "N", (void*)(intptr_t)sp_cur_P, - (void*)(intptr_t)sp_cur_N); - } - } - /* So, we know which we are going to use. */ - if (use_P) { - unsigned int m = next_P + 1; - while (true) { - MOZ_ASSERT(m < buff->entsUsed); - ProfileEntry ent = utb_get_profent(buff, m); - if (ent.is_ent_hint('Q')) { - next_P = m + 1; - break; - } - // we don't expect a flush-hint here - MOZ_ASSERT(!ent.is_ent_hint('F')); - // skip ones we can't copy - if (ent.is_ent_hint() || ent.is_ent('S')) { m++; continue; } - // and copy everything else - buff->aProfile->addTag( ent ); - m++; - } - } else { - buff->aProfile - ->addTag( ProfileEntry('l', reinterpret_cast(pairs[next_N].pc)) ); - next_N++; - } - /* Remember what we chose, for next time. */ - last_was_P = use_P; - } - - MOZ_ASSERT(next_P == ix_last_hQ + 1); - MOZ_ASSERT(next_N == n_pairs); - // END merge - - // Entries after the pseudostack frames - for (k = ix_last_hQ+1; k < buff->entsUsed; k++) { - ProfileEntry ent = utb_get_profent(buff, k); - // action flush-hints - if (ent.is_ent_hint('F')) { buff->aProfile->flush(); continue; } - // skip ones we can't copy - if (ent.is_ent_hint() || ent.is_ent('S')) { continue; } - // and copy everything else - buff->aProfile->addTag( ent ); - } - - // free native unwind info - if (pairs) - free(pairs); - } - -#if 0 - bool show = true; - if (show) LOG("----------------"); - for (k = 0; k < buff->entsUsed; k++) { - ProfileEntry ent = utb_get_profent(buff, k); - if (show) ent.log(); - if (ent.is_ent_hint('F')) { - /* This is a flush-hint */ - buff->aProfile->flush(); - } - else if (ent.is_ent_hint('N')) { - /* This is a do-a-native-unwind-right-now hint */ - MOZ_ASSERT(buff->haveNativeInfo); - PCandSP* pairs = NULL; - unsigned int nPairs = 0; - do_breakpad_unwind_Buffer(&pairs, &nPairs, buff, oldest_ix); - buff->aProfile->addTag( ProfileEntry('s', "(root)") ); - for (unsigned int i = 0; i < nPairs; i++) { - buff->aProfile - ->addTag( ProfileEntry('l', reinterpret_cast(pairs[i].pc)) ); - } - if (pairs) - free(pairs); - } else { - /* Copy in verbatim */ - buff->aProfile->addTag( ent ); - } - } -#endif - - buff->aProfile->GetMutex()->Unlock(); + process_buffer(buff, oldest_ix); /* And .. we're done. Mark the buffer as empty so it can be reused. First though, unmap any of the entsPages that got @@ -1427,6 +1529,26 @@ static void* unwind_thr_fn(void* exit_nowV) return NULL; } +static void finish_sync_buffer(ThreadProfile* profile, + UnwinderThreadBuffer* buff, + void* /* ucontext_t*, really */ ucV) +{ + SyncProfile* syncProfile = profile->AsSyncProfile(); + MOZ_ASSERT(syncProfile); + SyncUnwinderThreadBuffer* utb = static_cast( + syncProfile->GetUWTBuffer()); + fill_buffer(profile, utb->GetBuffer(), ucV); + utb->GetBuffer()->state = S_FULL; + PseudoStack* stack = profile->GetPseudoStack(); + stack->addLinkedUWTBuffer(utb); +} + +static void release_sync_buffer(LinkedUWTBuffer* buff) +{ + SyncUnwinderThreadBuffer* data = static_cast(buff); + MOZ_ASSERT(data->GetBuffer()->state == S_EMPTY); + delete data; +} //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////// diff --git a/tools/profiler/UnwinderThread2.h b/tools/profiler/UnwinderThread2.h index 96387df8e5fb..4ebf42fac453 100644 --- a/tools/profiler/UnwinderThread2.h +++ b/tools/profiler/UnwinderThread2.h @@ -72,4 +72,21 @@ void uwt__release_full_buffer(ThreadProfile* aProfile, UnwinderThreadBuffer* utb, void* /* ucontext_t*, really */ ucV); +struct LinkedUWTBuffer; + +// Get an empty buffer for synchronous unwinding. +// This function is NOT signal-safe. +LinkedUWTBuffer* utb__acquire_sync_buffer(void* stackTop); + +void utb__finish_sync_buffer(ThreadProfile* aProfile, + UnwinderThreadBuffer* utb, + void* /* ucontext_t*, really */ ucV); + +// Free an empty buffer that was previously allocated by +// utb__acquire_sync_buffer. +void utb__release_sync_buffer(LinkedUWTBuffer* utb); + +// This typedef must match uwt__release_full_buffer and uwt__finish_sync_buffer +typedef void (*UTB_RELEASE_FUNC)(ThreadProfile*,UnwinderThreadBuffer*,void*); + #endif /* ndef MOZ_UNWINDER_THREAD_2_H */ diff --git a/tools/profiler/android-signal-defs.h b/tools/profiler/android-signal-defs.h deleted file mode 100644 index 02122b5db0f0..000000000000 --- a/tools/profiler/android-signal-defs.h +++ /dev/null @@ -1,36 +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/. */ - -// Android runs a fairly new Linux kernel, so signal info is there, -// but the C library doesn't have the structs defined. - -#ifndef mozilla_android_signal_defs_h__ -#define mozilla_android_signal_defs_h__ - -#include -#include - -// All NDK platform versions have asm/sigcontext.h for ARM -// Only NDK >= 6, platform >= 9 have asm/sigcontext.h for x86 -// Only NDK >= 8, platform >= 9 have asm/sigcontext.h for MIPS -#if defined(__arm__) || defined(__thumb__) || __ANDROID_API__ >= 9 -#include -#else -#error use newer NDK or newer platform version (e.g. --with-android-version=9) -#endif - -#ifndef __BIONIC_HAVE_UCONTEXT_T -typedef uint32_t __sigset_t; -typedef struct sigcontext mcontext_t; -typedef struct ucontext { - uint32_t uc_flags; - struct ucontext* uc_link; - stack_t uc_stack; - mcontext_t uc_mcontext; - __sigset_t uc_sigmask; -} ucontext_t; -#endif - -#endif diff --git a/tools/profiler/moz.build b/tools/profiler/moz.build index dc32b1f5af89..09ffe0747758 100644 --- a/tools/profiler/moz.build +++ b/tools/profiler/moz.build @@ -39,8 +39,10 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']: 'JSCustomObjectBuilder.cpp', 'IOInterposer.cpp', 'NSPRInterposer.cpp', + 'ProfilerBacktrace.cpp', 'ProfilerIOInterposeObserver.cpp', 'ProfilerMarkers.cpp', + 'SyncProfile.cpp', ] if CONFIG['OS_TARGET'] in ('Android', 'Linux'): diff --git a/tools/profiler/platform-linux.cc b/tools/profiler/platform-linux.cc index 26a0891e3069..1466c914b225 100644 --- a/tools/profiler/platform-linux.cc +++ b/tools/profiler/platform-linux.cc @@ -49,6 +49,7 @@ #else #define __android_log_print(a, ...) #endif +#include // Ubuntu Dapper requires memory pages to be marked as // executable. Otherwise, OS raises an exception when executing code // in that page. @@ -93,6 +94,12 @@ pid_t gettid() } #endif +/* static */ Thread::tid_t +Thread::GetCurrentId() +{ + return gettid(); +} + #if !defined(ANDROID) // Keep track of when any of our threads calls fork(), so we can // temporarily disable signal delivery during the fork() call. Not @@ -134,10 +141,6 @@ static void* setup_atfork() { } #endif /* !defined(ANDROID) */ -#ifdef ANDROID -#include "android-signal-defs.h" -#endif - struct SamplerRegistry { static void AddActiveSampler(Sampler *sampler) { ASSERT(!SamplerRegistry::sampler); @@ -158,6 +161,42 @@ static void ProfilerSaveSignalHandler(int signal, siginfo_t* info, void* context Sampler::GetActiveSampler()->RequestSave(); } +static void SetSampleContext(TickSample* sample, void* context) +{ + // Extracting the sample from the context is extremely machine dependent. + ucontext_t* ucontext = reinterpret_cast(context); + mcontext_t& mcontext = ucontext->uc_mcontext; +#if V8_HOST_ARCH_IA32 + sample->pc = reinterpret_cast
(mcontext.gregs[REG_EIP]); + sample->sp = reinterpret_cast
(mcontext.gregs[REG_ESP]); + sample->fp = reinterpret_cast
(mcontext.gregs[REG_EBP]); +#elif V8_HOST_ARCH_X64 + sample->pc = reinterpret_cast
(mcontext.gregs[REG_RIP]); + sample->sp = reinterpret_cast
(mcontext.gregs[REG_RSP]); + sample->fp = reinterpret_cast
(mcontext.gregs[REG_RBP]); +#elif V8_HOST_ARCH_ARM +// An undefined macro evaluates to 0, so this applies to Android's Bionic also. +#if !defined(ANDROID) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) + sample->pc = reinterpret_cast
(mcontext.gregs[R15]); + sample->sp = reinterpret_cast
(mcontext.gregs[R13]); + sample->fp = reinterpret_cast
(mcontext.gregs[R11]); +#ifdef ENABLE_ARM_LR_SAVING + sample->lr = reinterpret_cast
(mcontext.gregs[R14]); +#endif +#else + sample->pc = reinterpret_cast
(mcontext.arm_pc); + sample->sp = reinterpret_cast
(mcontext.arm_sp); + sample->fp = reinterpret_cast
(mcontext.arm_fp); +#ifdef ENABLE_ARM_LR_SAVING + sample->lr = reinterpret_cast
(mcontext.arm_lr); +#endif +#endif +#elif V8_HOST_ARCH_MIPS + // Implement this on MIPS. + UNIMPLEMENTED(); +#endif +} + #ifdef ANDROID #define V8_HOST_ARCH_ARM 1 #define SYS_gettid __NR_gettid @@ -178,38 +217,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { #ifdef ENABLE_SPS_LEAF_DATA // If profiling, we extract the current pc and sp. if (Sampler::GetActiveSampler()->IsProfiling()) { - // Extracting the sample from the context is extremely machine dependent. - ucontext_t* ucontext = reinterpret_cast(context); - mcontext_t& mcontext = ucontext->uc_mcontext; -#if V8_HOST_ARCH_IA32 - sample->pc = reinterpret_cast
(mcontext.gregs[REG_EIP]); - sample->sp = reinterpret_cast
(mcontext.gregs[REG_ESP]); - sample->fp = reinterpret_cast
(mcontext.gregs[REG_EBP]); -#elif V8_HOST_ARCH_X64 - sample->pc = reinterpret_cast
(mcontext.gregs[REG_RIP]); - sample->sp = reinterpret_cast
(mcontext.gregs[REG_RSP]); - sample->fp = reinterpret_cast
(mcontext.gregs[REG_RBP]); -#elif V8_HOST_ARCH_ARM -// An undefined macro evaluates to 0, so this applies to Android's Bionic also. -#if !defined(ANDROID) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) - sample->pc = reinterpret_cast
(mcontext.gregs[R15]); - sample->sp = reinterpret_cast
(mcontext.gregs[R13]); - sample->fp = reinterpret_cast
(mcontext.gregs[R11]); -#ifdef ENABLE_ARM_LR_SAVING - sample->lr = reinterpret_cast
(mcontext.gregs[R14]); -#endif -#else - sample->pc = reinterpret_cast
(mcontext.arm_pc); - sample->sp = reinterpret_cast
(mcontext.arm_sp); - sample->fp = reinterpret_cast
(mcontext.arm_fp); -#ifdef ENABLE_ARM_LR_SAVING - sample->lr = reinterpret_cast
(mcontext.arm_lr); -#endif -#endif -#elif V8_HOST_ARCH_MIPS - // Implement this on MIPS. - UNIMPLEMENTED(); -#endif + SetSampleContext(sample, context); } #endif sample->threadProfile = sCurrentThreadProfile; @@ -395,6 +403,8 @@ bool Sampler::RegisterCurrentThread(const char* aName, mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); + set_tls_stack_top(stackTop); + ThreadInfo* info = new ThreadInfo(aName, gettid(), aIsMainThread, aPseudoStack, stackTop); @@ -413,6 +423,8 @@ void Sampler::UnregisterCurrentThread() if (!Sampler::sRegisteredThreadsMutex) return; + tlsStackTop.set(nullptr); + mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); int id = gettid(); @@ -479,6 +491,16 @@ void OS::RegisterStartHandler() } #endif +void TickSample::PopulateContext(void* aContext) +{ + MOZ_ASSERT(aContext); + ucontext_t* pContext = reinterpret_cast(aContext); + if (!getcontext(pContext)) { + context = pContext; + SetSampleContext(this, aContext); + } +} + void OS::SleepMicro(int microseconds) { usleep(microseconds); diff --git a/tools/profiler/platform-macos.cc b/tools/profiler/platform-macos.cc index 7ffd80e3e71b..f4968d12eccf 100644 --- a/tools/profiler/platform-macos.cc +++ b/tools/profiler/platform-macos.cc @@ -349,6 +349,12 @@ pid_t gettid() return (pid_t) syscall(SYS_thread_selfid); } +/* static */ Thread::tid_t +Thread::GetCurrentId() +{ + return gettid(); +} + bool Sampler::RegisterCurrentThread(const char* aName, PseudoStack* aPseudoStack, bool aIsMainThread, void* stackTop) @@ -356,6 +362,8 @@ bool Sampler::RegisterCurrentThread(const char* aName, if (!Sampler::sRegisteredThreadsMutex) return false; + set_tls_stack_top(stackTop); + mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); ThreadInfo* info = new ThreadInfo(aName, gettid(), @@ -376,6 +384,8 @@ void Sampler::UnregisterCurrentThread() if (!Sampler::sRegisteredThreadsMutex) return; + tlsStackTop.set(nullptr); + mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); int id = gettid(); @@ -389,3 +399,33 @@ void Sampler::UnregisterCurrentThread() } } } + +__attribute__((noinline)) static Address GetPC() +{ + return reinterpret_cast
(__builtin_return_address(0)); +} + +void TickSample::PopulateContext(void* aContext) +{ +#if defined(SPS_PLAT_amd64_darwin) + asm ( + "movq %%rsp, %0\n\t" + "movq %%rbp, %1\n\t" + : + "=g"(sp), + "=g"(fp) + ); +#elif defined(SPS_PLAT_x86_darwin) + asm ( + "movl %%esp, %0\n\t" + "movl %%ebp, %1\n\t" + : + "=g"(sp), + "=g"(fp) + ); +#else +# error "Unsupported architecture" +#endif + pc = GetPC(); +} + diff --git a/tools/profiler/platform-win32.cc b/tools/profiler/platform-win32.cc index 2317425bc61d..494e54334065 100644 --- a/tools/profiler/platform-win32.cc +++ b/tools/profiler/platform-win32.cc @@ -254,16 +254,22 @@ void Thread::Start() { ThreadEntry, this, 0, - &thread_id_)); + (unsigned int*) &thread_id_)); } // Wait for thread to terminate. void Thread::Join() { - if (thread_id_ != GetCurrentThreadId()) { + if (thread_id_ != GetCurrentId()) { WaitForSingleObject(thread_, INFINITE); } } +/* static */ Thread::tid_t +Thread::GetCurrentId() +{ + return GetCurrentThreadId(); +} + void OS::Sleep(int milliseconds) { ::Sleep(milliseconds); } @@ -275,6 +281,8 @@ bool Sampler::RegisterCurrentThread(const char* aName, if (!Sampler::sRegisteredThreadsMutex) return false; + set_tls_stack_top(stackTop); + mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); ThreadInfo* info = new ThreadInfo(aName, GetCurrentThreadId(), @@ -295,6 +303,8 @@ void Sampler::UnregisterCurrentThread() if (!Sampler::sRegisteredThreadsMutex) return; + tlsStackTop.set(nullptr); + mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); int id = GetCurrentThreadId(); @@ -308,3 +318,26 @@ void Sampler::UnregisterCurrentThread() } } } + +void TickSample::PopulateContext(void* aContext) +{ + MOZ_ASSERT(aContext); + CONTEXT* pContext = reinterpret_cast(aContext); + context = pContext; + RtlCaptureContext(pContext); + +#if defined(SPS_PLAT_amd64_windows) + + pc = reinterpret_cast
(pContext->Rip); + sp = reinterpret_cast
(pContext->Rsp); + fp = reinterpret_cast
(pContext->Rbp); + +#elif defined(SPS_PLAT_x86_windows) + + pc = reinterpret_cast
(pContext->Eip); + sp = reinterpret_cast
(pContext->Esp); + fp = reinterpret_cast
(pContext->Ebp); + +#endif +} + diff --git a/tools/profiler/platform.cpp b/tools/profiler/platform.cpp index 2e171ec9b044..360593e9da50 100644 --- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -31,6 +31,7 @@ mozilla::ThreadLocal tlsPseudoStack; mozilla::ThreadLocal tlsTicker; +mozilla::ThreadLocal tlsStackTop; // We need to track whether we've been initialized otherwise // we end up using tlsStack without initializing it. // Because tlsStack is totally opaque to us we can't reuse @@ -132,35 +133,6 @@ template void ProfilerMarker::BuildJSObject(JSObjectBuilder& b, JSObjectBuilder::ArrayHandle markers) const; -void -ProfilerMarkerLinkedList::insert(ProfilerMarker* elem) { - if (!mTail) { - mHead = elem; - mTail = elem; - } else { - mTail->mNext = elem; - mTail = elem; - } - elem->mNext = nullptr; -} - -ProfilerMarker* -ProfilerMarkerLinkedList::popHead() { - if (!mHead) { - MOZ_ASSERT(false); - return nullptr; - } - - ProfilerMarker* head = mHead; - - mHead = head->mNext; - if (!mHead) { - mTail = nullptr; - } - - return head; -} - PendingMarkers::~PendingMarkers() { clearMarkers(); if (mSignalLock != false) { @@ -382,6 +354,19 @@ void read_profiler_env_vars() return; } +void set_tls_stack_top(void* stackTop) +{ + // Round |stackTop| up to the end of the containing page. We may + // as well do this -- there's no danger of a fault, and we might + // get a few more base-of-the-stack frames as a result. This + // assumes that no target has a page size smaller than 4096. + uintptr_t stackTopR = (uintptr_t)stackTop; + if (stackTop) { + stackTopR = (stackTopR & ~(uintptr_t)4095) + (uintptr_t)4095; + } + tlsStackTop.set((void*)stackTopR); +} + //////////////////////////////////////////////////////////////////////// // BEGIN externally visible functions @@ -393,7 +378,7 @@ void mozilla_sampler_init(void* stackTop) return; LOG("BEGIN mozilla_sampler_init"); - if (!tlsPseudoStack.init() || !tlsTicker.init()) { + if (!tlsPseudoStack.init() || !tlsTicker.init() || !tlsStackTop.init()) { LOG("Failed to init."); return; } @@ -759,15 +744,48 @@ void mozilla_sampler_unregister_thread() #endif } -double mozilla_sampler_time() +double mozilla_sampler_time(const TimeStamp& aTime) { if (!mozilla_sampler_is_active()) { return 0.0; } - TimeDuration delta = TimeStamp::Now() - sStartTime; + TimeDuration delta = aTime - sStartTime; return delta.ToMilliseconds(); } +double mozilla_sampler_time() +{ + return mozilla_sampler_time(TimeStamp::Now()); +} + +ProfilerBacktrace* mozilla_sampler_get_backtrace() +{ + if (!stack_key_initialized) + return nullptr; + + // Don't capture a stack if we're not profiling + if (!profiler_is_active()) { + return nullptr; + } + + // Don't capture a stack if we don't want to include personal information + if (profiler_in_privacy_mode()) { + return nullptr; + } + + TableTicker* t = tlsTicker.get(); + if (!t) { + return nullptr; + } + + return new ProfilerBacktrace(t->GetBacktrace()); +} + +void mozilla_sampler_free_backtrace(ProfilerBacktrace* aBacktrace) +{ + delete aBacktrace; +} + // END externally visible functions //////////////////////////////////////////////////////////////////////// diff --git a/tools/profiler/platform.h b/tools/profiler/platform.h index 3b2350d7e168..bcc98174b959 100644 --- a/tools/profiler/platform.h +++ b/tools/profiler/platform.h @@ -199,12 +199,17 @@ class Thread { #ifdef XP_WIN HANDLE thread_; - unsigned thread_id_; + typedef DWORD tid_t; + tid_t thread_id_; +#else + typedef ::pid_t tid_t; #endif #if defined(XP_MACOSX) pthread_t thread_; #endif + static tid_t GetCurrentId(); + private: void set_name(const char *name); @@ -243,6 +248,7 @@ extern int sUnwindStackScan; /* max # of dubious frames allowed */ extern int sProfileEntries; /* how many entries do we store? */ +void set_tls_stack_top(void* stackTop); // ---------------------------------------------------------------------------- // Sampler @@ -265,27 +271,28 @@ class TickSample { #ifdef ENABLE_ARM_LR_SAVING lr(NULL), #endif - function(NULL), context(NULL), - frames_count(0) {} + isSamplingCurrentThread(false) {} + + void PopulateContext(void* aContext); + Address pc; // Instruction pointer. Address sp; // Stack pointer. Address fp; // Frame pointer. #ifdef ENABLE_ARM_LR_SAVING Address lr; // ARM link register #endif - Address function; // The last called JS function. void* context; // The context from the signal handler, if available. On // Win32 this may contain the windows thread context. + bool isSamplingCurrentThread; ThreadProfile* threadProfile; - static const int kMaxFramesCount = 64; - int frames_count; // Number of captured frames. mozilla::TimeStamp timestamp; }; class ThreadInfo; class PlatformData; class TableTicker; +class SyncProfile; class Sampler { public: // Initialize sampler. @@ -298,6 +305,9 @@ class Sampler { // program counter. virtual void Tick(TickSample* sample) = 0; + // Immediately captures the calling thread's call stack and returns it. + virtual SyncProfile* GetBacktrace() = 0; + // Request a save from a signal handler virtual void RequestSave() = 0; // Process any outstanding request outside a signal handler. From 439417c81903d05c70f23128696a546f63fae889 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 25 Sep 2013 11:50:51 -0400 Subject: [PATCH 18/62] Backed out changesets af0dda676cb7, 550e2f5b4224, and bb76828c5f22 (bug 842828) for B2G bustage and xpcshell failures. CLOSED TREE --- b2g/app/b2g.js | 3 + browser/app/profile/firefox.js | 3 + browser/metro/profile/metro.js | 3 + mobile/android/app/mobile.js | 3 + modules/libpref/src/init/all.js | 6 - toolkit/components/build/nsToolkitCompsCID.h | 6 + .../components/build/nsToolkitCompsModule.cpp | 4 + .../downloads/ApplicationReputation.cpp | 372 ++++++++---------- .../downloads/ApplicationReputation.h | 68 +++- .../downloads/nsIApplicationReputation.idl | 15 +- .../downloads/test/unit/data/digest.chunk | 2 - .../downloads/test/unit/test_app_rep.js | 180 ++------- .../url-classifier/SafeBrowsing.jsm | 10 +- toolkit/components/url-classifier/moz.build | 6 - .../nsUrlClassifierDBService.cpp | 105 +++-- .../url-classifier/nsUrlClassifierDBService.h | 2 +- 16 files changed, 338 insertions(+), 450 deletions(-) delete mode 100644 toolkit/components/downloads/test/unit/data/digest.chunk diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 1a5666467b53..8c528941c8ca 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -330,6 +330,9 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); +// The list of tables that use the gethash request to confirm partial results. +pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); + // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index f13caa8e32f8..4b9ebbc6ac3a 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -803,6 +803,9 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); +// The list of tables that use the gethash request to confirm partial results. +pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); + // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/browser/metro/profile/metro.js b/browser/metro/profile/metro.js index 346f8a3ef7de..c87617f0ca29 100644 --- a/browser/metro/profile/metro.js +++ b/browser/metro/profile/metro.js @@ -607,6 +607,9 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); +// The list of tables that use the gethash request to confirm partial results. +pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); + // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index c68a7f9eb4f8..000e442e88da 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -600,6 +600,9 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); +// The list of tables that use the gethash request to confirm partial results. +pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); + // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index feca2a6d015b..c5d986b9c736 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -4428,9 +4428,3 @@ pref("dom.telephony.enabled", false); // DOM Inter-App Communication API. pref("dom.inter-app-communication-api.enabled", false); - -// The tables used for Safebrowsing phishing and malware checks. -pref("urlclassifier.malware_table", "goog-malware-shavar"); -pref("urlclassifier.phish_table", "goog-phish-shavar"); -pref("urlclassifier.download_block_table", "goog-badbinurl-shavar"); -pref("urlclassifier.download_allow_table", "goog-downloadwhite-digest256"); diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index b0b12f44f978..9b25877e58f6 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -175,6 +175,12 @@ { 0xf3dcf644, 0x79e8, 0x4f59, { 0xa1, 0xbb, 0x87, 0x84, 0x54, 0x48, 0x8e, 0xf9 } } #endif +#define NS_APPLICATION_REPUTATION_QUERY_CONTRACTID \ + "@mozilla.org/downloads/application-reputation-query;1" + +#define NS_APPLICATION_REPUTATION_QUERY_CID \ +{ 0x857da2c0, 0xcfe5, 0x11e2, { 0x8b, 0x8b, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } } + #define NS_APPLICATION_REPUTATION_SERVICE_CONTRACTID \ "@mozilla.org/downloads/application-reputation-service;1" diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index ebeb8af008cc..eb77441573f0 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -79,6 +79,7 @@ nsUrlClassifierDBServiceConstructor(nsISupports *aOuter, REFNSIID aIID, } #endif +NS_GENERIC_FACTORY_CONSTRUCTOR(ApplicationReputationQuery) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ApplicationReputationService, ApplicationReputationService::GetSingleton) NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserStatusFilter) @@ -86,6 +87,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserStatusFilter) NS_GENERIC_FACTORY_CONSTRUCTOR(nsUpdateProcessor) #endif +NS_DEFINE_NAMED_CID(NS_APPLICATION_REPUTATION_QUERY_CID); NS_DEFINE_NAMED_CID(NS_APPLICATION_REPUTATION_SERVICE_CID); NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID); NS_DEFINE_NAMED_CID(NS_USERINFO_CID); @@ -111,6 +113,7 @@ NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID); #endif static const mozilla::Module::CIDEntry kToolkitCIDs[] = { + { &kNS_APPLICATION_REPUTATION_QUERY_CID, false, NULL, ApplicationReputationQueryConstructor }, { &kNS_APPLICATION_REPUTATION_SERVICE_CID, false, NULL, ApplicationReputationServiceConstructor }, { &kNS_TOOLKIT_APPSTARTUP_CID, false, NULL, nsAppStartupConstructor }, { &kNS_USERINFO_CID, false, NULL, nsUserInfoConstructor }, @@ -138,6 +141,7 @@ static const mozilla::Module::CIDEntry kToolkitCIDs[] = { }; static const mozilla::Module::ContractIDEntry kToolkitContracts[] = { + { NS_APPLICATION_REPUTATION_QUERY_CONTRACTID, &kNS_APPLICATION_REPUTATION_QUERY_CID }, { NS_APPLICATION_REPUTATION_SERVICE_CONTRACTID, &kNS_APPLICATION_REPUTATION_SERVICE_CID }, { NS_APPSTARTUP_CONTRACTID, &kNS_TOOLKIT_APPSTARTUP_CID }, { NS_USERINFO_CONTRACTID, &kNS_USERINFO_CID }, diff --git a/toolkit/components/downloads/ApplicationReputation.cpp b/toolkit/components/downloads/ApplicationReputation.cpp index 6dc936c321e2..99c743f9ea72 100644 --- a/toolkit/components/downloads/ApplicationReputation.cpp +++ b/toolkit/components/downloads/ApplicationReputation.cpp @@ -11,8 +11,8 @@ #include "nsIChannel.h" #include "nsIHttpChannel.h" #include "nsIIOService.h" +#include "nsIObserverService.h" #include "nsIPrefService.h" -#include "nsIScriptSecurityManager.h" #include "nsIStreamListener.h" #include "nsIStringStream.h" #include "nsIUploadChannel2.h" @@ -25,7 +25,6 @@ #include "nsDebug.h" #include "nsError.h" #include "nsNetCID.h" -#include "nsReadableUtils.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsThreadUtils.h" @@ -39,117 +38,79 @@ using mozilla::Preferences; #define PREF_SB_APP_REP_URL "browser.safebrowsing.appRepURL" #define PREF_SB_MALWARE_ENABLED "browser.safebrowsing.malware.enabled" #define PREF_GENERAL_LOCALE "general.useragent.locale" -#define PREF_DOWNLOAD_BLOCK_TABLE "urlclassifier.download_block_table" -#define PREF_DOWNLOAD_ALLOW_TABLE "urlclassifier.download_allow_table" -/** - * Keep track of pending lookups. Once the ApplicationReputationService creates - * this, it is guaranteed to call mCallback. This class is private to - * ApplicationReputationService. - */ -class PendingLookup MOZ_FINAL : - public nsIStreamListener, - public nsIUrlClassifierCallback { -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIURLCLASSIFIERCALLBACK - PendingLookup(nsIApplicationReputationQuery* aQuery, - nsIApplicationReputationCallback* aCallback); - ~PendingLookup(); +NS_IMPL_ISUPPORTS1(ApplicationReputationService, nsIApplicationReputationService) -private: - nsCOMPtr mQuery; - nsCOMPtr mCallback; - /** - * The response from the application reputation query. This is read in chunks - * as part of our nsIStreamListener implementation and may contain embedded - * NULLs. - */ - nsCString mResponse; - /** - * Clean up and call the callback. PendingLookup must not be used after this - * function is called. - */ - nsresult OnComplete(bool shouldBlock, nsresult rv); - /** - * Wrapper function for nsIStreamListener.onStopRequest to make it easy to - * guarantee calling the callback - */ - nsresult OnStopRequestInternal(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aResult, - bool* aShouldBlock); - /** - * Sends a query to the remote application reputation service. Returns NS_OK - * on success. - */ - nsresult SendRemoteQuery(); -}; +ApplicationReputationService* ApplicationReputationService::gApplicationReputationService = nullptr; -NS_IMPL_ISUPPORTS3(PendingLookup, - nsIStreamListener, - nsIRequestObserver, - nsIUrlClassifierCallback) +ApplicationReputationService * +ApplicationReputationService::GetSingleton() +{ + if (gApplicationReputationService) { + NS_ADDREF(gApplicationReputationService); + return gApplicationReputationService; + } -PendingLookup::PendingLookup(nsIApplicationReputationQuery* aQuery, - nsIApplicationReputationCallback* aCallback) : - mQuery(aQuery), - mCallback(aCallback) { + gApplicationReputationService = new ApplicationReputationService(); + if (gApplicationReputationService) { + NS_ADDREF(gApplicationReputationService); + } + + return gApplicationReputationService; } -PendingLookup::~PendingLookup() { -} +ApplicationReputationService::ApplicationReputationService() { } +ApplicationReputationService::~ApplicationReputationService() { } -nsresult -PendingLookup::OnComplete(bool shouldBlock, nsresult rv) { - nsresult res = mCallback->OnComplete(shouldBlock, rv); - return res; -} - -//////////////////////////////////////////////////////////////////////////////// -//// nsIUrlClassifierCallback NS_IMETHODIMP -PendingLookup::HandleEvent(const nsACString& tables) { - // HandleEvent is guaranteed to call the callback if either the URL can be - // classified locally, or if there is an error sending the remote lookup. - // Allow listing trumps block listing. - nsCString allow_list; - Preferences::GetCString(PREF_DOWNLOAD_ALLOW_TABLE, &allow_list); - if (FindInReadable(tables, allow_list)) { - return OnComplete(false, NS_OK); - } +ApplicationReputationService::QueryReputation( + nsIApplicationReputationQuery* aQuery, + nsIApplicationReputationCallback* aCallback) { + NS_ENSURE_ARG_POINTER(aQuery); + NS_ENSURE_ARG_POINTER(aCallback); - nsCString block_list; - Preferences::GetCString(PREF_DOWNLOAD_BLOCK_TABLE, &block_list); - if (FindInReadable(tables, block_list)) { - return OnComplete(true, NS_OK); - } - - nsresult rv = SendRemoteQuery(); + nsresult rv = QueryReputationInternal(aQuery, aCallback); if (NS_FAILED(rv)) { - return OnComplete(false, rv); + aCallback->OnComplete(false, rv); + aCallback = nullptr; } return NS_OK; } nsresult -PendingLookup::SendRemoteQuery() { - // We did not find a local result, so fire off the query to the application - // reputation service. - safe_browsing::ClientDownloadRequest req; - nsCOMPtr uri; +ApplicationReputationService::QueryReputationInternal( + nsIApplicationReputationQuery* aQuery, + nsIApplicationReputationCallback* aCallback) { nsresult rv; - rv = mQuery->GetSourceURI(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); - nsCString spec; - rv = uri->GetSpec(spec); - NS_ENSURE_SUCCESS(rv, rv); - req.set_url(spec.get()); + aQuery->SetCallback(aCallback); + // If malware checks aren't enabled, don't query application reputation. + if (!Preferences::GetBool(PREF_SB_MALWARE_ENABLED, false)) { + return NS_ERROR_NOT_AVAILABLE; + } + + // If there is no service URL for querying application reputation, abort. + nsCString serviceUrl; + NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_SB_APP_REP_URL, &serviceUrl), + NS_ERROR_NOT_AVAILABLE); + if (serviceUrl.EqualsLiteral("")) { + return NS_ERROR_NOT_AVAILABLE; + } + + safe_browsing::ClientDownloadRequest req; + + nsCString spec; + nsCOMPtr aURI; + rv = aQuery->GetSourceURI(getter_AddRefs(aURI)); + NS_ENSURE_SUCCESS(rv, rv); + // If the URI hasn't been set, bail + NS_ENSURE_STATE(aURI); + rv = aURI->GetSpec(spec); + NS_ENSURE_SUCCESS(rv, rv); + + req.set_url(spec.get()); uint32_t fileSize; - rv = mQuery->GetFileSize(&fileSize); + rv = aQuery->GetFileSize(&fileSize); NS_ENSURE_SUCCESS(rv, rv); req.set_length(fileSize); // We have no way of knowing whether or not a user initiated the download. @@ -160,11 +121,11 @@ PendingLookup::SendRemoteQuery() { NS_ERROR_NOT_AVAILABLE); req.set_locale(locale.get()); nsCString sha256Hash; - rv = mQuery->GetSha256Hash(sha256Hash); + rv = aQuery->GetSha256Hash(sha256Hash); NS_ENSURE_SUCCESS(rv, rv); req.mutable_digests()->set_sha256(sha256Hash.Data()); nsString fileName; - rv = mQuery->GetSuggestedFileName(fileName); + rv = aQuery->GetSuggestedFileName(fileName); NS_ENSURE_SUCCESS(rv, rv); req.set_file_basename(NS_ConvertUTF16toUTF8(fileName).get()); @@ -189,9 +150,6 @@ PendingLookup::SendRemoteQuery() { // Set up the channel to transmit the request to the service. nsCOMPtr channel; - nsCString serviceUrl; - NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_SB_APP_REP_URL, &serviceUrl), - NS_ERROR_NOT_AVAILABLE); rv = ios->NewChannel(serviceUrl, nullptr, nullptr, getter_AddRefs(channel)); NS_ENSURE_SUCCESS(rv, rv); @@ -213,14 +171,96 @@ PendingLookup::SendRemoteQuery() { NS_LITERAL_CSTRING("POST"), false); NS_ENSURE_SUCCESS(rv, rv); - rv = channel->AsyncOpen(this, nullptr); + nsCOMPtr listener = do_QueryInterface(aQuery, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = channel->AsyncOpen(listener, nullptr); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } +NS_IMPL_ISUPPORTS3(ApplicationReputationQuery, + nsIApplicationReputationQuery, + nsIStreamListener, + nsIRequestObserver) + +ApplicationReputationQuery::ApplicationReputationQuery() : + mURI(nullptr), + mFileSize(0), + mCallback(nullptr) { +} + +ApplicationReputationQuery::~ApplicationReputationQuery() { +} + +NS_IMETHODIMP +ApplicationReputationQuery::GetSourceURI(nsIURI** aURI) { + *aURI = mURI; + NS_IF_ADDREF(*aURI); + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::SetSourceURI(nsIURI* aURI) { + mURI = aURI; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::GetSuggestedFileName( + nsAString& aSuggestedFileName) { + aSuggestedFileName = mSuggestedFileName; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::SetSuggestedFileName( + const nsAString& aSuggestedFileName) { + mSuggestedFileName = aSuggestedFileName; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::GetFileSize(uint32_t* aFileSize) { + *aFileSize = mFileSize; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::SetFileSize(uint32_t aFileSize) { + mFileSize = aFileSize; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::GetSha256Hash(nsACString& aSha256Hash) { + aSha256Hash = mSha256Hash; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::SetSha256Hash(const nsACString& aSha256Hash) { + mSha256Hash = aSha256Hash; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::GetCallback( + nsIApplicationReputationCallback** aCallback) { + *aCallback = mCallback; + return NS_OK; +} + +NS_IMETHODIMP +ApplicationReputationQuery::SetCallback( + nsIApplicationReputationCallback* aCallback) { + mCallback = aCallback; + return NS_OK; +} + //////////////////////////////////////////////////////////////////////////////// //// nsIStreamListener + static NS_METHOD AppendSegmentToString(nsIInputStream* inputStream, void *closure, @@ -235,39 +275,40 @@ AppendSegmentToString(nsIInputStream* inputStream, } NS_IMETHODIMP -PendingLookup::OnDataAvailable(nsIRequest *aRequest, - nsISupports *aContext, - nsIInputStream *aStream, - uint64_t offset, - uint32_t count) { +ApplicationReputationQuery::OnDataAvailable(nsIRequest *aRequest, + nsISupports *aContext, + nsIInputStream *aStream, + uint64_t offset, + uint32_t count) { uint32_t read; return aStream->ReadSegments(AppendSegmentToString, &mResponse, count, &read); } NS_IMETHODIMP -PendingLookup::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) { +ApplicationReputationQuery::OnStartRequest(nsIRequest *aRequest, + nsISupports *aContext) { return NS_OK; } NS_IMETHODIMP -PendingLookup::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aResult) { +ApplicationReputationQuery::OnStopRequest(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aResult) { NS_ENSURE_STATE(mCallback); bool shouldBlock = false; nsresult rv = OnStopRequestInternal(aRequest, aContext, aResult, &shouldBlock); - OnComplete(shouldBlock, rv); + mCallback->OnComplete(shouldBlock, rv); + mCallback = nullptr; return rv; } nsresult -PendingLookup::OnStopRequestInternal(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aResult, - bool* aShouldBlock) { +ApplicationReputationQuery::OnStopRequestInternal(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aResult, + bool* aShouldBlock) { *aShouldBlock = false; nsresult rv; nsCOMPtr channel = do_QueryInterface(aRequest, &rv); @@ -296,102 +337,3 @@ PendingLookup::OnStopRequestInternal(nsIRequest *aRequest, return NS_OK; } - -NS_IMPL_ISUPPORTS1(ApplicationReputationService, - nsIApplicationReputationService) - -ApplicationReputationService* - ApplicationReputationService::gApplicationReputationService = nullptr; - -ApplicationReputationService* -ApplicationReputationService::GetSingleton() -{ - if (gApplicationReputationService) { - NS_ADDREF(gApplicationReputationService); - return gApplicationReputationService; - } - - // We're not initialized yet. - gApplicationReputationService = new ApplicationReputationService(); - if (gApplicationReputationService) { - NS_ADDREF(gApplicationReputationService); - } - - return gApplicationReputationService; -} - -ApplicationReputationService::ApplicationReputationService() : - mDBService(nullptr), - mSecurityManager(nullptr) { -} - -ApplicationReputationService::~ApplicationReputationService() { -} - -NS_IMETHODIMP -ApplicationReputationService::QueryReputation( - nsIApplicationReputationQuery* aQuery, - nsIApplicationReputationCallback* aCallback) { - NS_ENSURE_ARG_POINTER(aQuery); - NS_ENSURE_ARG_POINTER(aCallback); - - nsresult rv = QueryReputationInternal(aQuery, aCallback); - if (NS_FAILED(rv)) { - aCallback->OnComplete(false, rv); - } - return NS_OK; -} - -nsresult ApplicationReputationService::QueryReputationInternal( - nsIApplicationReputationQuery* aQuery, - nsIApplicationReputationCallback* aCallback) { - // Lazily instantiate mDBService and mSecurityManager - nsresult rv; - if (!mDBService) { - mDBService = do_GetService(NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - } - if (!mSecurityManager) { - mSecurityManager = do_GetService("@mozilla.org/scriptsecuritymanager;1", - &rv); - NS_ENSURE_SUCCESS(rv, rv); - } - // If malware checks aren't enabled, don't query application reputation. - if (!Preferences::GetBool(PREF_SB_MALWARE_ENABLED, false)) { - return NS_ERROR_NOT_AVAILABLE; - } - - // If there is no service URL for querying application reputation, abort. - nsCString serviceUrl; - NS_ENSURE_SUCCESS(Preferences::GetCString(PREF_SB_APP_REP_URL, &serviceUrl), - NS_ERROR_NOT_AVAILABLE); - if (serviceUrl.EqualsLiteral("")) { - return NS_ERROR_NOT_AVAILABLE; - } - - // We must be able to create a principal and query local lists. - NS_ENSURE_STATE(mDBService); - NS_ENSURE_STATE(mSecurityManager); - - // Create a new pending lookup. - nsRefPtr lookup(new PendingLookup(aQuery, aCallback)); - NS_ENSURE_STATE(lookup); - - nsCOMPtr uri; - rv = aQuery->GetSourceURI(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); - // If the URI hasn't been set, bail - NS_ENSURE_STATE(uri); - nsCOMPtr principal; - // In nsIUrlClassifierDBService.lookup, the only use of the principal is to - // wrap the URI. nsISecurityManager.getNoAppCodebasePrincipal is the easiest - // way to wrap a URI inside a principal, since principals can't be - // constructed. - rv = mSecurityManager->GetNoAppCodebasePrincipal(uri, - getter_AddRefs(principal)); - NS_ENSURE_SUCCESS(rv, rv); - - // Check local lists to see if the URI has already been whitelisted or - // blacklisted. - return mDBService->Lookup(principal, lookup); -} diff --git a/toolkit/components/downloads/ApplicationReputation.h b/toolkit/components/downloads/ApplicationReputation.h index c6774fb1f882..775cf2fcda25 100644 --- a/toolkit/components/downloads/ApplicationReputation.h +++ b/toolkit/components/downloads/ApplicationReputation.h @@ -11,16 +11,15 @@ #include "nsIRequestObserver.h" #include "nsIStreamListener.h" #include "nsISupports.h" -#include "nsIUrlClassifierDBService.h" -#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsString.h" +class nsIApplicationReputationListener; +class nsIChannel; +class nsIObserverService; class nsIRequest; -class nsIUrlClassifierDBService; -class nsIScriptSecurityManager; -class PendingLookup; +class PRLogModuleInfo; class ApplicationReputationService MOZ_FINAL : public nsIApplicationReputationService { @@ -36,16 +35,10 @@ private: * Global singleton object for holding this factory service. */ static ApplicationReputationService* gApplicationReputationService; - /** - * Keeps track of services used to query the local database of URLs. - */ - nsCOMPtr mDBService; - nsCOMPtr mSecurityManager; - /** - * This is a singleton, so disallow construction. - */ + ApplicationReputationService(); ~ApplicationReputationService(); + /** * Wrapper function for QueryReputation that makes it easier to ensure the * callback is called. @@ -53,4 +46,53 @@ private: nsresult QueryReputationInternal(nsIApplicationReputationQuery* aQuery, nsIApplicationReputationCallback* aCallback); }; + +/** + * This class implements nsIApplicationReputation. See the + * nsIApplicationReputation.idl for details. ApplicationReputation also + * implements nsIStreamListener because it calls nsIChannel->AsyncOpen. + */ +class ApplicationReputationQuery MOZ_FINAL : + public nsIApplicationReputationQuery, + public nsIStreamListener { +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIAPPLICATIONREPUTATIONQUERY + + ApplicationReputationQuery(); + ~ApplicationReputationQuery(); + +private: + /** + * Corresponding member variables for the attributes in the IDL. + */ + nsString mSuggestedFileName; + nsCOMPtr mURI; + uint32_t mFileSize; + nsCString mSha256Hash; + + /** + * The callback for the request. + */ + nsCOMPtr mCallback; + + /** + * The response from the application reputation query. This is read in chunks + * as part of our nsIStreamListener implementation and may contain embedded + * NULLs. + */ + nsCString mResponse; + + /** + * Wrapper function for nsIStreamListener.onStopRequest to make it easy to + * guarantee calling the callback + */ + nsresult OnStopRequestInternal(nsIRequest *aRequest, + nsISupports *aContext, + nsresult aResult, + bool* aShouldBlock); +}; + #endif /* ApplicationReputation_h__ */ diff --git a/toolkit/components/downloads/nsIApplicationReputation.idl b/toolkit/components/downloads/nsIApplicationReputation.idl index b346a8f49416..b947de9fecb3 100644 --- a/toolkit/components/downloads/nsIApplicationReputation.idl +++ b/toolkit/components/downloads/nsIApplicationReputation.idl @@ -43,12 +43,12 @@ interface nsIApplicationReputationService : nsISupports { * downloaded file. nsIApplicationReputationService.Start() may only be called * once with a single query. */ -[scriptable, uuid(5a054991-e489-4a1c-a0aa-ea7c69b20e3d)] +[scriptable, uuid(857da2c0-cfe5-11e2-8b8b-0800200c9a66)] interface nsIApplicationReputationQuery : nsISupports { /* * The nsIURI from which the file was downloaded. This may not be null. */ - readonly attribute nsIURI sourceURI; + attribute nsIURI sourceURI; /* * The target filename for the downloaded file, as inferred from the source @@ -56,19 +56,24 @@ interface nsIApplicationReputationQuery : nsISupports { * is not set by the caller, it will be passed as an empty string but the * query won't produce any useful information. */ - readonly attribute AString suggestedFileName; + attribute AString suggestedFileName; /* * The size of the downloaded file in bytes. */ - readonly attribute unsigned long fileSize; + attribute unsigned long fileSize; /* * The SHA256 hash of the downloaded file in raw bytes. If this is not set by * the caller, it will be passed as an empty string but the query won't * produce any useful information. */ - readonly attribute ACString sha256Hash; + attribute ACString sha256Hash; + + /** + * The callback object listening to this query. + */ + attribute nsIApplicationReputationCallback callback; }; [scriptable, function, uuid(9a228470-cfe5-11e2-8b8b-0800200c9a66)] diff --git a/toolkit/components/downloads/test/unit/data/digest.chunk b/toolkit/components/downloads/test/unit/data/digest.chunk deleted file mode 100644 index 738c96f6ba17..000000000000 --- a/toolkit/components/downloads/test/unit/data/digest.chunk +++ /dev/null @@ -1,2 +0,0 @@ -a:5:32:32 -“Ê_Há^˜aÍ7ÂÙ]´=#ÌnmåÃøún‹æo—ÌQ‰ \ No newline at end of file diff --git a/toolkit/components/downloads/test/unit/test_app_rep.js b/toolkit/components/downloads/test/unit/test_app_rep.js index c7155c339bf2..a77a75202e1d 100644 --- a/toolkit/components/downloads/test/unit/test_app_rep.js +++ b/toolkit/components/downloads/test/unit/test_app_rep.js @@ -7,47 +7,13 @@ Cu.import('resource://gre/modules/NetUtil.jsm'); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +const ApplicationReputationQuery = Components.Constructor( + "@mozilla.org/downloads/application-reputation-query;1", + "nsIApplicationReputationQuery"); + const gAppRep = Cc["@mozilla.org/downloads/application-reputation-service;1"]. getService(Ci.nsIApplicationReputationService); let gHttpServ = null; -let gTables = {}; - -function readFileToString(aFilename) { - let f = do_get_file(aFilename); - let stream = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - stream.init(f, -1, 0, 0); - let buf = NetUtil.readInputStreamToString(stream, stream.available()); - return buf; -} - -// Registers a table for which to serve update chunks. Returns a promise that -// resolves when that chunk has been downloaded. -function registerTableUpdate(aTable, aFilename) { - // If we haven't been given an update for this table yet, add it to the map - if (!(aTable in gTables)) { - gTables[aTable] = []; - } - - // The number of chunks associated with this table. - let numChunks = gTables[aTable].length + 1; - let redirectPath = "/" + aTable + "-" + numChunks; - let redirectUrl = "localhost:4444" + redirectPath; - - // Store redirect url for that table so we can return it later when we - // process an update request. - gTables[aTable].push(redirectUrl); - - gHttpServ.registerPathHandler(redirectPath, function(request, response) { - do_print("Mock safebrowsing server handling request for " + redirectPath); - let contents = readFileToString(aFilename); - do_print("Length of " + aFilename + ": " + contents.length); - response.setHeader("Content-Type", - "application/vnd.google.safebrowsing-update", false); - response.setStatusLine(request.httpVersion, 200, "OK"); - response.bodyOutputStream.write(contents, contents.length); - }); -} function run_test() { // Set up a local HTTP server to return bad verdicts. @@ -83,16 +49,13 @@ function run_test() { request.bodyInputStream, request.bodyInputStream.available()); do_print("Request length: " + buf.length); - // A garbage response. By default this produces NS_CANNOT_CONVERT_DATA as - // the callback status. + // A garbage response. let blob = "this is not a serialized protocol buffer"; // We can't actually parse the protocol buffer here, so just switch on the // length instead of inspecting the contents. if (buf.length == 35) { - // evil.com blob = createVerdict(true); } else if (buf.length == 38) { - // mozilla.com blob = createVerdict(false); } response.bodyOutputStream.write(blob, blob.length); @@ -104,10 +67,11 @@ function run_test() { } add_test(function test_shouldBlock() { - gAppRep.queryReputation({ - sourceURI: createURI("http://evil.com"), - fileSize: 12, - }, function onComplete(aShouldBlock, aStatus) { + let query = new ApplicationReputationQuery(); + query.sourceURI = createURI("http://evil.com"); + query.fileSize = 12; + + gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { do_check_true(aShouldBlock); do_check_eq(Cr.NS_OK, aStatus); run_next_test(); @@ -115,21 +79,35 @@ add_test(function test_shouldBlock() { }); add_test(function test_shouldNotBlock() { - gAppRep.queryReputation({ - sourceURI: createURI("http://mozilla.com"), - fileSize: 12, - }, function onComplete(aShouldBlock, aStatus) { + let query = new ApplicationReputationQuery(); + query.sourceURI = createURI("http://mozilla.com"); + query.fileSize = 12; + + gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { do_check_eq(Cr.NS_OK, aStatus); do_check_false(aShouldBlock); run_next_test(); }); }); +add_test(function test_garbage() { + let query = new ApplicationReputationQuery(); + query.sourceURI = createURI("http://thisisagarbageurl.com"); + query.fileSize = 12; + + gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { + // We should be getting the garbage response. + do_check_eq(Cr.NS_ERROR_CANNOT_CONVERT_DATA, aStatus); + do_check_false(aShouldBlock); + run_next_test(); + }); +}); + add_test(function test_nullSourceURI() { - gAppRep.queryReputation({ - // No source URI - fileSize: 12, - }, function onComplete(aShouldBlock, aStatus) { + let query = new ApplicationReputationQuery(); + query.fileSize = 12; + // No source URI + gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { do_check_eq(Cr.NS_ERROR_UNEXPECTED, aStatus); do_check_false(aShouldBlock); run_next_test(); @@ -137,11 +115,10 @@ add_test(function test_nullSourceURI() { }); add_test(function test_nullCallback() { + let query = new ApplicationReputationQuery(); + query.fileSize = 12; try { - gAppRep.queryReputation({ - sourceURI: createURI("http://example.com"), - fileSize: 12, - }, null); + gAppRep.queryReputation(query, null); do_throw("Callback cannot be null"); } catch (ex if ex.result == Cr.NS_ERROR_INVALID_POINTER) { run_next_test(); @@ -150,92 +127,13 @@ add_test(function test_nullCallback() { add_test(function test_disabled() { Services.prefs.setCharPref("browser.safebrowsing.appRepURL", ""); - gAppRep.queryReputation({ - sourceURI: createURI("http://example.com"), - fileSize: 12, - }, function onComplete(aShouldBlock, aStatus) { + let query = new ApplicationReputationQuery(); + query.sourceURI = createURI("http://example.com"); + query.fileSize = 12; + gAppRep.queryReputation(query, function onComplete(aShouldBlock, aStatus) { // We should be getting NS_ERROR_NOT_AVAILABLE if the service is disabled do_check_eq(Cr.NS_ERROR_NOT_AVAILABLE, aStatus); do_check_false(aShouldBlock); run_next_test(); }); }); - -add_test(function test_garbage() { - Services.prefs.setCharPref("browser.safebrowsing.appRepURL", - "http://localhost:4444/download"); - gAppRep.queryReputation({ - sourceURI: createURI("http://whitelisted.com"), - fileSize: 12, - }, function onComplete(aShouldBlock, aStatus) { - // We should be getting the garbage response. - do_check_eq(Cr.NS_ERROR_CANNOT_CONVERT_DATA, aStatus); - do_check_false(aShouldBlock); - run_next_test(); - }); -}); - -// Set up the local whitelist. -add_test(function test_local_list() { - // Construct a response with redirect urls. - function processUpdateRequest() { - let response = "n:1000\n"; - for (let table in gTables) { - response += "i:" + table + "\n"; - for (let i = 0; i < gTables[table].length; ++i) { - response += "u:" + gTables[table][i] + "\n"; - } - } - do_print("Returning update response: " + response); - return response; - } - gHttpServ.registerPathHandler("/downloads", function(request, response) { - let buf = NetUtil.readInputStreamToString(request.bodyInputStream, - request.bodyInputStream.available()); - let blob = processUpdateRequest(); - response.setHeader("Content-Type", - "application/vnd.google.safebrowsing-update", false); - response.setStatusLine(request.httpVersion, 200, "OK"); - response.bodyOutputStream.write(blob, blob.length); - }); - - let streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"] - .getService(Ci.nsIUrlClassifierStreamUpdater); - streamUpdater.updateUrl = "http://localhost:4444/downloads"; - - // Load up some update chunks for the safebrowsing server to serve. This - // particular chunk contains the hash of whitelisted.com/. - registerTableUpdate("goog-downloadwhite-digest256", "data/digest.chunk"); - - // Download some updates, and don't continue until the downloads are done. - function updateSuccess(aEvent) { - // Timeout of n:1000 is constructed in processUpdateRequest above and - // passed back in the callback in nsIUrlClassifierStreamUpdater on success. - do_check_eq("1000", aEvent); - do_print("All data processed"); - run_next_test(); - } - // Just throw if we ever get an update or download error. - function handleError(aEvent) { - do_throw("We didn't download or update correctly: " + aEvent); - } - streamUpdater.downloadUpdates( - "goog-downloadwhite-digest256", - "goog-downloadwhite-digest256;\n", "", - updateSuccess, handleError, handleError); -}); - -// After being whitelisted, we shouldn't throw. -add_test(function test_local_whitelist() { - Services.prefs.setCharPref("browser.safebrowsing.appRepURL", - "http://localhost:4444/download"); - gAppRep.queryReputation({ - sourceURI: createURI("http://whitelisted.com"), - fileSize: 12, - }, function onComplete(aShouldBlock, aStatus) { - // We would get garbage if this query made it to the remote server. - do_check_eq(Cr.NS_OK, aStatus); - do_check_false(aShouldBlock); - run_next_test(); - }); -}); diff --git a/toolkit/components/url-classifier/SafeBrowsing.jsm b/toolkit/components/url-classifier/SafeBrowsing.jsm index 5f6df334eeb4..099d38da0f62 100644 --- a/toolkit/components/url-classifier/SafeBrowsing.jsm +++ b/toolkit/components/url-classifier/SafeBrowsing.jsm @@ -10,12 +10,8 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); -const phishingList = Services.prefs.getCharPref("urlclassifier.phish_table"); -const malwareList = Services.prefs.getCharPref("urlclassifier.malware_table"); -const downloadBlockList = - Services.prefs.getCharPref("urlclassifier.download_block_table"); -const downloadAllowList = - Services.prefs.getCharPref("urlclassifier.download_allow_table"); +const [phishingList, malwareList] = + Services.prefs.getCharPref("urlclassifier.gethashtables").split(",").map(function(value) value.trim()); var debug = false; function log(...stuff) { @@ -43,8 +39,6 @@ this.SafeBrowsing = { getService(Ci.nsIUrlListManager); listManager.registerTable(phishingList, false); listManager.registerTable(malwareList, false); - listManager.registerTable(downloadBlockList, false); - listManager.registerTable(downloadAllowList, false); this.addMozEntries(); this.controlUpdateChecking(); diff --git a/toolkit/components/url-classifier/moz.build b/toolkit/components/url-classifier/moz.build index 07ca62105681..4112828827f8 100644 --- a/toolkit/components/url-classifier/moz.build +++ b/toolkit/components/url-classifier/moz.build @@ -48,12 +48,6 @@ EXTRA_JS_MODULES += [ 'SafeBrowsing.jsm', ] -EXPORTS += [ - 'Entries.h', - 'LookupCache.h', - 'nsUrlClassifierPrefixSet.h' -] - FAIL_ON_WARNINGS = True LIBXUL_LIBRARY = True diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index e970a9b62849..fbda1291ff16 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -33,7 +33,6 @@ #include "mozilla/Atomics.h" #include "mozilla/DebugOnly.h" #include "mozilla/Mutex.h" -#include "mozilla/Preferences.h" #include "mozilla/TimeStamp.h" #include "mozilla/Telemetry.h" #include "prlog.h" @@ -69,10 +68,7 @@ PRLogModuleInfo *gUrlClassifierDbServiceLog = nullptr; #define GETHASH_NOISE_PREF "urlclassifier.gethashnoise" #define GETHASH_NOISE_DEFAULT 4 -#define MALWARE_TABLE_PREF "urlclassifier.malware_table" -#define PHISH_TABLE_PREF "urlclassifier.phish_table" -#define DOWNLOAD_BLOCK_TABLE_PREF "urlclassifier.download_block_table" -#define DOWNLOAD_ALLOW_TABLE_PREF "urlclassifier.download_allow_table" +#define GETHASH_TABLES_PREF "urlclassifier.gethashtables" #define CONFIRM_AGE_PREF "urlclassifier.max-complete-age" #define CONFIRM_AGE_DEFAULT_SEC (45 * 60) @@ -1119,34 +1115,43 @@ nsUrlClassifierDBService::Init() gUrlClassifierDbServiceLog = PR_NewLogModule("UrlClassifierDbService"); #endif - // Retrieve all the preferences. - mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF, - CHECK_MALWARE_DEFAULT); - mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF, - CHECK_PHISHING_DEFAULT); - uint32_t gethashNoise = Preferences::GetUint(GETHASH_NOISE_PREF, - GETHASH_NOISE_DEFAULT); - gFreshnessGuarantee = Preferences::GetInt(CONFIRM_AGE_PREF, - CONFIRM_AGE_DEFAULT_SEC); - mGethashTables.AppendElement(Preferences::GetCString(PHISH_TABLE_PREF)); - mGethashTables.AppendElement(Preferences::GetCString(MALWARE_TABLE_PREF)); - mGethashTables.AppendElement(Preferences::GetCString( - DOWNLOAD_BLOCK_TABLE_PREF)); - mGethashTables.AppendElement(Preferences::GetCString( - DOWNLOAD_ALLOW_TABLE_PREF)); + nsresult rv; - // Do we *really* need to be able to change all of these at runtime? - Preferences::AddStrongObserver(this, CHECK_MALWARE_PREF); - Preferences::AddStrongObserver(this, CHECK_PHISHING_PREF); - Preferences::AddStrongObserver(this, GETHASH_NOISE_PREF); - Preferences::AddStrongObserver(this, CONFIRM_AGE_PREF); - Preferences::AddStrongObserver(this, PHISH_TABLE_PREF); - Preferences::AddStrongObserver(this, MALWARE_TABLE_PREF); - Preferences::AddStrongObserver(this, DOWNLOAD_BLOCK_TABLE_PREF); - Preferences::AddStrongObserver(this, DOWNLOAD_ALLOW_TABLE_PREF); + // Should we check document loads for malware URIs? + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + + uint32_t gethashNoise = 0; + if (prefs) { + bool tmpbool; + rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool); + mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT; + + prefs->AddObserver(CHECK_MALWARE_PREF, this, false); + + rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool); + mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT; + + prefs->AddObserver(CHECK_PHISHING_PREF, this, false); + + int32_t tmpint; + rv = prefs->GetIntPref(GETHASH_NOISE_PREF, &tmpint); + gethashNoise = (NS_SUCCEEDED(rv) && tmpint >= 0) ? + static_cast(tmpint) : GETHASH_NOISE_DEFAULT; + + nsXPIDLCString tmpstr; + if (NS_SUCCEEDED(prefs->GetCharPref(GETHASH_TABLES_PREF, getter_Copies(tmpstr)))) { + SplitTables(tmpstr, mGethashWhitelist); + } + + prefs->AddObserver(GETHASH_TABLES_PREF, this, false); + + rv = prefs->GetIntPref(CONFIRM_AGE_PREF, &tmpint); + gFreshnessGuarantee = NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC; + + prefs->AddObserver(CONFIRM_AGE_PREF, this, false); + } // Force PSM loading on main thread - nsresult rv; nsCOMPtr acryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -1424,7 +1429,7 @@ nsUrlClassifierDBService::GetCompleter(const nsACString &tableName, return true; } - if (!mGethashTables.Contains(tableName)) { + if (!mGethashWhitelist.Contains(tableName)) { return false; } @@ -1441,26 +1446,23 @@ nsUrlClassifierDBService::Observe(nsISupports *aSubject, const char *aTopic, nsCOMPtr prefs(do_QueryInterface(aSubject, &rv)); NS_ENSURE_SUCCESS(rv, rv); if (NS_LITERAL_STRING(CHECK_MALWARE_PREF).Equals(aData)) { - mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF, - CHECK_MALWARE_DEFAULT); + bool tmpbool; + rv = prefs->GetBoolPref(CHECK_MALWARE_PREF, &tmpbool); + mCheckMalware = NS_SUCCEEDED(rv) ? tmpbool : CHECK_MALWARE_DEFAULT; } else if (NS_LITERAL_STRING(CHECK_PHISHING_PREF).Equals(aData)) { - mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF, - CHECK_PHISHING_DEFAULT); - } else if (NS_LITERAL_STRING(PHISH_TABLE_PREF).Equals(aData) || - NS_LITERAL_STRING(MALWARE_TABLE_PREF).Equals(aData) || - NS_LITERAL_STRING(DOWNLOAD_BLOCK_TABLE_PREF).Equals(aData) || - NS_LITERAL_STRING(DOWNLOAD_ALLOW_TABLE_PREF).Equals(aData)) { - // Just read everything again. - mGethashTables.Clear(); - mGethashTables.AppendElement(Preferences::GetCString(PHISH_TABLE_PREF)); - mGethashTables.AppendElement(Preferences::GetCString(MALWARE_TABLE_PREF)); - mGethashTables.AppendElement(Preferences::GetCString( - DOWNLOAD_BLOCK_TABLE_PREF)); - mGethashTables.AppendElement(Preferences::GetCString( - DOWNLOAD_ALLOW_TABLE_PREF)); + bool tmpbool; + rv = prefs->GetBoolPref(CHECK_PHISHING_PREF, &tmpbool); + mCheckPhishing = NS_SUCCEEDED(rv) ? tmpbool : CHECK_PHISHING_DEFAULT; + } else if (NS_LITERAL_STRING(GETHASH_TABLES_PREF).Equals(aData)) { + mGethashWhitelist.Clear(); + nsXPIDLCString val; + if (NS_SUCCEEDED(prefs->GetCharPref(GETHASH_TABLES_PREF, getter_Copies(val)))) { + SplitTables(val, mGethashWhitelist); + } } else if (NS_LITERAL_STRING(CONFIRM_AGE_PREF).Equals(aData)) { - gFreshnessGuarantee = Preferences::GetInt(CONFIRM_AGE_PREF, - CONFIRM_AGE_DEFAULT_SEC); + int32_t tmpint; + rv = prefs->GetIntPref(CONFIRM_AGE_PREF, &tmpint); + gFreshnessGuarantee = NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC; } } else if (!strcmp(aTopic, "profile-before-change") || !strcmp(aTopic, "xpcom-shutdown-threads")) { @@ -1487,10 +1489,7 @@ nsUrlClassifierDBService::Shutdown() if (prefs) { prefs->RemoveObserver(CHECK_MALWARE_PREF, this); prefs->RemoveObserver(CHECK_PHISHING_PREF, this); - prefs->RemoveObserver(PHISH_TABLE_PREF, this); - prefs->RemoveObserver(MALWARE_TABLE_PREF, this); - prefs->RemoveObserver(DOWNLOAD_BLOCK_TABLE_PREF, this); - prefs->RemoveObserver(DOWNLOAD_ALLOW_TABLE_PREF, this); + prefs->RemoveObserver(GETHASH_TABLES_PREF, this); prefs->RemoveObserver(CONFIRM_AGE_PREF, this); } diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.h b/toolkit/components/url-classifier/nsUrlClassifierDBService.h index a951b2ee4d91..f3f6a63cda42 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.h +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.h @@ -101,7 +101,7 @@ private: bool mInUpdate; // The list of tables that can use the default hash completer object. - nsTArray mGethashTables; + nsTArray mGethashWhitelist; // Thread that we do the updates on. static nsIThread* gDbBackgroundThread; From 87e306bcb23f4b456ea8570887a2bbdc6f40b0a5 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 25 Sep 2013 19:25:30 +0200 Subject: [PATCH 19/62] Bug 919520 - Update web-platform-tests tests; r=jgraham --HG-- rename : dom/imptests/failures/html/old-tests/submission/Opera/microdata/Makefile.in => dom/imptests/failures/html/microdata/microdata-dom-api/Makefile.in rename : dom/imptests/failures/html/old-tests/submission/Opera/microdata/moz.build => dom/imptests/failures/html/microdata/microdata-dom-api/moz.build rename : dom/imptests/failures/html/old-tests/submission/Opera/microdata/test_001.html.json => dom/imptests/failures/html/microdata/microdata-dom-api/test_001.html.json rename : dom/imptests/html/html/dom/elements/global-attributes/test_dataset-instanceof.html => dom/imptests/html/html/dom/elements/global-attributes/test_dataset-prototype.html rename : dom/imptests/html/old-tests/submission/Opera/microdata/Makefile.in => dom/imptests/html/microdata/microdata-dom-api/Makefile.in rename : dom/imptests/html/old-tests/submission/Opera/microdata/moz.build => dom/imptests/html/microdata/microdata-dom-api/moz.build rename : dom/imptests/html/old-tests/submission/Opera/microdata/test_001.html => dom/imptests/html/microdata/microdata-dom-api/test_001.html --- .../elements/global-attributes/Makefile.in | 5 - .../test_document-dir.html.json | 3 - .../microdata-dom-api}/Makefile.in | 0 .../microdata-dom-api}/moz.build | 0 .../microdata-dom-api}/test_001.html.json | 0 dom/imptests/html.mozbuild | 2 +- dom/imptests/html.txt | 2 +- .../dta/test_document.body-setter-01.html | 4 + .../elements/global-attributes/Makefile.in | 2 +- .../global-attributes/test_dataset-get.html | 2 + ...nceof.html => test_dataset-prototype.html} | 10 + .../global-attributes/test_document-dir.html | 11 +- .../editing/the-hidden-attribute/Makefile.in | 1 + .../forms/the-form-element/Makefile.in | 1 + .../the-form-element/test_form-nameditem.html | 239 ++++++++++++++++++ .../html/webappapis/atob/test_base64.html | 21 -- .../microdata-dom-api}/Makefile.in | 0 .../microdata-dom-api}/moz.build | 0 .../microdata-dom-api}/test_001.html | 0 dom/imptests/moz.build | 3 +- 20 files changed, 267 insertions(+), 39 deletions(-) delete mode 100644 dom/imptests/failures/html/html/dom/elements/global-attributes/Makefile.in delete mode 100644 dom/imptests/failures/html/html/dom/elements/global-attributes/test_document-dir.html.json rename dom/imptests/failures/html/{old-tests/submission/Opera/microdata => microdata/microdata-dom-api}/Makefile.in (100%) rename dom/imptests/failures/html/{old-tests/submission/Opera/microdata => microdata/microdata-dom-api}/moz.build (100%) rename dom/imptests/failures/html/{old-tests/submission/Opera/microdata => microdata/microdata-dom-api}/test_001.html.json (100%) rename dom/imptests/html/html/dom/elements/global-attributes/{test_dataset-instanceof.html => test_dataset-prototype.html} (50%) create mode 100644 dom/imptests/html/html/semantics/forms/the-form-element/test_form-nameditem.html rename dom/imptests/html/{old-tests/submission/Opera/microdata => microdata/microdata-dom-api}/Makefile.in (100%) rename dom/imptests/html/{old-tests/submission/Opera/microdata => microdata/microdata-dom-api}/moz.build (100%) rename dom/imptests/html/{old-tests/submission/Opera/microdata => microdata/microdata-dom-api}/test_001.html (100%) diff --git a/dom/imptests/failures/html/html/dom/elements/global-attributes/Makefile.in b/dom/imptests/failures/html/html/dom/elements/global-attributes/Makefile.in deleted file mode 100644 index f34e6ea4b7fe..000000000000 --- a/dom/imptests/failures/html/html/dom/elements/global-attributes/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ -# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT - -MOCHITEST_FILES := \ - test_document-dir.html.json \ - $(NULL) diff --git a/dom/imptests/failures/html/html/dom/elements/global-attributes/test_document-dir.html.json b/dom/imptests/failures/html/html/dom/elements/global-attributes/test_document-dir.html.json deleted file mode 100644 index c258615b31a3..000000000000 --- a/dom/imptests/failures/html/html/dom/elements/global-attributes/test_document-dir.html.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Setting the idl attribute to the empty sting": true -} diff --git a/dom/imptests/failures/html/old-tests/submission/Opera/microdata/Makefile.in b/dom/imptests/failures/html/microdata/microdata-dom-api/Makefile.in similarity index 100% rename from dom/imptests/failures/html/old-tests/submission/Opera/microdata/Makefile.in rename to dom/imptests/failures/html/microdata/microdata-dom-api/Makefile.in diff --git a/dom/imptests/failures/html/old-tests/submission/Opera/microdata/moz.build b/dom/imptests/failures/html/microdata/microdata-dom-api/moz.build similarity index 100% rename from dom/imptests/failures/html/old-tests/submission/Opera/microdata/moz.build rename to dom/imptests/failures/html/microdata/microdata-dom-api/moz.build diff --git a/dom/imptests/failures/html/old-tests/submission/Opera/microdata/test_001.html.json b/dom/imptests/failures/html/microdata/microdata-dom-api/test_001.html.json similarity index 100% rename from dom/imptests/failures/html/old-tests/submission/Opera/microdata/test_001.html.json rename to dom/imptests/failures/html/microdata/microdata-dom-api/test_001.html.json diff --git a/dom/imptests/html.mozbuild b/dom/imptests/html.mozbuild index 9fc13daad968..af6f2bdffca3 100644 --- a/dom/imptests/html.mozbuild +++ b/dom/imptests/html.mozbuild @@ -22,7 +22,7 @@ DIRS += [ 'html/html/webappapis/scripting/processing-model-2', 'html/html/webappapis/timers', 'html/js/builtins', - 'html/old-tests/submission/Opera/microdata', + 'html/microdata/microdata-dom-api', 'html/typedarrays', 'html/webgl', ] diff --git a/dom/imptests/html.txt b/dom/imptests/html.txt index 120317f2b793..c12e4f88b42a 100644 --- a/dom/imptests/html.txt +++ b/dom/imptests/html.txt @@ -18,6 +18,6 @@ html/webappapis/scripting/events html/webappapis/scripting/processing-model-2 html/webappapis/timers js/builtins -old-tests/submission/Opera/microdata +microdata/microdata-dom-api typedarrays webgl diff --git a/dom/imptests/html/html/dom/documents/dta/test_document.body-setter-01.html b/dom/imptests/html/html/dom/documents/dta/test_document.body-setter-01.html index 319000b9418a..be1ae12d8fa2 100644 --- a/dom/imptests/html/html/dom/documents/dta/test_document.body-setter-01.html +++ b/dom/imptests/html/html/dom/documents/dta/test_document.body-setter-01.html @@ -7,6 +7,7 @@
diff --git a/dom/imptests/html/html/dom/elements/global-attributes/Makefile.in b/dom/imptests/html/html/dom/elements/global-attributes/Makefile.in index a075e62547a3..ea2bb3f6a512 100644 --- a/dom/imptests/html/html/dom/elements/global-attributes/Makefile.in +++ b/dom/imptests/html/html/dom/elements/global-attributes/Makefile.in @@ -6,7 +6,7 @@ MOCHITEST_FILES := \ test_dataset-enumeration.html \ test_dataset-get.html \ test_dataset.html \ - test_dataset-instanceof.html \ + test_dataset-prototype.html \ test_dataset-set.html \ test_document-dir.html \ test_id-attribute.html \ diff --git a/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-get.html b/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-get.html index 4c5e9930caae..ab4078c4fbf2 100644 --- a/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-get.html +++ b/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-get.html @@ -32,6 +32,8 @@ "Getting element.dataset[''] should return the value of element.getAttribute('data-')'"); test(function() { assert_true(testGet('data-\xE0', '\xE0')); }, "Getting element.dataset['\xE0'] should return the value of element.getAttribute('data-\xE0')'"); + test(function() { assert_true(testGet('data-to-string', 'toString')); }, + "Getting element.dataset['toString'] should return the value of element.getAttribute('data-to-string')'"); function matchesNothingInDataset(attr) { diff --git a/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-instanceof.html b/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-prototype.html similarity index 50% rename from dom/imptests/html/html/dom/elements/global-attributes/test_dataset-instanceof.html rename to dom/imptests/html/html/dom/elements/global-attributes/test_dataset-prototype.html index c1a9b5fb18d6..6b1661846126 100644 --- a/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-instanceof.html +++ b/dom/imptests/html/html/dom/elements/global-attributes/test_dataset-prototype.html @@ -11,6 +11,16 @@ diff --git a/dom/imptests/html/html/dom/elements/global-attributes/test_document-dir.html b/dom/imptests/html/html/dom/elements/global-attributes/test_document-dir.html index 734f922312be..cc1e092ff40c 100644 --- a/dom/imptests/html/html/dom/elements/global-attributes/test_document-dir.html +++ b/dom/imptests/html/html/dom/elements/global-attributes/test_document-dir.html @@ -1,10 +1,9 @@ document.dir - - + + -
@@ -20,6 +19,8 @@ test(function() { }, "Setting the idl attribute to a garbage value") test(function() { document.dir = ""; - assert_equals(document.documentElement.hasAttribute("dir"), false, "Attribute should be gone"); -}, "Setting the idl attribute to the empty sting") + assert_true(document.documentElement.hasAttribute("dir"), "Attribute should still be around"); + assert_equals(document.dir, ""); + assert_equals(document.documentElement.getAttribute("dir"), ""); +}, "Setting the idl attribute to the empty string") diff --git a/dom/imptests/html/html/editing/the-hidden-attribute/Makefile.in b/dom/imptests/html/html/editing/the-hidden-attribute/Makefile.in index 9b1aadfa4bb6..cea167986cae 100644 --- a/dom/imptests/html/html/editing/the-hidden-attribute/Makefile.in +++ b/dom/imptests/html/html/editing/the-hidden-attribute/Makefile.in @@ -1,2 +1,3 @@ # THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + diff --git a/dom/imptests/html/html/semantics/forms/the-form-element/Makefile.in b/dom/imptests/html/html/semantics/forms/the-form-element/Makefile.in index fc6edac896a6..bf2f035c1753 100644 --- a/dom/imptests/html/html/semantics/forms/the-form-element/Makefile.in +++ b/dom/imptests/html/html/semantics/forms/the-form-element/Makefile.in @@ -5,4 +5,5 @@ MOCHITEST_FILES := \ test_form-elements-matches.html \ test_form-elements-nameditem-01.html \ test_form-elements-nameditem-02.html \ + test_form-nameditem.html \ $(NULL) diff --git a/dom/imptests/html/html/semantics/forms/the-form-element/test_form-nameditem.html b/dom/imptests/html/html/semantics/forms/the-form-element/test_form-nameditem.html new file mode 100644 index 000000000000..f372742a7211 --- /dev/null +++ b/dom/imptests/html/html/semantics/forms/the-form-element/test_form-nameditem.html @@ -0,0 +1,239 @@ + + +Form named getter + + +
+ + + +
+ + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+ + + +
+ + +
+ diff --git a/dom/imptests/html/html/webappapis/atob/test_base64.html b/dom/imptests/html/html/webappapis/atob/test_base64.html index 28278d4ab086..da95c1ae1e99 100644 --- a/dom/imptests/html/html/webappapis/atob/test_base64.html +++ b/dom/imptests/html/html/webappapis/atob/test_base64.html @@ -7,27 +7,6 @@ to Google. --> + +
+
+
+
+ +
+ diff --git a/dom/imptests/webapps/DOMCore/tests/approved/common.js b/dom/imptests/html/dom/common.js similarity index 99% rename from dom/imptests/webapps/DOMCore/tests/approved/common.js rename to dom/imptests/html/dom/common.js index e7240570cae3..91ccb4425d7d 100644 --- a/dom/imptests/webapps/DOMCore/tests/approved/common.js +++ b/dom/imptests/html/dom/common.js @@ -14,7 +14,7 @@ var testDiv, paras, detachedDiv, detachedPara1, detachedPara2, detachedComment, foreignComment, detachedForeignComment, xmlComment, detachedXmlComment, docfrag, foreignDocfrag, xmlDocfrag, doctype, foreignDoctype, xmlDoctype; -var testRanges, testPoints, testNodes; +var testRangesShort, testRanges, testPoints, testNodesShort, testNodes; function setupRangeTests() { selection = getSelection(); @@ -121,7 +121,7 @@ function setupRangeTests() { doctype = document.doctype; foreignDoctype = foreignDoc.doctype; - testRanges = [ + testRangesShort = [ // Various ranges within the text node children of different // paragraphs. All should be valid. "[paras[0].firstChild, 0, paras[0].firstChild, 0]", @@ -129,14 +129,10 @@ function setupRangeTests() { "[paras[0].firstChild, 2, paras[0].firstChild, 8]", "[paras[0].firstChild, 2, paras[0].firstChild, 9]", "[paras[1].firstChild, 0, paras[1].firstChild, 0]", - "[paras[1].firstChild, 0, paras[1].firstChild, 1]", - "[paras[1].firstChild, 2, paras[1].firstChild, 8]", "[paras[1].firstChild, 2, paras[1].firstChild, 9]", "[detachedPara1.firstChild, 0, detachedPara1.firstChild, 0]", - "[detachedPara1.firstChild, 0, detachedPara1.firstChild, 1]", "[detachedPara1.firstChild, 2, detachedPara1.firstChild, 8]", "[foreignPara1.firstChild, 0, foreignPara1.firstChild, 0]", - "[foreignPara1.firstChild, 0, foreignPara1.firstChild, 1]", "[foreignPara1.firstChild, 2, foreignPara1.firstChild, 8]", // Now try testing some elements, not just text nodes. "[document.documentElement, 0, document.documentElement, 1]", @@ -145,11 +141,7 @@ function setupRangeTests() { "[document.head, 1, document.head, 1]", "[document.body, 4, document.body, 5]", "[foreignDoc.documentElement, 0, foreignDoc.documentElement, 1]", - "[foreignDoc.head, 1, foreignDoc.head, 1]", - "[foreignDoc.body, 0, foreignDoc.body, 0]", - "[paras[0], 0, paras[0], 0]", "[paras[0], 0, paras[0], 1]", - "[detachedPara1, 0, detachedPara1, 0]", "[detachedPara1, 0, detachedPara1, 1]", // Now try some ranges that span elements. "[paras[0].firstChild, 0, paras[1].firstChild, 0]", @@ -158,38 +150,47 @@ function setupRangeTests() { // How about something that spans a node and its descendant? "[paras[0], 0, paras[0].firstChild, 7]", "[testDiv, 2, paras[4], 1]", - "[testDiv, 1, paras[2].firstChild, 5]", - "[document.documentElement, 1, document.body, 0]", - "[foreignDoc.documentElement, 1, foreignDoc.body, 0]", // Then a few more interesting things just for good measure. "[document, 0, document, 1]", "[document, 0, document, 2]", - "[document, 1, document, 2]", "[comment, 2, comment, 3]", "[testDiv, 0, comment, 5]", + "[foreignDoc, 1, foreignComment, 2]", + "[foreignDoc.body, 0, foreignTextNode, 36]", + "[xmlDoc, 1, xmlComment, 0]", + "[detachedTextNode, 0, detachedTextNode, 8]", + "[detachedForeignTextNode, 0, detachedForeignTextNode, 8]", + "[detachedXmlTextNode, 0, detachedXmlTextNode, 8]", + "[detachedComment, 3, detachedComment, 4]", + "[detachedForeignComment, 0, detachedForeignComment, 1]", + "[detachedXmlComment, 2, detachedXmlComment, 6]", + "[docfrag, 0, docfrag, 0]", + ]; + + testRanges = testRangesShort.concat([ + "[paras[1].firstChild, 0, paras[1].firstChild, 1]", + "[paras[1].firstChild, 2, paras[1].firstChild, 8]", + "[detachedPara1.firstChild, 0, detachedPara1.firstChild, 1]", + "[foreignPara1.firstChild, 0, foreignPara1.firstChild, 1]", + "[foreignDoc.head, 1, foreignDoc.head, 1]", + "[foreignDoc.body, 0, foreignDoc.body, 0]", + "[paras[0], 0, paras[0], 0]", + "[detachedPara1, 0, detachedPara1, 0]", + "[testDiv, 1, paras[2].firstChild, 5]", + "[document.documentElement, 1, document.body, 0]", + "[foreignDoc.documentElement, 1, foreignDoc.body, 0]", + "[document, 1, document, 2]", "[paras[2].firstChild, 4, comment, 2]", "[paras[3], 1, comment, 8]", "[foreignDoc, 0, foreignDoc, 0]", - "[foreignDoc, 1, foreignComment, 2]", - "[foreignDoc.body, 0, foreignTextNode, 36]", "[xmlDoc, 0, xmlDoc, 0]", - // Opera 11 crashes if you extractContents() a range that ends at offset - // zero in a comment. Comment out this line to run the tests successfully. - "[xmlDoc, 1, xmlComment, 0]", - "[detachedTextNode, 0, detachedTextNode, 8]", "[detachedForeignTextNode, 7, detachedForeignTextNode, 7]", - "[detachedForeignTextNode, 0, detachedForeignTextNode, 8]", "[detachedXmlTextNode, 7, detachedXmlTextNode, 7]", - "[detachedXmlTextNode, 0, detachedXmlTextNode, 8]", - "[detachedComment, 3, detachedComment, 4]", "[detachedComment, 5, detachedComment, 5]", - "[detachedForeignComment, 0, detachedForeignComment, 1]", "[detachedForeignComment, 4, detachedForeignComment, 4]", - "[detachedXmlComment, 2, detachedXmlComment, 6]", - "[docfrag, 0, docfrag, 0]", "[foreignDocfrag, 0, foreignDocfrag, 0]", "[xmlDocfrag, 0, xmlDocfrag, 0]", - ]; + ]); testPoints = [ // Various positions within the page, some invalid. Remember that @@ -286,45 +287,48 @@ function setupRangeTests() { "[xmlDoctype, 0]", ]; - testNodes = [ + testNodesShort = [ "paras[0]", "paras[0].firstChild", - "paras[1]", "paras[1].firstChild", "foreignPara1", "foreignPara1.firstChild", "detachedPara1", "detachedPara1.firstChild", - "detachedPara2", - "detachedPara2.firstChild", - "testDiv", "document", "detachedDiv", "foreignDoc", "foreignPara2", "xmlDoc", "xmlElement", - "detachedXmlElement", "detachedTextNode", "foreignTextNode", - "detachedForeignTextNode", - "xmlTextNode", - "detachedXmlTextNode", "processingInstruction", "detachedProcessingInstruction", "comment", "detachedComment", - "foreignComment", - "detachedForeignComment", - "xmlComment", - "detachedXmlComment", "docfrag", - "foreignDocfrag", - "xmlDocfrag", "doctype", "foreignDoctype", - "xmlDoctype", ]; + + testNodes = testNodesShort.concat([ + "paras[1]", + "detachedPara2", + "detachedPara2.firstChild", + "testDiv", + "detachedXmlElement", + "detachedForeignTextNode", + "xmlTextNode", + "detachedXmlTextNode", + "xmlComment", + "foreignComment", + "detachedForeignComment", + "detachedXmlComment", + "foreignDocfrag", + "xmlDocfrag", + "xmlDoctype", + ]); } if ("setup" in window) { setup(setupRangeTests); diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/constants.js b/dom/imptests/html/dom/constants.js similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/constants.js rename to dom/imptests/html/dom/constants.js diff --git a/dom/imptests/html/dom/errors/Makefile.in b/dom/imptests/html/dom/errors/Makefile.in new file mode 100644 index 000000000000..836368524ba7 --- /dev/null +++ b/dom/imptests/html/dom/errors/Makefile.in @@ -0,0 +1,6 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +MOCHITEST_FILES := \ + test_DOMException-constants.html \ + test_exceptions.html \ + $(NULL) diff --git a/dom/imptests/html/dom/errors/moz.build b/dom/imptests/html/dom/errors/moz.build new file mode 100644 index 000000000000..1147426c7da9 --- /dev/null +++ b/dom/imptests/html/dom/errors/moz.build @@ -0,0 +1,4 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +DIRS += [ +] diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMException-constants.html b/dom/imptests/html/dom/errors/test_DOMException-constants.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMException-constants.html rename to dom/imptests/html/dom/errors/test_DOMException-constants.html diff --git a/dom/imptests/webapps/DOMCore/tests/approved/test_exceptions.html b/dom/imptests/html/dom/errors/test_exceptions.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/approved/test_exceptions.html rename to dom/imptests/html/dom/errors/test_exceptions.html diff --git a/dom/imptests/html/dom/events/Makefile.in b/dom/imptests/html/dom/events/Makefile.in new file mode 100644 index 000000000000..df1571695718 --- /dev/null +++ b/dom/imptests/html/dom/events/Makefile.in @@ -0,0 +1,14 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +MOCHITEST_FILES := \ + test_Event-constants.html \ + test_Event-constructors.html \ + test_Event-defaultPrevented.html \ + test_Event-initEvent.html \ + test_Event-propagation.html \ + test_EventTarget-addEventListener.html \ + test_EventTarget-dispatchEvent.html \ + test_EventTarget-removeEventListener.html \ + test_Event-type.html \ + test_ProgressEvent.html \ + $(NULL) diff --git a/dom/imptests/html/dom/events/moz.build b/dom/imptests/html/dom/events/moz.build new file mode 100644 index 000000000000..1147426c7da9 --- /dev/null +++ b/dom/imptests/html/dom/events/moz.build @@ -0,0 +1,4 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +DIRS += [ +] diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Event-constants.html b/dom/imptests/html/dom/events/test_Event-constants.html similarity index 93% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Event-constants.html rename to dom/imptests/html/dom/events/test_Event-constants.html index 2618a300771e..699815fab6ff 100644 --- a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Event-constants.html +++ b/dom/imptests/html/dom/events/test_Event-constants.html @@ -2,7 +2,7 @@ Event constants - +
+ + diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Event-type.html b/dom/imptests/html/dom/events/test_Event-type.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Event-type.html rename to dom/imptests/html/dom/events/test_Event-type.html diff --git a/dom/imptests/html/dom/events/test_EventTarget-addEventListener.html b/dom/imptests/html/dom/events/test_EventTarget-addEventListener.html new file mode 100644 index 000000000000..1c6a9b0de153 --- /dev/null +++ b/dom/imptests/html/dom/events/test_EventTarget-addEventListener.html @@ -0,0 +1,16 @@ + + +EventTarget.addEventListener + + + + +
+ diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_EventTarget-dispatchEvent.html b/dom/imptests/html/dom/events/test_EventTarget-dispatchEvent.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_EventTarget-dispatchEvent.html rename to dom/imptests/html/dom/events/test_EventTarget-dispatchEvent.html diff --git a/dom/imptests/html/dom/events/test_EventTarget-removeEventListener.html b/dom/imptests/html/dom/events/test_EventTarget-removeEventListener.html new file mode 100644 index 000000000000..ffdc44889a11 --- /dev/null +++ b/dom/imptests/html/dom/events/test_EventTarget-removeEventListener.html @@ -0,0 +1,16 @@ + + +EventTarget.removeEventListener + + + + +
+ diff --git a/dom/imptests/html/dom/events/test_ProgressEvent.html b/dom/imptests/html/dom/events/test_ProgressEvent.html new file mode 100644 index 000000000000..2b2f7bc51b7f --- /dev/null +++ b/dom/imptests/html/dom/events/test_ProgressEvent.html @@ -0,0 +1,25 @@ + +ProgressEvent constructor + + +
+ diff --git a/dom/imptests/html/dom/moz.build b/dom/imptests/html/dom/moz.build new file mode 100644 index 000000000000..1147426c7da9 --- /dev/null +++ b/dom/imptests/html/dom/moz.build @@ -0,0 +1,4 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +DIRS += [ +] diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/ChildNode-remove.js b/dom/imptests/html/dom/nodes/ChildNode-remove.js similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/ChildNode-remove.js rename to dom/imptests/html/dom/nodes/ChildNode-remove.js diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/Makefile.in b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/Makefile.in new file mode 100644 index 000000000000..befae50a7569 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/Makefile.in @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +MOCHITEST_FILES := \ + bare_mathml.html \ + bare_mathml.svg \ + bare_mathml.xhtml \ + bare_mathml.xml \ + bare_svg.html \ + bare_svg.svg \ + bare_svg.xhtml \ + bare_svg.xml \ + bare_xhtml.html \ + bare_xhtml.svg \ + bare_xhtml.xhtml \ + bare_xhtml.xml \ + empty.html \ + empty.svg \ + empty.xhtml \ + empty.xml \ + generate.py \ + mathml.html \ + mathml.svg \ + mathml.xhtml \ + mathml.xml \ + minimal_html.html \ + minimal_html.svg \ + minimal_html.xhtml \ + minimal_html.xml \ + svg.html \ + svg.svg \ + svg.xhtml \ + svg.xml \ + xhtml.html \ + xhtml_ns_changed.html \ + xhtml_ns_changed.svg \ + xhtml_ns_changed.xhtml \ + xhtml_ns_changed.xml \ + xhtml_ns_removed.html \ + xhtml_ns_removed.svg \ + xhtml_ns_removed.xhtml \ + xhtml_ns_removed.xml \ + xhtml.svg \ + xhtml.xhtml \ + xhtml.xml \ + $(NULL) diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.html new file mode 100644 index 000000000000..b80a99a78491 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.svg new file mode 100644 index 000000000000..b80a99a78491 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xhtml new file mode 100644 index 000000000000..b80a99a78491 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xhtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xml new file mode 100644 index 000000000000..b80a99a78491 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.html new file mode 100644 index 000000000000..dc1ced5b6b30 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.svg new file mode 100644 index 000000000000..dc1ced5b6b30 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.xhtml new file mode 100644 index 000000000000..dc1ced5b6b30 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.xhtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.xml new file mode 100644 index 000000000000..dc1ced5b6b30 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_svg.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.html new file mode 100644 index 000000000000..6c70bcfe4d48 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.svg new file mode 100644 index 000000000000..6c70bcfe4d48 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xhtml new file mode 100644 index 000000000000..6c70bcfe4d48 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xhtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xml new file mode 100644 index 000000000000..6c70bcfe4d48 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.html new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.svg new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.xhtml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/empty.xml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/generate.py b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/generate.py new file mode 100755 index 000000000000..88c4da198b12 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/generate.py @@ -0,0 +1,77 @@ +#!/usr/bin/python +import os +import sys + +THIS_NAME = "generate.py" + +# Note: these lists must be kept in sync with the lists in +# Document-createElement-namespace.html, and this script must be run whenever +# the lists are updated. (We could keep the lists in a shared JSON file, but +# seems like too much effort.) +FILES = ( + ("empty", ""), + ("minimal_html", ""), + + ("xhtml", ''), + ("svg", ''), + ("mathml", ''), + + ("bare_xhtml", ""), + ("bare_svg", ""), + ("bare_mathml", ""), + + ("xhtml_ns_removed", """\ + + + +"""), + ("xhtml_ns_changed", """\ + + + +"""), +) + +EXTENSIONS = ( + "html", + "xhtml", + "xml", + "svg", + # Was not able to get server MIME type working properly :( + #"mml", +) + +def __main__(): + if len(sys.argv) > 1: + print "No arguments expected, aborting" + return + + if not os.access(THIS_NAME, os.F_OK): + print "Must be run from the directory of " + THIS_NAME + ", aborting" + return + + for name in os.listdir("."): + if name == THIS_NAME: + continue + os.remove(name) + + manifest = open("MANIFEST", "w") + + for name, contents in FILES: + for extension in EXTENSIONS: + f = open(name + "." + extension, "w") + f.write(contents) + f.close() + manifest.write("support " + name + "." + extension + "\n") + + manifest.close() + +__main__() diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.html new file mode 100644 index 000000000000..0bec8e99e4aa --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.svg new file mode 100644 index 000000000000..0bec8e99e4aa --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.xhtml new file mode 100644 index 000000000000..0bec8e99e4aa --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.xhtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.xml new file mode 100644 index 000000000000..0bec8e99e4aa --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/mathml.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.html new file mode 100644 index 000000000000..a33d9859afa9 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.svg new file mode 100644 index 000000000000..a33d9859afa9 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml new file mode 100644 index 000000000000..a33d9859afa9 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.xml new file mode 100644 index 000000000000..a33d9859afa9 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/minimal_html.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/moz.build b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/moz.build new file mode 100644 index 000000000000..1147426c7da9 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/moz.build @@ -0,0 +1,4 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +DIRS += [ +] diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.html new file mode 100644 index 000000000000..64def4af7f76 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.svg new file mode 100644 index 000000000000..64def4af7f76 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.xhtml new file mode 100644 index 000000000000..64def4af7f76 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.xhtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.xml new file mode 100644 index 000000000000..64def4af7f76 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/svg.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.html new file mode 100644 index 000000000000..1cba99824136 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.svg new file mode 100644 index 000000000000..1cba99824136 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.xhtml new file mode 100644 index 000000000000..1cba99824136 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.xhtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.xml new file mode 100644 index 000000000000..1cba99824136 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.html new file mode 100644 index 000000000000..b228c7f74032 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.html @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.svg new file mode 100644 index 000000000000..b228c7f74032 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.svg @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xhtml new file mode 100644 index 000000000000..b228c7f74032 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xhtml @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xml new file mode 100644 index 000000000000..b228c7f74032 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xml @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.html b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.html new file mode 100644 index 000000000000..dba395fed064 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.html @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.svg b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.svg new file mode 100644 index 000000000000..dba395fed064 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.svg @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xhtml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xhtml new file mode 100644 index 000000000000..dba395fed064 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xhtml @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xml b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xml new file mode 100644 index 000000000000..dba395fed064 --- /dev/null +++ b/dom/imptests/html/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xml @@ -0,0 +1,7 @@ + + + diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/Document-createProcessingInstruction.js b/dom/imptests/html/dom/nodes/Document-createProcessingInstruction.js similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/Document-createProcessingInstruction.js rename to dom/imptests/html/dom/nodes/Document-createProcessingInstruction.js diff --git a/dom/imptests/html/dom/nodes/Makefile.in b/dom/imptests/html/dom/nodes/Makefile.in new file mode 100644 index 000000000000..09ce70959aea --- /dev/null +++ b/dom/imptests/html/dom/nodes/Makefile.in @@ -0,0 +1,78 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +MOCHITEST_FILES := \ + test_attributes.html \ + test_case.html \ + test_CharacterData-appendData.html \ + test_CharacterData-deleteData.html \ + test_CharacterData-insertData.html \ + test_CharacterData-remove.html \ + test_CharacterData-replaceData.html \ + test_Document-adoptNode.html \ + test_Document-createComment.html \ + test_Document-createElement.html \ + test_Document-createElement-namespace.html \ + test_Document-createElementNS.html \ + test_Document-createEvent.html \ + test_Document-createProcessingInstruction.html \ + test_Document-createProcessingInstruction-literal-1.xhtml \ + test_Document-createProcessingInstruction-literal-2.xhtml \ + test_Document-createProcessingInstruction.xhtml \ + test_Document-createTreeWalker.html \ + test_Document-getElementById.html \ + test_Document-getElementsByTagName.html \ + test_Document-getElementsByTagNameNS.html \ + test_Document-importNode.html \ + test_DocumentType-remove.html \ + test_DOMImplementation-createDocument.html \ + test_DOMImplementation-createDocumentType.html \ + test_DOMImplementation-createHTMLDocument.html \ + test_DOMImplementation-hasFeature.html \ + test_Element-children.html \ + test_Element-getElementsByClassName.html \ + test_Element-removeAttributeNS.html \ + test_Element-remove.html \ + test_Element-tagName.html \ + test_getElementsByClassName-01.htm \ + test_getElementsByClassName-02.htm \ + test_getElementsByClassName-03.htm \ + test_getElementsByClassName-04.htm \ + test_getElementsByClassName-05.htm \ + test_getElementsByClassName-06.htm \ + test_getElementsByClassName-07.htm \ + test_getElementsByClassName-08.htm \ + test_getElementsByClassName-09.htm \ + test_getElementsByClassName-10.xml \ + test_getElementsByClassName-11.xml \ + test_getElementsByClassName-12.htm \ + test_getElementsByClassName-13.htm \ + test_getElementsByClassName-14.htm \ + test_getElementsByClassName-15.htm \ + test_getElementsByClassName-16.htm \ + test_getElementsByClassName-17.htm \ + test_getElementsByClassName-18.htm \ + test_Node-appendChild.html \ + test_Node-cloneNode.html \ + test_Node-compareDocumentPosition.html \ + test_Node-constants.html \ + test_Node-contains.html \ + test_Node-contains.xml \ + test_Node-insertBefore.html \ + test_Node-isEqualNode.xhtml \ + test_Node-lookupPrefix.xhtml \ + test_Node-nodeName.html \ + test_Node-nodeName.xhtml \ + test_Node-normalize.html \ + test_Node-parentElement.html \ + test_Node-parentNode.html \ + test_Node-properties.html \ + test_Node-removeChild.html \ + test_Node-replaceChild.html \ + attributes.js \ + case.js \ + ChildNode-remove.js \ + creators.js \ + Document-createProcessingInstruction.js \ + encoding.php \ + productions.js \ + $(NULL) diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/attributes.js b/dom/imptests/html/dom/nodes/attributes.js similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/attributes.js rename to dom/imptests/html/dom/nodes/attributes.js diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/case.js b/dom/imptests/html/dom/nodes/case.js similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/case.js rename to dom/imptests/html/dom/nodes/case.js diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/creators.js b/dom/imptests/html/dom/nodes/creators.js similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/creators.js rename to dom/imptests/html/dom/nodes/creators.js diff --git a/dom/imptests/html/dom/nodes/encoding.php b/dom/imptests/html/dom/nodes/encoding.php new file mode 100644 index 000000000000..6252a1392f5d --- /dev/null +++ b/dom/imptests/html/dom/nodes/encoding.php @@ -0,0 +1,2 @@ + + diff --git a/dom/imptests/html/dom/nodes/moz.build b/dom/imptests/html/dom/nodes/moz.build new file mode 100644 index 000000000000..1147426c7da9 --- /dev/null +++ b/dom/imptests/html/dom/nodes/moz.build @@ -0,0 +1,4 @@ +# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT + +DIRS += [ +] diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/productions.js b/dom/imptests/html/dom/nodes/productions.js similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/productions.js rename to dom/imptests/html/dom/nodes/productions.js diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-appendData.html b/dom/imptests/html/dom/nodes/test_CharacterData-appendData.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-appendData.html rename to dom/imptests/html/dom/nodes/test_CharacterData-appendData.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-deleteData.html b/dom/imptests/html/dom/nodes/test_CharacterData-deleteData.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-deleteData.html rename to dom/imptests/html/dom/nodes/test_CharacterData-deleteData.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-insertData.html b/dom/imptests/html/dom/nodes/test_CharacterData-insertData.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-insertData.html rename to dom/imptests/html/dom/nodes/test_CharacterData-insertData.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-remove.html b/dom/imptests/html/dom/nodes/test_CharacterData-remove.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-remove.html rename to dom/imptests/html/dom/nodes/test_CharacterData-remove.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-replaceData.html b/dom/imptests/html/dom/nodes/test_CharacterData-replaceData.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_CharacterData-replaceData.html rename to dom/imptests/html/dom/nodes/test_CharacterData-replaceData.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-createDocument.html b/dom/imptests/html/dom/nodes/test_DOMImplementation-createDocument.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-createDocument.html rename to dom/imptests/html/dom/nodes/test_DOMImplementation-createDocument.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-createDocumentType.html b/dom/imptests/html/dom/nodes/test_DOMImplementation-createDocumentType.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-createDocumentType.html rename to dom/imptests/html/dom/nodes/test_DOMImplementation-createDocumentType.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-createHTMLDocument.html b/dom/imptests/html/dom/nodes/test_DOMImplementation-createHTMLDocument.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-createHTMLDocument.html rename to dom/imptests/html/dom/nodes/test_DOMImplementation-createHTMLDocument.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-hasFeature.html b/dom/imptests/html/dom/nodes/test_DOMImplementation-hasFeature.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DOMImplementation-hasFeature.html rename to dom/imptests/html/dom/nodes/test_DOMImplementation-hasFeature.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-adoptNode.html b/dom/imptests/html/dom/nodes/test_Document-adoptNode.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-adoptNode.html rename to dom/imptests/html/dom/nodes/test_Document-adoptNode.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createComment.html b/dom/imptests/html/dom/nodes/test_Document-createComment.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createComment.html rename to dom/imptests/html/dom/nodes/test_Document-createComment.html diff --git a/dom/imptests/html/dom/nodes/test_Document-createElement-namespace.html b/dom/imptests/html/dom/nodes/test_Document-createElement-namespace.html new file mode 100644 index 000000000000..4898eeabc813 --- /dev/null +++ b/dom/imptests/html/dom/nodes/test_Document-createElement-namespace.html @@ -0,0 +1,103 @@ + +document.createElement() namespace tests + +
+ + + diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createElement.html b/dom/imptests/html/dom/nodes/test_Document-createElement.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createElement.html rename to dom/imptests/html/dom/nodes/test_Document-createElement.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createElementNS.html b/dom/imptests/html/dom/nodes/test_Document-createElementNS.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createElementNS.html rename to dom/imptests/html/dom/nodes/test_Document-createElementNS.html diff --git a/dom/imptests/html/dom/nodes/test_Document-createEvent.html b/dom/imptests/html/dom/nodes/test_Document-createEvent.html new file mode 100644 index 000000000000..a14d7291131f --- /dev/null +++ b/dom/imptests/html/dom/nodes/test_Document-createEvent.html @@ -0,0 +1,63 @@ + + +Document.createEvent + + + +
+ diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction-literal-1.xhtml b/dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction-literal-1.xhtml similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction-literal-1.xhtml rename to dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction-literal-1.xhtml diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction-literal-2.xhtml b/dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction-literal-2.xhtml similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction-literal-2.xhtml rename to dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction-literal-2.xhtml diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction.html b/dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction.html rename to dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction.xhtml b/dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction.xhtml similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createProcessingInstruction.xhtml rename to dom/imptests/html/dom/nodes/test_Document-createProcessingInstruction.xhtml diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createTreeWalker.html b/dom/imptests/html/dom/nodes/test_Document-createTreeWalker.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createTreeWalker.html rename to dom/imptests/html/dom/nodes/test_Document-createTreeWalker.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-getElementById.html b/dom/imptests/html/dom/nodes/test_Document-getElementById.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-getElementById.html rename to dom/imptests/html/dom/nodes/test_Document-getElementById.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-getElementsByTagName.html b/dom/imptests/html/dom/nodes/test_Document-getElementsByTagName.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-getElementsByTagName.html rename to dom/imptests/html/dom/nodes/test_Document-getElementsByTagName.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-getElementsByTagNameNS.html b/dom/imptests/html/dom/nodes/test_Document-getElementsByTagNameNS.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-getElementsByTagNameNS.html rename to dom/imptests/html/dom/nodes/test_Document-getElementsByTagNameNS.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-importNode.html b/dom/imptests/html/dom/nodes/test_Document-importNode.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-importNode.html rename to dom/imptests/html/dom/nodes/test_Document-importNode.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DocumentType-remove.html b/dom/imptests/html/dom/nodes/test_DocumentType-remove.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_DocumentType-remove.html rename to dom/imptests/html/dom/nodes/test_DocumentType-remove.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-children.html b/dom/imptests/html/dom/nodes/test_Element-children.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-children.html rename to dom/imptests/html/dom/nodes/test_Element-children.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-getElementsByClassName.html b/dom/imptests/html/dom/nodes/test_Element-getElementsByClassName.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-getElementsByClassName.html rename to dom/imptests/html/dom/nodes/test_Element-getElementsByClassName.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-remove.html b/dom/imptests/html/dom/nodes/test_Element-remove.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-remove.html rename to dom/imptests/html/dom/nodes/test_Element-remove.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-removeAttributeNS.html b/dom/imptests/html/dom/nodes/test_Element-removeAttributeNS.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-removeAttributeNS.html rename to dom/imptests/html/dom/nodes/test_Element-removeAttributeNS.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-tagName.html b/dom/imptests/html/dom/nodes/test_Element-tagName.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Element-tagName.html rename to dom/imptests/html/dom/nodes/test_Element-tagName.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Node-appendChild.html b/dom/imptests/html/dom/nodes/test_Node-appendChild.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Node-appendChild.html rename to dom/imptests/html/dom/nodes/test_Node-appendChild.html diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Node-cloneNode.html b/dom/imptests/html/dom/nodes/test_Node-cloneNode.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Node-cloneNode.html rename to dom/imptests/html/dom/nodes/test_Node-cloneNode.html diff --git a/dom/imptests/webapps/DOMCore/tests/approved/test_Node-compareDocumentPosition.html b/dom/imptests/html/dom/nodes/test_Node-compareDocumentPosition.html similarity index 98% rename from dom/imptests/webapps/DOMCore/tests/approved/test_Node-compareDocumentPosition.html rename to dom/imptests/html/dom/nodes/test_Node-compareDocumentPosition.html index ad518783d232..afae60aad1e5 100644 --- a/dom/imptests/webapps/DOMCore/tests/approved/test_Node-compareDocumentPosition.html +++ b/dom/imptests/html/dom/nodes/test_Node-compareDocumentPosition.html @@ -4,7 +4,7 @@
- + - +
- + - + + - + - + + + + diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Range-commonAncestorContainer.html b/dom/imptests/html/dom/ranges/test_Range-commonAncestorContainer-2.html similarity index 100% rename from dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Range-commonAncestorContainer.html rename to dom/imptests/html/dom/ranges/test_Range-commonAncestorContainer-2.html diff --git a/dom/imptests/webapps/DOMCore/tests/approved/test_Range-commonAncestorContainer.html b/dom/imptests/html/dom/ranges/test_Range-commonAncestorContainer.html similarity index 76% rename from dom/imptests/webapps/DOMCore/tests/approved/test_Range-commonAncestorContainer.html rename to dom/imptests/html/dom/ranges/test_Range-commonAncestorContainer.html index d014b1228f0c..9375de3fba0f 100644 --- a/dom/imptests/webapps/DOMCore/tests/approved/test_Range-commonAncestorContainer.html +++ b/dom/imptests/html/dom/ranges/test_Range-commonAncestorContainer.html @@ -4,7 +4,7 @@
- + - + - + - + - + - + - + - + - + - + - + diff --git a/dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html b/dom/imptests/html/dom/ranges/test_Range-surroundContents.html similarity index 97% rename from dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html rename to dom/imptests/html/dom/ranges/test_Range-surroundContents.html index cd798d81e037..fdb0bf1980f4 100644 --- a/dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html +++ b/dom/imptests/html/dom/ranges/test_Range-surroundContents.html @@ -8,7 +8,7 @@ iframes in the DOM.
- + - +
- - - diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/Makefile.in b/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/Makefile.in index eb63c9d4b5ce..e69de29bb2d1 100644 --- a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/Makefile.in +++ b/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/Makefile.in @@ -1,71 +0,0 @@ -# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT - -MOCHITEST_FILES := \ - test_attributes.html \ - test_case.html \ - test_CharacterData-appendData.html \ - test_CharacterData-deleteData.html \ - test_CharacterData-insertData.html \ - test_CharacterData-remove.html \ - test_CharacterData-replaceData.html \ - test_Document-adoptNode.html \ - test_Document-createComment.html \ - test_Document-createElement.html \ - test_Document-createElementNS.html \ - test_Document-createEvent.html \ - test_Document-createProcessingInstruction.html \ - test_Document-createProcessingInstruction-literal-1.xhtml \ - test_Document-createProcessingInstruction-literal-2.xhtml \ - test_Document-createProcessingInstruction.xhtml \ - test_Document-createTreeWalker.html \ - test_Document-getElementById.html \ - test_Document-getElementsByTagName.html \ - test_Document-getElementsByTagNameNS.html \ - test_Document-importNode.html \ - test_DocumentType-remove.html \ - test_DOMException-constants.html \ - test_DOMImplementation-createDocument.html \ - test_DOMImplementation-createDocumentType.html \ - test_DOMImplementation-createHTMLDocument.html \ - test_DOMImplementation-hasFeature.html \ - test_Element-children.html \ - test_Element-getElementsByClassName.html \ - test_Element-remove.html \ - test_Element-removeAttributeNS.html \ - test_Element-tagName.html \ - test_Event-constants.html \ - test_Event-constructors.html \ - test_Event-defaultPrevented.html \ - test_Event-initEvent.html \ - test_EventTarget-dispatchEvent.html \ - test_Event-type.html \ - test_historical.html \ - test_interfaces.html \ - test_Node-appendChild.html \ - test_Node-cloneNode.html \ - test_Node-constants.html \ - test_Node-contains.xml \ - test_Node-insertBefore.html \ - test_Node-isEqualNode.xhtml \ - test_Node-lookupPrefix.xhtml \ - test_Node-nodeName.html \ - test_Node-nodeName.xhtml \ - test_Node-normalize.html \ - test_Node-parentElement.html \ - test_Node-parentNode.html \ - test_Node-removeChild.html \ - test_Node-replaceChild.html \ - test_NodeFilter-constants.html \ - test_Range-attributes.html \ - test_Range-commonAncestorContainer.html \ - test_Range-comparePoint.html \ - test_Range-detach.html \ - test_Range-intersectsNode-binding.html \ - attributes.js \ - case.js \ - creators.js \ - constants.js \ - ChildNode-remove.js \ - Document-createProcessingInstruction.js \ - productions.js \ - $(NULL) diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/moz.build b/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/moz.build deleted file mode 100644 index a2bfbb817b96..000000000000 --- a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/moz.build +++ /dev/null @@ -1,5 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT - -DIRS += [ -] diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createEvent.html b/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createEvent.html deleted file mode 100644 index 939f1248d1a2..000000000000 --- a/dom/imptests/webapps/DOMCore/tests/submissions/Ms2ger/test_Document-createEvent.html +++ /dev/null @@ -1,42 +0,0 @@ - - -Document.createEvent - - - -
- diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Opera/Makefile.in b/dom/imptests/webapps/DOMCore/tests/submissions/Opera/Makefile.in index 6b9df178acf6..e69de29bb2d1 100644 --- a/dom/imptests/webapps/DOMCore/tests/submissions/Opera/Makefile.in +++ b/dom/imptests/webapps/DOMCore/tests/submissions/Opera/Makefile.in @@ -1,22 +0,0 @@ -# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT - -MOCHITEST_FILES := \ - test_getElementsByClassName-01.htm \ - test_getElementsByClassName-02.htm \ - test_getElementsByClassName-03.htm \ - test_getElementsByClassName-04.htm \ - test_getElementsByClassName-05.htm \ - test_getElementsByClassName-06.htm \ - test_getElementsByClassName-07.htm \ - test_getElementsByClassName-08.htm \ - test_getElementsByClassName-09.htm \ - test_getElementsByClassName-10.xml \ - test_getElementsByClassName-11.xml \ - test_getElementsByClassName-12.htm \ - test_getElementsByClassName-13.htm \ - test_getElementsByClassName-14.htm \ - test_getElementsByClassName-15.htm \ - test_getElementsByClassName-16.htm \ - test_getElementsByClassName-17.htm \ - test_getElementsByClassName-18.htm \ - $(NULL) diff --git a/dom/imptests/webapps/DOMCore/tests/submissions/Opera/moz.build b/dom/imptests/webapps/DOMCore/tests/submissions/Opera/moz.build deleted file mode 100644 index a2bfbb817b96..000000000000 --- a/dom/imptests/webapps/DOMCore/tests/submissions/Opera/moz.build +++ /dev/null @@ -1,5 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# THIS FILE IS AUTOGENERATED BY importTestsuite.py - DO NOT EDIT - -DIRS += [ -] diff --git a/testing/mochitest/android.json b/testing/mochitest/android.json index 10637adf791e..ec0d4976037e 100644 --- a/testing/mochitest/android.json +++ b/testing/mochitest/android.json @@ -128,14 +128,14 @@ "dom/imptests/editing/conformancetest/test_runtest.html": "", "dom/imptests/editing/selecttest/test_addRange.html": "bug 775227", "dom/imptests/html/webgl": "WebGL", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-cloneContents.html": "bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-compareBoundaryPoints.html": "bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-deleteContents.html": "bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-extractContents.html": "bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-insertNode.html": "bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html": "bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-set.html": "bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-cloneContents.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-compareBoundaryPoints.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-deleteContents.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-extractContents.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-insertNode.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-mutations.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-set.html": "bug 775227", + "dom/imptests/html/dom/ranges/test_Range-surroundContents.html": "bug 775227", "dom/imptests/webapps/WebStorage/tests/submissions/Infraware/test_storage_local_key.html": "bug 775227", "dom/indexedDB/ipc/test_ipc.html": "bug 783513", "dom/indexedDB/test/test_third_party.html": "TIMED_OUT", diff --git a/testing/mochitest/b2g.json b/testing/mochitest/b2g.json index e86d52f5224d..6b74726abed4 100644 --- a/testing/mochitest/b2g.json +++ b/testing/mochitest/b2g.json @@ -67,14 +67,14 @@ "content/media/webspeech/synth/test/test_speech_simple.html": "Test timed out", "dom/imptests/editing/selecttest/test_addRange.html": "oom?, bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-insertNode.html":"oom?, bug 775227", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-cloneContents.html":"", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-compareBoundaryPoints.html":"times out, bug 862196", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-deleteContents.html":"", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-extractContents.html":"", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-set.html":"", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html":"", - "dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html":"Test timed out.", + "dom/imptests/html/dom/ranges/test_Range-insertNode.html":"oom?, bug 775227", + "dom/imptests/html/dom/ranges/test_Range-cloneContents.html":"", + "dom/imptests/html/dom/ranges/test_Range-compareBoundaryPoints.html":"times out, bug 862196", + "dom/imptests/html/dom/ranges/test_Range-deleteContents.html":"", + "dom/imptests/html/dom/ranges/test_Range-extractContents.html":"", + "dom/imptests/html/dom/ranges/test_Range-set.html":"", + "dom/imptests/html/dom/ranges/test_Range-surroundContents.html":"", + "dom/imptests/html/dom/ranges/test_Range-mutations.html":"Test timed out.", "dom/encoding/test/test_stringencoding.html":"Test timed out on b2g board", "content/events/test/test_bug615597.html":"bug 900969, 5 tests", From 2cc83081c0ec66dc88e568c01051ad12374e653b Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Wed, 25 Sep 2013 19:28:57 +0200 Subject: [PATCH 22/62] Bug 920064 - Fix DOM test_interfaces.html; r=jgraham --- .../html/dom/test_interfaces.html.json | 65 +++---------------- dom/imptests/html/dom/test_interfaces.html | 61 ++++++++--------- 2 files changed, 41 insertions(+), 85 deletions(-) diff --git a/dom/imptests/failures/html/dom/test_interfaces.html.json b/dom/imptests/failures/html/dom/test_interfaces.html.json index 651bd0413bce..9e282a81102d 100644 --- a/dom/imptests/failures/html/dom/test_interfaces.html.json +++ b/dom/imptests/failures/html/dom/test_interfaces.html.json @@ -1,34 +1,6 @@ { - "DOMException exception: existence and properties of exception interface object": true, "DOMException exception: existence and properties of exception interface prototype object": true, "DOMException exception: existence and properties of exception interface prototype object's \"name\" property": true, - "DOMException exception: existence and properties of exception interface prototype object's \"constructor\" property": true, - "DOMException exception: constant INDEX_SIZE_ERR on exception interface prototype object": true, - "DOMException exception: constant DOMSTRING_SIZE_ERR on exception interface prototype object": true, - "DOMException exception: constant HIERARCHY_REQUEST_ERR on exception interface prototype object": true, - "DOMException exception: constant WRONG_DOCUMENT_ERR on exception interface prototype object": true, - "DOMException exception: constant INVALID_CHARACTER_ERR on exception interface prototype object": true, - "DOMException exception: constant NO_DATA_ALLOWED_ERR on exception interface prototype object": true, - "DOMException exception: constant NO_MODIFICATION_ALLOWED_ERR on exception interface prototype object": true, - "DOMException exception: constant NOT_FOUND_ERR on exception interface prototype object": true, - "DOMException exception: constant NOT_SUPPORTED_ERR on exception interface prototype object": true, - "DOMException exception: constant INUSE_ATTRIBUTE_ERR on exception interface prototype object": true, - "DOMException exception: constant INVALID_STATE_ERR on exception interface prototype object": true, - "DOMException exception: constant SYNTAX_ERR on exception interface prototype object": true, - "DOMException exception: constant INVALID_MODIFICATION_ERR on exception interface prototype object": true, - "DOMException exception: constant NAMESPACE_ERR on exception interface prototype object": true, - "DOMException exception: constant INVALID_ACCESS_ERR on exception interface prototype object": true, - "DOMException exception: constant VALIDATION_ERR on exception interface prototype object": true, - "DOMException exception: constant TYPE_MISMATCH_ERR on exception interface prototype object": true, - "DOMException exception: constant SECURITY_ERR on exception interface prototype object": true, - "DOMException exception: constant NETWORK_ERR on exception interface prototype object": true, - "DOMException exception: constant ABORT_ERR on exception interface prototype object": true, - "DOMException exception: constant URL_MISMATCH_ERR on exception interface prototype object": true, - "DOMException exception: constant QUOTA_EXCEEDED_ERR on exception interface prototype object": true, - "DOMException exception: constant TIMEOUT_ERR on exception interface prototype object": true, - "DOMException exception: constant INVALID_NODE_TYPE_ERR on exception interface prototype object": true, - "DOMException exception: constant DATA_CLONE_ERR on exception interface prototype object": true, - "DOMException exception: field code on exception interface prototype object": true, "Event interface: document.createEvent(\"Event\") must have own property \"isTrusted\"": true, "Event interface: document.createEvent(\"Event\") must inherit property \"timeStamp\" with the proper type (15)": true, "Event interface: new Event(\"foo\") must have own property \"isTrusted\"": true, @@ -36,47 +8,32 @@ "CustomEvent interface: existence and properties of interface object": true, "Event interface: new CustomEvent(\"foo\") must have own property \"isTrusted\"": true, "Event interface: new CustomEvent(\"foo\") must inherit property \"timeStamp\" with the proper type (15)": true, + "EventListener interface: existence and properties of interface prototype object": true, + "EventListener interface: existence and properties of interface prototype object's \"constructor\" property": true, + "EventListener interface: operation handleEvent(Event)": true, "MutationObserver interface: operation observe(Node,MutationObserverInit)": true, "Node interface: existence and properties of interface object": true, "Document interface: existence and properties of interface object": true, - "Document interface: attribute children": true, - "Document interface: attribute firstElementChild": true, - "Document interface: attribute lastElementChild": true, - "Document interface: attribute childElementCount": true, "Document interface: operation prepend(union)": true, "Document interface: operation append(union)": true, "XMLDocument interface: existence and properties of interface object": true, - "Document interface: xmlDoc must inherit property \"children\" with the proper type (24)": true, - "Document interface: xmlDoc must inherit property \"firstElementChild\" with the proper type (25)": true, - "Document interface: xmlDoc must inherit property \"lastElementChild\" with the proper type (26)": true, - "Document interface: xmlDoc must inherit property \"childElementCount\" with the proper type (27)": true, "Document interface: xmlDoc must inherit property \"prepend\" with the proper type (28)": true, "Document interface: calling prepend(union) on xmlDoc with too few arguments must throw TypeError": true, "Document interface: xmlDoc must inherit property \"append\" with the proper type (29)": true, "Document interface: calling append(union) on xmlDoc with too few arguments must throw TypeError": true, + "DOMImplementation interface: operation createDocument(DOMString,DOMString,DocumentType)": true, + "DOMImplementation interface: calling createDocument(DOMString,DOMString,DocumentType) on document.implementation with too few arguments must throw TypeError": true, "DocumentFragment interface: existence and properties of interface object": true, - "DocumentFragment interface: attribute children": true, - "DocumentFragment interface: attribute firstElementChild": true, - "DocumentFragment interface: attribute lastElementChild": true, - "DocumentFragment interface: attribute childElementCount": true, "DocumentFragment interface: operation prepend(union)": true, "DocumentFragment interface: operation append(union)": true, - "DocumentFragment interface: document.createDocumentFragment() must inherit property \"children\" with the proper type (0)": true, - "DocumentFragment interface: document.createDocumentFragment() must inherit property \"firstElementChild\" with the proper type (1)": true, - "DocumentFragment interface: document.createDocumentFragment() must inherit property \"lastElementChild\" with the proper type (2)": true, - "DocumentFragment interface: document.createDocumentFragment() must inherit property \"childElementCount\" with the proper type (3)": true, "DocumentFragment interface: document.createDocumentFragment() must inherit property \"prepend\" with the proper type (4)": true, "DocumentFragment interface: calling prepend(union) on document.createDocumentFragment() with too few arguments must throw TypeError": true, "DocumentFragment interface: document.createDocumentFragment() must inherit property \"append\" with the proper type (5)": true, "DocumentFragment interface: calling append(union) on document.createDocumentFragment() with too few arguments must throw TypeError": true, "DocumentType interface: existence and properties of interface object": true, - "DocumentType interface: attribute previousElementSibling": true, - "DocumentType interface: attribute nextElementSibling": true, "DocumentType interface: operation before(union)": true, "DocumentType interface: operation after(union)": true, "DocumentType interface: operation replace(union)": true, - "DocumentType interface: document.doctype must inherit property \"previousElementSibling\" with the proper type (3)": true, - "DocumentType interface: document.doctype must inherit property \"nextElementSibling\" with the proper type (4)": true, "DocumentType interface: document.doctype must inherit property \"before\" with the proper type (5)": true, "DocumentType interface: calling before(union) on document.doctype with too few arguments must throw TypeError": true, "DocumentType interface: document.doctype must inherit property \"after\" with the proper type (6)": true, @@ -107,14 +64,10 @@ "Attr interface: existence and properties of interface object": true, "Attr interface: existence and properties of interface prototype object": true, "CharacterData interface: existence and properties of interface object": true, - "CharacterData interface: attribute previousElementSibling": true, - "CharacterData interface: attribute nextElementSibling": true, "CharacterData interface: operation before(union)": true, "CharacterData interface: operation after(union)": true, "CharacterData interface: operation replace(union)": true, "Text interface: existence and properties of interface object": true, - "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"previousElementSibling\" with the proper type (7)": true, - "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"nextElementSibling\" with the proper type (8)": true, "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"before\" with the proper type (9)": true, "CharacterData interface: calling before(union) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true, "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"after\" with the proper type (10)": true, @@ -122,8 +75,6 @@ "CharacterData interface: document.createTextNode(\"abc\") must inherit property \"replace\" with the proper type (11)": true, "CharacterData interface: calling replace(union) on document.createTextNode(\"abc\") with too few arguments must throw TypeError": true, "ProcessingInstruction interface: existence and properties of interface object": true, - "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"previousElementSibling\" with the proper type (7)": true, - "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"nextElementSibling\" with the proper type (8)": true, "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"before\" with the proper type (9)": true, "CharacterData interface: calling before(union) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true, "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"after\" with the proper type (10)": true, @@ -131,8 +82,6 @@ "CharacterData interface: xmlDoc.createProcessingInstruction(\"abc\", \"def\") must inherit property \"replace\" with the proper type (11)": true, "CharacterData interface: calling replace(union) on xmlDoc.createProcessingInstruction(\"abc\", \"def\") with too few arguments must throw TypeError": true, "Comment interface: existence and properties of interface object": true, - "CharacterData interface: document.createComment(\"abc\") must inherit property \"previousElementSibling\" with the proper type (7)": true, - "CharacterData interface: document.createComment(\"abc\") must inherit property \"nextElementSibling\" with the proper type (8)": true, "CharacterData interface: document.createComment(\"abc\") must inherit property \"before\" with the proper type (9)": true, "CharacterData interface: calling before(union) on document.createComment(\"abc\") with too few arguments must throw TypeError": true, "CharacterData interface: document.createComment(\"abc\") must inherit property \"after\" with the proper type (10)": true, @@ -141,5 +90,9 @@ "CharacterData interface: calling replace(union) on document.createComment(\"abc\") with too few arguments must throw TypeError": true, "NodeFilter interface: existence and properties of interface object": true, "NodeList interface: existence and properties of interface prototype object": true, + "DOMTokenList interface: operation add(DOMString)": true, + "DOMTokenList interface: operation remove(DOMString)": true, + "DOMTokenList interface: calling add(DOMString) on document.body.classList with too few arguments must throw TypeError": true, + "DOMTokenList interface: calling remove(DOMString) on document.body.classList with too few arguments must throw TypeError": true, "DOMSettableTokenList interface: existence and properties of interface object": true } diff --git a/dom/imptests/html/dom/test_interfaces.html b/dom/imptests/html/dom/test_interfaces.html index 67123d26651d..6d0c53058b10 100644 --- a/dom/imptests/html/dom/test_interfaces.html +++ b/dom/imptests/html/dom/test_interfaces.html @@ -334,7 +334,7 @@ interface Range { void setStartAfter(Node refNode); void setEndBefore(Node refNode); void setEndAfter(Node refNode); - void collapse(optional boolean toStart = false); + void collapse(optional boolean toStart /* = false */); void selectNode(Node refNode); void selectNodeContents(Node refNode); @@ -442,35 +442,38 @@ interface DOMSettableTokenList : DOMTokenList { From aa859ecb8bdbab51293aa5b253a838eb70bbe193 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Wed, 25 Sep 2013 10:54:55 -0700 Subject: [PATCH 23/62] Bug 919813 part 1: Remove never-checked return value from frame methods SetPrevInFlow, SetNextInFlow, SetPrevContinuation, SetNextContinuation. r=mats --- layout/generic/nsFrame.cpp | 20 ++++++++------------ layout/generic/nsFrame.h | 8 ++++---- layout/generic/nsIFrame.h | 8 ++++---- layout/generic/nsSplittableFrame.cpp | 16 ++++++++-------- layout/generic/nsSplittableFrame.h | 8 ++++---- layout/generic/nsTextFrame.cpp | 6 ++---- layout/generic/nsTextFrame.h | 6 ++---- 7 files changed, 32 insertions(+), 40 deletions(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 9c57329e9354..2cde8f549e17 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4246,15 +4246,13 @@ nsIFrame* nsFrame::GetPrevContinuation() const return nullptr; } -NS_IMETHODIMP nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation) +void +nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation) { // Ignore harmless requests to set it to NULL if (aPrevContinuation) { NS_ERROR("not splittable"); - return NS_ERROR_NOT_IMPLEMENTED; } - - return NS_OK; } nsIFrame* nsFrame::GetNextContinuation() const @@ -4262,10 +4260,10 @@ nsIFrame* nsFrame::GetNextContinuation() const return nullptr; } -NS_IMETHODIMP nsFrame::SetNextContinuation(nsIFrame*) +void +nsFrame::SetNextContinuation(nsIFrame*) { NS_ERROR("not splittable"); - return NS_ERROR_NOT_IMPLEMENTED; } nsIFrame* nsFrame::GetPrevInFlowVirtual() const @@ -4273,15 +4271,13 @@ nsIFrame* nsFrame::GetPrevInFlowVirtual() const return nullptr; } -NS_IMETHODIMP nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow) +void +nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow) { // Ignore harmless requests to set it to NULL if (aPrevInFlow) { NS_ERROR("not splittable"); - return NS_ERROR_NOT_IMPLEMENTED; } - - return NS_OK; } nsIFrame* nsFrame::GetNextInFlowVirtual() const @@ -4289,10 +4285,10 @@ nsIFrame* nsFrame::GetNextInFlowVirtual() const return nullptr; } -NS_IMETHODIMP nsFrame::SetNextInFlow(nsIFrame*) +void +nsFrame::SetNextInFlow(nsIFrame*) { NS_ERROR("not splittable"); - return NS_ERROR_NOT_IMPLEMENTED; } nsIFrame* nsIFrame::GetTailContinuation() diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index 6c8d8483b610..faa3fa45a485 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -191,13 +191,13 @@ public: int32_t aModType) MOZ_OVERRIDE; virtual nsSplittableType GetSplittableType() const MOZ_OVERRIDE; virtual nsIFrame* GetPrevContinuation() const MOZ_OVERRIDE; - NS_IMETHOD SetPrevContinuation(nsIFrame*) MOZ_OVERRIDE; + virtual void SetPrevContinuation(nsIFrame*) MOZ_OVERRIDE; virtual nsIFrame* GetNextContinuation() const MOZ_OVERRIDE; - NS_IMETHOD SetNextContinuation(nsIFrame*) MOZ_OVERRIDE; + virtual void SetNextContinuation(nsIFrame*) MOZ_OVERRIDE; virtual nsIFrame* GetPrevInFlowVirtual() const MOZ_OVERRIDE; - NS_IMETHOD SetPrevInFlow(nsIFrame*) MOZ_OVERRIDE; + virtual void SetPrevInFlow(nsIFrame*) MOZ_OVERRIDE; virtual nsIFrame* GetNextInFlowVirtual() const MOZ_OVERRIDE; - NS_IMETHOD SetNextInFlow(nsIFrame*) MOZ_OVERRIDE; + virtual void SetNextInFlow(nsIFrame*) MOZ_OVERRIDE; NS_IMETHOD GetOffsetFromView(nsPoint& aOffset, nsView** aView) const MOZ_OVERRIDE; virtual nsIAtom* GetType() const MOZ_OVERRIDE; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 7b3c21279c09..fb74802937c0 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -1485,9 +1485,9 @@ public: * Continuation member functions */ virtual nsIFrame* GetPrevContinuation() const = 0; - NS_IMETHOD SetPrevContinuation(nsIFrame*) = 0; + virtual void SetPrevContinuation(nsIFrame*) = 0; virtual nsIFrame* GetNextContinuation() const = 0; - NS_IMETHOD SetNextContinuation(nsIFrame*) = 0; + virtual void SetNextContinuation(nsIFrame*) = 0; virtual nsIFrame* FirstContinuation() const { return const_cast(this); } @@ -1507,11 +1507,11 @@ public: */ virtual nsIFrame* GetPrevInFlowVirtual() const = 0; nsIFrame* GetPrevInFlow() const { return GetPrevInFlowVirtual(); } - NS_IMETHOD SetPrevInFlow(nsIFrame*) = 0; + virtual void SetPrevInFlow(nsIFrame*) = 0; virtual nsIFrame* GetNextInFlowVirtual() const = 0; nsIFrame* GetNextInFlow() const { return GetNextInFlowVirtual(); } - NS_IMETHOD SetNextInFlow(nsIFrame*) = 0; + virtual void SetNextInFlow(nsIFrame*) = 0; /** * Return the first frame in our current flow. diff --git a/layout/generic/nsSplittableFrame.cpp b/layout/generic/nsSplittableFrame.cpp index d792b4801a3e..c757444c627a 100644 --- a/layout/generic/nsSplittableFrame.cpp +++ b/layout/generic/nsSplittableFrame.cpp @@ -50,13 +50,13 @@ nsIFrame* nsSplittableFrame::GetPrevContinuation() const return mPrevContinuation; } -NS_METHOD nsSplittableFrame::SetPrevContinuation(nsIFrame* aFrame) +void +nsSplittableFrame::SetPrevContinuation(nsIFrame* aFrame) { NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a prev continuation with incorrect type!"); NS_ASSERTION (!IsInPrevContinuationChain(aFrame, this), "creating a loop in continuation chain!"); mPrevContinuation = aFrame; RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } nsIFrame* nsSplittableFrame::GetNextContinuation() const @@ -64,14 +64,14 @@ nsIFrame* nsSplittableFrame::GetNextContinuation() const return mNextContinuation; } -NS_METHOD nsSplittableFrame::SetNextContinuation(nsIFrame* aFrame) +void +nsSplittableFrame::SetNextContinuation(nsIFrame* aFrame) { NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a next continuation with incorrect type!"); NS_ASSERTION (!IsInNextContinuationChain(aFrame, this), "creating a loop in continuation chain!"); mNextContinuation = aFrame; if (aFrame) aFrame->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } nsIFrame* @@ -129,13 +129,13 @@ nsIFrame* nsSplittableFrame::GetPrevInFlow() const return (GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ? mPrevContinuation : nullptr; } -NS_METHOD nsSplittableFrame::SetPrevInFlow(nsIFrame* aFrame) +void +nsSplittableFrame::SetPrevInFlow(nsIFrame* aFrame) { NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a prev in flow with incorrect type!"); NS_ASSERTION (!IsInPrevContinuationChain(aFrame, this), "creating a loop in continuation chain!"); mPrevContinuation = aFrame; AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } nsIFrame* nsSplittableFrame::GetNextInFlow() const @@ -144,14 +144,14 @@ nsIFrame* nsSplittableFrame::GetNextInFlow() const mNextContinuation : nullptr; } -NS_METHOD nsSplittableFrame::SetNextInFlow(nsIFrame* aFrame) +void +nsSplittableFrame::SetNextInFlow(nsIFrame* aFrame) { NS_ASSERTION (!aFrame || GetType() == aFrame->GetType(), "setting a next in flow with incorrect type!"); NS_ASSERTION (!IsInNextContinuationChain(aFrame, this), "creating a loop in continuation chain!"); mNextContinuation = aFrame; if (aFrame) aFrame->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } nsIFrame* diff --git a/layout/generic/nsSplittableFrame.h b/layout/generic/nsSplittableFrame.h index dfc666c0a7b4..11e51227503b 100644 --- a/layout/generic/nsSplittableFrame.h +++ b/layout/generic/nsSplittableFrame.h @@ -41,8 +41,8 @@ public: virtual nsIFrame* GetNextContinuation() const MOZ_OVERRIDE; // Set a previous/next non-fluid continuation. - NS_IMETHOD SetPrevContinuation(nsIFrame*) MOZ_OVERRIDE; - NS_IMETHOD SetNextContinuation(nsIFrame*) MOZ_OVERRIDE; + virtual void SetPrevContinuation(nsIFrame*) MOZ_OVERRIDE; + virtual void SetNextContinuation(nsIFrame*) MOZ_OVERRIDE; // Get the first/last continuation for this frame. virtual nsIFrame* FirstContinuation() const MOZ_OVERRIDE; @@ -62,8 +62,8 @@ public: virtual nsIFrame* GetNextInFlowVirtual() const MOZ_OVERRIDE { return GetNextInFlow(); } // Set a previous/next fluid continuation. - NS_IMETHOD SetPrevInFlow(nsIFrame*) MOZ_OVERRIDE; - NS_IMETHOD SetNextInFlow(nsIFrame*) MOZ_OVERRIDE; + virtual void SetPrevInFlow(nsIFrame*) MOZ_OVERRIDE; + virtual void SetNextInFlow(nsIFrame*) MOZ_OVERRIDE; // Get the first/last frame in the current flow. virtual nsIFrame* FirstInFlow() const MOZ_OVERRIDE; diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 8676c0e4c128..4b7ec99d1919 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -3902,27 +3902,25 @@ public: virtual nsIFrame* GetPrevContinuation() const { return mPrevContinuation; } - NS_IMETHOD SetPrevContinuation(nsIFrame* aPrevContinuation) { + virtual void SetPrevContinuation(nsIFrame* aPrevContinuation) { NS_ASSERTION (!aPrevContinuation || GetType() == aPrevContinuation->GetType(), "setting a prev continuation with incorrect type!"); NS_ASSERTION (!nsSplittableFrame::IsInPrevContinuationChain(aPrevContinuation, this), "creating a loop in continuation chain!"); mPrevContinuation = aPrevContinuation; RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } virtual nsIFrame* GetPrevInFlowVirtual() const { return GetPrevInFlow(); } nsIFrame* GetPrevInFlow() const { return (GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ? mPrevContinuation : nullptr; } - NS_IMETHOD SetPrevInFlow(nsIFrame* aPrevInFlow) { + virtual void SetPrevInFlow(nsIFrame* aPrevInFlow) MOZ_OVERRIDE { NS_ASSERTION (!aPrevInFlow || GetType() == aPrevInFlow->GetType(), "setting a prev in flow with incorrect type!"); NS_ASSERTION (!nsSplittableFrame::IsInPrevContinuationChain(aPrevInFlow, this), "creating a loop in continuation chain!"); mPrevContinuation = aPrevInFlow; AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } virtual nsIFrame* FirstInFlow() const MOZ_OVERRIDE; virtual nsIFrame* FirstContinuation() const MOZ_OVERRIDE; diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index ce2cf3852d17..1024e922732d 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -71,7 +71,7 @@ public: virtual nsIFrame* GetNextContinuation() const MOZ_OVERRIDE { return mNextContinuation; } - NS_IMETHOD SetNextContinuation(nsIFrame* aNextContinuation) MOZ_OVERRIDE { + virtual void SetNextContinuation(nsIFrame* aNextContinuation) MOZ_OVERRIDE { NS_ASSERTION (!aNextContinuation || GetType() == aNextContinuation->GetType(), "setting a next continuation with incorrect type!"); NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextContinuation, this), @@ -79,14 +79,13 @@ public: mNextContinuation = aNextContinuation; if (aNextContinuation) aNextContinuation->RemoveStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } virtual nsIFrame* GetNextInFlowVirtual() const MOZ_OVERRIDE { return GetNextInFlow(); } nsIFrame* GetNextInFlow() const { return mNextContinuation && (mNextContinuation->GetStateBits() & NS_FRAME_IS_FLUID_CONTINUATION) ? mNextContinuation : nullptr; } - NS_IMETHOD SetNextInFlow(nsIFrame* aNextInFlow) MOZ_OVERRIDE { + virtual void SetNextInFlow(nsIFrame* aNextInFlow) MOZ_OVERRIDE { NS_ASSERTION (!aNextInFlow || GetType() == aNextInFlow->GetType(), "setting a next in flow with incorrect type!"); NS_ASSERTION (!nsSplittableFrame::IsInNextContinuationChain(aNextInFlow, this), @@ -94,7 +93,6 @@ public: mNextContinuation = aNextInFlow; if (aNextInFlow) aNextInFlow->AddStateBits(NS_FRAME_IS_FLUID_CONTINUATION); - return NS_OK; } virtual nsIFrame* LastInFlow() const MOZ_OVERRIDE; virtual nsIFrame* LastContinuation() const MOZ_OVERRIDE; From ffdecec1a8a5f437d808f96eabc623f5412f2851 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Wed, 25 Sep 2013 10:54:56 -0700 Subject: [PATCH 24/62] Bug 919813 part 2: Upgrade NS_ERROR to MOZ_ASSERT in nsFrame's impl of SetPrevInFlow, SetNextInFlow, SetPrevContinuation, SetNextContinuation. rs=mats --- layout/generic/nsFrame.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 2cde8f549e17..6f6efe0cab16 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -4249,10 +4249,7 @@ nsIFrame* nsFrame::GetPrevContinuation() const void nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation) { - // Ignore harmless requests to set it to NULL - if (aPrevContinuation) { - NS_ERROR("not splittable"); - } + MOZ_ASSERT(false, "not splittable"); } nsIFrame* nsFrame::GetNextContinuation() const @@ -4263,7 +4260,7 @@ nsIFrame* nsFrame::GetNextContinuation() const void nsFrame::SetNextContinuation(nsIFrame*) { - NS_ERROR("not splittable"); + MOZ_ASSERT(false, "not splittable"); } nsIFrame* nsFrame::GetPrevInFlowVirtual() const @@ -4274,10 +4271,7 @@ nsIFrame* nsFrame::GetPrevInFlowVirtual() const void nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow) { - // Ignore harmless requests to set it to NULL - if (aPrevInFlow) { - NS_ERROR("not splittable"); - } + MOZ_ASSERT(false, "not splittable"); } nsIFrame* nsFrame::GetNextInFlowVirtual() const @@ -4288,7 +4282,7 @@ nsIFrame* nsFrame::GetNextInFlowVirtual() const void nsFrame::SetNextInFlow(nsIFrame*) { - NS_ERROR("not splittable"); + MOZ_ASSERT(false, "not splittable"); } nsIFrame* nsIFrame::GetTailContinuation() From d0b24c7ccf922c4f53e7fcf701553ba63b760d98 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Tue, 24 Sep 2013 21:37:53 +0200 Subject: [PATCH 25/62] Bug 920196 - Make QueryInterface opt-in for WebIDL interfaces. r=bz. --HG-- extra : rebase_source : 4cf7f9dc90f234dd663da05f27c0dc9484c7c0e1 --- dom/bindings/BindingUtils.h | 13 +--- dom/bindings/Bindings.conf | 5 -- dom/bindings/Codegen.py | 45 ++++++++++--- dom/bindings/Configuration.py | 22 ------ dom/webidl/LegacyQueryInterface.webidl | 93 ++++++++++++++++++++++++++ dom/webidl/moz.build | 1 + 6 files changed, 134 insertions(+), 45 deletions(-) create mode 100644 dom/webidl/LegacyQueryInterface.webidl diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 55a134a4c912..f07565c29f5d 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -1378,19 +1378,12 @@ InitIds(JSContext* cx, const Prefable* prefableSpecs, jsid* ids) bool QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp); -template ::value> +template struct WantsQueryInterface { - static bool Enabled(JSContext* aCx, JSObject* aGlobal) - { - return false; - } -}; -template -struct -WantsQueryInterface -{ + static_assert(IsBaseOf::value, + "QueryInterface can't work without an nsISupports."); static bool Enabled(JSContext* aCx, JSObject* aGlobal) { return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal); diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index f4df93ae3968..bec3a79e8f29 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -30,8 +30,6 @@ # true for workers, false otherwise). # * customFinalize - The native class will use a custom finalize hook # (defaults to true for workers, false otherwise). -# * wantsQI - Indicates whether the interface should have a QueryInterface -# method available to chrome. # * notflattened - The native type does not have nsIClassInfo, so when # wrapping it the right IID needs to be passed in. # * register - True if this binding should be registered. Defaults to true. @@ -318,7 +316,6 @@ DOMInterfaces = { }, 'DOMException': { - 'wantsQI': False, 'binaryNames': { 'message': 'messageMoz', }, @@ -395,7 +392,6 @@ DOMInterfaces = { 'Exception': { 'headerFile': 'mozilla/dom/DOMException.h', - 'wantsQI': False, 'binaryNames': { 'message': 'messageMoz', }, @@ -660,7 +656,6 @@ DOMInterfaces = { 'ImageData': [ { 'wrapperCache': False, - 'wantsQI': False, }], 'InputStream': [ diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index fe4e620ced07..09b30b471e4a 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1462,6 +1462,41 @@ class MethodDefiner(PropertyDefiner): self.chrome = [] self.regular = [] for m in methods: + if m.identifier.name == 'queryInterface': + if self.descriptor.workers: + continue + if m.isStatic(): + raise TypeError("Legacy queryInterface member shouldn't be static") + signatures = m.signatures() + def argTypeIsIID(arg): + return arg.type.inner.isExternal() and arg.type.inner.identifier.name == 'IID' + if len(signatures) > 1 or len(signatures[0][1]) > 1 or not argTypeIsIID(signatures[0][1][0]): + raise TypeError("There should be only one queryInterface method with 1 argument of type IID") + # Make sure to not stick QueryInterface on abstract interfaces that + # have hasXPConnectImpls (like EventTarget). So only put it on + # interfaces that are concrete and all of whose ancestors are abstract. + def allAncestorsAbstract(iface): + if not iface.parent: + return True + desc = self.descriptor.getDescriptor(iface.parent.identifier.name) + if desc.concrete: + return False + return allAncestorsAbstract(iface.parent) + if (not self.descriptor.interface.hasInterfacePrototypeObject() or + not self.descriptor.concrete or + not allAncestorsAbstract(self.descriptor.interface)): + raise TypeError("QueryInterface is only supported on " + "interfaces that are concrete and all " + "of whose ancestors are abstract: " + + self.descriptor.name) + condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType + self.regular.append({"name": 'QueryInterface', + "methodInfo": False, + "length": 1, + "flags": "0", + "condition": MemberCondition(None, condition) }) + continue + method = { "name": m.identifier.name, "methodInfo": not m.isStatic(), "length": methodLength(m), @@ -1481,14 +1516,6 @@ class MethodDefiner(PropertyDefiner): "flags": "JSPROP_ENUMERATE", "condition": MemberCondition(None, None) }) - if not static and descriptor.wantsQI(): - condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType - self.regular.append({"name": 'QueryInterface', - "methodInfo": False, - "length": 1, - "flags": "0", - "condition": MemberCondition(None, condition) }) - if not static: stringifier = descriptor.operations['Stringifier'] if stringifier: @@ -7860,6 +7887,8 @@ class CGDescriptor(CGThing): cgThings.append(CGClassConstructor(descriptor, n, NamedConstructorName(n))) for m in descriptor.interface.members: + if m.isMethod() and m.identifier.name == 'queryInterface': + continue if (m.isMethod() and m == descriptor.operations['Jsonifier']): hasJsonifier = True hasMethod = True diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py index 62767b186396..6b0b397bf947 100644 --- a/dom/bindings/Configuration.py +++ b/dom/bindings/Configuration.py @@ -356,8 +356,6 @@ class Descriptor(DescriptorProvider): (self.interface.identifier.name, self.nativeOwnership)) self.customTrace = desc.get('customTrace', self.workers) self.customFinalize = desc.get('customFinalize', self.workers) - if desc.get('wantsQI', None) != None: - self._wantsQI = desc.get('wantsQI', None) self.wrapperCache = (not self.interface.isCallback() and (self.nativeOwnership == 'worker' or (self.nativeOwnership != 'owned' and @@ -477,26 +475,6 @@ class Descriptor(DescriptorProvider): any((m.isAttr() or m.isMethod()) and m.isStatic() for m in self.interface.members)) - def wantsQI(self): - # If it was specified explicitly use that. - if hasattr(self, '_wantsQI'): - return self._wantsQI - - # Make sure to not stick QueryInterface on abstract interfaces that - # have hasXPConnectImpls (like EventTarget). So only put it on - # interfaces that are concrete and all of whose ancestors are abstract. - def allAncestorsAbstract(iface): - if not iface.parent: - return True - desc = self.getDescriptor(iface.parent.identifier.name) - if desc.concrete: - return False - return allAncestorsAbstract(iface.parent) - return (not self.workers and - self.interface.hasInterfacePrototypeObject() and - self.concrete and - allAncestorsAbstract(self.interface)) - # Some utility methods def getTypesFromDescriptor(descriptor): """ diff --git a/dom/webidl/LegacyQueryInterface.webidl b/dom/webidl/LegacyQueryInterface.webidl new file mode 100644 index 000000000000..53e5bffadc9c --- /dev/null +++ b/dom/webidl/LegacyQueryInterface.webidl @@ -0,0 +1,93 @@ +/* -*- Mode: IDL; 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/. + */ + +interface nsISupports; +interface IID; + +[NoInterfaceObject] +interface LegacyQueryInterface { + // Legacy QueryInterface, only exposed to chrome or XBL code on the + // main thread. + nsISupports queryInterface(IID iid); +}; + +Attr implements LegacyQueryInterface; +BarProp implements LegacyQueryInterface; +CaretPosition implements LegacyQueryInterface; +ClientRect implements LegacyQueryInterface; +ClientRectList implements LegacyQueryInterface; +Comment implements LegacyQueryInterface; +Crypto implements LegacyQueryInterface; +CSSPrimitiveValue implements LegacyQueryInterface; +CSSStyleDeclaration implements LegacyQueryInterface; +CSSValueList implements LegacyQueryInterface; +DOMImplementation implements LegacyQueryInterface; +DOMParser implements LegacyQueryInterface; +DOMStringMap implements LegacyQueryInterface; +DOMTokenList implements LegacyQueryInterface; +Document implements LegacyQueryInterface; +DocumentFragment implements LegacyQueryInterface; +DocumentType implements LegacyQueryInterface; +Element implements LegacyQueryInterface; +Event implements LegacyQueryInterface; +EventSource implements LegacyQueryInterface; +FileList implements LegacyQueryInterface; +FormData implements LegacyQueryInterface; +HTMLCollection implements LegacyQueryInterface; +History implements LegacyQueryInterface; +IDBCursor implements LegacyQueryInterface; +IDBDatabase implements LegacyQueryInterface; +IDBFactory implements LegacyQueryInterface; +IDBIndex implements LegacyQueryInterface; +IDBObjectStore implements LegacyQueryInterface; +IDBRequest implements LegacyQueryInterface; +IDBTransaction implements LegacyQueryInterface; +MimeTypeArray implements LegacyQueryInterface; +MozNamedAttrMap implements LegacyQueryInterface; +MutationObserver implements LegacyQueryInterface; +MutationRecord implements LegacyQueryInterface; +Navigator implements LegacyQueryInterface; +NodeIterator implements LegacyQueryInterface; +NodeList implements LegacyQueryInterface; +Notification implements LegacyQueryInterface; +OfflineResourceList implements LegacyQueryInterface; +PaintRequest implements LegacyQueryInterface; +PaintRequestList implements LegacyQueryInterface; +Performance implements LegacyQueryInterface; +Plugin implements LegacyQueryInterface; +PluginArray implements LegacyQueryInterface; +ProcessingInstruction implements LegacyQueryInterface; +Range implements LegacyQueryInterface; +Rect implements LegacyQueryInterface; +SVGAnimatedEnumeration implements LegacyQueryInterface; +SVGAnimatedInteger implements LegacyQueryInterface; +SVGAnimatedNumber implements LegacyQueryInterface; +SVGAnimatedNumberList implements LegacyQueryInterface; +SVGAnimatedPreserveAspectRatio implements LegacyQueryInterface; +SVGAnimatedString implements LegacyQueryInterface; +SVGLengthList implements LegacyQueryInterface; +SVGNumberList implements LegacyQueryInterface; +SVGPathSegList implements LegacyQueryInterface; +SVGPoint implements LegacyQueryInterface; +SVGPointList implements LegacyQueryInterface; +SVGPreserveAspectRatio implements LegacyQueryInterface; +SVGRect implements LegacyQueryInterface; +SVGStringList implements LegacyQueryInterface; +SVGTransformList implements LegacyQueryInterface; +Screen implements LegacyQueryInterface; +StyleSheet implements LegacyQueryInterface; +Text implements LegacyQueryInterface; +Touch implements LegacyQueryInterface; +TouchList implements LegacyQueryInterface; +TreeColumns implements LegacyQueryInterface; +TreeWalker implements LegacyQueryInterface; +UndoManager implements LegacyQueryInterface; +ValidityState implements LegacyQueryInterface; +WebSocket implements LegacyQueryInterface; +XMLHttpRequest implements LegacyQueryInterface; +XMLHttpRequestUpload implements LegacyQueryInterface; +XMLSerializer implements LegacyQueryInterface; +XPathEvaluator implements LegacyQueryInterface; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 9202ae1f8f17..f11183738b6d 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -193,6 +193,7 @@ WEBIDL_FILES = [ 'InterAppMessagePort.webidl', 'KeyboardEvent.webidl', 'KeyEvent.webidl', + 'LegacyQueryInterface.webidl', 'LinkStyle.webidl', 'LocalMediaStream.webidl', 'Location.webidl', From 54c9f49b7a5a4c28391de0f13cb8cfdc1b91123a Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Tue, 24 Sep 2013 15:23:36 -0400 Subject: [PATCH 26/62] Bug 918833 - Improved profiler thread register. r=ehsan --- tools/profiler/platform-linux.cc | 13 ++++++++++++- tools/profiler/platform-macos.cc | 16 ++++++++++++++-- tools/profiler/platform-win32.cc | 17 +++++++++++++++-- tools/profiler/platform.cpp | 16 +++++++++------- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/tools/profiler/platform-linux.cc b/tools/profiler/platform-linux.cc index 1466c914b225..a05ac3263acf 100644 --- a/tools/profiler/platform-linux.cc +++ b/tools/profiler/platform-linux.cc @@ -403,9 +403,20 @@ bool Sampler::RegisterCurrentThread(const char* aName, mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); + int id = gettid(); + for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) { + ThreadInfo* info = sRegisteredThreads->at(i); + if (info->ThreadId() == id) { + // Thread already registered. This means the first unregister will be + // too early. + ASSERT(false); + return false; + } + } + set_tls_stack_top(stackTop); - ThreadInfo* info = new ThreadInfo(aName, gettid(), + ThreadInfo* info = new ThreadInfo(aName, id, aIsMainThread, aPseudoStack, stackTop); if (sActiveSampler) { diff --git a/tools/profiler/platform-macos.cc b/tools/profiler/platform-macos.cc index f4968d12eccf..f26fc1c698f7 100644 --- a/tools/profiler/platform-macos.cc +++ b/tools/profiler/platform-macos.cc @@ -362,11 +362,23 @@ bool Sampler::RegisterCurrentThread(const char* aName, if (!Sampler::sRegisteredThreadsMutex) return false; - set_tls_stack_top(stackTop); mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); - ThreadInfo* info = new ThreadInfo(aName, gettid(), + int id = gettid(); + for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) { + ThreadInfo* info = sRegisteredThreads->at(i); + if (info->ThreadId() == id) { + // Thread already registered. This means the first unregister will be + // too early. + ASSERT(false); + return false; + } + } + + set_tls_stack_top(stackTop); + + ThreadInfo* info = new ThreadInfo(aName, id, aIsMainThread, aPseudoStack, stackTop); if (sActiveSampler) { diff --git a/tools/profiler/platform-win32.cc b/tools/profiler/platform-win32.cc index 494e54334065..e4615a81ca4b 100644 --- a/tools/profiler/platform-win32.cc +++ b/tools/profiler/platform-win32.cc @@ -281,11 +281,24 @@ bool Sampler::RegisterCurrentThread(const char* aName, if (!Sampler::sRegisteredThreadsMutex) return false; - set_tls_stack_top(stackTop); mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex); - ThreadInfo* info = new ThreadInfo(aName, GetCurrentThreadId(), + int id = GetCurrentThreadId(); + + for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) { + ThreadInfo* info = sRegisteredThreads->at(i); + if (info->ThreadId() == id) { + // Thread already registered. This means the first unregister will be + // too early. + ASSERT(false); + return false; + } + } + + set_tls_stack_top(stackTop); + + ThreadInfo* info = new ThreadInfo(aName, id, aIsMainThread, aPseudoStack, stackTop); if (sActiveSampler) { diff --git a/tools/profiler/platform.cpp b/tools/profiler/platform.cpp index 360593e9da50..bdd0ca3621d6 100644 --- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -719,29 +719,31 @@ void mozilla_sampler_unlock() bool mozilla_sampler_register_thread(const char* aName, void* stackTop) { -#ifndef MOZ_WIDGET_GONK +#if defined(MOZ_WIDGET_GONK) && !defined(MOZ_PROFILING) + // The only way to profile secondary threads on b2g + // is to build with profiling OR have the profiler + // running on startup. + if (!profiler_is_active()) { + return false; + } +#endif + PseudoStack* stack = new PseudoStack(); tlsPseudoStack.set(stack); return Sampler::RegisterCurrentThread(aName, stack, false, stackTop); -#else - return false; -#endif } void mozilla_sampler_unregister_thread() { -#ifndef MOZ_WIDGET_GONK Sampler::UnregisterCurrentThread(); PseudoStack *stack = tlsPseudoStack.get(); if (!stack) { - ASSERT(false); return; } delete stack; tlsPseudoStack.set(nullptr); -#endif } double mozilla_sampler_time(const TimeStamp& aTime) From 59c5157dca2b485dc5daf394637ba858163f24bc Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 25 Sep 2013 14:38:29 -0400 Subject: [PATCH 27/62] Bug 905493. Fix setting document.location via an Xray to not enter the content compartment. r=peterv --- dom/bindings/BindingUtils.cpp | 59 +++++++++++++++---- dom/bindings/Codegen.py | 24 +------- dom/bindings/test/Makefile.in | 2 + .../file_document_location_set_via_xray.html | 5 ++ .../test_document_location_set_via_xray.html | 49 +++++++++++++++ 5 files changed, 103 insertions(+), 36 deletions(-) create mode 100644 dom/bindings/test/file_document_location_set_via_xray.html create mode 100644 dom/bindings/test/test_document_location_set_via_xray.html diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index d2edabddc93c..c6abe542a5a2 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -872,6 +872,15 @@ GetNativePropertyHooks(JSContext *cx, JS::Handle obj, return ifaceAndProtoJSClass->mNativeHooks; } +// Try to resolve a property as an unforgeable property from the given +// NativeProperties, if it's there. nativeProperties is allowed to be null (in +// which case we of course won't resolve anything). +static bool +XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle wrapper, + JS::Handle obj, JS::Handle id, + JS::MutableHandle desc, + const NativeProperties* nativeProperties); + bool XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, @@ -881,7 +890,29 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, const NativePropertyHooks *nativePropertyHooks = GetNativePropertyHooks(cx, obj, type); - return type != eInstance || !nativePropertyHooks->mResolveOwnProperty || + if (type != eInstance) { + return true; + } + + // Check for unforgeable properties before doing mResolveOwnProperty weirdness + const NativePropertiesHolder& nativeProperties = + nativePropertyHooks->mNativeProperties; + if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, + nativeProperties.regular)) { + return false; + } + if (desc.object()) { + return true; + } + if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, + nativeProperties.chromeOnly)) { + return false; + } + if (desc.object()) { + return true; + } + + return !nativePropertyHooks->mResolveOwnProperty || nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, desc, flags); } @@ -936,6 +967,20 @@ XrayResolveAttribute(JSContext* cx, JS::Handle wrapper, return true; } +/* static */ bool +XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle wrapper, + JS::Handle obj, JS::Handle id, + JS::MutableHandle desc, + const NativeProperties* nativeProperties) +{ + return !nativeProperties || !nativeProperties->unforgeableAttributes || + XrayResolveAttribute(cx, wrapper, obj, id, + nativeProperties->unforgeableAttributes, + nativeProperties->unforgeableAttributeIds, + nativeProperties->unforgeableAttributeSpecs, + desc); +} + static bool XrayResolveProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, @@ -1008,18 +1053,6 @@ XrayResolveProperty(JSContext* cx, JS::Handle wrapper, return true; } } - if (nativeProperties->unforgeableAttributes) { - if (!XrayResolveAttribute(cx, wrapper, obj, id, - nativeProperties->unforgeableAttributes, - nativeProperties->unforgeableAttributeIds, - nativeProperties->unforgeableAttributeSpecs, - desc)) { - return false; - } - if (desc.object()) { - return true; - } - } } if (nativeProperties->constants) { diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 09b30b471e4a..341d7eca50ca 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -7280,22 +7280,6 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod): CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" + "}\n") % (self.descriptor.nativeType) - if UseHolderForUnforgeable(self.descriptor): - getUnforgeable = """if (!JS_GetPropertyDescriptorById(cx, ${holder}, id, flags, desc)) { - return false; -} -MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});""" - getUnforgeable = CallOnUnforgeableHolder(self.descriptor, - getUnforgeable, "isXray") - getUnforgeable += """if (desc.object()) { - desc.object().set(proxy); - return !isXray || JS_WrapPropertyDescriptor(cx, desc); -} - -""" - else: - getUnforgeable = "" - if indexedSetter or self.descriptor.operations['NamedSetter']: setOrIndexedGet += "if (flags & JSRESOLVE_ASSIGNING) {\n" if indexedSetter: @@ -7309,7 +7293,6 @@ MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});""" setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" + " return true;\n" + " }\n") - setOrIndexedGet += CGIndenter(CGGeneric(getUnforgeable)).define() if self.descriptor.operations['NamedSetter']: if not 'NamedCreator' in self.descriptor.operations: # FIXME need to check that this is a 'supported property name' @@ -7324,11 +7307,7 @@ MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});""" setOrIndexedGet += "}" if indexedGetter: setOrIndexedGet += (" else {\n" + - CGIndenter(CGGeneric(get + "\n" + getUnforgeable)).define() + - "}") - else: - setOrIndexedGet += (" else {\n" + - CGIndenter(CGGeneric(getUnforgeable)).define() + + CGIndenter(CGGeneric(get)).define() + "}") setOrIndexedGet += "\n\n" else: @@ -7336,7 +7315,6 @@ MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});""" setOrIndexedGet += ("if (!(flags & JSRESOLVE_ASSIGNING)) {\n" + CGIndenter(CGGeneric(get)).define() + "}\n\n") - setOrIndexedGet += getUnforgeable if self.descriptor.supportsNamedProperties(): readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None) diff --git a/dom/bindings/test/Makefile.in b/dom/bindings/test/Makefile.in index ab7b73006e1a..b9e982ce4024 100644 --- a/dom/bindings/test/Makefile.in +++ b/dom/bindings/test/Makefile.in @@ -68,11 +68,13 @@ MOCHITEST_FILES := \ test_exception_messages.html \ test_bug707564.html \ test_defineProperty.html \ + file_document_location_set_via_xray.html \ $(NULL) MOCHITEST_CHROME_FILES = \ test_bug775543.html \ test_bug707564-chrome.html \ + test_document_location_set_via_xray.html \ $(NULL) ifdef GNU_CC diff --git a/dom/bindings/test/file_document_location_set_via_xray.html b/dom/bindings/test/file_document_location_set_via_xray.html new file mode 100644 index 000000000000..323acba6663e --- /dev/null +++ b/dom/bindings/test/file_document_location_set_via_xray.html @@ -0,0 +1,5 @@ + + + diff --git a/dom/bindings/test/test_document_location_set_via_xray.html b/dom/bindings/test/test_document_location_set_via_xray.html new file mode 100644 index 000000000000..cdadc5063928 --- /dev/null +++ b/dom/bindings/test/test_document_location_set_via_xray.html @@ -0,0 +1,49 @@ + + + + + + Test for Bug 905493 + + + + +Mozilla Bug 905493 +

+ +
+
+
+ + From e45147038627c091c09d1f4e6e01b77647801e76 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 25 Sep 2013 14:38:30 -0400 Subject: [PATCH 28/62] Bug 920125. getOwnPropertyDescriptor on Xrays for DOM interface and prototype objects should actually work. r=peterv --- dom/bindings/BindingUtils.cpp | 14 ++++++++++++-- .../mochitest/chrome/test_sandbox_bindings.xul | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index c6abe542a5a2..5ee0a608772a 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -881,6 +881,13 @@ XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle wrapper, JS::MutableHandle desc, const NativeProperties* nativeProperties); +static bool +XrayResolveNativeProperty(JSContext* cx, JS::Handle wrapper, + const NativePropertyHooks* nativePropertyHooks, + DOMObjectType type, JS::Handle obj, + JS::Handle id, + JS::MutableHandle desc); + bool XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, @@ -891,7 +898,10 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, GetNativePropertyHooks(cx, obj, type); if (type != eInstance) { - return true; + // For prototype objects and interface objects, just return their + // normal set of properties. + return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, + obj, id, desc); } // Check for unforgeable properties before doing mResolveOwnProperty weirdness @@ -1101,7 +1111,7 @@ ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle wrapper, return JS_WrapPropertyDescriptor(cx, desc); } -bool +/* static */ bool XrayResolveNativeProperty(JSContext* cx, JS::Handle wrapper, const NativePropertyHooks* nativePropertyHooks, DOMObjectType type, JS::Handle obj, diff --git a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul index 0f13617826a6..a9cddb9a4bd4 100644 --- a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul +++ b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul @@ -49,6 +49,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267 ok(xhr, "'XMLHttpRequest.prototype' in a sandbox should return the XMLHttpRequest interface prototype object"); ok(isXrayWrapper(xhr), "Getting an interface prototype object on an Xray wrapper should return an Xray wrapper"); ok(isXrayWrapper(xhr.constructor), "Getting the constructor property on an Xray wrapper of an interface prototype object should return an Xray wrapper"); + isnot(Object.getOwnPropertyDescriptor(xhr, "send"), undefined, + "We should claim to have a send() method"); + isnot(Object.keys(xhr).indexOf("responseType"), -1, + "We should claim to have a responseType property"); + isnot(Object.getOwnPropertyNames(xhr).indexOf("open"), -1, + "We should claim to have an open() method"); + isnot(Object.getOwnPropertyDescriptor(xhr, "constructor"), undefined, + "We should claim to have a 'constructor' property"); } catch (e) { ok(false, "'XMLHttpRequest.prototype' shouldn't throw in a sandbox"); } @@ -87,6 +95,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267 var xhr = Components.utils.evalInSandbox("XMLHttpRequest", sandbox); is(xhr, "[object XrayWrapper " + XMLHttpRequest + "]", "'XMLHttpRequest' in a sandbox should return the XMLHttpRequest interface object"); ok(isXrayWrapper(xhr.prototype), "Getting the prototype property on an Xray wrapper of an interface object should return an Xray wrapper"); + isnot(Object.getOwnPropertyDescriptor(xhr, "UNSENT"), undefined, + "We should claim to have an UNSENT constant"); + isnot(Object.keys(xhr).indexOf("OPENED"), -1, + "We should claim to have an OPENED constant"); + isnot(Object.getOwnPropertyNames(xhr).indexOf("DONE"), -1, + "We should claim to have a DONE constant"); + isnot(Object.getOwnPropertyDescriptor(xhr, "prototype"), undefined, + "We should claim to have 'prototype' property"); } catch (e) { ok(false, "'XMLHttpRequest' shouldn't throw in a sandbox"); } From 3f8499abaea8b8f646d464e5603032f161f3e0d6 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 25 Sep 2013 14:38:30 -0400 Subject: [PATCH 29/62] Bug 919603 part 1. Introduce support for the [Global] extended attribute. r=peterv --- dom/bindings/parser/WebIDL.py | 43 ++++++ .../parser/tests/test_global_extended_attr.py | 122 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 dom/bindings/parser/tests/test_global_extended_attr.py diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index b47d985e3470..33d6c79d3709 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -523,6 +523,7 @@ class IDLInterface(IDLObjectWithScope): # have self as a consequential interface self.interfacesImplementingSelf = set() self._hasChildInterfaces = False + self._isOnGlobalProtoChain = False IDLObjectWithScope.__init__(self, location, parentScope, name) @@ -586,6 +587,15 @@ class IDLInterface(IDLObjectWithScope): self.parent._hasChildInterfaces = True + # Interfaces with [Global] must not have anything inherit from them + if self.parent.getExtendedAttribute("Global"): + # Note: This is not a self.parent.isOnGlobalProtoChain() check + # because ancestors of a [Global] interface can have other + # descendants. + raise WebIDLError("[Global] interface has another interface " + "inheriting from it", + [self.location, self.parent.location]) + # Callbacks must not inherit from non-callbacks or inherit from # anything that has consequential interfaces. # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending. @@ -741,6 +751,31 @@ class IDLInterface(IDLObjectWithScope): specialMembersSeen[memberType] = member + if self._isOnGlobalProtoChain: + # Make sure we have no named setters, creators, or deleters + for memberType in ["setter", "creator", "deleter"]: + memberId = "named " + memberType + "s" + if memberId in specialMembersSeen: + raise WebIDLError("Interface with [Global] has a named %s" % + memberType, + [self.location, + specialMembersSeen[memberId].location]) + # Make sure we're not [OverrideBuiltins] + if self.getExtendedAttribute("OverrideBuiltins"): + raise WebIDLError("Interface with [Global] also has " + "[OverrideBuiltins]", + [self.location]) + # Mark all of our ancestors as being on the global's proto chain too + parent = self.parent + while parent: + # Must not inherit from an interface with [OverrideBuiltins] + if parent.getExtendedAttribute("OverrideBuiltins"): + raise WebIDLError("Interface with [Global] inherits from " + "interface with [OverrideBuiltins]", + [self.location, parent.location]) + parent._isOnGlobalProtoChain = True + parent = parent.parent + def validate(self): for member in self.members: member.validate() @@ -924,6 +959,11 @@ class IDLInterface(IDLObjectWithScope): raise WebIDLError("[ArrayClass] must not be specified on " "an interface with inherited interfaces", [attr.location, self.location]) + elif identifier == "Global": + if not attr.noArguments(): + raise WebIDLError("[Global] must take no arguments", + [attr.location]) + self._isOnGlobalProtoChain = True elif (identifier == "PrefControlled" or identifier == "NeedNewResolve" or identifier == "OverrideBuiltins" or @@ -1042,6 +1082,9 @@ class IDLInterface(IDLObjectWithScope): def hasChildInterfaces(self): return self._hasChildInterfaces + def isOnGlobalProtoChain(self): + return self._isOnGlobalProtoChain + def _getDependentObjects(self): deps = set(self.members) deps.union(self.implementedInterfaces) diff --git a/dom/bindings/parser/tests/test_global_extended_attr.py b/dom/bindings/parser/tests/test_global_extended_attr.py new file mode 100644 index 000000000000..c752cecd298b --- /dev/null +++ b/dom/bindings/parser/tests/test_global_extended_attr.py @@ -0,0 +1,122 @@ +def WebIDLTest(parser, harness): + parser.parse(""" + [Global] + interface Foo : Bar { + getter any(DOMString name); + }; + interface Bar {}; + """) + + results = parser.finish() + + harness.ok(results[0].isOnGlobalProtoChain(), + "[Global] interface should be on global's proto chain") + harness.ok(results[1].isOnGlobalProtoChain(), + "[Global] interface should be on global's proto chain") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + getter any(DOMString name); + setter void(DOMString name, any arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "named setter") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + getter any(DOMString name); + creator void(DOMString name, any arg); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "named creator") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + getter any(DOMString name); + deleter void(DOMString name); + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "named deleter") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global, OverrideBuiltins] + interface Foo { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "[OverrideBuiltins]") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo : Bar { + }; + [OverrideBuiltins] + interface Bar { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with an " + "[OverrideBuiltins] ancestor") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Global] + interface Foo { + }; + interface Bar : Foo { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, + "Should have thrown for [Global] used on an interface with a " + "descendant") From d7f8928b368d5fa4cbaad232346360ec9212eda0 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 25 Sep 2013 14:38:30 -0400 Subject: [PATCH 30/62] Bug 919603 part 2. Change this-handling in codegen to only do the special global object stuff on interfaces where it might matter. r=peterv --- dom/bindings/BindingUtils.cpp | 5 +++-- dom/bindings/BindingUtils.h | 2 +- dom/bindings/Codegen.py | 41 ++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 5ee0a608772a..49aefd24d4bb 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1947,9 +1947,10 @@ InterfaceHasInstance(JSContext* cx, int prototypeID, int depth, } bool -ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle obj) +ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj) { - GlobalObject global(cx, obj); + JS::Rooted rootedObj(cx, obj); + GlobalObject global(cx, rootedObj); if (global.Failed()) { return false; } diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index f07565c29f5d..c383e156f5ac 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -2062,7 +2062,7 @@ InterfaceHasInstance(JSContext* cx, int prototypeID, int depth, // Helper for lenient getters/setters to report to console. If this // returns false, we couldn't even get a global. bool -ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle obj); +ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj); inline JSObject* GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 341d7eca50ca..ff653942ebf5 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -5321,9 +5321,18 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod): |this| object. Subclasses are expected to override the generate_code function to do the rest of the work. This function should return a CGThing which is already properly indented. + + getThisObj should be code for getting a JSObject* for the binding + object. If this is None, we will auto-generate code based on + descriptor to do the right thing. "" can be passed in if the + binding object is already stored in 'obj'. + + callArgs should be code for getting a JS::CallArgs into a variable + called 'args'. This can be "" if there is already such a variable + around. """ def __init__(self, descriptor, name, args, unwrapFailureCode=None, - getThisObj="args.computeThis(cx).toObjectOrNull()", + getThisObj=None, callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);"): CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args) @@ -5331,7 +5340,26 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod): self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");' % descriptor.interface.identifier.name else: self.unwrapFailureCode = unwrapFailureCode - self.getThisObj = getThisObj + + if getThisObj == "": + self.getThisObj = None + else: + if getThisObj is None: + if descriptor.interface.isOnGlobalProtoChain(): + ensureCondition = "!args.thisv().isNullOrUndefined() && !args.thisv().isObject()" + getThisObj = "args.thisv().isObject() ? &args.thisv().toObject() : js::GetGlobalForObjectCrossCompartment(&args.callee())" + else: + ensureCondition = "!args.thisv().isObject()" + getThisObj = "&args.thisv().toObject()" + ensureThisObj = CGIfWrapper(CGGeneric(self.unwrapFailureCode), + ensureCondition) + else: + ensureThisObj = None + self.getThisObj = CGList( + [ensureThisObj, + CGGeneric("JS::RootedObject obj(cx, %s);\n" % + getThisObj)], + "\n") self.callArgs = callArgs def definition_body(self): @@ -5341,10 +5369,7 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod): # consumption by CastableObjectUnwrapper. getThis = CGList([ CGGeneric(self.callArgs) if self.callArgs != "" else None, - CGGeneric("JS::RootedObject obj(cx, %s);\n" - "if (!obj) {\n" - " return false;\n" - "}" % self.getThisObj) if self.getThisObj else None, + self.getThisObj, CGGeneric("%s* self;" % self.descriptor.nativeType) ], "\n") unwrapThis = CGGeneric( @@ -5585,7 +5610,7 @@ class CGGenericGetter(CGAbstractBindingMethod): name = "genericLenientGetter" unwrapFailureCode = ( "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n" - "if (!ReportLenientThisUnwrappingFailure(cx, obj)) {\n" + "if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {\n" " return false;\n" "}\n" "args.rval().set(JS::UndefinedValue());\n" @@ -5665,7 +5690,7 @@ class CGGenericSetter(CGAbstractBindingMethod): name = "genericLenientSetter" unwrapFailureCode = ( "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n" - "if (!ReportLenientThisUnwrappingFailure(cx, obj)) {\n" + "if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) {\n" " return false;\n" "}\n" "args.rval().set(JS::UndefinedValue());\n" From ea618751908b05658f30a4dc37ed4a192900690b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez?= Date: Wed, 25 Sep 2013 21:08:04 +0200 Subject: [PATCH 31/62] Bug 919429 - [Message manager] We must not force weak listeners to implement Ci.nsIMessageListener. r=smaug --- content/base/src/nsFrameMessageManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 36ee6d4a9098..f5d787620886 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -757,7 +757,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, for (uint32_t i = 0; i < mListeners.Length(); ++i) { // Remove mListeners[i] if it's an expired weak listener. - nsCOMPtr weakListener; + nsCOMPtr weakListener; if (mListeners[i].mWeakListener) { weakListener = do_QueryReferent(mListeners[i].mWeakListener); if (!weakListener) { From f52d0268b75039711dbf5904cf67e509da3012ff Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 25 Sep 2013 08:31:14 -0700 Subject: [PATCH 32/62] Bug 916635 - IonMonkey: Rewrite markBlocksInLoopBody to avoid recursion. r=bhackett --- js/src/jit/RangeAnalysis.cpp | 54 ++++++++++++++++++++++++------------ js/src/jit/RangeAnalysis.h | 4 +-- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 61057f9f36ef..f5ecc6a5e458 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -1209,24 +1209,38 @@ MArgumentsLength::computeRange() // Range Analysis /////////////////////////////////////////////////////////////////////////////// -void -RangeAnalysis::markBlocksInLoopBody(MBasicBlock *header, MBasicBlock *current) +bool +RangeAnalysis::markBlocksInLoopBody(MBasicBlock *header, MBasicBlock *backedge) { - // Visited. - current->mark(); + Vector worklist; - // If we haven't reached the loop header yet, recursively explore predecessors - // if we haven't seen them already. - if (current != header) { + // Mark the header as being in the loop. This terminates the walk. + header->mark(); + + backedge->mark(); + if (!worklist.append(backedge)) + return false; + + // If we haven't reached the loop header yet, walk up the predecessors + // we haven't seen already. + while (!worklist.empty()) { + MBasicBlock *current = worklist.popCopy(); for (size_t i = 0; i < current->numPredecessors(); i++) { - if (current->getPredecessor(i)->isMarked()) + MBasicBlock *pred = current->getPredecessor(i); + + if (pred->isMarked()) continue; - markBlocksInLoopBody(header, current->getPredecessor(i)); + + pred->mark(); + if (!worklist.append(pred)) + return false; } } + + return true; } -void +bool RangeAnalysis::analyzeLoop(MBasicBlock *header) { JS_ASSERT(header->hasUniqueBackedge()); @@ -1238,9 +1252,10 @@ RangeAnalysis::analyzeLoop(MBasicBlock *header) // Ignore trivial infinite loops. if (backedge == header) - return; + return true; - markBlocksInLoopBody(header, backedge); + if (!markBlocksInLoopBody(header, backedge)) + return false; LoopIterationBound *iterationBound = NULL; @@ -1268,7 +1283,7 @@ RangeAnalysis::analyzeLoop(MBasicBlock *header) if (!iterationBound) { graph_.unmarkBlocks(); - return; + return true; } #ifdef DEBUG @@ -1300,8 +1315,10 @@ RangeAnalysis::analyzeLoop(MBasicBlock *header) for (MDefinitionIterator iter(block); iter; iter++) { MDefinition *def = *iter; if (def->isBoundsCheck() && def->isMovable()) { - if (tryHoistBoundsCheck(header, def->toBoundsCheck())) - hoistedChecks.append(def->toBoundsCheck()); + if (tryHoistBoundsCheck(header, def->toBoundsCheck())) { + if (!hoistedChecks.append(def->toBoundsCheck())) + return false; + } } } } @@ -1319,6 +1336,7 @@ RangeAnalysis::analyzeLoop(MBasicBlock *header) } graph_.unmarkBlocks(); + return true; } LoopIterationBound * @@ -1668,8 +1686,10 @@ RangeAnalysis::analyze() SpewRange(def); } - if (block->isLoopHeader()) - analyzeLoop(block); + if (block->isLoopHeader()) { + if (!analyzeLoop(block)) + return false; + } if (mir->compilingAsmJS()) { for (MInstructionIterator i = block->begin(); i != block->end(); i++) { diff --git a/js/src/jit/RangeAnalysis.h b/js/src/jit/RangeAnalysis.h index 797df13370f1..d835a7b00bd3 100644 --- a/js/src/jit/RangeAnalysis.h +++ b/js/src/jit/RangeAnalysis.h @@ -87,12 +87,12 @@ class RangeAnalysis bool truncate(); private: - void analyzeLoop(MBasicBlock *header); + bool analyzeLoop(MBasicBlock *header); LoopIterationBound *analyzeLoopIterationCount(MBasicBlock *header, MTest *test, BranchDirection direction); void analyzeLoopPhi(MBasicBlock *header, LoopIterationBound *loopBound, MPhi *phi); bool tryHoistBoundsCheck(MBasicBlock *header, MBoundsCheck *ins); - void markBlocksInLoopBody(MBasicBlock *header, MBasicBlock *current); + bool markBlocksInLoopBody(MBasicBlock *header, MBasicBlock *current); }; class Range : public TempObject { From a2c515239b0fc01045426923ebbd94ce96eac97c Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Wed, 25 Sep 2013 13:14:21 -0600 Subject: [PATCH 33/62] Bug 919140 - Watch for lazy scripts in AddPossibleCallees, r=jandem. --- js/src/jit/CodeGenerator.cpp | 2 +- js/src/jit/ParallelSafetyAnalysis.cpp | 8 +++----- js/src/jit/ParallelSafetyAnalysis.h | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 533f07dc9867..c37ce363f477 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -5680,7 +5680,7 @@ CodeGenerator::link() // only tracked when compiling for parallel execution. CallTargetVector callTargets; if (executionMode == ParallelExecution) - AddPossibleCallees(graph.mir(), callTargets); + AddPossibleCallees(cx, graph.mir(), callTargets); IonScript *ionScript = IonScript::New(cx, graph.totalSlotCount(), scriptFrameSize, snapshots_.size(), diff --git a/js/src/jit/ParallelSafetyAnalysis.cpp b/js/src/jit/ParallelSafetyAnalysis.cpp index 26e5f549608d..23a8eda47f2f 100644 --- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -780,10 +780,8 @@ static bool AddCallTarget(HandleScript script, CallTargetVector &targets); bool -jit::AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets) +jit::AddPossibleCallees(JSContext *cx, MIRGraph &graph, CallTargetVector &targets) { - JSContext *cx = GetIonContext()->cx; - for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) { for (MInstructionIterator ins(block->begin()); ins != block->end(); ins++) { @@ -797,8 +795,8 @@ jit::AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets) JS_ASSERT_IF(!target->isInterpreted(), target->hasParallelNative()); if (target->isInterpreted()) { - RootedScript script(cx, target->nonLazyScript()); - if (!AddCallTarget(script, targets)) + RootedScript script(cx, target->getOrCreateScript(cx)); + if (!script || !AddCallTarget(script, targets)) return false; } diff --git a/js/src/jit/ParallelSafetyAnalysis.h b/js/src/jit/ParallelSafetyAnalysis.h index 5a9acd71b86c..3e68d6faacc2 100644 --- a/js/src/jit/ParallelSafetyAnalysis.h +++ b/js/src/jit/ParallelSafetyAnalysis.h @@ -47,7 +47,7 @@ class ParallelSafetyAnalysis // This code may clone scripts and thus may invoke the GC. Hence only // run from the link phase, which executes on the main thread. typedef Vector CallTargetVector; -bool AddPossibleCallees(MIRGraph &graph, CallTargetVector &targets); +bool AddPossibleCallees(JSContext *cx, MIRGraph &graph, CallTargetVector &targets); } // namespace jit } // namespace js From 37b7da75e9e919e8536722c4886c1b850854eab5 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 25 Sep 2013 12:18:43 -0700 Subject: [PATCH 34/62] Bug 916580 - Fix bugs related to the usage of calloc. r=luke --- js/jsd/jsd_lock.cpp | 2 +- js/public/Utility.h | 6 ++++++ js/src/jit/BaselineBailouts.cpp | 2 ++ js/src/jit/IonCode.h | 4 ++-- js/src/jsutil.cpp | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/js/jsd/jsd_lock.cpp b/js/jsd/jsd_lock.cpp index f50ea1376132..8d9bf81d6667 100644 --- a/js/jsd/jsd_lock.cpp +++ b/js/jsd/jsd_lock.cpp @@ -86,7 +86,7 @@ jsd_CreateLock() { JSDStaticLock* lock; - if( ! (lock = js_pod_calloc(1)) || + if( ! (lock = js_pod_calloc()) || ! (lock->lock = PR_NewLock()) ) { if(lock) diff --git a/js/public/Utility.h b/js/public/Utility.h index 044f18568f40..028786ee407a 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -148,6 +148,12 @@ static JS_INLINE void* js_calloc(size_t bytes) return calloc(bytes, 1); } +static JS_INLINE void* js_calloc(size_t nmemb, size_t size) +{ + JS_OOM_POSSIBLY_FAIL(); + return calloc(nmemb, size); +} + static JS_INLINE void* js_realloc(void* p, size_t bytes) { JS_OOM_POSSIBLY_FAIL(); diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 1637f5d78b8f..15ffdf81266e 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -125,6 +125,8 @@ struct BaselineStackBuilder bool enlarge() { JS_ASSERT(buffer_ != NULL); + if (bufferTotal_ & mozilla::tl::MulOverflowMask<2>::value) + return false; size_t newSize = bufferTotal_ * 2; uint8_t *newBuffer = reinterpret_cast(js_calloc(newSize)); if (!newBuffer) diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index 9b9b1db94d83..9fa94c425c6e 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -572,7 +572,7 @@ struct IonBlockCounts offset_ = offset; numSuccessors_ = numSuccessors; if (numSuccessors) { - successors_ = (uint32_t *) js_calloc(numSuccessors * sizeof(uint32_t)); + successors_ = js_pod_calloc(numSuccessors); if (!successors_) return false; } @@ -670,7 +670,7 @@ struct IonScriptCounts bool init(size_t numBlocks) { numBlocks_ = numBlocks; - blocks_ = (IonBlockCounts *) js_calloc(numBlocks * sizeof(IonBlockCounts)); + blocks_ = js_pod_calloc(numBlocks); return blocks_ != NULL; } diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index 29eab6ce971b..904d05d37922 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -31,7 +31,7 @@ using mozilla::PodArrayZero; static void * zlib_alloc(void *cx, uInt items, uInt size) { - return js_malloc(items * size); + return js_calloc(items, size); } static void From 483c701a7d657c58ed918280fc00f9bb2ac42188 Mon Sep 17 00:00:00 2001 From: Frank Yan Date: Mon, 24 Jun 2013 00:32:44 -0700 Subject: [PATCH 35/62] Bug 880672: Add support for unprefixed cursor:grab and cursor:grabbing. r=bzbarsky sr=dbaron --- layout/style/nsCSSKeywordList.h | 2 ++ layout/style/nsCSSProps.cpp | 2 ++ layout/style/test/property_database.js | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 0f20a4093875..041ab324cb4e 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -281,6 +281,8 @@ CSS_KEY(forwards, forwards) CSS_KEY(from-image, from_image) CSS_KEY(full-width, full_width) CSS_KEY(georgian, georgian) +CSS_KEY(grab, grab) +CSS_KEY(grabbing, grabbing) CSS_KEY(grad, grad) CSS_KEY(grayscale, grayscale) CSS_KEY(graytext, graytext) diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 0a2c5812ddb0..187fc4592498 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -911,6 +911,8 @@ const int32_t nsCSSProps::kCursorKTable[] = { eCSSKeyword_ns_resize, NS_STYLE_CURSOR_NS_RESIZE, eCSSKeyword_ew_resize, NS_STYLE_CURSOR_EW_RESIZE, eCSSKeyword_none, NS_STYLE_CURSOR_NONE, + eCSSKeyword_grab, NS_STYLE_CURSOR_GRAB, + eCSSKeyword_grabbing, NS_STYLE_CURSOR_GRABBING, eCSSKeyword_zoom_in, NS_STYLE_CURSOR_ZOOM_IN, eCSSKeyword_zoom_out, NS_STYLE_CURSOR_ZOOM_OUT, // -moz- prefixed vendor specific diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 17f6c96f3ebd..4e208789d555 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -2336,7 +2336,7 @@ var gCSSProperties = { inherited: true, type: CSS_TYPE_LONGHAND, initial_values: [ "auto" ], - other_values: [ "crosshair", "default", "pointer", "move", "e-resize", "ne-resize", "nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", "w-resize", "text", "wait", "help", "progress", "copy", "alias", "context-menu", "cell", "not-allowed", "col-resize", "row-resize", "no-drop", "vertical-text", "all-scroll", "nesw-resize", "nwse-resize", "ns-resize", "ew-resize", "none", "zoom-in", "zoom-out", "-moz-grab", "-moz-grabbing", "-moz-zoom-in", "-moz-zoom-out", "url(foo.png), move", "url(foo.png) 5 7, move", "url(foo.png) 12 3, url(bar.png), no-drop", "url(foo.png), url(bar.png) 7 2, wait", "url(foo.png) 3 2, url(bar.png) 7 9, pointer" ], + other_values: [ "crosshair", "default", "pointer", "move", "e-resize", "ne-resize", "nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", "w-resize", "text", "wait", "help", "progress", "copy", "alias", "context-menu", "cell", "not-allowed", "col-resize", "row-resize", "no-drop", "vertical-text", "all-scroll", "nesw-resize", "nwse-resize", "ns-resize", "ew-resize", "none", "grab", "grabbing", "zoom-in", "zoom-out", "-moz-grab", "-moz-grabbing", "-moz-zoom-in", "-moz-zoom-out", "url(foo.png), move", "url(foo.png) 5 7, move", "url(foo.png) 12 3, url(bar.png), no-drop", "url(foo.png), url(bar.png) 7 2, wait", "url(foo.png) 3 2, url(bar.png) 7 9, pointer" ], invalid_values: [ "url(foo.png)", "url(foo.png) 5 5" ] }, "direction": { From acdeb3e74668072c62b981ff9515ae22fc88d1d3 Mon Sep 17 00:00:00 2001 From: Brandon Benvie Date: Tue, 24 Sep 2013 14:58:30 -0700 Subject: [PATCH 36/62] Bug 843019 - Add VariablesViewController#setSingleVariable. r=vp, r=msucan --- .../netmonitor/netmonitor-controller.js | 1 + .../devtools/netmonitor/netmonitor-view.js | 8 +- browser/devtools/scratchpad/scratchpad.js | 11 +-- .../widgets/VariablesViewController.jsm | 36 ++++++++- browser/devtools/webconsole/test/Makefile.in | 1 + ...onsole_bug_843019_variables_view_filter.js | 79 +++++++++++++++++++ browser/devtools/webconsole/webconsole.js | 15 ++-- 7 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js diff --git a/browser/devtools/netmonitor/netmonitor-controller.js b/browser/devtools/netmonitor/netmonitor-controller.js index c49d0b37df88..8ff53a2d409e 100644 --- a/browser/devtools/netmonitor/netmonitor-controller.js +++ b/browser/devtools/netmonitor/netmonitor-controller.js @@ -65,6 +65,7 @@ Cu.import("resource:///modules/devtools/sourceeditor/source-editor.jsm"); Cu.import("resource:///modules/devtools/shared/event-emitter.js"); Cu.import("resource:///modules/devtools/SideMenuWidget.jsm"); Cu.import("resource:///modules/devtools/VariablesView.jsm"); +Cu.import("resource:///modules/devtools/VariablesViewController.jsm"); Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", diff --git a/browser/devtools/netmonitor/netmonitor-view.js b/browser/devtools/netmonitor/netmonitor-view.js index 40887523f1b2..ef9c63a20944 100644 --- a/browser/devtools/netmonitor/netmonitor-view.js +++ b/browser/devtools/netmonitor/netmonitor-view.js @@ -1539,6 +1539,7 @@ NetworkDetailsView.prototype = { Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, { searchPlaceholder: L10N.getStr("jsonFilterText") })); + VariablesViewController.attach(this._json); this._paramsQueryString = L10N.getStr("paramsQueryString"); this._paramsFormData = L10N.getStr("paramsFormData"); @@ -1889,9 +1890,10 @@ NetworkDetailsView.prototype = { ? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1)) : L10N.getStr("jsonScopeName"); - let jsonScope = this._json.addScope(jsonScopeName); - jsonScope.addItem().populate(jsonObject, { expanded: true }); - jsonScope.expanded = true; + this._json.controller.setSingleVariable({ + label: jsonScopeName, + rawObject: jsonObject, + }); } // Malformed JSON. else { diff --git a/browser/devtools/scratchpad/scratchpad.js b/browser/devtools/scratchpad/scratchpad.js index ab835ec699c7..fc9fbec839d4 100644 --- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -1816,15 +1816,8 @@ ScratchpadSidebar.prototype = { */ _update: function SS__update(aObject) { - let view = this.variablesView; - view.empty(); - - let scope = view.addScope(); - scope.expanded = true; - scope.locked = true; - - let container = scope.addItem(); - return view.controller.expand(container, aObject); + let options = { objectActor: aObject }; + return this.variablesView.controller.setSingleVariable(options).expanded; } }; diff --git a/browser/devtools/shared/widgets/VariablesViewController.jsm b/browser/devtools/shared/widgets/VariablesViewController.jsm index 97c1a5b5c918..0f42bfcb45d0 100644 --- a/browser/devtools/shared/widgets/VariablesViewController.jsm +++ b/browser/devtools/shared/widgets/VariablesViewController.jsm @@ -40,7 +40,7 @@ this.EXPORTED_SYMBOLS = ["VariablesViewController"]; * * @param VariablesView aView * The view to attach to. - * @param object aOptions + * @param object aOptions [optional] * Options for configuring the controller. Supported options: * - getObjectClient: callback for creating an object grip client * - getLongStringClient: callback for creating a long string grip client @@ -49,7 +49,7 @@ this.EXPORTED_SYMBOLS = ["VariablesViewController"]; * - getterOrSetterEvalMacro: callback for creating a getter/setter eval macro * - simpleValueEvalMacro: callback for creating a simple value eval macro */ -function VariablesViewController(aView, aOptions) { +function VariablesViewController(aView, aOptions = {}) { this.addExpander = this.addExpander.bind(this); this._getObjectClient = aOptions.getObjectClient; @@ -341,6 +341,38 @@ VariablesViewController.prototype = { } } }, + + /** + * Helper function for setting up a single Scope with a single Variable + * contained within it. + * + * @param object aOptions + * Options for the contents of the view: + * - objectActor: the grip of the new ObjectActor to show. + * - rawObject: the new raw object to show. + * - label: the new label for the inspected object. + * @return Object + * - variable: the created Variable. + * - expanded: the Promise that resolves when the variable expands. + */ + setSingleVariable: function(aOptions) { + this.view.empty(); + let scope = this.view.addScope(aOptions.label); + scope.expanded = true; + scope.locked = true; + + let variable = scope.addItem(); + let expanded; + + if (aOptions.objectActor) { + expanded = this.expand(variable, aOptions.objectActor); + } else if (aOptions.rawObject) { + variable.populate(aOptions.rawObject, { expanded: true }); + expanded = promise.resolve(); + } + + return { variable: variable, expanded: expanded }; + }, }; diff --git a/browser/devtools/webconsole/test/Makefile.in b/browser/devtools/webconsole/test/Makefile.in index 2fee168b4ea3..658e83ccd5b5 100644 --- a/browser/devtools/webconsole/test/Makefile.in +++ b/browser/devtools/webconsole/test/Makefile.in @@ -92,6 +92,7 @@ MOCHITEST_BROWSER_FILES = \ browser_webconsole_bug_770099_violation.js \ browser_webconsole_bug_766001_JS_Console_in_Debugger.js \ browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js \ + browser_webconsole_bug_843019_variables_view_filter.js \ browser_cached_messages.js \ browser_bug664688_sandbox_update_after_navigation.js \ browser_result_format_as_string.js \ diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js b/browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js new file mode 100644 index 000000000000..cbc449ce249e --- /dev/null +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js @@ -0,0 +1,79 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Test for bug 843019. +// Check that variables view filter works as expected in the web console. + +const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html"; + +let gVariablesView; + +function test() +{ + addTab(TEST_URI); + browser.addEventListener("load", function onLoad() { + browser.removeEventListener("load", onLoad, true); + openConsole(null, consoleOpened); + }, true); +} + +function consoleOpened(hud) +{ + hud.jsterm.execute("fooObj", (msg) => { + ok(msg, "output message found"); + isnot(msg.textContent.indexOf("[object Object]"), -1, "message text check"); + + hud.jsterm.once("variablesview-fetched", (aEvent, aVar) => { + gVariablesView = aVar._variablesView; + ok(gVariablesView, "variables view object"); + + findVariableViewProperties(aVar, [ + { name: "testProp", value: "testValue" }, + ], { webconsole: hud }).then(onTestPropFound); + }); + + let anchor = msg.querySelector("a"); + executeSoon(() => + EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow) + ); + }); +} + +let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console; + +function onTestPropFound([result]) +{ + let target = result.matchedProp.target; + let searchbox = gVariablesView._searchboxContainer.firstChild; + gVariablesView.lazySearch = false; + + searchbox.addEventListener("focus", function onFocus() { + searchbox.removeEventListener("focus", onFocus); + + // Test initial state. + ok(!target.hasAttribute("non-match"), + "Property starts visible"); + + // Test a non-matching search. + EventUtils.sendChar("x"); + ok(target.hasAttribute("non-match"), + "Property is hidden on non-matching search"); + + // Test clearing the search. + EventUtils.sendKey("ESCAPE"); + ok(!target.hasAttribute("non-match"), + "Pressing ESC makes the property visible again"); + + // Test a matching search. + EventUtils.sendChar("t"); + ok(!target.hasAttribute("non-match"), + "Property still visible when search matches"); + + gVariablesView = null; + finishTest(); + }); + + searchbox.focus(); +} diff --git a/browser/devtools/webconsole/webconsole.js b/browser/devtools/webconsole/webconsole.js index f330dcce38b9..f4a38567bc7f 100644 --- a/browser/devtools/webconsole/webconsole.js +++ b/browser/devtools/webconsole/webconsole.js @@ -3481,20 +3481,13 @@ JSTerm.prototype = { view.delete = null; } - let scope = view.addScope(aOptions.label); - scope.expanded = true; - scope.locked = true; - - let container = scope.addItem(); - container.evaluationMacro = simpleValueEvalMacro; + let { variable, expanded } = view.controller.setSingleVariable(aOptions); + variable.evaluationMacro = simpleValueEvalMacro; if (aOptions.objectActor) { - view.controller.expand(container, aOptions.objectActor); view._consoleLastObjectActor = aOptions.objectActor.actor; } else if (aOptions.rawObject) { - container.populate(aOptions.rawObject); - view.commitHierarchy(); view._consoleLastObjectActor = null; } else { @@ -3502,7 +3495,9 @@ JSTerm.prototype = { "display."); } - this.emit("variablesview-updated", view, aOptions); + expanded.then(() => { + this.emit("variablesview-updated", view, aOptions); + }); }, /** From 4168ecf66b2801a6585dd591b0cefc3c748e5f53 Mon Sep 17 00:00:00 2001 From: Brandon Benvie Date: Mon, 23 Sep 2013 13:36:44 -0700 Subject: [PATCH 37/62] Bug 915875 - Clean up devtools/framework/toolbox.js. --- browser/devtools/framework/gDevTools.jsm | 59 +++-- browser/devtools/framework/toolbox.js | 303 ++++++++++------------- 2 files changed, 163 insertions(+), 199 deletions(-) diff --git a/browser/devtools/framework/gDevTools.jsm b/browser/devtools/framework/gDevTools.jsm index 4fad0295362b..3db3f78391e8 100644 --- a/browser/devtools/framework/gDevTools.jsm +++ b/browser/devtools/framework/gDevTools.jsm @@ -126,6 +126,33 @@ DevTools.prototype = { return tools.sort(this.ordinalSort); }, + /** + * Get a tool definition if it exists and is enabled. + * + * @param {string} toolId + * The id of the tool to show + * + * @return {ToolDefinition|null} tool + * The ToolDefinition for the id or null. + */ + getToolDefinition: function DT_getToolDefinition(toolId) { + let tool = this._tools.get(toolId); + if (!tool) { + return null; + } else if (tool.id == "options") { + return tool; + } + + let enabled; + try { + enabled = Services.prefs.getBoolPref(tool.visibilityswitch); + } catch (e) { + enabled = true; + } + + return enabled ? tool : null; + }, + /** * Allow ToolBoxes to get at the list of tools that they should populate * themselves with. @@ -136,19 +163,12 @@ DevTools.prototype = { getToolDefinitionMap: function DT_getToolDefinitionMap() { let tools = new Map(); - for (let [key, value] of this._tools) { - let enabled; - - try { - enabled = Services.prefs.getBoolPref(value.visibilityswitch); - } catch(e) { - enabled = true; - } - - if (enabled || value.id == "options") { - tools.set(key, value); + for (let [id, definition] of this._tools) { + if (this.getToolDefinition(id)) { + tools.set(id, definition); } } + return tools; }, @@ -162,8 +182,11 @@ DevTools.prototype = { */ getToolDefinitionArray: function DT_getToolDefinitionArray() { let definitions = []; - for (let [id, definition] of this.getToolDefinitionMap()) { - definitions.push(definition); + + for (let [id, definition] of this._tools) { + if (this.getToolDefinition(id)) { + definitions.push(definition); + } } return definitions.sort(this.ordinalSort); @@ -415,8 +438,7 @@ let gDevToolsBrowser = { selectToolCommand: function(gBrowser, toolId) { let target = devtools.TargetFactory.forTab(gBrowser.selectedTab); let toolbox = gDevTools.getToolbox(target); - let tools = gDevTools.getToolDefinitionMap(); - let toolDefinition = tools.get(toolId); + let toolDefinition = gDevTools.getToolDefinition(toolId); if (toolbox && toolbox.currentToolId == toolId) { toolbox.fireCustomKey(toolId); @@ -603,13 +625,6 @@ let gDevToolsBrowser = { continue; } - // Skip if the tool is disabled. - try { - if (!Services.prefs.getBoolPref(toolDefinition.visibilityswitch)) { - continue; - } - } catch(e) {} - let elements = gDevToolsBrowser._createToolMenuElements(toolDefinition, doc); if (!elements) { diff --git a/browser/devtools/framework/toolbox.js b/browser/devtools/framework/toolbox.js index 4eee0e9aa684..8ec4d9579082 100644 --- a/browser/devtools/framework/toolbox.js +++ b/browser/devtools/framework/toolbox.js @@ -4,50 +4,44 @@ "use strict"; -const {Cc, Ci, Cu} = require("chrome"); const MAX_ORDINAL = 99; const ZOOM_PREF = "devtools.toolbox.zoomValue"; const MIN_ZOOM = 0.5; const MAX_ZOOM = 2; +let {Cc, Ci, Cu} = require("chrome"); let promise = require("sdk/core/promise"); let EventEmitter = require("devtools/shared/event-emitter"); let Telemetry = require("devtools/shared/telemetry"); let HUDService = require("devtools/webconsole/hudservice"); -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/devtools/gDevTools.jsm"); Cu.import("resource:///modules/devtools/scratchpad-manager.jsm"); loader.lazyGetter(this, "Hosts", () => require("devtools/framework/toolbox-hosts").Hosts); -XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils", - "resource:///modules/devtools/DeveloperToolbar.jsm"); +loader.lazyImporter(this, "CommandUtils", "resource:///modules/devtools/DeveloperToolbar.jsm"); -XPCOMUtils.defineLazyGetter(this, "toolboxStrings", function() { +loader.lazyGetter(this, "toolboxStrings", () => { let bundle = Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties"); - let l10n = function(aName, ...aArgs) { + return (name, ...args) => { try { - if (aArgs.length == 0) { - return bundle.GetStringFromName(aName); - } else { - return bundle.formatStringFromName(aName, aArgs, aArgs.length); + if (!args.length) { + return bundle.GetStringFromName(name); } + return bundle.formatStringFromName(name, args, args.length); } catch (ex) { - Services.console.logStringMessage("Error reading '" + aName + "'"); + Services.console.logStringMessage("Error reading '" + name + "'"); } }; - return l10n; }); -XPCOMUtils.defineLazyGetter(this, "Requisition", function() { - let scope = {}; - Cu.import("resource://gre/modules/devtools/Require.jsm", scope); +loader.lazyGetter(this, "Requisition", () => { + let {require} = Cu.import("resource://gre/modules/devtools/Require.jsm", {}); Cu.import("resource://gre/modules/devtools/gcli.jsm", {}); - - let req = scope.require; - return req('gcli/cli').Requisition; + return require("gcli/cli").Requisition; }); /** @@ -69,6 +63,7 @@ function Toolbox(target, selectedTool, hostType) { this._toolRegistered = this._toolRegistered.bind(this); this._toolUnregistered = this._toolUnregistered.bind(this); + this._refreshHostTitle = this._refreshHostTitle.bind(this); this.destroy = this.destroy.bind(this); this._target.on("close", this.destroy); @@ -79,8 +74,7 @@ function Toolbox(target, selectedTool, hostType) { if (!selectedTool) { selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL); } - let definitions = gDevTools.getToolDefinitionMap(); - if (!definitions.get(selectedTool) && selectedTool != "options") { + if (!gDevTools.getToolDefinition(selectedTool)) { selectedTool = "webconsole"; } this._defaultToolId = selectedTool; @@ -89,7 +83,6 @@ function Toolbox(target, selectedTool, hostType) { EventEmitter.decorate(this); - this._refreshHostTitle = this._refreshHostTitle.bind(this); this._target.on("navigate", this._refreshHostTitle); this.on("host-changed", this._refreshHostTitle); this.on("select", this._refreshHostTitle); @@ -107,7 +100,7 @@ Toolbox.HostType = { BOTTOM: "bottom", SIDE: "side", WINDOW: "window" -} +}; Toolbox.prototype = { _URL: "chrome://browser/content/devtools/framework/toolbox.xul", @@ -118,7 +111,7 @@ Toolbox.prototype = { SIDE_ENABLED: "devtools.toolbox.sideEnabled" }, - HostType: Toolbox.HostType, + currentToolId: null, /** * Returns a *copy* of the _toolPanels collection. @@ -126,20 +119,15 @@ Toolbox.prototype = { * @return {Map} panels * All the running panels in the toolbox */ - getToolPanels: function TB_getToolPanels() { - let panels = new Map(); - - for (let [key, value] of this._toolPanels) { - panels.set(key, value); - } - return panels; + getToolPanels: function() { + return new Map(this._toolPanels); }, /** * Access the panel for a given tool */ - getPanel: function TBOX_getPanel(id) { - return this.getToolPanels().get(id); + getPanel: function(id) { + return this._toolPanels.get(id); }, /** @@ -147,8 +135,8 @@ Toolbox.prototype = { * likely that we're going to want to get the panel that we've just made * visible */ - getCurrentPanel: function TBOX_getCurrentPanel() { - return this.getToolPanels().get(this.currentToolId); + getCurrentPanel: function() { + return this._toolPanels.get(this.currentToolId); }, /** @@ -168,17 +156,6 @@ Toolbox.prototype = { return this._host.type; }, - /** - * Get/alter the currently displayed tool. - */ - get currentToolId() { - return this._currentToolId; - }, - - set currentToolId(value) { - this._currentToolId = value; - }, - /** * Get the iframe containing the toolbox UI. */ @@ -203,10 +180,12 @@ Toolbox.prototype = { /** * Open the toolbox */ - open: function TBOX_open() { + open: function() { let deferred = promise.defer(); - this._host.create().then(iframe => { + return this._host.create().then(iframe => { + let deferred = promise.defer(); + let domReady = () => { iframe.removeEventListener("DOMContentLoaded", domReady, true); @@ -226,27 +205,27 @@ Toolbox.prototype = { this._telemetry.toolOpened("toolbox"); - this.selectTool(this._defaultToolId).then(function(panel) { + this.selectTool(this._defaultToolId).then(panel => { this.emit("ready"); deferred.resolve(); - }.bind(this)); + }); }; iframe.addEventListener("DOMContentLoaded", domReady, true); iframe.setAttribute("src", this._URL); + + return deferred.promise; }); - - return deferred.promise; }, - _buildOptions: function TBOX__buildOptions() { + _buildOptions: function() { let key = this.doc.getElementById("toolbox-options-key"); - key.addEventListener("command", function(toolId) { - this.selectTool(toolId); - }.bind(this, "options"), true); + key.addEventListener("command", () => { + this.selectTool("options"); + }, true); }, - _addToolSwitchingKeys: function TBOX__addToolSwitchingKeys() { + _addToolSwitchingKeys: function() { let nextKey = this.doc.getElementById("toolbox-next-tool-key"); nextKey.addEventListener("command", this.selectNextTool.bind(this), true); let prevKey = this.doc.getElementById("toolbox-previous-tool-key"); @@ -256,7 +235,7 @@ Toolbox.prototype = { /** * Wire up the listeners for the zoom keys. */ - _addZoomKeys: function TBOX__addZoomKeys() { + _addZoomKeys: function() { let inKey = this.doc.getElementById("toolbox-zoom-in-key"); inKey.addEventListener("command", this.zoomIn.bind(this), true); @@ -273,28 +252,28 @@ Toolbox.prototype = { /** * Set zoom on toolbox to whatever the last setting was. */ - _loadInitialZoom: function TBOX__loadInitialZoom() { + _loadInitialZoom: function() { this.setZoom(this.zoomValue); }, /** * Increase zoom level of toolbox window - make things bigger. */ - zoomIn: function TBOX__zoomIn() { + zoomIn: function() { this.setZoom(this.zoomValue + 0.1); }, /** * Decrease zoom level of toolbox window - make things smaller. */ - zoomOut: function TBOX__zoomOut() { + zoomOut: function() { this.setZoom(this.zoomValue - 0.1); }, /** * Reset zoom level of the toolbox window. */ - zoomReset: function TBOX__zoomReset() { + zoomReset: function() { this.setZoom(1); }, @@ -304,7 +283,7 @@ Toolbox.prototype = { * @param {number} zoomValue * Zoom level e.g. 1.2 */ - setZoom: function TBOX__setZoom(zoomValue) { + setZoom: function(zoomValue) { // cap zoom value zoomValue = Math.max(zoomValue, MIN_ZOOM); zoomValue = Math.min(zoomValue, MAX_ZOOM); @@ -320,60 +299,47 @@ Toolbox.prototype = { /** * Adds the keys and commands to the Toolbox Window in window mode. */ - _addKeysToWindow: function TBOX__addKeysToWindow() { + _addKeysToWindow: function() { if (this.hostType != Toolbox.HostType.WINDOW) { return; } + let doc = this.doc.defaultView.parent.document; + for (let [id, toolDefinition] of gDevTools.getToolDefinitionMap()) { - if (toolDefinition.key) { - // Prevent multiple entries for the same tool. - if (doc.getElementById("key_" + id)) { - continue; - } - let key = doc.createElement("key"); - key.id = "key_" + id; - - if (toolDefinition.key.startsWith("VK_")) { - key.setAttribute("keycode", toolDefinition.key); - } else { - key.setAttribute("key", toolDefinition.key); - } - - key.setAttribute("modifiers", toolDefinition.modifiers); - key.setAttribute("oncommand", "void(0);"); // needed. See bug 371900 - key.addEventListener("command", function(toolId) { - this.selectTool(toolId).then(() => { - this.fireCustomKey(toolId); - }); - }.bind(this, id), true); - doc.getElementById("toolbox-keyset").appendChild(key); + // Prevent multiple entries for the same tool. + if (!toolDefinition.key || doc.getElementById("key_" + id)) { + continue; } - } - // Add key for opening Scratchpad from the detached window - if(doc.getElementById("key_scratchpad") == null) { + let toolId = id; let key = doc.createElement("key"); - key.id = "key_scratchpad"; - key.setAttribute("keycode", toolboxStrings("scratchpad.keycode")); - key.setAttribute("modifiers", "shift"); - key.setAttribute("oncommand", "void(0)"); // needed. See bug 371900 - key.addEventListener("command", function() { - ScratchpadManager.openScratchpad(); + key.id = "key_" + toolId; + + if (toolDefinition.key.startsWith("VK_")) { + key.setAttribute("keycode", toolDefinition.key); + } else { + key.setAttribute("key", toolDefinition.key); + } + + key.setAttribute("modifiers", toolDefinition.modifiers); + key.setAttribute("oncommand", "void(0);"); // needed. See bug 371900 + key.addEventListener("command", () => { + this.selectTool(toolId).then(() => this.fireCustomKey(toolId)); }, true); doc.getElementById("toolbox-keyset").appendChild(key); } // Add key for toggling the browser console from the detached window - if(doc.getElementById("key_browserconsole") == null) { + if (!doc.getElementById("key_browserconsole")) { let key = doc.createElement("key"); key.id = "key_browserconsole"; key.setAttribute("key", toolboxStrings("browserConsoleCmd.commandkey")); key.setAttribute("modifiers", "accel,shift"); key.setAttribute("oncommand", "void(0)"); // needed. See bug 371900 - key.addEventListener("command", function() { + key.addEventListener("command", () => { HUDService.toggleBrowserConsole(); }, true); doc.getElementById("toolbox-keyset").appendChild(key); @@ -386,12 +352,11 @@ Toolbox.prototype = { * @param {string} toolId * Which tool to run the command on (skip if not current) */ - fireCustomKey: function TBOX_fireCustomKey(toolId) { - let tools = gDevTools.getToolDefinitionMap(); - let activeToolDefinition = tools.get(toolId); + fireCustomKey: function(toolId) { + let toolDefinition = gDevTools.getToolDefinition(toolId); - if (activeToolDefinition.onkey && this.currentToolId === toolId) { - activeToolDefinition.onkey(this.getCurrentPanel()); + if (toolDefinition.onkey && this.currentToolId === toolId) { + toolDefinition.onkey(this.getCurrentPanel()); } }, @@ -399,7 +364,7 @@ Toolbox.prototype = { * Build the buttons for changing hosts. Called every time * the host changes. */ - _buildDockButtons: function TBOX_createDockButtons() { + _buildDockButtons: function() { let dockBox = this.doc.getElementById("toolbox-dock-buttons"); while (dockBox.firstChild) { @@ -411,7 +376,7 @@ Toolbox.prototype = { } let closeButton = this.doc.getElementById("toolbox-close"); - if (this.hostType === this.HostType.WINDOW) { + if (this.hostType == Toolbox.HostType.WINDOW) { closeButton.setAttribute("hidden", "true"); } else { closeButton.removeAttribute("hidden"); @@ -419,9 +384,10 @@ Toolbox.prototype = { let sideEnabled = Services.prefs.getBoolPref(this._prefs.SIDE_ENABLED); - for each (let position in this.HostType) { + for (let type in Toolbox.HostType) { + let position = Toolbox.HostType[type]; if (position == this.hostType || - (!sideEnabled && position == this.HostType.SIDE)) { + (!sideEnabled && position == Toolbox.HostType.SIDE)) { continue; } @@ -430,9 +396,9 @@ Toolbox.prototype = { button.className = "toolbox-dock-button"; button.setAttribute("tooltiptext", toolboxStrings("toolboxDockButtons." + position + ".tooltip")); - button.addEventListener("command", function(position) { + button.addEventListener("command", () => { this.switchHost(position); - }.bind(this, position)); + }); dockBox.appendChild(button); } @@ -441,7 +407,7 @@ Toolbox.prototype = { /** * Add tabs to the toolbox UI for registered tools */ - _buildTabs: function TBOX_buildTabs() { + _buildTabs: function() { for (let definition of gDevTools.getToolDefinitionArray()) { this._buildTabForTool(definition); } @@ -450,18 +416,16 @@ Toolbox.prototype = { /** * Add buttons to the UI as specified in the devtools.window.toolbarSpec pref */ - _buildButtons: function TBOX_buildButtons() { + _buildButtons: function() { if (!this.target.isLocalTab) { return; } - let toolbarSpec = CommandUtils.getCommandbarSpec("devtools.toolbox.toolbarSpec"); + let spec = CommandUtils.getCommandbarSpec("devtools.toolbox.toolbarSpec"); let env = CommandUtils.createEnvironment(this.target.tab.ownerDocument, this.target.window.document); - let requisition = new Requisition(env); - - let buttons = CommandUtils.createButtons(toolbarSpec, this._target, this.doc, requisition); - + let req = new Requisition(env); + let buttons = CommandUtils.createButtons(spec, this._target, this.doc, req); let container = this.doc.getElementById("toolbox-buttons"); buttons.forEach(container.appendChild.bind(container)); }, @@ -472,7 +436,7 @@ Toolbox.prototype = { * @param {string} toolDefinition * Tool definition of the tool to build a tab for. */ - _buildTabForTool: function TBOX_buildTabForTool(toolDefinition) { + _buildTabForTool: function(toolDefinition) { if (!toolDefinition.isTargetSupported(this._target)) { return; } @@ -482,6 +446,10 @@ Toolbox.prototype = { let id = toolDefinition.id; + if (toolDefinition.ordinal == undefined || toolDefinition.ordinal < 0) { + toolDefinition.ordinal = MAX_ORDINAL; + } + let radio = this.doc.createElement("radio"); // The radio element is not being used in the conventional way, thus // the devtools-tab class replaces the radio XBL binding with its base @@ -489,15 +457,12 @@ Toolbox.prototype = { radio.className = "toolbox-tab devtools-tab"; radio.id = "toolbox-tab-" + id; radio.setAttribute("toolid", id); - if (toolDefinition.ordinal == undefined || toolDefinition.ordinal < 0) { - toolDefinition.ordinal = MAX_ORDINAL; - } radio.setAttribute("ordinal", toolDefinition.ordinal); radio.setAttribute("tooltiptext", toolDefinition.tooltip); - radio.addEventListener("command", function(id) { + radio.addEventListener("command", () => { this.selectTool(id); - }.bind(this, id)); + }); // spacer lets us center the image and label, while allowing cropping let spacer = this.doc.createElement("spacer"); @@ -537,9 +502,8 @@ Toolbox.prototype = { +tabs.lastChild.getAttribute("ordinal") <= toolDefinition.ordinal) { tabs.appendChild(radio); deck.appendChild(vbox); - } - // else, iterate over all the tabs to get the correct location. - else { + } else { + // else, iterate over all the tabs to get the correct location. Array.some(tabs.childNodes, (node, i) => { if (+node.getAttribute("ordinal") > toolDefinition.ordinal) { tabs.insertBefore(radio, node); @@ -558,7 +522,7 @@ Toolbox.prototype = { * @param {string} id * The id of the tool to load. */ - loadTool: function TBOX_loadTool(id) { + loadTool: function(id) { let deferred = promise.defer(); let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id); @@ -567,18 +531,19 @@ Toolbox.prototype = { if (panel) { deferred.resolve(panel); } else { - this.once(id + "-ready", (panel) => { + this.once(id + "-ready", panel => { deferred.resolve(panel); }); } return deferred.promise; } - let definition = gDevTools.getToolDefinitionMap().get(id); + let definition = gDevTools.getToolDefinition(id); if (!definition) { deferred.reject(new Error("no such tool id "+id)); return deferred.promise; } + iframe = this.doc.createElement("iframe"); iframe.className = "toolbox-panel-iframe"; iframe.id = "toolbox-panel-iframe-" + id; @@ -612,17 +577,17 @@ Toolbox.prototype = { * @param {string} id * The id of the tool to switch to */ - selectTool: function TBOX_selectTool(id) { + selectTool: function(id) { let selected = this.doc.querySelector(".devtools-tab[selected]"); if (selected) { selected.removeAttribute("selected"); } + let tab = this.doc.getElementById("toolbox-tab-" + id); tab.setAttribute("selected", "true"); - let prevToolId = this._currentToolId; - if (this._currentToolId == id) { + if (this.currentToolId == id) { // re-focus tool to get key events again this.focusTool(id); @@ -633,11 +598,12 @@ Toolbox.prototype = { if (!this.isReady) { throw new Error("Can't select tool, wait for toolbox 'ready' event"); } - let tab = this.doc.getElementById("toolbox-tab-" + id); + + tab = this.doc.getElementById("toolbox-tab-" + id); if (tab) { - if (prevToolId) { - this._telemetry.toolClosed(prevToolId); + if (this.currentToolId) { + this._telemetry.toolClosed(this.currentToolId); } this._telemetry.toolOpened(id); } else { @@ -662,12 +628,12 @@ Toolbox.prototype = { let deck = this.doc.getElementById("toolbox-deck"); deck.selectedIndex = index; - this._currentToolId = id; + this.currentToolId = id; if (id != "options") { Services.prefs.setCharPref(this._prefs.LAST_TOOL, id); } - return this.loadTool(id).then((panel) => { + return this.loadTool(id).then(panel => { // focus the tool's frame to start receiving key events this.focusTool(id); @@ -690,7 +656,7 @@ Toolbox.prototype = { /** * Loads the tool next to the currently selected tool. */ - selectNextTool: function TBOX_selectNextTool() { + selectNextTool: function() { let selected = this.doc.querySelector(".devtools-tab[selected]"); let next = selected.nextSibling || selected.parentNode.firstChild; let tool = next.getAttribute("toolid"); @@ -700,7 +666,7 @@ Toolbox.prototype = { /** * Loads the tool just left to the currently selected tool. */ - selectPreviousTool: function TBOX_selectPreviousTool() { + selectPreviousTool: function() { let selected = this.doc.querySelector(".devtools-tab[selected]"); let previous = selected.previousSibling || selected.parentNode.lastChild; let tool = previous.getAttribute("toolid"); @@ -713,7 +679,7 @@ Toolbox.prototype = { * @param {string} id * The id of the tool to highlight */ - highlightTool: function TBOX_highlightTool(id) { + highlightTool: function(id) { let tab = this.doc.getElementById("toolbox-tab-" + id); tab && tab.classList.add("highlighted"); }, @@ -724,7 +690,7 @@ Toolbox.prototype = { * @param {string} id * The id of the tool to unhighlight */ - unhighlightTool: function TBOX_unhighlightTool(id) { + unhighlightTool: function(id) { let tab = this.doc.getElementById("toolbox-tab-" + id); tab && tab.classList.remove("highlighted"); }, @@ -732,17 +698,16 @@ Toolbox.prototype = { /** * Raise the toolbox host. */ - raise: function TBOX_raise() { + raise: function() { this._host.raise(); }, /** * Refresh the host's title. */ - _refreshHostTitle: function TBOX_refreshHostTitle() { + _refreshHostTitle: function() { let toolName; - let toolId = this.currentToolId; - let toolDef = gDevTools.getToolDefinitionMap().get(toolId); + let toolDef = gDevTools.getToolDefinition(this.currentToolId); if (toolDef) { toolName = toolDef.label; } else { @@ -767,15 +732,14 @@ Toolbox.prototype = { * @return {Host} host * The created host object */ - _createHost: function TBOX_createHost(hostType) { + _createHost: function(hostType) { if (!Hosts[hostType]) { - throw new Error('Unknown hostType: '+ hostType); + throw new Error("Unknown hostType: " + hostType); } - let newHost = new Hosts[hostType](this.target.tab); // clean up the toolbox if its window is closed + let newHost = new Hosts[hostType](this.target.tab); newHost.on("window-closed", this.destroy); - return newHost; }, @@ -786,17 +750,13 @@ Toolbox.prototype = { * @param {string} hostType * The host type of the new host object */ - switchHost: function TBOX_switchHost(hostType) { - if (hostType == this._host.type) { - return; - } - - if (!this._target.isLocalTab) { + switchHost: function(hostType) { + if (hostType == this._host.type || !this._target.isLocalTab) { return; } let newHost = this._createHost(hostType); - return newHost.create().then(function(iframe) { + return newHost.create().then(iframe => { // change toolbox document's parent to the new host iframe.QueryInterface(Ci.nsIFrameLoaderOwner); iframe.swapFrameLoaders(this.frame); @@ -812,7 +772,7 @@ Toolbox.prototype = { this._addKeysToWindow(); this.emit("host-changed"); - }.bind(this)); + }); }, /** @@ -822,10 +782,8 @@ Toolbox.prototype = { * @param {string} toolId * Id of the tool that was registered */ - _toolRegistered: function TBOX_toolRegistered(event, toolId) { - let defs = gDevTools.getToolDefinitionMap(); - let tool = defs.get(toolId); - + _toolRegistered: function(event, toolId) { + let tool = gDevTools.getToolDefinition(toolId); this._buildTabForTool(tool); }, @@ -837,7 +795,7 @@ Toolbox.prototype = { * Definition or id of the tool that was unregistered. Passing the * tool id should be avoided as it is a temporary measure. */ - _toolUnregistered: function TBOX_toolUnregistered(event, toolId) { + _toolUnregistered: function(event, toolId) { if (typeof toolId != "string") { toolId = toolId.id; } @@ -852,7 +810,7 @@ Toolbox.prototype = { let panel = this.doc.getElementById("toolbox-panel-" + toolId); if (radio) { - if (this._currentToolId == toolId) { + if (this.currentToolId == toolId) { let nextToolName = null; if (radio.nextSibling) { nextToolName = radio.nextSibling.getAttribute("toolid"); @@ -880,30 +838,24 @@ Toolbox.prototype = { } }, - /** * Get the toolbox's notification box * * @return The notification box element. */ - getNotificationBox: function TBOX_getNotificationBox() { + getNotificationBox: function() { return this.doc.getElementById("toolbox-notificationbox"); }, /** * Remove all UI elements, detach from target and clear up */ - destroy: function TBOX_destroy() { + destroy: function() { // If several things call destroy then we give them all the same // destruction promise so we're sure to destroy only once if (this._destroyer) { return this._destroyer; } - // Assign the "_destroyer" property before calling the other - // destroyer methods to guarantee that the Toolbox's destroy - // method is only executed once. - let deferred = promise.defer(); - this._destroyer = deferred.promise; this._target.off("navigate", this._refreshHostTitle); this.off("select", this._refreshHostTitle); @@ -917,7 +869,7 @@ Toolbox.prototype = { if (typeof this._origAllowJavascript != "undefined") { let docShell = this._host.hostTab.linkedBrowser.docShell; docShell.allowJavascript = this._origAllowJavascript; - delete this._origAllowJavascript; + this._origAllowJavascript = undefined; } let outstanding = []; @@ -925,14 +877,14 @@ Toolbox.prototype = { for (let [id, panel] of this._toolPanels) { try { outstanding.push(panel.destroy()); - } catch(e) { + } catch (e) { // We don't want to stop here if any panel fail to close. console.error(e); } } let container = this.doc.getElementById("toolbox-buttons"); - while(container.firstChild) { + while (container.firstChild) { container.removeChild(container.firstChild); } @@ -940,7 +892,7 @@ Toolbox.prototype = { this._telemetry.destroy(); - promise.all(outstanding).then(() => { + return this._destroyer = promise.all(outstanding).then(() => { // Targets need to be notified that the toolbox is being torn down. // This is done after other destruction tasks since it may tear down // fronts and the debugger transport which earlier destroy methods may @@ -951,14 +903,11 @@ Toolbox.prototype = { target.off("close", this.destroy); return target.destroy(); } - }).then(function() { + }).then(() => { this.emit("destroyed"); // Free _host after the call to destroyed in order to let a chance // to destroyed listeners to still query toolbox attributes this._host = null; - deferred.resolve(); - }.bind(this)); - - return this._destroyer; + }); } }; From 64acb4c746f4386138394a6c207a2d234295134b Mon Sep 17 00:00:00 2001 From: Michael Comella Date: Wed, 25 Sep 2013 11:52:48 -0700 Subject: [PATCH 38/62] Bug 920642: Remove dead files from bug 870171. r=rnewman --- .../AnnouncementsStartReceiver.java | 30 ---- .../upload/HealthReportBroadcastReceiver.java | 47 ----- .../upload/HealthReportBroadcastService.java | 165 ------------------ .../HealthReportUploadStartReceiver.java | 34 ---- 4 files changed, 276 deletions(-) delete mode 100644 mobile/android/base/background/announcements/AnnouncementsStartReceiver.java delete mode 100644 mobile/android/base/background/healthreport/upload/HealthReportBroadcastReceiver.java delete mode 100644 mobile/android/base/background/healthreport/upload/HealthReportBroadcastService.java delete mode 100644 mobile/android/base/background/healthreport/upload/HealthReportUploadStartReceiver.java diff --git a/mobile/android/base/background/announcements/AnnouncementsStartReceiver.java b/mobile/android/base/background/announcements/AnnouncementsStartReceiver.java deleted file mode 100644 index 94301af2cf8b..000000000000 --- a/mobile/android/base/background/announcements/AnnouncementsStartReceiver.java +++ /dev/null @@ -1,30 +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/. */ - -package org.mozilla.gecko.background.announcements; - -import org.mozilla.gecko.background.BackgroundService; -import org.mozilla.gecko.background.common.log.Logger; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -/** - * Start the announcements service when instructed by the {@link android.app.AlarmManager}. - */ -public class AnnouncementsStartReceiver extends BroadcastReceiver { - - private static final String LOG_TAG = "AnnounceStartRec"; - - @Override - public void onReceive(Context context, Intent intent) { - if (AnnouncementsConstants.DISABLED) { - return; - } - - Logger.debug(LOG_TAG, "AnnouncementsStartReceiver.onReceive()."); - BackgroundService.runIntentInService(context, intent, AnnouncementsService.class); - } -} diff --git a/mobile/android/base/background/healthreport/upload/HealthReportBroadcastReceiver.java b/mobile/android/base/background/healthreport/upload/HealthReportBroadcastReceiver.java deleted file mode 100644 index 2555474d1704..000000000000 --- a/mobile/android/base/background/healthreport/upload/HealthReportBroadcastReceiver.java +++ /dev/null @@ -1,47 +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/. */ - -package org.mozilla.gecko.background.healthreport.upload; - -import org.mozilla.gecko.background.common.log.Logger; -import org.mozilla.gecko.background.healthreport.HealthReportConstants; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -/** - * Watch for notifications to start the Health Report background upload service. - * - * Some observations: - * - * From the Android documentation: "Also note that as of Android 3.0 the user - * needs to have started the application at least once before your application - * can receive android.intent.action.BOOT_COMPLETED events." - * - * We really do want to launch on BOOT_COMPLETED, since it's possible for a user - * to run Firefox, shut down the phone, then power it on again on the same day. - * We want to submit a health report in this case, even though they haven't - * launched Firefox since boot. - */ -public class HealthReportBroadcastReceiver extends BroadcastReceiver { - public static final String LOG_TAG = HealthReportBroadcastReceiver.class.getSimpleName(); - - /** - * Forward the intent to an IntentService to do background processing. - */ - @Override - public void onReceive(Context context, Intent intent) { - if (HealthReportConstants.UPLOAD_FEATURE_DISABLED) { - Logger.debug(LOG_TAG, "Health report upload feature is compile-time disabled; not forwarding intent."); - return; - } - - Logger.debug(LOG_TAG, "Health report upload feature is compile-time enabled; forwarding intent."); - Intent service = new Intent(context, HealthReportBroadcastService.class); - service.putExtras(intent); - service.setAction(intent.getAction()); - context.startService(service); - } -} diff --git a/mobile/android/base/background/healthreport/upload/HealthReportBroadcastService.java b/mobile/android/base/background/healthreport/upload/HealthReportBroadcastService.java deleted file mode 100644 index 2927e26bc7b1..000000000000 --- a/mobile/android/base/background/healthreport/upload/HealthReportBroadcastService.java +++ /dev/null @@ -1,165 +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/. */ - -package org.mozilla.gecko.background.healthreport.upload; - -import org.mozilla.gecko.background.BackgroundService; -import org.mozilla.gecko.background.common.GlobalConstants; -import org.mozilla.gecko.background.common.log.Logger; -import org.mozilla.gecko.background.healthreport.HealthReportConstants; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; - -/** - * A service which listens to broadcast intents from the system and from the - * browser, registering or unregistering the main - * {@link HealthReportUploadStartReceiver} with the {@link AlarmManager}. - */ -public class HealthReportBroadcastService extends BackgroundService { - public static final String LOG_TAG = HealthReportBroadcastService.class.getSimpleName(); - public static final String WORKER_THREAD_NAME = LOG_TAG + "Worker"; - - public HealthReportBroadcastService() { - super(WORKER_THREAD_NAME); - } - - protected SharedPreferences getSharedPreferences() { - return this.getSharedPreferences(HealthReportConstants.PREFS_BRANCH, GlobalConstants.SHARED_PREFERENCES_MODE); - } - - public long getPollInterval() { - return getSharedPreferences().getLong(HealthReportConstants.PREF_SUBMISSION_INTENT_INTERVAL_MSEC, HealthReportConstants.DEFAULT_SUBMISSION_INTENT_INTERVAL_MSEC); - } - - public void setPollInterval(long interval) { - getSharedPreferences().edit().putLong(HealthReportConstants.PREF_SUBMISSION_INTENT_INTERVAL_MSEC, interval).commit(); - } - - /** - * Set or cancel an alarm to submit data for a profile. - * - * @param context - * Android context. - * @param profileName - * to submit data for. - * @param profilePath - * to submit data for. - * @param enabled - * whether the user has enabled submitting health report data for - * this profile. - * @param serviceEnabled - * whether submitting should be scheduled. If the user turns off - * submitting, enabled could be false but we could need - * to delete so serviceEnabled could be true. - */ - protected void toggleAlarm(final Context context, String profileName, String profilePath, boolean enabled, boolean serviceEnabled) { - Logger.info(LOG_TAG, (serviceEnabled ? "R" : "Unr") + "egistering health report start broadcast receiver."); - - // PendingIntents are compared without reference to their extras. Therefore - // even though we pass the profile details to the action, different - // profiles will share the *same* pending intent. In a multi-profile future, - // this will need to be addressed. See Bug 882182. - final Intent service = new Intent(context, HealthReportUploadStartReceiver.class); - service.setAction("upload"); // PendingIntents "lose" their extras if no action is set. - service.putExtra("uploadEnabled", enabled); - service.putExtra("profileName", profileName); - service.putExtra("profilePath", profilePath); - final PendingIntent pending = PendingIntent.getBroadcast(context, 0, service, PendingIntent.FLAG_CANCEL_CURRENT); - - if (!serviceEnabled) { - cancelAlarm(pending); - return; - } - - final long pollInterval = getPollInterval(); - scheduleAlarm(pollInterval, pending); - } - - @Override - protected void onHandleIntent(Intent intent) { - Logger.setThreadLogTag(HealthReportConstants.GLOBAL_LOG_TAG); - - if (HealthReportConstants.UPLOAD_FEATURE_DISABLED) { - Logger.debug(LOG_TAG, "Health report upload feature is compile-time disabled; not handling intent."); - return; - } - - final String action = intent.getAction(); - Logger.debug(LOG_TAG, "Health report upload feature is compile-time enabled; handling intent with action " + action + "."); - - if (HealthReportConstants.ACTION_HEALTHREPORT_UPLOAD_PREF.equals(action)) { - handlePrefIntent(intent); - return; - } - - if (Intent.ACTION_BOOT_COMPLETED.equals(action) || - Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { - BackgroundService.reflectContextToFennec(this, - GlobalConstants.GECKO_PREFERENCES_CLASS, - GlobalConstants.GECKO_BROADCAST_HEALTHREPORT_UPLOAD_PREF_METHOD); - return; - } - - // Failure case. - Logger.warn(LOG_TAG, "Unknown intent " + action + "."); - } - - /** - * Handle the intent sent by the browser when it wishes to notify us - * of the value of the user preference. Look at the value and toggle the - * alarm service accordingly. - */ - protected void handlePrefIntent(Intent intent) { - if (!intent.hasExtra("enabled")) { - Logger.warn(LOG_TAG, "Got " + HealthReportConstants.ACTION_HEALTHREPORT_UPLOAD_PREF + " intent without enabled. Ignoring."); - return; - } - - final boolean enabled = intent.getBooleanExtra("enabled", true); - Logger.debug(LOG_TAG, intent.getStringExtra("branch") + "/" + - intent.getStringExtra("pref") + " = " + - (intent.hasExtra("enabled") ? enabled : "")); - - String profileName = intent.getStringExtra("profileName"); - String profilePath = intent.getStringExtra("profilePath"); - - if (profileName == null || profilePath == null) { - Logger.warn(LOG_TAG, "Got " + HealthReportConstants.ACTION_HEALTHREPORT_UPLOAD_PREF + " intent without profilePath or profileName. Ignoring."); - return; - } - - Logger.pii(LOG_TAG, "Updating health report alarm for profile " + profileName + " at " + profilePath + "."); - - final SharedPreferences sharedPrefs = getSharedPreferences(); - final ObsoleteDocumentTracker tracker = new ObsoleteDocumentTracker(sharedPrefs); - final boolean hasObsoleteIds = tracker.hasObsoleteIds(); - - if (!enabled) { - final Editor editor = sharedPrefs.edit(); - editor.remove(HealthReportConstants.PREF_LAST_UPLOAD_DOCUMENT_ID); - - if (hasObsoleteIds) { - Logger.debug(LOG_TAG, "Health report upload disabled; scheduling deletion of " + tracker.numberOfObsoleteIds() + " documents."); - tracker.limitObsoleteIds(); - } else { - // Primarily intended for debugging and testing. - Logger.debug(LOG_TAG, "Health report upload disabled and no deletes to schedule: clearing prefs."); - editor.remove(HealthReportConstants.PREF_FIRST_RUN); - editor.remove(HealthReportConstants.PREF_NEXT_SUBMISSION); - } - - editor.commit(); - } - - // The user can toggle us off or on, or we can have obsolete documents to - // remove. - final boolean serviceEnabled = hasObsoleteIds || enabled; - toggleAlarm(this, profileName, profilePath, enabled, serviceEnabled); - } -} diff --git a/mobile/android/base/background/healthreport/upload/HealthReportUploadStartReceiver.java b/mobile/android/base/background/healthreport/upload/HealthReportUploadStartReceiver.java deleted file mode 100644 index e4a9017f29e7..000000000000 --- a/mobile/android/base/background/healthreport/upload/HealthReportUploadStartReceiver.java +++ /dev/null @@ -1,34 +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/. */ - -package org.mozilla.gecko.background.healthreport.upload; - -import org.mozilla.gecko.background.common.log.Logger; -import org.mozilla.gecko.background.healthreport.HealthReportConstants; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -/** - * Start the Health Report background upload service when instructed by the - * {@link android.app.AlarmManager}. - */ -public class HealthReportUploadStartReceiver extends BroadcastReceiver { - public static final String LOG_TAG = HealthReportUploadStartReceiver.class.getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - if (HealthReportConstants.UPLOAD_FEATURE_DISABLED) { - Logger.debug(LOG_TAG, "Health report upload feature is compile-time disabled; not starting background upload service."); - return; - } - - Logger.debug(LOG_TAG, "Health report upload feature is compile-time enabled; starting background upload service."); - Intent service = new Intent(context, HealthReportUploadService.class); - service.setAction(intent.getAction()); - service.putExtras(intent); // profileName, profilePath, uploadEnabled are in the extras. - context.startService(service); - } -} From 38a76e02aebf90e57ae04f1dcb109d061e0aeb20 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:07 -0700 Subject: [PATCH 39/62] Bug 898333, patch 1: Restyle the :after pseudo-element after the content children. r=bzbarsky --- layout/base/RestyleManager.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index ef9daf9e2a8c..bbdd61e9d208 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -2374,13 +2374,6 @@ ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint) RestyleBeforePseudo(); } - // Check whether we might need to create a new ::after frame. - // See comments above regarding :before. - if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && - aChildRestyleHint) { - RestyleAfterPseudo(); - } - // There is no need to waste time crawling into a frame's children // on a frame change. The act of reconstructing frames will force // new style contexts to be resolved on all of this frame's @@ -2397,6 +2390,13 @@ ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint) SendAccessibilityNotifications(); } + + // Check whether we might need to create a new ::after frame. + // See comments above regarding :before. + if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && + aChildRestyleHint) { + RestyleAfterPseudo(); + } } void From c18e1d2515c5fb70543fba2b51ce61d434d9b48e Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:07 -0700 Subject: [PATCH 40/62] Bug 898333, patch 2: Change RestyleManager::Restyle's tree traversal to reach next-continuations (and same-display block-in-inline siblings) from their prev-continuation rather than from their parent. r=bzbarsky This patch fundamentally makes three changes: (1) Change the way RestyleSelf is used so that it is called in a loop, over all of the same-style continuations and block-in-inline siblings. (I had a note here reminding myself: TODO: Don't set hints for descendants! but I no longer remember what it meant.) (2) Change the traversal of children to traverse all of the children of the items traversed in (1). (3) When traversing children, skip children that are continuations, since we already reached them in (1) and (2). A later patch will change the RestyleSelf loop to copy for the later continuations rather than repeating the work. This will mean reverting many of the RestyleSelf changes contained here. Some of the pieces marked temporary will be removed in bug 828312 patch 11, and the rest should hopefully be removed in bug 918064. --- layout/base/RestyleManager.cpp | 310 ++++++++++++++++++++------------- layout/base/RestyleManager.h | 8 +- 2 files changed, 196 insertions(+), 122 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index bbdd61e9d208..0a3ac572378f 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -1703,6 +1703,9 @@ ElementForStyleContext(nsIContent* aParentContent, return content->AsElement(); } +/** + * FIXME: Temporary. Should merge with following function. + */ static nsIFrame* GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame) { @@ -1728,9 +1731,84 @@ GetPrevContinuationWithPossiblySameStyle(nsIFrame* aFrame) prevContinuation->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling())); } } + + NS_ASSERTION(!prevContinuation || + prevContinuation->GetContent() == aFrame->GetContent(), + "unexpected content mismatch"); + return prevContinuation; } +/** + * Get the previous continuation or similar special sibling (assuming + * block/inline alternation), conditionally on it having the same style. + * This assumes that we're not between resolving the two (i.e., that + * they're both already resolved. + */ +static nsIFrame* +GetPrevContinuationWithSameStyle(nsIFrame* aFrame) +{ + nsIFrame* prevContinuation = GetPrevContinuationWithPossiblySameStyle(aFrame); + if (!prevContinuation) { + return nullptr; + } + + nsStyleContext* prevStyle = prevContinuation->StyleContext(); + nsStyleContext* selfStyle = aFrame->StyleContext(); + if (prevStyle != selfStyle) { + NS_ASSERTION(prevStyle->GetPseudo() != selfStyle->GetPseudo() || + prevStyle->GetParent() != selfStyle->GetParent(), + "continuations should have the same style context"); + prevContinuation = nullptr; + } + return prevContinuation; +} + +/** + * Get the next continuation or similar special sibling (assuming + * block/inline alternation), conditionally on it having the same style. + * + * Since this is used when deciding to copy the new style context, it + * takes as an argument the old style context to check if the style is + * the same. When it is used in other contexts (i.e., where the next + * continuation would already have the new style context), the current + * style context should be passed. + */ +static nsIFrame* +GetNextContinuationWithSameStyle(nsIFrame* aFrame, + nsStyleContext* aOldStyleContext) +{ + // See GetPrevContinuationWithSameStyle about {ib} splits. + + nsIFrame *nextContinuation = aFrame->GetNextContinuation(); + if (!nextContinuation && (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) { + // We're the last continuation, so we have to hop back to the first + // before getting the frame property + nextContinuation = static_cast(aFrame->FirstContinuation()-> + Properties().Get(nsIFrame::IBSplitSpecialSibling())); + if (nextContinuation) { + nextContinuation = static_cast( + nextContinuation->Properties().Get(nsIFrame::IBSplitSpecialSibling())); + } + } + + if (!nextContinuation) { + return nullptr; + } + + NS_ASSERTION(nextContinuation->GetContent() == aFrame->GetContent(), + "unexpected content mismatch"); + + nsStyleContext* nextStyle = nextContinuation->StyleContext(); + if (nextStyle != aOldStyleContext) { + NS_ASSERTION(aOldStyleContext->GetPseudo() != nextStyle->GetPseudo() || + aOldStyleContext->GetParent() != nextStyle->GetParent(), + "continuations should have the same style context"); + nextContinuation = nullptr; + } + return nextContinuation; +} + nsresult RestyleManager::ReparentStyleContext(nsIFrame* aFrame) { @@ -2012,6 +2090,7 @@ ElementRestyler::ElementRestyler(ParentContextFromChildFrame, void ElementRestyler::CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext, + nsIFrame* aContinuation, // TEMPORARY (until bug 828312 patch 11) nsChangeHint aChangeToAssume) { // Check some invariants about replacing one style context with another. @@ -2037,7 +2116,7 @@ ElementRestyler::CaptureChange(nsStyleContext* aOldContext, NS_UpdateHint(ourChange, aChangeToAssume); if (NS_UpdateHint(mHintsHandled, ourChange)) { if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) { - mChangeList->AppendChange(mFrame, mContent, ourChange); + mChangeList->AppendChange(aContinuation, mContent, ourChange); } } NS_UpdateHint(mHintsNotHandledForDescendants, @@ -2045,8 +2124,12 @@ ElementRestyler::CaptureChange(nsStyleContext* aOldContext, } /** - * Recompute style for mFrame and accumulate changes into mChangeList - * given that mHintsHandled is already accumulated for an ancestor. + * Recompute style for mFrame (which should not have a prev continuation + * with the same style), all of its next continuations with the same + * style, and all special siblings of the same type (either block or + * inline, skipping the intermediates of the other type) and accumulate + * changes into mChangeList given that mHintsHandled is already accumulated + * for an ancestor. * mParentContent is the content node used to resolve the parent style * context. This means that, for pseudo-elements, it is the content * that should be used for selector matching (rather than the fake @@ -2067,6 +2150,9 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint) !mParentContent->GetParent(), "frame must have content (unless at the top of the tree)"); + NS_ASSERTION(!GetPrevContinuationWithSameStyle(mFrame), + "should not be trying to restyle this frame separately"); + if (mContent && mContent->IsElement()) { mContent->OwnerDoc()->FlushPendingLinkUpdates(); RestyleTracker::RestyleData restyleData; @@ -2084,13 +2170,29 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint) childRestyleHint = nsRestyleHint(0); } - RestyleSelf(aRestyleHint); + { + nsRefPtr oldContext = mFrame->StyleContext(); + + // TEMPORARY (until bug 918064): Call RestyleSelf for each + // continuation or block-in-inline sibling. + nsChangeHint hintsHandled = mHintsHandled; + + for (nsIFrame* f = mFrame; f; + f = GetNextContinuationWithSameStyle(f, oldContext)) { + // restore for each continuation, since we need the change hint + // posted for each continuation and failing to restore would + // suppress that. + mHintsHandled = hintsHandled; + + RestyleSelf(f, aRestyleHint); + } + } RestyleChildren(childRestyleHint); } void -ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) +ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint) { // XXXldb get new context from prev-in-flow if possible, to avoid // duplication. (Or should we just let |GetContext| handle that?) @@ -2101,7 +2203,7 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) // that the frame has the last reference to it, so AddRef it here. nsChangeHint assumeDifferenceHint = NS_STYLE_HINT_NONE; - nsRefPtr oldContext = mFrame->StyleContext(); + nsRefPtr oldContext = aSelf->StyleContext(); nsStyleSet* styleSet = mPresContext->StyleSet(); #ifdef ACCESSIBILITY @@ -2115,8 +2217,8 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) nsStyleContext* parentContext; // Get the frame providing the parent style context. If it is a // child, then resolve the provider first. - nsIFrame* providerFrame = mFrame->GetParentStyleContextFrame(); - bool isChild = providerFrame && providerFrame->GetParent() == mFrame; + nsIFrame* providerFrame = aSelf->GetParentStyleContextFrame(); + bool isChild = providerFrame && providerFrame->GetParent() == aSelf; if (!isChild) { if (providerFrame) parentContext = providerFrame->StyleContext(); @@ -2124,12 +2226,12 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) parentContext = nullptr; } else { - MOZ_ASSERT(providerFrame->GetContent() == mFrame->GetContent(), + MOZ_ASSERT(providerFrame->GetContent() == aSelf->GetContent(), "Postcondition for GetParentStyleContextFrame() violated. " "That means we need to add the current element to the " "ancestor filter."); - // resolve the provider here (before mFrame below). + // resolve the provider here (before aSelf below). // assumeDifferenceHint forces the parent's change to be also // applied to this frame, no matter what @@ -2144,70 +2246,24 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) assumeDifferenceHint = providerRestyler.HintsHandledForFrame(); // The provider's new context becomes the parent context of - // mFrame's context. + // aSelf's context. parentContext = providerFrame->StyleContext(); // Set |mResolvedChild| so we don't bother resolving the // provider again. mResolvedChild = providerFrame; } - if (providerFrame != mFrame->GetParent()) { + if (providerFrame != aSelf->GetParent()) { // We don't actually know what the parent style context's // non-inherited hints were, so assume the worst. mParentFrameHintsNotHandledForDescendants = nsChangeHint_Hints_NotHandledForDescendants; } -#ifdef DEBUG - { - // Check that our assumption that continuations of the same - // pseudo-type and with the same style context parent have the - // same style context is valid before the reresolution. (We need - // to check the pseudo-type and style context parent because of - // :first-letter and :first-line, where we create styled and - // unstyled letter/line frames distinguished by pseudo-type, and - // then need to distinguish their descendants based on having - // different parents.) - nsIFrame *nextContinuation = mFrame->GetNextContinuation(); - if (nextContinuation) { - nsStyleContext *nextContinuationContext = - nextContinuation->StyleContext(); - NS_ASSERTION(oldContext == nextContinuationContext || - oldContext->GetPseudo() != - nextContinuationContext->GetPseudo() || - oldContext->GetParent() != - nextContinuationContext->GetParent(), - "continuations should have the same style context"); - } - // And assert the same thing for {ib} splits. See the comments in - // GetPrevContinuationWithPossiblySameStyle for an explanation of - // why we step two forward in the special sibling chain. - if ((mFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) && - !mFrame->GetPrevContinuation()) { - nsIFrame *nextIBSibling = static_cast( - mFrame->Properties().Get(nsIFrame::IBSplitSpecialSibling())); - if (nextIBSibling) { - nextIBSibling = static_cast( - nextIBSibling->Properties().Get(nsIFrame::IBSplitSpecialSibling())); - } - if (nextIBSibling) { - nsStyleContext *nextIBSiblingContext = - nextIBSibling->StyleContext(); - NS_ASSERTION(oldContext == nextIBSiblingContext || - oldContext->GetPseudo() != - nextIBSiblingContext->GetPseudo() || - oldContext->GetParent() != - nextIBSiblingContext->GetParent(), - "continuations should have the same style context"); - } - } - } -#endif - // do primary context nsRefPtr newContext; nsIFrame *prevContinuation = - GetPrevContinuationWithPossiblySameStyle(mFrame); + GetPrevContinuationWithPossiblySameStyle(aSelf); nsStyleContext *prevContinuationContext; bool copyFromContinuation = prevContinuation && @@ -2216,13 +2272,11 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) prevContinuationContext->GetParent() == parentContext; if (copyFromContinuation) { // Just use the style context from the frame's previous - // continuation (see assertion about mFrame->GetNextContinuation() - // above, which we would have previously hit for mFrame's previous - // continuation). + // continuation. newContext = prevContinuationContext; } else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) { - NS_ASSERTION(mFrame->GetContent(), + NS_ASSERTION(aSelf->GetContent(), "non pseudo-element frame without content node"); newContext = styleSet->ResolveStyleForNonElement(parentContext); } @@ -2238,16 +2292,13 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) newContext = styleSet->ReparentStyleContext(oldContext, parentContext, ElementForStyleContext(mParentContent, - mFrame, - pseudoType)); + aSelf, pseudoType)); } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) { newContext = styleSet->ResolveAnonymousBoxStyle(pseudoTag, parentContext); } else { - Element* element = ElementForStyleContext(mParentContent, - mFrame, - pseudoType); + Element* element = ElementForStyleContext(mParentContent, aSelf, pseudoType); if (pseudoTag) { if (pseudoTag == nsCSSPseudoElements::before || pseudoTag == nsCSSPseudoElements::after) { @@ -2259,7 +2310,7 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) if (!newContext) { // This pseudo should no longer exist; gotta reframe NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame); - mChangeList->AppendChange(mFrame, element, + mChangeList->AppendChange(aSelf, element, nsChangeHint_ReconstructFrame); // We're reframing anyway; just keep the same context newContext = oldContext; @@ -2276,7 +2327,7 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) } } else { - NS_ASSERTION(mFrame->GetContent(), + NS_ASSERTION(aSelf->GetContent(), "non pseudo-element frame without content node"); // Skip flex-item style fixup for anonymous subtrees: TreeMatchContext::AutoFlexItemStyleFixupSkipper @@ -2305,14 +2356,14 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) if (newContext != oldContext) { if (!copyFromContinuation) { - TryStartingTransition(mPresContext, mFrame->GetContent(), + TryStartingTransition(mPresContext, aSelf->GetContent(), oldContext, &newContext); } - CaptureChange(oldContext, newContext, assumeDifferenceHint); + CaptureChange(oldContext, newContext, aSelf, assumeDifferenceHint); if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { // if frame gets regenerated, let it keep old context - mFrame->SetStyleContext(newContext); + aSelf->SetStyleContext(newContext); } } oldContext = nullptr; @@ -2322,7 +2373,7 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) // cases; won't worry about it for now. int32_t contextIndex = 0; for (nsStyleContext* oldExtraContext; - (oldExtraContext = mFrame->GetAdditionalStyleContext(contextIndex)); + (oldExtraContext = aSelf->GetAdditionalStyleContext(contextIndex)); ++contextIndex) { nsRefPtr newExtraContext; nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo(); @@ -2349,9 +2400,10 @@ ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint) MOZ_ASSERT(newExtraContext); if (oldExtraContext != newExtraContext) { - CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint); + CaptureChange(oldExtraContext, newExtraContext, aSelf, + assumeDifferenceHint); if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { - mFrame->SetAdditionalStyleContext(contextIndex, newExtraContext); + aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext); } } } @@ -2383,10 +2435,15 @@ ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint) // kids would use mFrame->StyleContext(), which is out of date if // mHintsHandled has a ReconstructFrame hint; doing this could trigger // assertions about mismatched rule trees. + nsIFrame *lastContinuation; if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { InitializeAccessibilityNotifications(); - RestyleContentChildren(aChildRestyleHint); + for (nsIFrame* f = mFrame; f; + f = GetNextContinuationWithSameStyle(f, f->StyleContext())) { + lastContinuation = f; + RestyleContentChildren(f, aChildRestyleHint); + } SendAccessibilityNotifications(); } @@ -2395,7 +2452,7 @@ ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint) // See comments above regarding :before. if (!(mHintsHandled & nsChangeHint_ReconstructFrame) && aChildRestyleHint) { - RestyleAfterPseudo(); + RestyleAfterPseudo(lastContinuation); } } @@ -2514,31 +2571,35 @@ ElementRestyler::RestyleBeforePseudo() } } +/** + * aFrame is the last continuation or block-in-inline sibling that this + * ElementRestyler is restyling. + */ void -ElementRestyler::RestyleAfterPseudo() +ElementRestyler::RestyleAfterPseudo(nsIFrame* aFrame) { // Make sure not to do this for pseudo-frames or frames that // can't have generated content. - if (!mFrame->StyleContext()->GetPseudo() && - ((mFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) || + if (!aFrame->StyleContext()->GetPseudo() && + ((aFrame->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT) || // Our content insertion frame might have gotten flagged - (mFrame->GetContentInsertionFrame()->GetStateBits() & + (aFrame->GetContentInsertionFrame()->GetStateBits() & NS_FRAME_MAY_HAVE_GENERATED_CONTENT))) { // Check for new :after content, but only if the frame is the // last continuation. - nsIFrame* nextContinuation = mFrame->GetNextContinuation(); + nsIFrame* nextContinuation = aFrame->GetNextContinuation(); if (!nextContinuation) { // Getting the :after frame is more expensive than getting the pseudo // context, so get the pseudo context first. - if (nsLayoutUtils::HasPseudoStyle(mFrame->GetContent(), - mFrame->StyleContext(), + if (nsLayoutUtils::HasPseudoStyle(aFrame->GetContent(), + aFrame->StyleContext(), nsCSSPseudoElements::ePseudo_after, mPresContext) && - !nsLayoutUtils::GetAfterFrame(mFrame)) { + !nsLayoutUtils::GetAfterFrame(aFrame)) { // have to create the new :after frame NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame); - mChangeList->AppendChange(mFrame, mContent, + mChangeList->AppendChange(aFrame, mContent, nsChangeHint_ReconstructFrame); } } @@ -2586,9 +2647,10 @@ ElementRestyler::InitializeAccessibilityNotifications() } void -ElementRestyler::RestyleContentChildren(nsRestyleHint aChildRestyleHint) +ElementRestyler::RestyleContentChildren(nsIFrame* aParent, + nsRestyleHint aChildRestyleHint) { - nsIFrame::ChildListIterator lists(mFrame); + nsIFrame::ChildListIterator lists(aParent); for (TreeMatchContext::AutoAncestorPusher pushAncestor(!lists.IsDone(), mTreeMatchContext, @@ -2598,7 +2660,10 @@ ElementRestyler::RestyleContentChildren(nsRestyleHint aChildRestyleHint) nsFrameList::Enumerator childFrames(lists.CurrentList()); for (; !childFrames.AtEnd(); childFrames.Next()) { nsIFrame* child = childFrames.get(); - if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { + // Out-of-flows are reached through their placeholders. Continuations + // and block-in-inline splits are reached through those chains. + if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && + !GetPrevContinuationWithSameStyle(child)) { // Get the parent of the child frame's content and check if it // is a XBL children element. Push the children element as an // ancestor here because it does not have a frame and would not @@ -2635,6 +2700,13 @@ ElementRestyler::RestyleContentChildren(nsRestyleHint aChildRestyleHint) // |nsFrame::GetParentStyleContextFrame| checks being out // of flow so that this works correctly. do { + if (GetPrevContinuationWithSameStyle(outOfFlowFrame)) { + // Later continuations are likely restyled as a result of + // the restyling of the previous continuation. + // (Currently that's always true, but it's likely to + // change if we implement overflow:fragments or similar.) + continue; + } ElementRestyler oofRestyler(*this, outOfFlowFrame, FOR_OUT_OF_FLOW_CHILD); oofRestyler.Restyle(aChildRestyleHint); @@ -2708,13 +2780,16 @@ RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame, } nsIFrame* frame = aFrame; - nsIFrame* frame2 = aFrame; NS_ASSERTION(!frame->GetPrevContinuation(), "must start with the first in flow"); - // We want to start with this frame and walk all its next-in-flows, - // as well as all its special siblings and their next-in-flows, - // reresolving style on all the frames we encounter in this walk. + // We need to handle aFrame and all of its continuations and special + // siblings and their continuations. ReResolveStyleContext loops over + // the continuations, and also loops over the similar-type sequences + // in block-in-inline splits (i.e., either all the blocks or all the + // inlines), so here we only have to advance one step to the other set + // of special siblings (i.e., switch from blocks to inlines, or + // vice-versa). FramePropertyTable* propTable = mPresContext->PropertyTable(); @@ -2726,39 +2801,36 @@ RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame, parent && parent->IsElement() ? parent->AsElement() : nullptr; treeMatchContext.InitAncestors(parentElement); nsTArray visibleKidsOfHiddenElement; - do { - // Outer loop over special siblings - do { - // Inner loop over next-in-flows of the current frame - ElementRestyler restyler(mPresContext, frame, aChangeList, - aMinChange, aRestyleTracker, - treeMatchContext, - visibleKidsOfHiddenElement); + for (int ibSet = 0; ibSet < 2; ++ibSet) { + // loop over the two sets (blocks, inlines) of special siblings + ElementRestyler restyler(mPresContext, frame, aChangeList, + aMinChange, aRestyleTracker, + treeMatchContext, + visibleKidsOfHiddenElement); - restyler.Restyle(aRestyleDescendants ? eRestyle_Subtree : eRestyle_Self); + restyler.Restyle(aRestyleDescendants ? eRestyle_Subtree : eRestyle_Self); - if (restyler.HintsHandledForFrame() & nsChangeHint_ReconstructFrame) { - // If it's going to cause a framechange, then don't bother - // with the continuations or special siblings since they'll be - // clobbered by the frame reconstruct anyway. - NS_ASSERTION(!frame->GetPrevContinuation(), - "continuing frame had more severe impact than first-in-flow"); - return; - } - - frame = frame->GetNextContinuation(); - } while (frame); + if (restyler.HintsHandledForFrame() & nsChangeHint_ReconstructFrame) { + // If it's going to cause a framechange, then don't bother + // with the continuations or special siblings since they'll be + // clobbered by the frame reconstruct anyway. + NS_ASSERTION(!frame->GetPrevContinuation(), + "continuing frame had more severe impact than first-in-flow"); + return; + } // Might we have special siblings? - if (!(frame2->GetStateBits() & NS_FRAME_IS_SPECIAL)) { + if (!(frame->GetStateBits() & NS_FRAME_IS_SPECIAL)) { // nothing more to do here return; } - frame2 = static_cast - (propTable->Get(frame2, nsIFrame::IBSplitSpecialSibling())); - frame = frame2; - } while (frame2); + frame = static_cast + (propTable->Get(frame, nsIFrame::IBSplitSpecialSibling())); + if (!frame) { + return; + } + } } } // namespace mozilla diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h index ab27c33e1610..d01264022851 100644 --- a/layout/base/RestyleManager.h +++ b/layout/base/RestyleManager.h @@ -322,7 +322,7 @@ private: /** * First half of Restyle(). */ - void RestyleSelf(nsRestyleHint aRestyleHint); + void RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint); /** * Restyle the children of this frame (and, in turn, their children). @@ -336,6 +336,7 @@ private: */ void CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext, + nsIFrame* aContinuation, // TEMPORARY (until bug 828312 patch 11) nsChangeHint aChangeToAssume); /** @@ -343,8 +344,9 @@ private: */ void RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint); void RestyleBeforePseudo(); - void RestyleAfterPseudo(); - void RestyleContentChildren(nsRestyleHint aChildRestyleHint); + void RestyleAfterPseudo(nsIFrame* aFrame); + void RestyleContentChildren(nsIFrame* aParent, + nsRestyleHint aChildRestyleHint); void InitializeAccessibilityNotifications(); void SendAccessibilityNotifications(); From e1a486d3f277e4dd4efedbdfe6926a8035d50ef7 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:07 -0700 Subject: [PATCH 41/62] Bug 898209 patch 16: Move a comment that should have been moved in patch 15. No review. --- layout/base/RestyleManager.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 0a3ac572378f..f03eec339aa1 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -2055,6 +2055,16 @@ ElementRestyler::ElementRestyler(const ElementRestyler& aParentRestyler, #endif { if (aConstructorFlags & FOR_OUT_OF_FLOW_CHILD) { + // Note that the out-of-flow may not be a geometric descendant of + // the frame where we started the reresolve. Therefore, even if + // mHintsHandled already includes nsChangeHint_AllReflowHints we + // don't want to pass that on to the out-of-flow reresolve, since + // that can lead to the out-of-flow not getting reflowed when it + // should be (eg a reresolve starting at that involves + // reflowing the would miss reflowing fixed-pos nodes that + // also need reflow). In the cases when the out-of-flow _is_ a + // geometric descendant of a frame we already have a reflow hint + // for, reflow coalescing should keep us from doing the work twice. mHintsHandled = NS_SubtractHint(mHintsHandled, nsChangeHint_AllReflowHints); } } @@ -2686,17 +2696,6 @@ ElementRestyler::RestyleContentChildren(nsIFrame* aParent, NS_ASSERTION(outOfFlowFrame != mResolvedChild, "out-of-flow frame not a true descendant"); - // Note that the out-of-flow may not be a geometric descendant of - // the frame where we started the reresolve. Therefore, even if - // mHintsHandled already includes nsChangeHint_AllReflowHints we don't - // want to pass that on to the out-of-flow reresolve, since that - // can lead to the out-of-flow not getting reflowed when it should - // be (eg a reresolve starting at that involves reflowing - // the would miss reflowing fixed-pos nodes that also need - // reflow). In the cases when the out-of-flow _is_ a geometric - // descendant of a frame we already have a reflow hint for, - // reflow coalescing should keep us from doing the work twice. - // |nsFrame::GetParentStyleContextFrame| checks being out // of flow so that this works correctly. do { From ee558d6e7979bb7bd8fa84dc7cf068c7c31fbea1 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:07 -0700 Subject: [PATCH 42/62] Bug 828312 patch 5: Don't handle UpdateCursor more than once per round of style change processing, since it's global. r=bzbarsky (This is part of the patch stack making change hints apply across all continuations and block-in-inline siblings. In this case, however, the change hint only needs to apply once, globally.) --- layout/base/RestyleManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index f03eec339aa1..6f7af256f8da 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -603,6 +603,8 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) index = count; + bool didUpdateCursor = false; + while (0 <= --index) { nsIFrame* frame; nsIContent* content; @@ -730,8 +732,9 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) } } } - if (hint & nsChangeHint_UpdateCursor) { + if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) { mPresContext->PresShell()->SynthesizeMouseMove(false); + didUpdateCursor = true; } } } From b741eb1e7b9231f776962144cf9a2627edc1880d Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:07 -0700 Subject: [PATCH 43/62] Bug 828312 patch 6: Make early transform handling check continuations. r=bzbarsky This is part of the patch stack making change hints apply across all continuations and block-in-inline siblings. --- layout/base/RestyleManager.cpp | 43 ++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 6f7af256f8da..879c4ba997fd 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -635,26 +635,29 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) if (NeedToReframeForAddingOrRemovingTransform(frame)) { NS_UpdateHint(hint, nsChangeHint_ReconstructFrame); } else { - // Normally frame construction would set state bits as needed, - // but we're not going to reconstruct the frame so we need to set them. - // It's because we need to set this state on each affected frame - // that we can't coalesce nsChangeHint_AddOrRemoveTransform hints up - // to ancestors (i.e. it can't be an inherited change hint). - if (frame->IsPositioned()) { - // If a transform has been added, we'll be taking this path, - // but we may be taking this path even if a transform has been - // removed. It's OK to add the bit even if it's not needed. - frame->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED); - if (!frame->IsAbsoluteContainer() && - (frame->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) { - frame->MarkAsAbsoluteContainingBlock(); - } - } else { - // Don't remove NS_FRAME_MAY_BE_TRANSFORMED since it may still by - // transformed by other means. It's OK to have the bit even if it's - // not needed. - if (frame->IsAbsoluteContainer()) { - frame->MarkAsNotAbsoluteContainingBlock(); + for (nsIFrame *cont = frame; cont; + cont = nsLayoutUtils::GetNextContinuationOrSpecialSibling(cont)) { + // Normally frame construction would set state bits as needed, + // but we're not going to reconstruct the frame so we need to set them. + // It's because we need to set this state on each affected frame + // that we can't coalesce nsChangeHint_AddOrRemoveTransform hints up + // to ancestors (i.e. it can't be an inherited change hint). + if (cont->IsPositioned()) { + // If a transform has been added, we'll be taking this path, + // but we may be taking this path even if a transform has been + // removed. It's OK to add the bit even if it's not needed. + cont->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED); + if (!cont->IsAbsoluteContainer() && + (cont->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) { + cont->MarkAsAbsoluteContainingBlock(); + } + } else { + // Don't remove NS_FRAME_MAY_BE_TRANSFORMED since it may still by + // transformed by other means. It's OK to have the bit even if it's + // not needed. + if (cont->IsAbsoluteContainer()) { + cont->MarkAsNotAbsoluteContainingBlock(); + } } } } From 82151d195887a07870aa9ec02d8691eb0787a09c Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:07 -0700 Subject: [PATCH 44/62] Bug 828312 patch 7: Use more typical loop structure and don't mutate |frame| in UpdateOverflow hint handling. r=bzbarsky --- layout/base/RestyleManager.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 879c4ba997fd..dabef44ac682 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -727,11 +727,9 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) // overflows since that will happen when it's reflowed. if (!(frame->GetStateBits() & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) { - while (frame) { - mOverflowChangedTracker.AddFrame(frame); - - frame = - nsLayoutUtils::GetNextContinuationOrSpecialSibling(frame); + for (nsIFrame *cont = frame; cont; cont = + nsLayoutUtils::GetNextContinuationOrSpecialSibling(cont)) { + mOverflowChangedTracker.AddFrame(cont); } } } From 95e754510edf28b23e67b0926e51269291161ae5 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:07 -0700 Subject: [PATCH 45/62] Bug 828312 patch 8: Make handling of UpdateEffects hint check continuations. r=bzbarsky This is part of the patch stack making change hints apply across all continuations and block-in-inline siblings. --- layout/base/RestyleManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index dabef44ac682..e363eab56aa4 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -683,7 +683,10 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) } if (hint & nsChangeHint_UpdateEffects) { - nsSVGEffects::UpdateEffects(frame); + for (nsIFrame *cont = frame; cont; + cont = nsLayoutUtils::GetNextContinuationOrSpecialSibling(cont)) { + nsSVGEffects::UpdateEffects(cont); + } } if (hint & nsChangeHint_NeedReflow) { StyleChangeReflow(frame, hint); From d0255c650f9b176c4724dab2eeca51a0f4edced8 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:08 -0700 Subject: [PATCH 46/62] Bug 828312 patch 9a: Make sticky positioning handle block-in-inline splits correctly. r=dholbert This assumes that the specification for how position:sticky behaves for block-in-inline splits matches the specification for position:relative, in other words, matches http://www.w3.org/TR/CSS21/visuren.html#anonymous-block-level . It's also necessary for patch 9b since the new rule for handling of style change hints is that a style change hint applies to all continuations and all block-in-inline siblings ("special siblings"). The change in StickyScrollContainer::GetScrollRanges is really the fix for bug 918994, but adjusted for the change here to use block-in-inline siblings ("special siblings") in addition to continuations. --- layout/base/nsLayoutUtils.cpp | 14 ++++++ layout/base/nsLayoutUtils.h | 7 +++ layout/generic/StickyScrollContainer.cpp | 39 ++++++++++++---- layout/generic/nsFrame.cpp | 5 ++ layout/generic/nsHTMLReflowState.cpp | 4 +- .../block-in-inline-1-ref.html | 41 +++++++++++++++++ .../position-sticky/block-in-inline-1.html | 42 +++++++++++++++++ .../block-in-inline-2-ref.html | 41 +++++++++++++++++ .../position-sticky/block-in-inline-2.html | 45 ++++++++++++++++++ .../block-in-inline-3-ref.html | 41 +++++++++++++++++ .../position-sticky/block-in-inline-3.html | 46 +++++++++++++++++++ layout/reftests/position-sticky/reftest.list | 3 ++ layout/style/ua.css | 4 +- 13 files changed, 320 insertions(+), 12 deletions(-) create mode 100644 layout/reftests/position-sticky/block-in-inline-1-ref.html create mode 100644 layout/reftests/position-sticky/block-in-inline-1.html create mode 100644 layout/reftests/position-sticky/block-in-inline-2-ref.html create mode 100644 layout/reftests/position-sticky/block-in-inline-2.html create mode 100644 layout/reftests/position-sticky/block-in-inline-3-ref.html create mode 100644 layout/reftests/position-sticky/block-in-inline-3.html diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 8f0a0765c625..45330ae294fb 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2545,6 +2545,20 @@ nsLayoutUtils::FirstContinuationOrSpecialSibling(nsIFrame *aFrame) return result; } +bool +nsLayoutUtils::IsFirstContinuationOrSpecialSibling(nsIFrame *aFrame) +{ + if (aFrame->GetPrevContinuation()) { + return false; + } + if ((aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) && + aFrame->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling())) { + return false; + } + + return true; +} + bool nsLayoutUtils::IsViewportScrollbarFrame(nsIFrame* aFrame) { diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 3bddedeb1578..4fa8ab6f2f61 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -944,6 +944,13 @@ public: static nsIFrame* FirstContinuationOrSpecialSibling(nsIFrame *aFrame); + /** + * Is FirstContinuationOrSpecialSibling(aFrame) going to return + * aFrame? + */ + static bool + IsFirstContinuationOrSpecialSibling(nsIFrame *aFrame); + /** * Check whether aFrame is a part of the scrollbar or scrollcorner of * the root content. diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp index 6b2ca7acf5e3..b79e2d105b93 100644 --- a/layout/generic/StickyScrollContainer.cpp +++ b/layout/generic/StickyScrollContainer.cpp @@ -129,7 +129,7 @@ void StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick, nsRect* aContain) const { - NS_ASSERTION(!aFrame->GetPrevContinuation(), + NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrSpecialSibling(aFrame), "Can't sticky position individual continuations"); aStick->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX); @@ -144,6 +144,11 @@ StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick, } nsIFrame* scrolledFrame = mScrollFrame->GetScrolledFrame(); + // FIXME (Bug 920688): cbFrame isn't quite right if we're dealing + // with a block-in-inline split whose first part is a block. We + // probably want the first in flow of the containing block of the + // first inline part. (Or maybe those block-in-inline split pieces + // are never a containing block, and we're ok?) nsIFrame* cbFrame = aFrame->GetContainingBlock(); NS_ASSERTION(cbFrame == scrolledFrame || nsLayoutUtils::IsProperAncestorFrame(scrolledFrame, cbFrame), @@ -156,6 +161,10 @@ StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick, if (cbFrame != scrolledFrame) { *aContain = nsLayoutUtils::GetAllInFlowRectsUnion(cbFrame, cbFrame); aContain->MoveBy(-aFrame->GetParent()->GetOffsetTo(cbFrame)); + // FIXME (Bug 920688): GetUsedBorderAndPadding / GetUsedMargin + // consider skip-sides, which doesn't quite mesh with the use of + // GetAllInFlowRectsUnion here. This probably needs to do that + // computation *inside* the accumuation function over the in-flows. aContain->Deflate(cbFrame->GetUsedBorderAndPadding()); aContain->Deflate(aFrame->GetUsedMargin()); aContain->Deflate(nsMargin(0, rect.width, rect.height, 0)); @@ -229,9 +238,15 @@ void StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter, nsRect* aInner) const { + // We need to use the first in flow; ComputeStickyLimits requires + // this, at the very least because its call to + // nsLayoutUtils::GetAllInFlowRectsUnion requires it. + nsIFrame *firstCont = + nsLayoutUtils::FirstContinuationOrSpecialSibling(aFrame); + nsRect stick; nsRect contain; - ComputeStickyLimits(aFrame, &stick, &contain); + ComputeStickyLimits(firstCont, &stick, &contain); aOuter->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX); aInner->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX); @@ -264,15 +279,13 @@ StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter, void StickyScrollContainer::PositionContinuations(nsIFrame* aFrame) { - NS_ASSERTION(!aFrame->GetPrevContinuation(), + NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrSpecialSibling(aFrame), "Should be starting from the first continuation"); - nsPoint newPosition = ComputePosition(aFrame); - nsPoint translation = newPosition - aFrame->GetPosition(); - aFrame->SetPosition(newPosition); + nsPoint translation = ComputePosition(aFrame) - aFrame->GetPosition(); // Move all continuation frames by the same amount. - for (nsIFrame* cont = aFrame->GetNextContinuation(); cont; - cont = cont->GetNextContinuation()) { + for (nsIFrame* cont = aFrame; cont; + cont = nsLayoutUtils::GetNextContinuationOrSpecialSibling(cont)) { cont->SetPosition(cont->GetPosition() + translation); } } @@ -294,6 +307,13 @@ StickyScrollContainer::UpdatePositions(nsPoint aScrollPosition, oct.SetSubtreeRoot(aSubtreeRoot); for (nsTArray::size_type i = 0; i < mFrames.Length(); i++) { nsIFrame* f = mFrames[i]; + if (!nsLayoutUtils::IsFirstContinuationOrSpecialSibling(f)) { + // This frame was added in nsFrame::Init before we knew it wasn't + // the first special-sibling. + mFrames.RemoveElementAt(i); + --i; + continue; + } if (aSubtreeRoot) { // Reflowing the scroll frame, so recompute offsets. @@ -303,7 +323,8 @@ StickyScrollContainer::UpdatePositions(nsPoint aScrollPosition, // nsIFrame::Init. PositionContinuations(f); - for (nsIFrame* cont = f; cont; cont = cont->GetNextContinuation()) { + for (nsIFrame* cont = f; cont; + cont = nsLayoutUtils::GetNextContinuationOrSpecialSibling(cont)) { oct.AddFrame(cont); } } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 6f6efe0cab16..eac36615b999 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -515,6 +515,11 @@ nsFrame::Init(nsIContent* aContent, if (disp->mPosition == NS_STYLE_POSITION_STICKY && !aPrevInFlow && !(mState & NS_FRAME_IS_NONDISPLAY)) { + // Note that we only add first continuations, but we really only + // want to add first continuation-or-special-siblings. But since we + // don't yet know if we're a later part of a block-in-inline split, + // we'll just add later members of a block-in-inline split here, and + // then StickyScrollContainer will remove them later. StickyScrollContainer* ssc = StickyScrollContainer::GetStickyScrollContainerForFrame(this); if (ssc) { diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index 0aa76c208fde..bebcb58d62d2 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -874,7 +874,9 @@ nsHTMLReflowState::ApplyRelativePositioning(nsIFrame* aFrame, if (NS_STYLE_POSITION_RELATIVE == display->mPosition) { *aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top); } else if (NS_STYLE_POSITION_STICKY == display->mPosition && - !aFrame->GetNextContinuation() && !aFrame->GetPrevContinuation()) { + !aFrame->GetNextContinuation() && + !aFrame->GetPrevContinuation() && + !(aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) { // Sticky positioning for elements with multiple frames needs to be // computed all at once. We can't safely do that here because we might be // partway through (re)positioning the frames, so leave it until the scroll diff --git a/layout/reftests/position-sticky/block-in-inline-1-ref.html b/layout/reftests/position-sticky/block-in-inline-1-ref.html new file mode 100644 index 000000000000..ce6f2580626e --- /dev/null +++ b/layout/reftests/position-sticky/block-in-inline-1-ref.html @@ -0,0 +1,41 @@ + + + + + CSS Test: Sticky Positioning - block inside inline, normal position + + + + + +
+
+
+ before inline + before block +
in block
+ after block + after inline +
+
+
+ + diff --git a/layout/reftests/position-sticky/block-in-inline-1.html b/layout/reftests/position-sticky/block-in-inline-1.html new file mode 100644 index 000000000000..a613421d9267 --- /dev/null +++ b/layout/reftests/position-sticky/block-in-inline-1.html @@ -0,0 +1,42 @@ + + + + + CSS Test: Sticky Positioning - block inside inline, normal position + + + + + + + +
+
+
+ before inline +
+ before block +
in block
+ after block +
+ after inline +
+
+
+ + diff --git a/layout/reftests/position-sticky/block-in-inline-2-ref.html b/layout/reftests/position-sticky/block-in-inline-2-ref.html new file mode 100644 index 000000000000..08239c50b21e --- /dev/null +++ b/layout/reftests/position-sticky/block-in-inline-2-ref.html @@ -0,0 +1,41 @@ + + + + + CSS Test: Sticky Positioning - block inside inline, normal position + + + + + +
+
+
+ before inline + before block +
in block
+ after block + after inline +
+
+
+ + diff --git a/layout/reftests/position-sticky/block-in-inline-2.html b/layout/reftests/position-sticky/block-in-inline-2.html new file mode 100644 index 000000000000..084f9b04f382 --- /dev/null +++ b/layout/reftests/position-sticky/block-in-inline-2.html @@ -0,0 +1,45 @@ + + + + + CSS Test: Sticky Positioning - block inside inline, stuck position + + + + + + + +
+
+
+ before inline +
+ before block +
in block
+ after block +
+ after inline +
+
+
+ + + diff --git a/layout/reftests/position-sticky/block-in-inline-3-ref.html b/layout/reftests/position-sticky/block-in-inline-3-ref.html new file mode 100644 index 000000000000..13e29a9f77b5 --- /dev/null +++ b/layout/reftests/position-sticky/block-in-inline-3-ref.html @@ -0,0 +1,41 @@ + + + + + CSS Test: Sticky Positioning - block inside inline, normal position + + + + + +
+
+
+ before inline + before block +
in block
+ after block + after inline +
+
+
+ + diff --git a/layout/reftests/position-sticky/block-in-inline-3.html b/layout/reftests/position-sticky/block-in-inline-3.html new file mode 100644 index 000000000000..f4acbc7f1519 --- /dev/null +++ b/layout/reftests/position-sticky/block-in-inline-3.html @@ -0,0 +1,46 @@ + + + + + CSS Test: Sticky Positioning - block inside inline, contained position + + + + + + + +
+
+
+ before inline +
+ before block +
in block
+ after block +
+ after inline +
+
+
+ + + diff --git a/layout/reftests/position-sticky/reftest.list b/layout/reftests/position-sticky/reftest.list index 9abd7ae355dd..2b724e8446b1 100644 --- a/layout/reftests/position-sticky/reftest.list +++ b/layout/reftests/position-sticky/reftest.list @@ -46,3 +46,6 @@ fuzzy-if(Android,4,1) == containing-block-1.html containing-block-1-ref.html fails == inline-3.html inline-3-ref.html # bug 916302 fails == column-contain-1a.html column-contain-1-ref.html == column-contain-1b.html column-contain-1-ref.html +== block-in-inline-1.html block-in-inline-1-ref.html +== block-in-inline-2.html block-in-inline-2-ref.html +== block-in-inline-3.html block-in-inline-3-ref.html diff --git a/layout/style/ua.css b/layout/style/ua.css index 608d76a98475..0ef35ddd9a7c 100644 --- a/layout/style/ua.css +++ b/layout/style/ua.css @@ -209,8 +209,8 @@ *|*::-moz-anonymous-positioned-block { display: block !important; - position: relative; - top: inherit; + position: inherit; /* relative or sticky */ + top: inherit; left: inherit; bottom: inherit; right: inherit; From 4e703ff3330c5f107d81aee5b4780d9240bad1af Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:08 -0700 Subject: [PATCH 47/62] Bug 828312 patch 9b: Make handling of RecomputePosition hint check continuations. r=bzbarsky This is part of the patch stack making change hints apply across all continuations and block-in-inline siblings. --- layout/base/RestyleManager.cpp | 41 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index e363eab56aa4..c634a9e15805 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -345,38 +345,39 @@ RestyleManager::RecomputePosition(nsIFrame* aFrame) break; } - nsIFrame* cb = aFrame->GetContainingBlock(); - nsMargin newOffsets; // Move the frame if (display->mPosition == NS_STYLE_POSITION_STICKY) { // Update sticky positioning for an entire element at once when // RecomputePosition is called with the first continuation in a chain. - if (!aFrame->GetPrevContinuation()) { - StickyScrollContainer::ComputeStickyOffsets(aFrame); - StickyScrollContainer* ssc = - StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame); - if (ssc) { - ssc->PositionContinuations(aFrame); - } + StickyScrollContainer::ComputeStickyOffsets(aFrame); + StickyScrollContainer* ssc = + StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame); + if (ssc) { + ssc->PositionContinuations(aFrame); } } else { MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition, "Unexpected type of positioning"); - const nsSize size = cb->GetContentRectRelativeToSelf().Size(); + for (nsIFrame *cont = aFrame; cont; + cont = nsLayoutUtils::GetNextContinuationOrSpecialSibling(cont)) { + nsIFrame* cb = cont->GetContainingBlock(); + nsMargin newOffsets; + const nsSize size = cb->GetContentRectRelativeToSelf().Size(); - nsHTMLReflowState::ComputeRelativeOffsets( - cb->StyleVisibility()->mDirection, - aFrame, size.width, size.height, newOffsets); - NS_ASSERTION(newOffsets.left == -newOffsets.right && - newOffsets.top == -newOffsets.bottom, - "ComputeRelativeOffsets should return valid results"); + nsHTMLReflowState::ComputeRelativeOffsets( + cb->StyleVisibility()->mDirection, + cont, size.width, size.height, newOffsets); + NS_ASSERTION(newOffsets.left == -newOffsets.right && + newOffsets.top == -newOffsets.bottom, + "ComputeRelativeOffsets should return valid results"); - // nsHTMLReflowState::ApplyRelativePositioning would work here, but - // since we've already checked mPosition and aren't changing the frame's - // normal position, go ahead and add the offsets directly. - aFrame->SetPosition(aFrame->GetNormalPosition() + + // nsHTMLReflowState::ApplyRelativePositioning would work here, but + // since we've already checked mPosition and aren't changing the frame's + // normal position, go ahead and add the offsets directly. + cont->SetPosition(cont->GetNormalPosition() + nsPoint(newOffsets.left, newOffsets.top)); + } } return true; From 36acc15f31648151dff79079084d05800f40793a Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:08 -0700 Subject: [PATCH 48/62] Bug 828312 patch 10: Add assertions to check that handling of nsChangeHint_ChildrenOnlyTransform doesn't need to check continuations. r=bzbarsky This is part of the patch stack making change hints apply across all continuations and block-in-inline siblings. --- layout/base/RestyleManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index c634a9e15805..b4804a17dbc6 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -712,6 +712,10 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList) // The overflow areas of the child frames need to be updated: nsIFrame* hintFrame = GetFrameForChildrenOnlyTransformHint(frame); nsIFrame* childFrame = hintFrame->GetFirstPrincipalChild(); + NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrSpecialSibling(frame), + "SVG frames should not have continuations or special siblings"); + NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrSpecialSibling(hintFrame), + "SVG frames should not have continuations or special siblings"); for ( ; childFrame; childFrame = childFrame->GetNextSibling()) { NS_ABORT_IF_FALSE(childFrame->IsFrameOfType(nsIFrame::eSVG), "Not expecting non-SVG children"); From d01753dad0e77630ec170265b384e35c16a063f9 Mon Sep 17 00:00:00 2001 From: "L. David Baron" Date: Wed, 25 Sep 2013 12:28:08 -0700 Subject: [PATCH 49/62] Bug 828312 patch 11: Don't generate change hints for restyling of later continuations, since the handling of the change hints from the first continuation is required to do the necessary work. r=bzbarsky This depends on bug 898333 in order to avoid causing: TEST-UNEXPECTED-FAIL | chrome://mochitests/content/chrome/dom/tests/mochitest/chrome/test_focused_link_scroll.xul | Assertion count 1 is greater than expected range 0-0 assertions. due to the assertion: ###!!! ASSERTION: Shouldn't be trying to restyle non-elements directly: '!aContent || aContent->IsElement()', file ../../../layout/base/nsStyleChangeList.cpp, line 62 The assertion count change in layout/generic/crashtests/571995.xhtml is expected because it changes us from having 7 of: ###!!! ASSERTION: Shouldn't be trying to restyle non-elements directly: '!aContent || aContent->IsElement()', file ../../../layout/base/nsStyleChangeList.cpp, line 62 with the stack: mozilla::ElementRestyler::CaptureChange(nsStyleContext*, nsStyleContext*, nsChangeHint) [layout/base/nsChangeHint.h:191] mozilla::ElementRestyler::RestyleSelf(nsRestyleHint) [layout/base/RestyleManager.cpp:2304] to only having one. This is expected since this patch changes RestyleSelf to only call CaptureChange for the first continuation or block-in-inline sibling. --- layout/base/RestyleManager.cpp | 43 ++++++++++++----------- layout/base/RestyleManager.h | 1 - layout/generic/crashtests/crashtests.list | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index b4804a17dbc6..80b4af773315 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -1923,14 +1923,16 @@ RestyleManager::ReparentStyleContext(nsIFrame* aFrame) // Make sure to call CalcStyleDifference so that the new context ends // up resolving all the structs the old context resolved. - DebugOnly styleChange = - oldContext->CalcStyleDifference(newContext, nsChangeHint(0)); - // The style change is always 0 because we have the same rulenode and - // CalcStyleDifference optimizes us away. That's OK, though: - // reparenting should never trigger a frame reconstruct, and whenever - // it's happening we already plan to reflow and repaint the frames. - NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame), - "Our frame tree is likely to be bogus!"); + if (!copyFromContinuation) { + DebugOnly styleChange = + oldContext->CalcStyleDifference(newContext, nsChangeHint(0)); + // The style change is always 0 because we have the same rulenode and + // CalcStyleDifference optimizes us away. That's OK, though: + // reparenting should never trigger a frame reconstruct, and whenever + // it's happening we already plan to reflow and repaint the frames. + NS_ASSERTION(!(styleChange & nsChangeHint_ReconstructFrame), + "Our frame tree is likely to be bogus!"); + } aFrame->SetStyleContext(newContext); @@ -1986,7 +1988,7 @@ RestyleManager::ReparentStyleContext(nsIFrame* aFrame) // Make sure to call CalcStyleDifference so that the new // context ends up resolving all the structs the old context // resolved. - styleChange = + DebugOnly styleChange = oldExtraContext->CalcStyleDifference(newExtraContext, nsChangeHint(0)); // The style change is always 0 because we have the same @@ -2112,7 +2114,6 @@ ElementRestyler::ElementRestyler(ParentContextFromChildFrame, void ElementRestyler::CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext, - nsIFrame* aContinuation, // TEMPORARY (until bug 828312 patch 11) nsChangeHint aChangeToAssume) { // Check some invariants about replacing one style context with another. @@ -2138,7 +2139,7 @@ ElementRestyler::CaptureChange(nsStyleContext* aOldContext, NS_UpdateHint(ourChange, aChangeToAssume); if (NS_UpdateHint(mHintsHandled, ourChange)) { if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) { - mChangeList->AppendChange(aContinuation, mContent, ourChange); + mChangeList->AppendChange(mFrame, mContent, ourChange); } } NS_UpdateHint(mHintsNotHandledForDescendants, @@ -2197,15 +2198,9 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint) // TEMPORARY (until bug 918064): Call RestyleSelf for each // continuation or block-in-inline sibling. - nsChangeHint hintsHandled = mHintsHandled; for (nsIFrame* f = mFrame; f; f = GetNextContinuationWithSameStyle(f, oldContext)) { - // restore for each continuation, since we need the change hint - // posted for each continuation and failing to restore would - // suppress that. - mHintsHandled = hintsHandled; - RestyleSelf(f, aRestyleHint); } } @@ -2380,11 +2375,18 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint) if (!copyFromContinuation) { TryStartingTransition(mPresContext, aSelf->GetContent(), oldContext, &newContext); + + CaptureChange(oldContext, newContext, assumeDifferenceHint); } - CaptureChange(oldContext, newContext, aSelf, assumeDifferenceHint); if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { - // if frame gets regenerated, let it keep old context + // If the frame gets regenerated, let it keep its old context, + // which is important to maintain various invariants about + // frame types matching their style contexts. + // Note that this check even makes sense if we didn't call + // CaptureChange because of copyFromContinuation being true, + // since we'll have copied the existing context from the + // previous continuation, so newContext == oldContext. aSelf->SetStyleContext(newContext); } } @@ -2422,8 +2424,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf, nsRestyleHint aRestyleHint) MOZ_ASSERT(newExtraContext); if (oldExtraContext != newExtraContext) { - CaptureChange(oldExtraContext, newExtraContext, aSelf, - assumeDifferenceHint); + CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint); if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) { aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext); } diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h index d01264022851..469496ae46ff 100644 --- a/layout/base/RestyleManager.h +++ b/layout/base/RestyleManager.h @@ -336,7 +336,6 @@ private: */ void CaptureChange(nsStyleContext* aOldContext, nsStyleContext* aNewContext, - nsIFrame* aContinuation, // TEMPORARY (until bug 828312 patch 11) nsChangeHint aChangeToAssume); /** diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 233bd85651a8..4258a5d6715e 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -389,7 +389,7 @@ load 570160.html load 570289-1.html load 571618-1.svg asserts(1) load 571975-1.html # bug 574889 -asserts(7) load 571995.xhtml # 761848 +asserts(1) load 571995.xhtml # 761848 load 574958.xhtml asserts(0-4) load 578977.html # bug 757305 load 580504-1.xhtml From faaf3281fa1be20d19020a25544b2b8e5f0a6190 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 25 Sep 2013 12:00:36 -0700 Subject: [PATCH 50/62] Bug 920248: Temporarily disable TLS false start, r=keeler, r=wtc --HG-- extra : rebase_source : 4fc35de2d6e2dc99de11b2a2d0c0f3ebe1de8b97 --- netwerk/base/public/security-prefs.js | 2 +- security/manager/ssl/src/nsNSSComponent.cpp | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/netwerk/base/public/security-prefs.js b/netwerk/base/public/security-prefs.js index d256b8aece21..aa10e3a2abb6 100644 --- a/netwerk/base/public/security-prefs.js +++ b/netwerk/base/public/security-prefs.js @@ -13,7 +13,7 @@ pref("security.ssl.treat_unsafe_negotiation_as_broken", false); pref("security.ssl.require_safe_negotiation", false); pref("security.ssl.warn_missing_rfc5746", 1); pref("security.ssl.enable_ocsp_stapling", true); -pref("security.ssl.enable_false_start", true); +pref("security.ssl.enable_false_start", false); pref("security.ssl.false_start.require-npn", true); pref("security.ssl.false_start.require-forward-secrecy", false); diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp index 78a156296453..a2c4468de6cb 100644 --- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -1215,11 +1215,10 @@ nsNSSComponent::InitializeNSS(bool showWarningBox) SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN); -#ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8 - bool falseStartEnabled = Preferences::GetBool("security.ssl.enable_false_start", - FALSE_START_ENABLED_DEFAULT); - SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, falseStartEnabled); -#endif +// Bug 920248: temporarily disable false start +// bool falseStartEnabled = Preferences::GetBool("security.ssl.enable_false_start", +// FALSE_START_ENABLED_DEFAULT); + SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, false); // Disable any ciphers that NSS might have enabled by default for (uint16_t i = 0; i < SSL_NumImplementedCiphers; ++i) @@ -1651,12 +1650,11 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic, allowUnrestrictedRenego ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN); -#ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8 } else if (prefName.Equals("security.ssl.enable_false_start")) { - bool falseStartEnabled = Preferences::GetBool("security.ssl.enable_false_start", - FALSE_START_ENABLED_DEFAULT); - SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, falseStartEnabled); -#endif +// Bug 920248: temporarily disable false start +// bool falseStartEnabled = Preferences::GetBool("security.ssl.enable_false_start", +// FALSE_START_ENABLED_DEFAULT); + SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, false); } else if (prefName.Equals("security.OCSP.enabled") || prefName.Equals("security.CRL_download.enabled") || prefName.Equals("security.fresh_revocation_info.require") From 5a3c6a793ec4c0791b4dd9d78c53a464f4eff092 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 25 Sep 2013 15:29:06 -0400 Subject: [PATCH 51/62] Backed out changeset 272dabb40b3d (bug 843019) for mochitest-bc failures. --- .../netmonitor/netmonitor-controller.js | 1 - .../devtools/netmonitor/netmonitor-view.js | 8 +- browser/devtools/scratchpad/scratchpad.js | 11 ++- .../widgets/VariablesViewController.jsm | 36 +-------- browser/devtools/webconsole/test/Makefile.in | 1 - ...onsole_bug_843019_variables_view_filter.js | 79 ------------------- browser/devtools/webconsole/webconsole.js | 15 ++-- 7 files changed, 24 insertions(+), 127 deletions(-) delete mode 100644 browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js diff --git a/browser/devtools/netmonitor/netmonitor-controller.js b/browser/devtools/netmonitor/netmonitor-controller.js index 8ff53a2d409e..c49d0b37df88 100644 --- a/browser/devtools/netmonitor/netmonitor-controller.js +++ b/browser/devtools/netmonitor/netmonitor-controller.js @@ -65,7 +65,6 @@ Cu.import("resource:///modules/devtools/sourceeditor/source-editor.jsm"); Cu.import("resource:///modules/devtools/shared/event-emitter.js"); Cu.import("resource:///modules/devtools/SideMenuWidget.jsm"); Cu.import("resource:///modules/devtools/VariablesView.jsm"); -Cu.import("resource:///modules/devtools/VariablesViewController.jsm"); Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", diff --git a/browser/devtools/netmonitor/netmonitor-view.js b/browser/devtools/netmonitor/netmonitor-view.js index ef9c63a20944..40887523f1b2 100644 --- a/browser/devtools/netmonitor/netmonitor-view.js +++ b/browser/devtools/netmonitor/netmonitor-view.js @@ -1539,7 +1539,6 @@ NetworkDetailsView.prototype = { Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, { searchPlaceholder: L10N.getStr("jsonFilterText") })); - VariablesViewController.attach(this._json); this._paramsQueryString = L10N.getStr("paramsQueryString"); this._paramsFormData = L10N.getStr("paramsFormData"); @@ -1890,10 +1889,9 @@ NetworkDetailsView.prototype = { ? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1)) : L10N.getStr("jsonScopeName"); - this._json.controller.setSingleVariable({ - label: jsonScopeName, - rawObject: jsonObject, - }); + let jsonScope = this._json.addScope(jsonScopeName); + jsonScope.addItem().populate(jsonObject, { expanded: true }); + jsonScope.expanded = true; } // Malformed JSON. else { diff --git a/browser/devtools/scratchpad/scratchpad.js b/browser/devtools/scratchpad/scratchpad.js index fc9fbec839d4..ab835ec699c7 100644 --- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -1816,8 +1816,15 @@ ScratchpadSidebar.prototype = { */ _update: function SS__update(aObject) { - let options = { objectActor: aObject }; - return this.variablesView.controller.setSingleVariable(options).expanded; + let view = this.variablesView; + view.empty(); + + let scope = view.addScope(); + scope.expanded = true; + scope.locked = true; + + let container = scope.addItem(); + return view.controller.expand(container, aObject); } }; diff --git a/browser/devtools/shared/widgets/VariablesViewController.jsm b/browser/devtools/shared/widgets/VariablesViewController.jsm index 0f42bfcb45d0..97c1a5b5c918 100644 --- a/browser/devtools/shared/widgets/VariablesViewController.jsm +++ b/browser/devtools/shared/widgets/VariablesViewController.jsm @@ -40,7 +40,7 @@ this.EXPORTED_SYMBOLS = ["VariablesViewController"]; * * @param VariablesView aView * The view to attach to. - * @param object aOptions [optional] + * @param object aOptions * Options for configuring the controller. Supported options: * - getObjectClient: callback for creating an object grip client * - getLongStringClient: callback for creating a long string grip client @@ -49,7 +49,7 @@ this.EXPORTED_SYMBOLS = ["VariablesViewController"]; * - getterOrSetterEvalMacro: callback for creating a getter/setter eval macro * - simpleValueEvalMacro: callback for creating a simple value eval macro */ -function VariablesViewController(aView, aOptions = {}) { +function VariablesViewController(aView, aOptions) { this.addExpander = this.addExpander.bind(this); this._getObjectClient = aOptions.getObjectClient; @@ -341,38 +341,6 @@ VariablesViewController.prototype = { } } }, - - /** - * Helper function for setting up a single Scope with a single Variable - * contained within it. - * - * @param object aOptions - * Options for the contents of the view: - * - objectActor: the grip of the new ObjectActor to show. - * - rawObject: the new raw object to show. - * - label: the new label for the inspected object. - * @return Object - * - variable: the created Variable. - * - expanded: the Promise that resolves when the variable expands. - */ - setSingleVariable: function(aOptions) { - this.view.empty(); - let scope = this.view.addScope(aOptions.label); - scope.expanded = true; - scope.locked = true; - - let variable = scope.addItem(); - let expanded; - - if (aOptions.objectActor) { - expanded = this.expand(variable, aOptions.objectActor); - } else if (aOptions.rawObject) { - variable.populate(aOptions.rawObject, { expanded: true }); - expanded = promise.resolve(); - } - - return { variable: variable, expanded: expanded }; - }, }; diff --git a/browser/devtools/webconsole/test/Makefile.in b/browser/devtools/webconsole/test/Makefile.in index 658e83ccd5b5..2fee168b4ea3 100644 --- a/browser/devtools/webconsole/test/Makefile.in +++ b/browser/devtools/webconsole/test/Makefile.in @@ -92,7 +92,6 @@ MOCHITEST_BROWSER_FILES = \ browser_webconsole_bug_770099_violation.js \ browser_webconsole_bug_766001_JS_Console_in_Debugger.js \ browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js \ - browser_webconsole_bug_843019_variables_view_filter.js \ browser_cached_messages.js \ browser_bug664688_sandbox_update_after_navigation.js \ browser_result_format_as_string.js \ diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js b/browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js deleted file mode 100644 index cbc449ce249e..000000000000 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_843019_variables_view_filter.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ - -// Test for bug 843019. -// Check that variables view filter works as expected in the web console. - -const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-eval-in-stackframe.html"; - -let gVariablesView; - -function test() -{ - addTab(TEST_URI); - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - openConsole(null, consoleOpened); - }, true); -} - -function consoleOpened(hud) -{ - hud.jsterm.execute("fooObj", (msg) => { - ok(msg, "output message found"); - isnot(msg.textContent.indexOf("[object Object]"), -1, "message text check"); - - hud.jsterm.once("variablesview-fetched", (aEvent, aVar) => { - gVariablesView = aVar._variablesView; - ok(gVariablesView, "variables view object"); - - findVariableViewProperties(aVar, [ - { name: "testProp", value: "testValue" }, - ], { webconsole: hud }).then(onTestPropFound); - }); - - let anchor = msg.querySelector("a"); - executeSoon(() => - EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow) - ); - }); -} - -let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console; - -function onTestPropFound([result]) -{ - let target = result.matchedProp.target; - let searchbox = gVariablesView._searchboxContainer.firstChild; - gVariablesView.lazySearch = false; - - searchbox.addEventListener("focus", function onFocus() { - searchbox.removeEventListener("focus", onFocus); - - // Test initial state. - ok(!target.hasAttribute("non-match"), - "Property starts visible"); - - // Test a non-matching search. - EventUtils.sendChar("x"); - ok(target.hasAttribute("non-match"), - "Property is hidden on non-matching search"); - - // Test clearing the search. - EventUtils.sendKey("ESCAPE"); - ok(!target.hasAttribute("non-match"), - "Pressing ESC makes the property visible again"); - - // Test a matching search. - EventUtils.sendChar("t"); - ok(!target.hasAttribute("non-match"), - "Property still visible when search matches"); - - gVariablesView = null; - finishTest(); - }); - - searchbox.focus(); -} diff --git a/browser/devtools/webconsole/webconsole.js b/browser/devtools/webconsole/webconsole.js index f4a38567bc7f..f330dcce38b9 100644 --- a/browser/devtools/webconsole/webconsole.js +++ b/browser/devtools/webconsole/webconsole.js @@ -3481,13 +3481,20 @@ JSTerm.prototype = { view.delete = null; } - let { variable, expanded } = view.controller.setSingleVariable(aOptions); - variable.evaluationMacro = simpleValueEvalMacro; + let scope = view.addScope(aOptions.label); + scope.expanded = true; + scope.locked = true; + + let container = scope.addItem(); + container.evaluationMacro = simpleValueEvalMacro; if (aOptions.objectActor) { + view.controller.expand(container, aOptions.objectActor); view._consoleLastObjectActor = aOptions.objectActor.actor; } else if (aOptions.rawObject) { + container.populate(aOptions.rawObject); + view.commitHierarchy(); view._consoleLastObjectActor = null; } else { @@ -3495,9 +3502,7 @@ JSTerm.prototype = { "display."); } - expanded.then(() => { - this.emit("variablesview-updated", view, aOptions); - }); + this.emit("variablesview-updated", view, aOptions); }, /** From a3a5ce0f416bfffe010b046dd2e0a47e1c3474c8 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Wed, 25 Sep 2013 13:05:57 -0700 Subject: [PATCH 52/62] NO BUG Add Vagrantfile for documentation build environment DONTBUILD (NPOTB) --- build/docs/Vagrantfile | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 build/docs/Vagrantfile diff --git a/build/docs/Vagrantfile b/build/docs/Vagrantfile new file mode 100644 index 000000000000..b01e9ebdc638 --- /dev/null +++ b/build/docs/Vagrantfile @@ -0,0 +1,8 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + config.vm.box = "precise64" + config.vm.box_url = "http://files.vagrantup.com/precise64.box" + config.vm.synced_folder "../..", "/gecko" +end From dc1d69b5471f608bde0b649780aea8006d31223a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 25 Sep 2013 16:07:08 -0400 Subject: [PATCH 53/62] Bug 919603 followup. Make sure EventTarget has a [Global] descendant, so it actually works right. r=peterv pending, because CLOSED TREE --- dom/webidl/DummyBinding.webidl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/webidl/DummyBinding.webidl b/dom/webidl/DummyBinding.webidl index 62dde6264f87..4ee74ac824dd 100644 --- a/dom/webidl/DummyBinding.webidl +++ b/dom/webidl/DummyBinding.webidl @@ -7,7 +7,8 @@ // Dummy bindings that we need to force generation of things that // aren't actually referenced anywhere in IDL yet but are used in C++. -interface DummyInterface { +[Global] +interface DummyInterface : EventTarget { readonly attribute OnErrorEventHandlerNonNull onErrorEventHandler; FilePropertyBag fileBag(); InspectorRGBTriple rgbTriple(); From 5c2f9237786d608dc9880b0d20df0cd09da758ba Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 25 Sep 2013 13:41:29 -0700 Subject: [PATCH 54/62] Bug 875924 - Initialize the NewTabUtils thumbnail expiration filter [r=sfoster] --- browser/metro/base/content/TopSites.js | 5 +---- browser/metro/base/content/browser-scripts.js | 3 +++ browser/metro/base/content/browser-ui.js | 2 +- browser/metro/base/content/startui/TopSitesView.js | 6 ------ 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/browser/metro/base/content/TopSites.js b/browser/metro/base/content/TopSites.js index e5cd48b2c297..55e9058f8939 100644 --- a/browser/metro/base/content/TopSites.js +++ b/browser/metro/base/content/TopSites.js @@ -8,10 +8,6 @@ * singleton to provide data-level functionality to the views */ let TopSites = { - _initialized: false, - - Site: Site, - prepareCache: function(aForce){ // front to the NewTabUtils' links cache // -ensure NewTabUtils.links links are pre-cached @@ -151,6 +147,7 @@ let TopSites = { this._sitesDirty.clear(); this.update(); }, + _linkFromNode: function _linkFromNode(aNode) { return { url: aNode.getAttribute("value"), diff --git a/browser/metro/base/content/browser-scripts.js b/browser/metro/base/content/browser-scripts.js index e38884cb7d53..5d426ec04052 100644 --- a/browser/metro/base/content/browser-scripts.js +++ b/browser/metro/base/content/browser-scripts.js @@ -16,6 +16,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "Downloads", XPCOMUtils.defineLazyModuleGetter(this, "FormHistory", "resource://gre/modules/FormHistory.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", + "resource://gre/modules/PageThumbs.jsm"); + XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm"); diff --git a/browser/metro/base/content/browser-ui.js b/browser/metro/base/content/browser-ui.js index 358f9e0e094e..3dbd5775f123 100644 --- a/browser/metro/base/content/browser-ui.js +++ b/browser/metro/base/content/browser-ui.js @@ -4,7 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -Cu.import("resource://gre/modules/PageThumbs.jsm"); Cu.import("resource://gre/modules/devtools/dbg-server.jsm") /** @@ -108,6 +107,7 @@ var BrowserUI = { PanelUI.init(); FlyoutPanelsUI.init(); PageThumbs.init(); + NewTabUtils.init(); SettingsCharm.init(); NavButtonSlider.init(); diff --git a/browser/metro/base/content/startui/TopSitesView.js b/browser/metro/base/content/startui/TopSitesView.js index 6b3f30dad551..f550b59b7f61 100644 --- a/browser/metro/base/content/startui/TopSitesView.js +++ b/browser/metro/base/content/startui/TopSitesView.js @@ -21,7 +21,6 @@ function TopSitesView(aGrid, aMaxSites) { getService(Ci.nsINavHistoryService); history.addObserver(this, false); - PageThumbs.addExpirationFilter(this); Services.obs.addObserver(this, "Metro:RefreshTopsiteThumbnail", false); NewTabUtils.allPages.register(this); @@ -40,7 +39,6 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), { destruct: function destruct() { Services.obs.removeObserver(this, "Metro:RefreshTopsiteThumbnail"); - PageThumbs.removeExpirationFilter(this); NewTabUtils.allPages.unregister(this); if (StartUI.chromeWin) { StartUI.chromeWin.removeEventListener('MozAppbarDismissing', this, false); @@ -216,10 +214,6 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), { } }, - filterForThumbnailExpiration: function filterForThumbnailExpiration(aCallback) { - aCallback([item.getAttribute("value") for (item of this._set.children)]); - }, - isFirstRun: function isFirstRun() { return prefs.getBoolPref("browser.firstrun.show.localepicker"); }, From b876771668437efb9a4a3f424225ecbc9dae4068 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 25 Sep 2013 13:42:09 -0700 Subject: [PATCH 55/62] Bug 920333 - Use a white background by default for thumbnail tile icon and label [r=sfoster] --- browser/metro/theme/tiles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/metro/theme/tiles.css b/browser/metro/theme/tiles.css index f93d6a56a883..b78f174cc403 100644 --- a/browser/metro/theme/tiles.css +++ b/browser/metro/theme/tiles.css @@ -111,7 +111,6 @@ richgriditem:not([tiletype="thumbnail"]) .tile-start-container { richgriditem:not([iconURI]) .tile-icon-box, richgriditem[iconURI=""] .tile-icon-box, richgriditem[iconsize="large"] .tile-icon-box { - background-color: transparent!important; border-color: transparent!important; padding: 4px; } @@ -129,6 +128,7 @@ richgriditem[iconsize="large"] .tile-icon-box > image, left: 52px; /* label goes to the right of the favicon */ right: 0; padding: 1em 6px 6px 12px; + background: white; color: #333; margin: 0; -moz-margin-start: 0; From 5ba817092303607cd4d028e09d69df5ea8cbc95a Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 25 Sep 2013 13:42:46 -0700 Subject: [PATCH 56/62] Bug 900072 - Work around line wrapping bugs in flyoutpanels [r=sfoster] --- browser/metro/base/content/browser.xul | 10 +++++++--- browser/metro/theme/flyoutpanel.css | 4 ---- browser/metro/theme/platform.css | 13 ++++++++++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/browser/metro/base/content/browser.xul b/browser/metro/base/content/browser.xul index 888ebf3bdcf9..9781b20792d0 100644 --- a/browser/metro/base/content/browser.xul +++ b/browser/metro/base/content/browser.xul @@ -424,6 +424,7 @@