author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Mon, 29 Feb 2016 11:35:30 +0100 | |
changeset 285999 | 9da51cb4974e03cdd8fa45a34086fe1033abfeaf |
parent 285796 | 4972f77869de55becd41d6b726b25fca2f523232 (current diff) |
parent 285998 | 7882aa8df614f30d441d924afcc93c1539cc3118 (diff) |
child 286000 | e153836569007d614aa6b2260f30f0e8994e69e4 |
child 286001 | 008d7f4d10bf9694b2dc3bdd3568575e22cdbf6a |
child 286069 | 164b34c28be4c5415b9a5c8e09a1c422cabed902 |
push id | 30036 |
push user | cbook@mozilla.com |
push date | Mon, 29 Feb 2016 10:35:59 +0000 |
treeherder | mozilla-central@9da51cb4974e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 47.0a1 |
first release with | nightly linux32
9da51cb4974e
/
47.0a1
/
20160229030448
/
files
nightly linux64
9da51cb4974e
/
47.0a1
/
20160229030448
/
files
nightly mac
9da51cb4974e
/
47.0a1
/
20160229030448
/
files
nightly win32
9da51cb4974e
/
47.0a1
/
20160229030448
/
files
nightly win64
9da51cb4974e
/
47.0a1
/
20160229030448
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
47.0a1
/
20160229030448
/
pushlog to previous
nightly linux64
47.0a1
/
20160229030448
/
pushlog to previous
nightly mac
47.0a1
/
20160229030448
/
pushlog to previous
nightly win32
47.0a1
/
20160229030448
/
pushlog to previous
nightly win64
47.0a1
/
20160229030448
/
pushlog to previous
|
--- a/accessible/base/TreeWalker.cpp +++ b/accessible/base/TreeWalker.cpp @@ -16,134 +16,124 @@ using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // TreeWalker //////////////////////////////////////////////////////////////////////////////// TreeWalker:: - TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) : - mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aContent), - mFlags(aFlags) + TreeWalker(Accessible* aContext) : + mDoc(aContext->Document()), mContext(aContext), mAnchorNode(nullptr), + mARIAOwnsIdx(0), + mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0) { - NS_ASSERTION(aContent, "No node for the accessible tree walker!"); + mChildFilter |= mContext->NoXBLKids() ? + nsIContent::eAllButXBL : nsIContent::eAllChildren; + + mAnchorNode = mContext->IsDoc() ? + mDoc->DocumentNode()->GetRootElement() : mContext->GetContent(); + + if (mAnchorNode) { + PushState(mAnchorNode); + } - mChildFilter = mContext->NoXBLKids() ? + MOZ_COUNT_CTOR(TreeWalker); +} + +TreeWalker:: + TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) : + mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode), + mARIAOwnsIdx(0), + mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags) +{ + MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker"); + MOZ_ASSERT(mDoc->GetAccessibleOrContainer(aAnchorNode) == mContext, + "Unexpected anchor node was given"); + + mChildFilter |= mContext->NoXBLKids() ? nsIContent::eAllButXBL : nsIContent::eAllChildren; - mChildFilter |= nsIContent::eSkipPlaceholderContent; - if (aContent) - PushState(aContent); + PushState(aAnchorNode); MOZ_COUNT_CTOR(TreeWalker); } TreeWalker::~TreeWalker() { MOZ_COUNT_DTOR(TreeWalker); } //////////////////////////////////////////////////////////////////////////////// // TreeWalker: private Accessible* TreeWalker::Next() { - if (mStateStack.IsEmpty()) - return nullptr; + if (mStateStack.IsEmpty()) { + return mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++); + } - ChildrenIterator* top = &mStateStack[mStateStack.Length() - 1]; + dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1]; while (top) { - Accessible* child = nullptr; - bool skipSubtree = false; - while (nsIContent* childNode = Next(top, &child, &skipSubtree)) { - if (child) + while (nsIContent* childNode = top->GetNextChild()) { + bool skipSubtree = false; + Accessible* child = nullptr; + if (mFlags & eWalkCache) { + child = mDoc->GetAccessible(childNode); + } + else if (mContext->IsAcceptableChild(childNode)) { + child = GetAccService()-> + GetOrCreateAccessible(childNode, mContext, &skipSubtree); + } + + // Ignore the accessible and its subtree if it was repositioned by means + // of aria-owns. + if (child) { + if (child->IsRelocated()) { + continue; + } return child; + } // Walk down into subtree to find accessibles. - if (!skipSubtree && childNode->IsElement()) + if (!skipSubtree && childNode->IsElement()) { top = PushState(childNode); + } } - top = PopState(); } // If we traversed the whole subtree of the anchor node. Move to next node // relative anchor node within the context subtree if possible. if (mFlags != eWalkContextTree) - return nullptr; + return Next(); nsINode* contextNode = mContext->GetNode(); while (mAnchorNode != contextNode) { nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent(); if (!parentNode || !parentNode->IsElement()) return nullptr; nsIContent* parent = parentNode->AsElement(); top = PushState(parent); - if (top->mDOMIter.Seek(mAnchorNode)) { + if (top->Seek(mAnchorNode)) { mAnchorNode = parent; return Next(); } // XXX We really should never get here, it means we're trying to find an // accessible for a dom node where iterating over its parent's children // doesn't return it. However this sometimes happens when we're asked for // the nearest accessible to place holder content which we ignore. mAnchorNode = parent; } - return nullptr; + return Next(); } -nsIContent* -TreeWalker::Next(ChildrenIterator* aIter, Accessible** aAccesible, - bool* aSkipSubtree) -{ - nsIContent* childEl = aIter->mDOMIter.GetNextChild(); - if (!aAccesible) - return childEl; - - *aAccesible = nullptr; - *aSkipSubtree = false; - - if (childEl) { - Accessible* accessible = nullptr; - if (mFlags & eWalkCache) { - accessible = mDoc->GetAccessible(childEl); - } - else if (mContext->IsAcceptableChild(childEl)) { - accessible = GetAccService()-> - GetOrCreateAccessible(childEl, mContext, aSkipSubtree); - } - - // Ignore the accessible and its subtree if it was repositioned by means of - // aria-owns. - if (accessible) { - if (accessible->IsRelocated()) { - *aSkipSubtree = true; - } else { - *aAccesible = accessible; - } - } - return childEl; - } - - // At last iterate over ARIA owned children. - Accessible* parent = mDoc->GetAccessible(aIter->mDOMIter.Parent()); - if (parent) { - Accessible* child = mDoc->ARIAOwnedAt(parent, aIter->mARIAOwnsIdx++); - if (child) { - *aAccesible = child; - return child->GetContent(); - } - } - return nullptr; -} - -TreeWalker::ChildrenIterator* +dom::AllChildrenIterator* TreeWalker::PopState() { size_t length = mStateStack.Length(); mStateStack.RemoveElementAt(length - 1); return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1]; }
--- a/accessible/base/TreeWalker.h +++ b/accessible/base/TreeWalker.h @@ -28,71 +28,70 @@ public: enum { // used to walk the existing tree of the given node eWalkCache = 1, // used to walk the context tree starting from given node eWalkContextTree = 2 | eWalkCache }; /** - * Constructor + * Used to navigate and create if needed the accessible children. + */ + explicit TreeWalker(Accessible* aContext); + + /** + * Used to navigate the accessible children relative to the anchor. * * @param aContext [in] container accessible for the given node, used to * define accessible context - * @param aNode [in] the node the search will be prepared relative to + * @param aAnchorNode [in] the node the search will be prepared relative to * @param aFlags [in] flags (see enum above) */ - TreeWalker(Accessible* aContext, nsIContent* aNode, uint32_t aFlags = 0); + TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags = 0); + ~TreeWalker(); /** * Return the next accessible. * * @note Returned accessible is bound to the document, if the accessible is * rejected during tree creation then the caller should be unbind it * from the document. */ Accessible* Next(); private: TreeWalker(); TreeWalker(const TreeWalker&); TreeWalker& operator =(const TreeWalker&); - struct ChildrenIterator { - ChildrenIterator(nsIContent* aNode, uint32_t aFilter) : - mDOMIter(aNode, aFilter), mARIAOwnsIdx(0) { } - - dom::AllChildrenIterator mDOMIter; - uint32_t mARIAOwnsIdx; - }; - - nsIContent* Next(ChildrenIterator* aIter, Accessible** aAccessible = nullptr, - bool* aSkipSubtree = nullptr); - /** * Create new state for the given node and push it on top of stack. * * @note State stack is used to navigate up/down the DOM subtree during * accessible children search. */ - ChildrenIterator* PushState(nsIContent* aContent) + dom::AllChildrenIterator* PushState(nsIContent* aContent) { - return mStateStack.AppendElement(ChildrenIterator(aContent, mChildFilter)); + return mStateStack.AppendElement( + dom::AllChildrenIterator(aContent, mChildFilter)); } /** * Pop state from stack. */ - ChildrenIterator* PopState(); + dom::AllChildrenIterator* PopState(); DocAccessible* mDoc; Accessible* mContext; nsIContent* mAnchorNode; - AutoTArray<ChildrenIterator, 20> mStateStack; + + AutoTArray<dom::AllChildrenIterator, 20> mStateStack; + uint32_t mARIAOwnsIdx; + int32_t mChildFilter; uint32_t mFlags; }; } // namespace a11y } // namespace mozilla #endif // mozilla_a11y_TreeWalker_h_
--- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -2536,20 +2536,19 @@ Accessible::LastRelease() } // ... then die. delete this; } void Accessible::CacheChildren() { - DocAccessible* doc = Document(); - NS_ENSURE_TRUE_VOID(doc); - - TreeWalker walker(this, mContent); + NS_ENSURE_TRUE_VOID(Document()); + + TreeWalker walker(this); Accessible* child = nullptr; while ((child = walker.Next()) && AppendChild(child)); } void Accessible::TestChildCache(Accessible* aCachedChild) const {
--- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -1243,16 +1243,22 @@ DocAccessible::GetAccessibleOrContainer( // Fallback to just get parent node, in case there is no parent content // node. Or current node is not a content node. if (!parent) parent = currNode->GetParentNode(); if (!(currNode = parent)) break; } + // HTML comboboxes have no-content list accessible as an intermediate + // containing all options. + if (accessible && accessible->IsHTMLCombobox()) { + return accessible->FirstChild(); + } + return accessible; } Accessible* DocAccessible::GetAccessibleOrDescendant(nsINode* aNode) const { Accessible* acc = GetAccessible(aNode); if (acc) @@ -1414,35 +1420,16 @@ if (!aNode->IsContent() || !aNode->AsCon return nullptr; } } return GetAccessible(aNode); } //////////////////////////////////////////////////////////////////////////////// -// Accessible protected - -void -DocAccessible::CacheChildren() -{ - // Search for accessible children starting from the document element since - // some web pages tend to insert elements under it rather than document body. - dom::Element* rootElm = mDocumentNode->GetRootElement(); - if (!rootElm) - return; - - TreeWalker walker(this, rootElm); - Accessible* child = nullptr; - while ((child = walker.Next())) { - AppendChild(child); - } -} - -//////////////////////////////////////////////////////////////////////////////// // Protected members void DocAccessible::NotifyOfLoading(bool aIsReloading) { // Mark the document accessible as loading, if it stays alive then we'll mark // it as loaded when we receive proper notification. mLoadState &= ~eDOMLoaded; @@ -1720,21 +1707,16 @@ DocAccessible::ProcessContentInserted(Ac SetRoleMapEntry(aria::GetRoleMap(mContent)); } // Continue to update the tree even if we don't have root content. // For example, elements may be inserted under the document element while // there is no HTML body element. } - // HTML comboboxes have no-content list accessible as an intermidiate - // containing all options. - if (container->IsHTMLCombobox()) - container = container->FirstChild(); - // We have a DOM/layout change under the container accessible, and its tree // might need an update. Since DOM/layout change of the element may affect // on the accessibleness of adjacent elements (for example, insertion of // extra HTML:body make the old body accessible) then we have to recache // children of the container, and then fire show/hide events for a change. UpdateTreeOnInsertion(container); break; }
--- a/accessible/generic/DocAccessible.h +++ b/accessible/generic/DocAccessible.h @@ -354,19 +354,16 @@ public: */ DocAccessibleChild* IPCDoc() const { return mIPCDoc; } protected: virtual ~DocAccessible(); void LastRelease(); - // Accessible - virtual void CacheChildren() override; - // DocAccessible virtual nsresult AddEventListeners(); virtual nsresult RemoveEventListeners(); /** * Marks this document as loaded or loading. */ void NotifyOfLoad(uint32_t aLoadEventType);
--- a/accessible/html/HTMLSelectAccessible.cpp +++ b/accessible/html/HTMLSelectAccessible.cpp @@ -109,45 +109,22 @@ HTMLSelectListAccessible::CurrentItem() void HTMLSelectListAccessible::SetCurrentItem(Accessible* aItem) { aItem->GetContent()->SetAttr(kNameSpaceID_None, nsGkAtoms::selected, NS_LITERAL_STRING("true"), true); } -//////////////////////////////////////////////////////////////////////////////// -// HTMLSelectListAccessible: Accessible protected - -void -HTMLSelectListAccessible::CacheChildren() +bool +HTMLSelectListAccessible::IsAcceptableChild(nsIContent* aEl) const { - // Cache accessibles for <optgroup> and <option> DOM decendents as children, - // as well as the accessibles for them. Avoid whitespace text nodes. We want - // to count all the <optgroup>s and <option>s as children because we want - // a flat tree under the Select List. - for (nsIContent* childContent = mContent->GetFirstChild(); childContent; - childContent = childContent->GetNextSibling()) { - if (!childContent->IsHTMLElement()) { - continue; - } - - if (childContent->IsAnyOfHTMLElements(nsGkAtoms::option, - nsGkAtoms::optgroup)) { - - // Get an accessible for option or optgroup and cache it. - RefPtr<Accessible> accessible = - GetAccService()->GetOrCreateAccessible(childContent, this); - if (accessible) - AppendChild(accessible); - } - } + return aEl->IsAnyOfHTMLElements(nsGkAtoms::option, nsGkAtoms::optgroup); } - //////////////////////////////////////////////////////////////////////////////// // HTMLSelectOptionAccessible //////////////////////////////////////////////////////////////////////////////// HTMLSelectOptionAccessible:: HTMLSelectOptionAccessible(nsIContent* aContent, DocAccessible* aDoc) : HyperTextAccessibleWrap(aContent, aDoc) {
--- a/accessible/html/HTMLSelectAccessible.h +++ b/accessible/html/HTMLSelectAccessible.h @@ -46,20 +46,17 @@ public: // Widgets virtual bool IsWidget() const override; virtual bool IsActiveWidget() const override; virtual bool AreItemsOperable() const override; virtual Accessible* CurrentItem() override; virtual void SetCurrentItem(Accessible* aItem) override; -protected: - - // Accessible - virtual void CacheChildren() override; + virtual bool IsAcceptableChild(nsIContent* aEl) const override; }; /* * Options inside the select, contained within the list */ class HTMLSelectOptionAccessible : public HyperTextAccessibleWrap { public:
--- a/accessible/mac/mozActionElements.mm +++ b/accessible/mac/mozActionElements.mm @@ -246,21 +246,23 @@ enum CheckboxValue { /** * Returns the selected tab (the mozAccessible) */ - (id)value { mozAccessible* nativeAcc = nil; if (AccessibleWrap* accWrap = [self getGeckoAccessible]) { - Accessible* accTab = accWrap->GetSelectedItem(0); - accTab->GetNativeInterface((void**)&nativeAcc); + if (Accessible* accTab = accWrap->GetSelectedItem(0)) { + accTab->GetNativeInterface((void**)&nativeAcc); + } } else if (ProxyAccessible* proxy = [self getProxyAccessible]) { - ProxyAccessible* proxyTab = proxy->GetSelectedItem(0); - nativeAcc = GetNativeFromProxy(proxyTab); + if (ProxyAccessible* proxyTab = proxy->GetSelectedItem(0)) { + nativeAcc = GetNativeFromProxy(proxyTab); + } } return nativeAcc; } /** * Return the mozAccessibles that are the tabs. */
--- a/accessible/tests/mochitest/treeupdate/test_optgroup.html +++ b/accessible/tests/mochitest/treeupdate/test_optgroup.html @@ -97,17 +97,17 @@ } this.getID = function removeOptGroup_getID() { return "test optgroup's removal from a select"; } } -// gA11yEventDumpToConsole = true; + //gA11yEventDumpToConsole = true; function doTest() { gQueue = new eventQueue(); gQueue.push(new addOptGroup("select")); gQueue.push(new removeOptGroup("select"));
--- a/addon-sdk/source/test/addons/jetpack-addon.ini +++ b/addon-sdk/source/test/addons/jetpack-addon.ini @@ -37,10 +37,9 @@ skip-if = true [self.xpi] [simple-prefs.xpi] [simple-prefs-l10n.xpi] [simple-prefs-regression.xpi] [standard-id.xpi] [tab-close-on-startup.xpi] [toolkit-require-reload.xpi] [translators.xpi] -[unpacked.xpi] [unsafe-content-script.xpi]
--- a/addon-sdk/source/test/addons/main/main.js +++ b/addon-sdk/source/test/addons/main/main.js @@ -12,17 +12,19 @@ exports.main = function main(options, ca let tests = {}; tests.testMainArguments = function(assert) { assert.ok(!!options, 'options argument provided to main'); assert.ok('loadReason' in options, 'loadReason is in options provided by main'); assert.equal(typeof callbacks.print, 'function', 'callbacks.print is a function'); assert.equal(typeof callbacks.quit, 'function', 'callbacks.quit is a function'); - assert.equal(options.loadReason, 'install', 'options.loadReason is install'); + + // Re-enable when bug 1251664 is fixed + //assert.equal(options.loadReason, 'install', 'options.loadReason is install'); } require('sdk/test/runner').runTestsFromModule({exports: tests}); } // this causes a fail if main does not start setTimeout(function() { if (mainStarted)
deleted file mode 100644 --- a/addon-sdk/source/test/addons/unpacked/main.js +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -const { packed } = require("sdk/self"); -const url = require("sdk/url"); - -exports["test self.packed"] = function (assert) { - assert.ok(!packed, "require('sdk/self').packed is correct"); -} - -exports["test url.toFilename"] = function (assert) { - assert.ok(/.*main\.js$/.test(url.toFilename(module.uri)), - "url.toFilename() on resource: URIs should work"); -} - -require("sdk/test/runner").runTestsFromModule(module);
deleted file mode 100644 --- a/addon-sdk/source/test/addons/unpacked/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": "test-url@jetpack", - "unpack": true, - "main": "./main.js", - "version": "0.0.1" -}
--- a/b2g/locales/en-US/chrome/overrides/appstrings.properties +++ b/b2g/locales/en-US/chrome/overrides/appstrings.properties @@ -26,15 +26,15 @@ unsafeContentType=The page you are tryin externalProtocolTitle=External Protocol Request externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n #LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined externalProtocolUnknown=<Unknown> externalProtocolChkMsg=Remember my choice for all links of this type. externalProtocolLaunchBtn=Launch application malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences. unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences. -phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information. +deceptiveBlocked=This web page at %S has been reported as a deceptive site and has been blocked based on your security preferences. forbiddenBlocked=The site at %S has been blocked by your browser configuration. cspBlocked=This page has a content security policy that prevents it from being loaded in this way. corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected. remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox. sslv3Used=Firefox cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol. weakCryptoUsed=The owner of %S has configured their website improperly. To protect your information from being stolen, Firefox has not connected to this website.
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1196,20 +1196,16 @@ pref("dom.ipc.plugins.sandbox-level.flas // See - security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp // SetSecurityLevelForContentProcess() for what the different settings mean. #if defined(NIGHTLY_BUILD) pref("security.sandbox.content.level", 2); #else pref("security.sandbox.content.level", 0); #endif -// ID (a UUID when set by gecko) that is used as a per profile suffix to a low -// integrity temp directory. -pref("security.sandbox.content.tempDirSuffix", ""); - #if defined(MOZ_STACKWALKING) // This controls the depth of stack trace that is logged when Windows sandbox // logging is turned on. This is only currently available for the content // process because the only other sandbox (for GMP) has too strict a policy to // allow stack tracing. This does not require a restart to take effect. pref("security.sandbox.windows.log.stackTraceDepth", 0); #endif #endif @@ -1222,16 +1218,25 @@ pref("security.sandbox.windows.log.stack // 1 -> "an imperfect sandbox designed to allow firefox to run reasonably well" // 2 -> "an ideal sandbox which may break many things" // This setting is read when the content process is started. On Mac the content // process is killed when all windows are closed, so a change will take effect // when the 1st window is opened. pref("security.sandbox.content.level", 1); #endif +#if defined(XP_MACOSX) || defined(XP_WIN) +#if defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX) +// ID (a UUID when set by gecko) that is used to form the name of a +// sandbox-writable temporary directory to be used by content processes +// when a temporary writable file is required in a level 1 sandbox. +pref("security.sandbox.content.tempDirSuffix", ""); +#endif +#endif + // This pref governs whether we attempt to work around problems caused by // plugins using OS calls to manipulate the cursor while running out-of- // process. These workarounds all involve intercepting (hooking) certain // OS calls in the plugin process, then arranging to make certain OS calls // in the browser process. Eventually plugins will be required to use the // NPAPI to manipulate the cursor, and these workarounds will be removed. // See bug 621117. #ifdef XP_MACOSX
--- a/browser/base/content/aboutNetError.xhtml +++ b/browser/base/content/aboutNetError.xhtml @@ -409,19 +409,16 @@ <h1 id="et_netInterrupt">&netInterrupt.title;</h1> <h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1> <h1 id="et_proxyResolveFailure">&proxyResolveFailure.title;</h1> <h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1> <h1 id="et_contentEncodingError">&contentEncodingError.title;</h1> <h1 id="et_unsafeContentType">&unsafeContentType.title;</h1> <h1 id="et_nssFailure2">&nssFailure2.title;</h1> <h1 id="et_nssBadCert">&nssBadCert.title;</h1> - <h1 id="et_malwareBlocked">&malwareBlocked.title;</h1> - <h1 id="et_unwantedBlocked">&unwantedBlocked.title;</h1> - <h1 id="et_forbiddenBlocked">&forbiddenBlocked.title;</h1> <h1 id="et_cspBlocked">&cspBlocked.title;</h1> <h1 id="et_remoteXUL">&remoteXUL.title;</h1> <h1 id="et_corruptedContentError">&corruptedContentError.title;</h1> <h1 id="et_sslv3Used">&sslv3Used.title;</h1> <h1 id="et_weakCryptoUsed">&weakCryptoUsed.title;</h1> </div> <div id="errorDescriptionsContainer"> <div id="ed_generic">&generic.longDesc;</div> @@ -439,19 +436,16 @@ <div id="ed_netInterrupt">&netInterrupt.longDesc;</div> <div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div> <div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc;</div> <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div> <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div> <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div> <div id="ed_nssFailure2">&nssFailure2.longDesc2;</div> <div id="ed_nssBadCert">&nssBadCert.longDesc2;</div> - <div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div> - <div id="ed_unwantedBlocked">&unwantedBlocked.longDesc;</div> - <div id="ed_forbiddenBlocked">&forbiddenBlocked.longDesc;</div> <div id="ed_cspBlocked">&cspBlocked.longDesc;</div> <div id="ed_remoteXUL">&remoteXUL.longDesc;</div> <div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div> <div id="ed_sslv3Used">&sslv3Used.longDesc2;</div> <div id="ed_weakCryptoUsed">&weakCryptoUsed.longDesc2;</div> </div> </div>
--- a/browser/base/content/blockedSite.xhtml +++ b/browser/base/content/blockedSite.xhtml @@ -83,17 +83,17 @@ function initPage() { var error = ""; switch (getErrorCode()) { case "malwareBlocked" : error = "malware"; break; - case "phishingBlocked" : + case "deceptiveBlocked" : error = "phishing"; break; case "unwantedBlocked" : error = "unwanted"; break; case "forbiddenBlocked" : error = "forbidden"; break; @@ -195,35 +195,35 @@ </style> </head> <body dir="&locale.dir;"> <div id="errorPageContainer"> <!-- Error Title --> <div id="errorTitle"> - <h1 id="errorTitleText_phishing">&safeb.blocked.phishingPage.title;</h1> + <h1 id="errorTitleText_phishing">&safeb.blocked.phishingPage.title2;</h1> <h1 id="errorTitleText_malware">&safeb.blocked.malwarePage.title;</h1> <h1 id="errorTitleText_unwanted">&safeb.blocked.unwantedPage.title;</h1> <h1 id="errorTitleText_forbidden">&safeb.blocked.forbiddenPage.title2;</h1> </div> <div id="errorLongContent"> <!-- Short Description --> <div id="errorShortDesc"> - <p id="errorShortDescText_phishing">&safeb.blocked.phishingPage.shortDesc;</p> + <p id="errorShortDescText_phishing">&safeb.blocked.phishingPage.shortDesc2;</p> <p id="errorShortDescText_malware">&safeb.blocked.malwarePage.shortDesc;</p> <p id="errorShortDescText_unwanted">&safeb.blocked.unwantedPage.shortDesc;</p> <p id="errorShortDescText_forbidden">&safeb.blocked.forbiddenPage.shortDesc2;</p> </div> <!-- Long Description --> <div id="errorLongDesc"> - <p id="errorLongDescText_phishing">&safeb.blocked.phishingPage.longDesc;</p> + <p id="errorLongDescText_phishing">&safeb.blocked.phishingPage.longDesc2;</p> <p id="errorLongDescText_malware">&safeb.blocked.malwarePage.longDesc;</p> <p id="errorLongDescText_unwanted">&safeb.blocked.unwantedPage.longDesc;</p> </div> <!-- Action buttons --> <div id="buttons"> <!-- Commands handled in browser.js --> <button id="getMeOutButton">&safeb.palm.accept.label;</button>
--- a/browser/base/content/browser-safebrowsing.js +++ b/browser/base/content/browser-safebrowsing.js @@ -10,17 +10,17 @@ var gSafeBrowsing = { setReportPhishingMenu: function() { // In order to detect whether or not we're at the phishing warning // page, we have to check the documentURI instead of the currentURI. // This is because when the DocShell loads an error page, the // currentURI stays at the original target, while the documentURI // will point to the internal error page we loaded instead. var docURI = gBrowser.selectedBrowser.documentURI; var isPhishingPage = - docURI && docURI.spec.startsWith("about:blocked?e=phishingBlocked"); + docURI && docURI.spec.startsWith("about:blocked?e=deceptiveBlocked"); // Show/hide the appropriate menu item. document.getElementById("menu_HelpPopup_reportPhishingtoolmenu") .hidden = isPhishingPage; document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu") .hidden = !isPhishingPage; var broadcasterId = isPhishingPage
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -2910,20 +2910,20 @@ var BrowserOnClick = { buttons[1] = { label: gNavigatorBundle.getString("safebrowsing.notAnAttackButton.label"), accessKey: gNavigatorBundle.getString("safebrowsing.notAnAttackButton.accessKey"), callback: function() { openUILinkIn(gSafeBrowsing.getReportURL('MalwareMistake'), 'tab'); } }; } else if (reason === 'phishing') { - title = gNavigatorBundle.getString("safebrowsing.reportedWebForgery"); + title = gNavigatorBundle.getString("safebrowsing.deceptiveSite"); buttons[1] = { - label: gNavigatorBundle.getString("safebrowsing.notAForgeryButton.label"), - accessKey: gNavigatorBundle.getString("safebrowsing.notAForgeryButton.accessKey"), + label: gNavigatorBundle.getString("safebrowsing.notADeceptiveSiteButton.label"), + accessKey: gNavigatorBundle.getString("safebrowsing.notADeceptiveSiteButton.accessKey"), callback: function() { openUILinkIn(gSafeBrowsing.getReportURL('PhishMistake'), 'tab'); } }; } else if (reason === 'unwanted') { title = gNavigatorBundle.getString("safebrowsing.reportedUnwantedSite"); // There is no button for reporting errors since Google doesn't currently // provide a URL endpoint for these reports.
--- a/browser/base/content/report-phishing-overlay.xul +++ b/browser/base/content/report-phishing-overlay.xul @@ -13,23 +13,23 @@ <overlay id="reportPhishingMenuOverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <broadcasterset id="mainBroadcasterSet"> <broadcaster id="reportPhishingBroadcaster" disabled="true"/> <broadcaster id="reportPhishingErrorBroadcaster" disabled="true"/> </broadcasterset> <menupopup id="menu_HelpPopup"> <menuitem id="menu_HelpPopup_reportPhishingtoolmenu" - label="&reportPhishSiteMenu.title2;" - accesskey="&reportPhishSiteMenu.accesskey;" + label="&reportDeceptiveSiteMenu.title;" + accesskey="&reportDeceptiveSiteMenu.accesskey;" insertbefore="aboutSeparator" observes="reportPhishingBroadcaster" oncommand="openUILink(gSafeBrowsing.getReportURL('Phish'), event);" onclick="checkForMiddleClick(this, event);"/> <menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu" - label="&safeb.palm.notforgery.label2;" - accesskey="&reportPhishSiteMenu.accesskey;" + label="&safeb.palm.notdeceptive.label;" + accesskey="&reportDeceptiveSiteMenu.accesskey;" insertbefore="aboutSeparator" observes="reportPhishingErrorBroadcaster" oncommand="openUILinkIn(gSafeBrowsing.getReportURL('PhishMistake'), 'tab');" onclick="checkForMiddleClick(this, event);"/> </menupopup> </overlay>
--- a/browser/base/content/test/alerts/browser_notification_close.js +++ b/browser/base/content/test/alerts/browser_notification_close.js @@ -1,16 +1,33 @@ "use strict"; +const {PlacesTestUtils} = + Cu.import("resource://testing-common/PlacesTestUtils.jsm", {}); + let tab; let notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html"; +let oldShowFavicons; add_task(function* test_notificationClose() { let pm = Services.perms; - pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); + let notificationURI = makeURI(notificationURL); + pm.add(notificationURI, "desktop-notification", pm.ALLOW_ACTION); + + oldShowFavicons = Services.prefs.getBoolPref("alerts.showFavicons"); + Services.prefs.setBoolPref("alerts.showFavicons", true); + + yield PlacesTestUtils.addVisits(notificationURI); + let faviconURI = yield new Promise(resolve => { + let faviconURI = makeURI("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC"); + PlacesUtils.favicons.setAndFetchFaviconForPage(notificationURI, faviconURI, + true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + (faviconURI, iconSize, iconData, mimeType) => resolve(faviconURI), + Services.scriptSecurityManager.getSystemPrincipal()); + }); yield BrowserTestUtils.withNewTab({ gBrowser, url: notificationURL }, function* dummyTabTask(aBrowser) { yield openNotification(aBrowser, "showNotification2"); info("Notification alert showing"); @@ -21,16 +38,18 @@ add_task(function* test_notificationClos yield closeNotification(aBrowser); return; } let alertTitleLabel = alertWindow.document.getElementById("alertTitleLabel"); is(alertTitleLabel.value, "Test title", "Title text of notification should be present"); let alertTextLabel = alertWindow.document.getElementById("alertTextLabel"); is(alertTextLabel.textContent, "Test body 2", "Body text of notification should be present"); + let alertIcon = alertWindow.document.getElementById("alertIcon"); + is(alertIcon.src, faviconURI.spec, "Icon of notification should be present"); let alertCloseButton = alertWindow.document.querySelector(".alertCloseButton"); is(alertCloseButton.localName, "toolbarbutton", "close button found"); let promiseBeforeUnloadEvent = BrowserTestUtils.waitForEvent(alertWindow, "beforeunload"); let closedTime = alertWindow.Date.now(); alertCloseButton.click(); info("Clicked on close button"); @@ -42,9 +61,12 @@ add_task(function* test_notificationClos // that the notification closed before the timeout. ok(currentTime - closedTime < 5000, "Close requested at " + closedTime + ", actually closed at " + currentTime); }); }); add_task(function* cleanup() { Services.perms.remove(makeURI(notificationURL), "desktop-notification"); + if (typeof oldShowFavicons == "boolean") { + Services.prefs.setBoolPref("alerts.showFavicons", oldShowFavicons); + } });
--- a/browser/components/sessionstore/SessionFile.jsm +++ b/browser/components/sessionstore/SessionFile.jsm @@ -172,44 +172,62 @@ var SessionFileInternal = { if (SessionFileInternal.latestUpgradeBackupID) { // We have an upgradeBackup order.push("upgradeBackup"); } return order; }, }), - // `true` once `write` has succeeded at last once. - // Used for error-reporting. - _hasWriteEverSucceeded: false, + // Number of attempted calls to `write`. + // Note that we may have _attempts > _successes + _failures, + // if attempts never complete. + // Used for error reporting. + _attempts: 0, + + // Number of successful calls to `write`. + // Used for error reporting. + _successes: 0, + + // Number of failed calls to `write`. + // Used for error reporting. + _failures: 0, // Resolved once initialization is complete. // The promise never rejects. _deferredInitialized: PromiseUtils.defer(), + // `true` once we have started initialization, i.e. once something + // has been scheduled that will eventually resolve `_deferredInitialized`. + _initializationStarted: false, + // The ID of the latest version of Gecko for which we have an upgrade backup // or |undefined| if no upgrade backup was ever written. get latestUpgradeBackupID() { try { return Services.prefs.getCharPref(PREF_UPGRADE_BACKUP); } catch (ex) { return undefined; } }, + // Find the correct session file, read it and setup the worker. read: Task.async(function* () { + this._initializationStarted = true; + let result; let noFilesFound = true; // Attempt to load by order of priority from the various backups for (let key of this.Paths.loadOrder) { let corrupted = false; let exists = true; try { let path = this.Paths[key]; let startMs = Date.now(); + let source = yield OS.File.read(path, { encoding: "utf-8" }); let parsed = JSON.parse(source); if (!SessionStore.isFormatVersionCompatible(parsed.version || ["sessionrestore", 0] /*fallback for old versions*/)) { // Skip sessionstore files that we don't understand. Cu.reportError("Cannot extract data from Session Restore file " + path + ". Wrong format/version: " + JSON.stringify(parsed.version) + "."); continue; } @@ -254,76 +272,100 @@ var SessionFileInternal = { origin: "empty", source: "", parsed: null }; } result.noFilesFound = noFilesFound; - // Initialize the worker to let it handle backups and also + // Initialize the worker (in the background) to let it handle backups and also // as a workaround for bug 964531. - let initialized = SessionWorker.post("init", [result.origin, this.Paths, { + let promiseInitialized = SessionWorker.post("init", [result.origin, this.Paths, { maxUpgradeBackups: Preferences.get(PREF_MAX_UPGRADE_BACKUPS, 3), maxSerializeBack: Preferences.get(PREF_MAX_SERIALIZE_BACK, 10), maxSerializeForward: Preferences.get(PREF_MAX_SERIALIZE_FWD, -1) }]); - initialized.catch(Promise.reject).then(() => this._deferredInitialized.resolve()); + promiseInitialized.catch(err => { + // Ensure that we report errors but that they do not stop us. + Promise.reject(err); + }).then(() => this._deferredInitialized.resolve()); return result; }), + // Post a message to the worker, making sure that it has been initialized + // first. + _postToWorker: Task.async(function*(...args) { + if (!this._initializationStarted) { + // Initializing the worker is somewhat complex, as proper handling of + // backups requires us to first read and check the session. Consequently, + // the only way to initialize the worker is to first call `this.read()`. + + // The call to `this.read()` causes background initialization of the worker. + // Initialization will be complete once `this._deferredInitialized.promise` + // resolves. + this.read(); + } + yield this._deferredInitialized.promise; + return SessionWorker.post(...args) + }), + write: function (aData) { if (RunState.isClosed) { return Promise.reject(new Error("SessionFile is closed")); } let isFinalWrite = false; if (RunState.isClosing) { // If shutdown has started, we will want to stop receiving // write instructions. isFinalWrite = true; RunState.setClosed(); } let performShutdownCleanup = isFinalWrite && !sessionStartup.isAutomaticRestoreEnabled(); + this._attempts++; let options = {isFinalWrite, performShutdownCleanup}; - let promise = this._deferredInitialized.promise.then(() => SessionWorker.post("write", [aData, options])); + let promise = this._postToWorker("write", [aData, options]); // Wait until the write is done. promise = promise.then(msg => { // Record how long the write took. this._recordTelemetry(msg.telemetry); - this._hasWriteEverSucceeded = true; + this._successes++; if (msg.result.upgradeBackup) { // We have just completed a backup-on-upgrade, store the information // in preferences. Services.prefs.setCharPref(PREF_UPGRADE_BACKUP, Services.appinfo.platformBuildID); } }, err => { // Catch and report any errors. console.error("Could not write session state file ", err, err.stack); + this._failures++; // By not doing anything special here we ensure that |promise| cannot // be rejected anymore. The shutdown/cleanup code at the end of the // function will thus always be executed. }); // Ensure that we can write sessionstore.js cleanly before the profile // becomes unaccessible. AsyncShutdown.profileBeforeChange.addBlocker( "SessionFile: Finish writing Session Restore data", promise, { fetchState: () => ({ options, - hasEverSucceeded: this._hasWriteEverSucceeded + attempts: this._attempts, + successes: this._successes, + failures: this._failures, }) }); // This code will always be executed because |promise| can't fail anymore. // We ensured that by having a reject handler that reports the failure but // doesn't forward the rejection. return promise.then(() => { // Remove the blocker, no matter if writing failed or not. @@ -331,17 +373,17 @@ var SessionFileInternal = { if (isFinalWrite) { Services.obs.notifyObservers(null, "sessionstore-final-state-write-complete", ""); } }); }, wipe: function () { - return this._deferredInitialized.promise.then(() => SessionWorker.post("wipe")); + return this._postToWorker("wipe"); }, _recordTelemetry: function(telemetry) { for (let id of Object.keys(telemetry)){ let value = telemetry[id]; let samples = []; if (Array.isArray(value)) { samples.push(...value);
--- a/browser/components/sessionstore/SessionStorage.jsm +++ b/browser/components/sessionstore/SessionStorage.jsm @@ -146,18 +146,20 @@ var SessionStorageInternal = { let hostData = {}; let storage; let window = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow); try { let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager); storage = storageManager.getStorage(window, aPrincipal); + storage.length; // XXX: Bug 1232955 - storage.length can throw, catch that failure } catch (e) { // sessionStorage might throw if it's turned off, see bug 458954 + storage = null; } if (storage && storage.length) { for (let i = 0; i < storage.length; i++) { try { let key = storage.key(i); hostData[key] = storage.getItem(key); } catch (e) {
--- a/browser/components/sessionstore/test/browser.ini +++ b/browser/components/sessionstore/test/browser.ini @@ -47,16 +47,17 @@ support-files = browser_662743_sample.html browser_739531_sample.html browser_911547_sample.html browser_911547_sample.html^headers^ restore_redirect_http.html restore_redirect_http.html^headers^ restore_redirect_js.html restore_redirect_target.html + browser_1234021_page.html #NB: the following are disabled # browser_464620_a.html # browser_464620_b.html # browser_464620_xd.html #disabled-for-intermittent-failures--bug-766044, browser_459906_empty.html @@ -215,8 +216,9 @@ skip-if = os == "mac" [browser_911547.js] [browser_send_async_message_oom.js] [browser_multiple_navigateAndRestore.js] run-if = e10s [browser_async_window_flushing.js] [browser_forget_async_closings.js] [browser_sessionStoreContainer.js] +[browser_1234021.js]
new file mode 100644 --- /dev/null +++ b/browser/components/sessionstore/test/browser_1234021.js @@ -0,0 +1,18 @@ +"use strict"; + +const PREF = 'network.cookie.cookieBehavior'; +const PAGE_URL = 'http://mochi.test:8888/browser/' + + 'browser/components/sessionstore/test/browser_1234021_page.html'; +const BEHAVIOR_REJECT = 2; + +add_task(function* test() { + yield pushPrefs([PREF, BEHAVIOR_REJECT]); + + yield BrowserTestUtils.withNewTab({ + gBrowser: gBrowser, + url: PAGE_URL + }, function* handler(aBrowser) { + yield TabStateFlusher.flush(aBrowser); + ok(true, "Flush didn't time out"); + }); +});
new file mode 100644 --- /dev/null +++ b/browser/components/sessionstore/test/browser_1234021_page.html @@ -0,0 +1,6 @@ +<!doctype html> +<html> + <script> + sessionStorage + </script> +</html>
--- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -398,19 +398,19 @@ pointerLock.title3=Would you like to all pointerLock.autoLock.title3=This site will hide the pointer. # Phishing/Malware Notification Bar. # LOCALIZATION NOTE (notAForgery, notAnAttack) # The two button strings will never be shown at the same time, so # it's okay for them to have the same access key safebrowsing.getMeOutOfHereButton.label=Get me out of here! safebrowsing.getMeOutOfHereButton.accessKey=G -safebrowsing.reportedWebForgery=Reported Web Forgery! -safebrowsing.notAForgeryButton.label=This isn't a web forgery… -safebrowsing.notAForgeryButton.accessKey=F +safebrowsing.deceptiveSite=Deceptive Site! +safebrowsing.notADeceptiveSiteButton.label=This isn't a deceptive site… +safebrowsing.notADeceptiveSiteButton.accessKey=D safebrowsing.reportedAttackSite=Reported Attack Site! safebrowsing.notAnAttackButton.label=This isn't an attack site… safebrowsing.notAnAttackButton.accessKey=A safebrowsing.reportedUnwantedSite=Reported Unwanted Software Site! # Ctrl-Tab # LOCALIZATION NOTE (ctrlTab.listAllTabs.label): #1 represents the number # of tabs in the current browser window. It will always be 2 at least.
--- a/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd +++ b/browser/locales/en-US/chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd @@ -1,29 +1,30 @@ <!-- 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/. --> <!ENTITY safeb.palm.accept.label "Get me out of here!"> <!ENTITY safeb.palm.decline.label "Ignore this warning"> -<!ENTITY safeb.palm.notforgery.label2 "This isn't a web forgery…"> +<!-- Localization note (safeb.palm.notdeceptive.label) - Label of the Help menu item. --> +<!ENTITY safeb.palm.notdeceptive.label "This isn't a deceptive site…"> <!ENTITY safeb.palm.reportPage.label "Why was this page blocked?"> <!ENTITY safeb.palm.whyForbidden.label "Why was this page blocked?"> <!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!"> <!-- Localization note (safeb.blocked.malwarePage.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) --> <!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences."> <!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>"> <!ENTITY safeb.blocked.unwantedPage.title "Reported Unwanted Software Page!"> <!-- Localization note (safeb.blocked.unwantedPage.shortDesc) - Please don't translate the contents of the <span id="unwanted_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) --> <!ENTITY safeb.blocked.unwantedPage.shortDesc "This web page at <span id='unwanted_sitename'/> has been reported to contain unwanted software and has been blocked based on your security preferences."> <!ENTITY safeb.blocked.unwantedPage.longDesc "<p>Unwanted software pages try to install software that can be deceptive and affect your system in unexpected ways.</p>"> -<!ENTITY safeb.blocked.phishingPage.title "Reported Web Forgery!"> -<!-- Localization note (safeb.blocked.phishingPage.shortDesc) - Please don't translate the contents of the <span id="phishing_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) --> -<!ENTITY safeb.blocked.phishingPage.shortDesc "This web page at <span id='phishing_sitename'/> has been reported as a web forgery and has been blocked based on your security preferences."> -<!ENTITY safeb.blocked.phishingPage.longDesc "<p>Web forgeries are designed to trick you into revealing personal or financial information by imitating sources you may trust.</p><p>Entering any information on this web page may result in identity theft or other fraud.</p>"> +<!ENTITY safeb.blocked.phishingPage.title2 "Deceptive Site!"> +<!-- Localization note (safeb.blocked.phishingPage.shortDesc2) - Please don't translate the contents of the <span id="phishing_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) --> +<!ENTITY safeb.blocked.phishingPage.shortDesc2 "This web page at <span id='phishing_sitename'/> has been reported as a deceptive site and has been blocked based on your security preferences."> +<!ENTITY safeb.blocked.phishingPage.longDesc2 "<p>Deceptive sites are designed to trick you into doing something dangerous, like installing software, or revealing your personal information, like passwords, phone numbers or credit cards.</p><p>Entering any information on this web page may result in identity theft or other fraud.</p>"> <!ENTITY safeb.blocked.forbiddenPage.title2 "Blocked Site"> <!-- Localization note (safeb.blocked.forbiddenPage.shortDesc2) - Please don't translate the contents of the <span id="forbidden_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) --> <!ENTITY safeb.blocked.forbiddenPage.shortDesc2 "The Web page at <span id='forbidden_sitename'/> has been blocked by your admin profile.">
--- a/browser/locales/en-US/chrome/browser/safebrowsing/report-phishing.dtd +++ b/browser/locales/en-US/chrome/browser/safebrowsing/report-phishing.dtd @@ -1,6 +1,6 @@ <!-- 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/. --> -<!ENTITY reportPhishSiteMenu.title2 "Report Web Forgery…"> -<!ENTITY reportPhishSiteMenu.accesskey "F"> \ No newline at end of file +<!ENTITY reportDeceptiveSiteMenu.title "Report deceptive site…"> +<!ENTITY reportDeceptiveSiteMenu.accesskey "D">
--- a/browser/locales/en-US/chrome/overrides/appstrings.properties +++ b/browser/locales/en-US/chrome/overrides/appstrings.properties @@ -26,17 +26,17 @@ unsafeContentType=The page you are tryin externalProtocolTitle=External Protocol Request externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n #LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined externalProtocolUnknown=<Unknown> externalProtocolChkMsg=Remember my choice for all links of this type. externalProtocolLaunchBtn=Launch application malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences. unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences. -phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information. +deceptiveBlocked=This web page at %S has been reported as a deceptive site and has been blocked based on your security preferences. forbiddenBlocked=The site at %S has been blocked by your browser configuration. cspBlocked=This page has a content security policy that prevents it from being loaded in this way. corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected. remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox. ## LOCALIZATION NOTE (sslv3Used) - Do not translate "%S". sslv3Used=Firefox cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol. ## LOCALIZATION NOTE (weakCryptoUsed) - Do not translate "%S". weakCryptoUsed=The owner of %S has configured their website improperly. To protect your information from being stolen, Firefox has not connected to this website.
--- a/browser/locales/en-US/chrome/overrides/netError.dtd +++ b/browser/locales/en-US/chrome/overrides/netError.dtd @@ -155,37 +155,16 @@ be temporary, and you can try again late moments.</li> <li>If you are unable to load any pages, check your computer's network connection.</li> <li>If your computer or network is protected by a firewall or proxy, make sure that &brandShortName; is permitted to access the Web.</li> </ul> "> -<!ENTITY malwareBlocked.title "Suspected Attack Site!"> -<!ENTITY malwareBlocked.longDesc " -<p>Attack sites try to install programs that steal private information, use your computer to attack others, or damage your system.</p> -<p>Website owners who believe their site has been reported as an attack site in error may <a href='http://www.stopbadware.org/home/reviewinfo' >request a review</a>.</p> -"> - -<!ENTITY unwantedBlocked.title "Suspected Unwanted Software Site!"> -<!ENTITY unwantedBlocked.longDesc " -<p>Unwanted software pages try to install software that can be deceptive and affect your system in unexpected ways.</p> -"> - -<!ENTITY phishingBlocked.title "Suspected Web Forgery!"> -<!ENTITY phishingBlocked.longDesc " -<p>Entering any personal information on this page may result in identity theft or other fraud.</p> -<p>These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.</p> -"> - -<!ENTITY forbiddenBlocked.title "Forbidden Site"> -<!ENTITY forbiddenBlocked.longDesc "<p>&brandShortName; prevented this page from loading because it is configured to block it.</p> -"> - <!ENTITY cspBlocked.title "Blocked by Content Security Policy"> <!ENTITY cspBlocked.longDesc "<p>&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.</p>"> <!ENTITY corruptedContentError.title "Corrupted Content Error"> <!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>"> <!ENTITY securityOverride.linkText "Or you can add an exception…">
deleted file mode 100644 --- a/browser/tools/mozscreenshots/mozscreenshots/extension/Makefile.in +++ /dev/null @@ -1,12 +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/. - -TEST_EXTENSIONS_DIR = $(DEPTH)/_tests/testing/mochitest/extensions -GENERATED_DIRS = $(TEST_EXTENSIONS_DIR) -XPI_PKGNAME = mozscreenshots@mozilla.org - -include $(topsrcdir)/config/rules.mk - -libs:: - (cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - $(XPI_NAME)) | (cd $(TEST_EXTENSIONS_DIR) && tar -xf -)
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf +++ b/browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf @@ -4,17 +4,17 @@ - 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/. --> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>mozscreenshots@mozilla.org</em:id> -#expand <em:version>__MOZILLA_VERSION_U__</em:version> + <em:version>0.3.2</em:version> <em:bootstrap>true</em:bootstrap> <!-- for running custom screenshot binaries --> <em:unpack>true</em:unpack> <!-- Front End MetaData --> <em:name>mozscreenshots</em:name> <em:description>Take screenshots of Mozilla applications in various UI configurations.</em:description>
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/moz.build +++ b/browser/tools/mozscreenshots/mozscreenshots/extension/moz.build @@ -10,8 +10,12 @@ JAR_MANIFESTS += ['jar.mn'] USE_EXTENSION_MANIFEST = True NO_JS_MANIFEST = True FINAL_TARGET_PP_FILES += [ 'bootstrap.js', 'install.rdf', ] + +TEST_HARNESS_FILES.testing.mochitest.extensions += [ + 'mozscreenshots-signed.xpi', +]
new file mode 100644 index 0000000000000000000000000000000000000000..af47dca31ea885380144d612e86b7cc6fbf5da2d GIT binary patch literal 38341 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
--- a/build/autoconf/clang-plugin.m4 +++ b/build/autoconf/clang-plugin.m4 @@ -4,23 +4,28 @@ dnl file, You can obtain one at http://m AC_DEFUN([MOZ_CONFIG_CLANG_PLUGIN], [ MOZ_ARG_ENABLE_BOOL(clang-plugin, [ --enable-clang-plugin Enable building with the mozilla clang plugin ], ENABLE_CLANG_PLUGIN=1, ENABLE_CLANG_PLUGIN= ) if test -n "$ENABLE_CLANG_PLUGIN"; then - if test -z "$CLANG_CC"; then + if test -z "${CLANG_CC}${CLANG_CL}"; then AC_MSG_ERROR([Can't use clang plugin without clang.]) fi AC_MSG_CHECKING([for llvm-config]) if test -z "$LLVMCONFIG"; then - LLVMCONFIG=`$CXX -print-prog-name=llvm-config` + if test -n "$CLANG_CL"; then + CXX_COMPILER="$(dirname "$CXX")/clang" + else + CXX_COMPILER="${CXX}" + fi + LLVMCONFIG=`$CXX_COMPILER -print-prog-name=llvm-config` fi if test -z "$LLVMCONFIG"; then LLVMCONFIG=`which llvm-config` fi if test ! -x "$LLVMCONFIG"; then AC_MSG_RESULT([not found]) @@ -31,28 +36,67 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then if test -z "$LLVMCONFIG"; then AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin]) fi LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags` dnl The clang package we use on OSX is old, and its llvm-config doesn't dnl recognize --system-libs, so ask for that separately. llvm-config's dnl failure here is benign, so we can ignore it if it happens. - LLVM_LDFLAGS=`$LLVMCONFIG --system-libs | xargs` - LLVM_LDFLAGS="$LLVM_LDFLAGS `$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader option | xargs`" + dnl Use tr instead of xargs in order to avoid problems with path separators on Windows. + LLVM_LDFLAGS=`$LLVMCONFIG --system-libs | tr '\n' ' '` + LLVM_LDFLAGS="$LLVM_LDFLAGS `$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader option | tr '\n' ' '`" if test "${HOST_OS_ARCH}" = "Darwin"; then CLANG_LDFLAGS="-lclangFrontend -lclangDriver -lclangSerialization" CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangParse -lclangSema -lclangAnalysis" CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangEdit -lclangAST -lclangLex" CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangBasic -lclangASTMatchers" + elif test "${HOST_OS_ARCH}" = "WINNT"; then + CLANG_LDFLAGS="clangFrontend.lib clangDriver.lib clangSerialization.lib" + CLANG_LDFLAGS="$CLANG_LDFLAGS clangParse.lib clangSema.lib clangAnalysis.lib" + CLANG_LDFLAGS="$CLANG_LDFLAGS clangEdit.lib clangAST.lib clangLex.lib" + CLANG_LDFLAGS="$CLANG_LDFLAGS clangBasic.lib clangASTMatchers.lib" else CLANG_LDFLAGS="-lclangASTMatchers" fi + if test -n "$CLANG_CL"; then + dnl The llvm-config coming with clang-cl may give us arguments in the + dnl /ARG form, which in msys will be interpreted as a path name. So we + dnl need to split the args and convert the leading slashes that we find + dnl into a dash. + LLVM_REPLACE_CXXFLAGS='' + for arg in $LLVM_CXXFLAGS; do + dnl The following expression replaces a leading slash with a dash. + dnl Also replace any backslashes with forward slash. + arg=`echo "$arg"|sed -e 's/^\//-/' -e 's/\\\\/\//g'` + LLVM_REPLACE_CXXFLAGS="$LLVM_REPLACE_CXXFLAGS $arg" + done + LLVM_CXXFLAGS="$LLVM_REPLACE_CXXFLAGS" + + LLVM_REPLACE_LDFLAGS='' + for arg in $LLVM_LDFLAGS; do + dnl The following expression replaces a leading slash with a dash. + dnl Also replace any backslashes with forward slash. + arg=`echo "$arg"|sed -e 's/^\//-/' -e 's/\\\\/\//g'` + LLVM_REPLACE_LDFLAGS="$LLVM_REPLACE_LDFLAGS $arg" + done + LLVM_LDFLAGS="$LLVM_REPLACE_LDFLAGS" + + CLANG_REPLACE_LDFLAGS='' + for arg in $CLANG_LDFLAGS; do + dnl The following expression replaces a leading slash with a dash. + dnl Also replace any backslashes with forward slash. + arg=`echo "$arg"|sed -e 's/^\//-/' -e 's/\\\\/\//g'` + CLANG_REPLACE_LDFLAGS="$CLANG_REPLACE_LDFLAGS $arg" + done + CLANG_LDFLAGS="$CLANG_REPLACE_LDFLAGS" + fi + dnl Check for the new ASTMatcher API names. Since this happened in the dnl middle of the 3.8 cycle, our CLANG_VERSION_FULL is impossible to use dnl correctly, so we have to detect this at configure time. AC_CACHE_CHECK(for new ASTMatcher names, ac_cv_have_new_ASTMatcher_names, [ AC_LANG_SAVE AC_LANG_CPLUSPLUS
--- a/build/clang-plugin/Makefile.in +++ b/build/clang-plugin/Makefile.in @@ -4,20 +4,24 @@ # LLVM_CXXFLAGS comes with its own optimization flags. MOZ_OPTIMIZE = include $(topsrcdir)/config/config.mk # In the current moz.build world, we need to override essentially every # variable to limit ourselves to what we need to build the clang plugin. +ifeq ($(HOST_OS_ARCH),WINNT) +OS_CXXFLAGS := $(LLVM_CXXFLAGS) -GR- -EHsc +else OS_CXXFLAGS := $(LLVM_CXXFLAGS) -fno-rtti -fno-exceptions +DSO_LDOPTS := -shared +endif OS_COMPILE_CXXFLAGS := OS_LDFLAGS := $(LLVM_LDFLAGS) $(CLANG_LDFLAGS) -DSO_LDOPTS := -shared ifeq ($(HOST_OS_ARCH)_$(OS_ARCH),Linux_Darwin) # Use the host compiler instead of the target compiler. CXX := $(HOST_CXX) # expandlibs doesn't know the distinction between host and target toolchains, # and on cross linux/darwin builds, the options to give to the linker for file # lists differ between both, so don't use file lists. EXPAND_MKSHLIB_ARGS :=
--- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -1512,8 +1512,12 @@ public: const std::vector<std::string> &args) override { return true; } }; } static FrontendPluginRegistry::Add<MozCheckAction> X("moz-check", "check moz action"); +// Export the registry on Windows. +#ifdef LLVM_EXPORT_REGISTRY +LLVM_EXPORT_REGISTRY(FrontendPluginRegistry) +#endif
--- a/build/sanitizers/lsan_suppressions.txt +++ b/build/sanitizers/lsan_suppressions.txt @@ -49,37 +49,30 @@ leak:recv_function_udp # Bug 987385 - Various plugin leaks. m3 leak:mozilla::plugins::PPluginInstanceParent::CallNPP_HandleEvent leak:mozilla::plugins::PPluginModuleParent::OnCallReceived # Bug 987925 - Small leak under PK11_ChangePW. m5 leak:sec_asn1e_allocate_item leak:PORT_Strdup_Util -# Bug 1021302 - Leak of fds allocated in nsSocketTransport::BuildSocket(). m1, m5, dt, oth -leak:nsSocketTransport::BuildSocket -leak:nsServerSocket::OnSocketReady - # Bug 1021350 - Small leak under event_base_once. m1, m4, bc3 leak:event_base_once -# Bug 1021854 - nsFileStreamBase::DoOpen() leaking fds. bc1, oth -leak:nsLocalFile::OpenNSPRFileDesc - # Bug 1022010 - Small leak under _render_glyph_outline. bc1 leak:_render_glyph_outline # Bug 1023548 - Small leak under SECITEM_AllocItem_Util. bc1, bc3 leak:SECITEM_AllocItem_Util # This is a one-time leak, so it is probably okay to ignore. bc3, oth leak:GlobalPrinters::InitializeGlobalPrinters leak:nsPSPrinterList::GetPrinterList -# Bug 1028456 - More leaks with _PR_Getfd, in nsLocalFile::CopyToNative and do_create. bc1, bc3 +# Bug 1028456 - Various NSPR fd-related leaks. m1-m5, bc1,bc2,bc5,bc7,dt4,dt5. leak:_PR_Getfd # Bug 1028483 - The XML parser sometimes leaks an object. bc3 leak:processInternalEntity # Bug 1187421 - With e10s, NSS does not always free the error stack. m1. leak:nss_ClearErrorStack
--- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -490,16 +490,18 @@ nsScriptSecurityManager::ContentSecurity unsigned lineNum = 0; NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP"); JS::UniqueChars scriptFilename; if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) { if (const char *file = scriptFilename.get()) { CopyUTF8toUTF16(nsDependentCString(file), fileName); } + } else { + MOZ_ASSERT(!JS_IsExceptionPending(cx)); } csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, fileName, scriptSample, lineNum, EmptyString(), EmptyString()); }
--- a/config/static-checking-config.mk +++ b/config/static-checking-config.mk @@ -1,12 +1,12 @@ # 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/. # The entire tree should be subject to static analysis using the XPCOM # script. Additional scripts may be added by specific subdirectories. ifdef ENABLE_CLANG_PLUGIN -CLANG_PLUGIN := $(DEPTH)/build/clang-plugin/$(DLL_PREFIX)clang-plugin$(DLL_SUFFIX) +CLANG_PLUGIN := $(topobjdir)/build/clang-plugin/$(DLL_PREFIX)clang-plugin$(DLL_SUFFIX) OS_CXXFLAGS += -Xclang -load -Xclang $(CLANG_PLUGIN) -Xclang -add-plugin -Xclang moz-check OS_CFLAGS += -Xclang -load -Xclang $(CLANG_PLUGIN) -Xclang -add-plugin -Xclang moz-check endif
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -4964,17 +4964,17 @@ nsDocShell::DisplayLoadError(nsresult aE if (alternateErrorPage) { errorPage.Assign(alternateErrorPage); } uint32_t bucketId; bool sendTelemetry = false; if (NS_ERROR_PHISHING_URI == aError) { sendTelemetry = true; - error.AssignLiteral("phishingBlocked"); + error.AssignLiteral("deceptiveBlocked"); bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_PHISHING_PAGE_FRAME : nsISecurityUITelemetry::WARNING_PHISHING_PAGE_TOP; } else if (NS_ERROR_MALWARE_URI == aError) { sendTelemetry = true; error.AssignLiteral("malwareBlocked"); bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_MALWARE_PAGE_FRAME : nsISecurityUITelemetry::WARNING_MALWARE_PAGE_TOP; } else if (NS_ERROR_UNWANTED_URI == aError) {
--- a/dom/animation/AnimationEffectTiming.cpp +++ b/dom/animation/AnimationEffectTiming.cpp @@ -13,10 +13,37 @@ namespace mozilla { namespace dom { JSObject* AnimationEffectTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return AnimationEffectTimingBinding::Wrap(aCx, this, aGivenProto); } +void +AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration) +{ + if (mTiming.mDuration.IsUnrestrictedDouble() && + aDuration.IsUnrestrictedDouble() && + mTiming.mDuration.GetAsUnrestrictedDouble() == + aDuration.GetAsUnrestrictedDouble()) { + return; + } + + if (mTiming.mDuration.IsString() && aDuration.IsString() && + mTiming.mDuration.GetAsString() == aDuration.GetAsString()) { + return; + } + + if (aDuration.IsUnrestrictedDouble()) { + mTiming.mDuration.SetAsUnrestrictedDouble() = + aDuration.GetAsUnrestrictedDouble(); + } else { + mTiming.mDuration.SetAsString() = aDuration.GetAsString(); + } + + if (mEffect) { + mEffect->NotifySpecifiedTimingUpdated(); + } +} + } // namespace dom } // namespace mozilla
--- a/dom/animation/AnimationEffectTiming.h +++ b/dom/animation/AnimationEffectTiming.h @@ -3,25 +3,34 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_AnimationEffectTiming_h #define mozilla_dom_AnimationEffectTiming_h #include "mozilla/dom/AnimationEffectTimingReadOnly.h" +#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF namespace mozilla { namespace dom { class AnimationEffectTiming : public AnimationEffectTimingReadOnly { public: - explicit AnimationEffectTiming(const TimingParams& aTiming) - : AnimationEffectTimingReadOnly(aTiming) { } + AnimationEffectTiming(const TimingParams& aTiming, KeyframeEffect* aEffect) + : AnimationEffectTimingReadOnly(aTiming) + , mEffect(aEffect) { } JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; + + void Unlink() override { mEffect = nullptr; } + + void SetDuration(const UnrestrictedDoubleOrString& aDuration); + +private: + KeyframeEffect* MOZ_NON_OWNING_REF mEffect; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_AnimationEffectTiming_h
--- a/dom/animation/AnimationEffectTimingReadOnly.h +++ b/dom/animation/AnimationEffectTimingReadOnly.h @@ -92,16 +92,18 @@ public: aRetVal = mTiming.mDuration; } PlaybackDirection Direction() const { return mTiming.mDirection; } void GetEasing(nsString& aRetVal) const; const TimingParams& AsTimingParams() const { return mTiming; } void SetTimingParams(const TimingParams& aTiming) { mTiming = aTiming; } + virtual void Unlink() { } + protected: nsCOMPtr<nsISupports> mParent; TimingParams mTiming; }; } // namespace dom } // namespace mozilla
--- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -14,16 +14,17 @@ #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt #include "mozilla/StyleAnimationValue.h" #include "Layers.h" // For Layer #include "nsCSSParser.h" #include "nsCSSPropertySet.h" #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags #include "nsCSSPseudoElements.h" #include "nsCSSValue.h" +#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch #include "nsStyleUtil.h" #include <algorithm> // For std::max namespace mozilla { // Helper functions for generating a ComputedTimingProperties dictionary static void GetComputedTimingDictionary(const ComputedTiming& aComputedTiming, @@ -2137,21 +2138,55 @@ KeyframeEffectReadOnly::ShouldBlockCompo // //--------------------------------------------------------------------- KeyframeEffect::KeyframeEffect(nsIDocument* aDocument, Element* aTarget, CSSPseudoElementType aPseudoType, const TimingParams& aTiming) : KeyframeEffectReadOnly(aDocument, aTarget, aPseudoType, - new AnimationEffectTiming(aTiming)) + new AnimationEffectTiming(aTiming, this)) { } JSObject* KeyframeEffect::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return KeyframeEffectBinding::Wrap(aCx, this, aGivenProto); } +void KeyframeEffect::NotifySpecifiedTimingUpdated() +{ + nsIDocument* doc = nullptr; + // Bug 1249219: + // We don't support animation mutation observers on pseudo-elements yet. + if (mTarget && + mPseudoType == CSSPseudoElementType::NotPseudo) { + doc = mTarget->OwnerDoc(); + } + + nsAutoAnimationMutationBatch mb(doc); + + if (mAnimation) { + mAnimation->NotifyEffectTimingUpdated(); + + if (mAnimation->IsRelevant()) { + nsNodeUtils::AnimationChanged(mAnimation); + } + + nsPresContext* presContext = GetPresContext(); + if (presContext) { + presContext->EffectCompositor()-> + RequestRestyle(mTarget, mPseudoType, + EffectCompositor::RestyleType::Layer, + mAnimation->CascadeLevel()); + } + } +} + +KeyframeEffect::~KeyframeEffect() +{ + mTiming->Unlink(); +} + } // namespace dom } // namespace mozilla
--- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -14,17 +14,16 @@ #include "mozilla/Attributes.h" #include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction #include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords #include "mozilla/OwningNonNull.h" // OwningNonNull<...> #include "mozilla/StickyTimeDuration.h" #include "mozilla/StyleAnimationValue.h" #include "mozilla/TimeStamp.h" #include "mozilla/dom/AnimationEffectReadOnly.h" -#include "mozilla/dom/AnimationEffectTiming.h" #include "mozilla/dom/AnimationEffectTimingReadOnly.h" // TimingParams #include "mozilla/dom/Element.h" #include "mozilla/dom/KeyframeBinding.h" #include "mozilla/dom/Nullable.h" struct JSContext; class nsCSSPropertySet; @@ -423,14 +422,19 @@ public: const Nullable<ElementOrCSSPseudoElement>& aTarget, JS::Handle<JSObject*> aFrames, const TimingParams& aTiming, ErrorResult& aRv) { return ConstructKeyframeEffect<KeyframeEffect>(aGlobal, aTarget, aFrames, aTiming, aRv); } + + void NotifySpecifiedTimingUpdated(); + +protected: + ~KeyframeEffect() override; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_KeyframeEffect_h
--- a/dom/animation/test/chrome/test_animation_observers.html +++ b/dom/animation/test/chrome/test_animation_observers.html @@ -1465,16 +1465,57 @@ addAsyncAnimTest("tree_ordering", { obse "records after finishing"); // Clean up div.style = ""; childA.remove(); childB.remove(); }); + +addAsyncAnimTest("change_duration_and_currenttime", + { observe: div, subtree: true }, function*() { + var anim = div.animate({ opacity: [ 0, 1 ] }, 100000); + yield await_frame(); + assert_records([{ added: [anim], changed: [], removed: [] }], + "records after animation is added"); + + anim.effect.timing.duration = 10000; + yield await_frame(); + + assert_records([{ added: [], changed: [anim], removed: [] }], + "records after duration is changed"); + + anim.effect.timing.duration = 10000; + yield await_frame(); + assert_records([], "records after assigning same value"); + + anim.currentTime = 50000; + yield await_frame(); + assert_records([{ added: [], changed: [], removed: [anim] }], + "records after animation end"); + + anim.effect.timing.duration = 100000; + yield await_frame(); + assert_records([{ added: [anim], changed: [], removed: [] }], + "records after animation restarted"); + + anim.effect.timing.duration = "auto"; + yield await_frame(); + assert_records([{ added: [], changed: [], removed: [anim] }], + "records after duration set \"auto\""); + + anim.effect.timing.duration = "auto"; + yield await_frame(); + assert_records([], "records after assigning same value \"auto\""); + + anim.cancel(); + yield await_frame(); +}); + // Run the tests. SimpleTest.requestLongerTimeout(2); SimpleTest.waitForExplicitFinish(); runAllAsyncTests().then(function() { SimpleTest.finish(); }, function(aError) { ok(false, "Something failed: " + aError);
--- a/dom/animation/test/chrome/test_restyles.html +++ b/dom/animation/test/chrome/test_restyles.html @@ -341,12 +341,32 @@ waitForAllPaints(function() { var markers = yield observeStyling(5); is(markers.length, 1, 'Bug 1235478: Animations running on the compositor should only once ' + 'update style when currentTime is set to middle of duration time'); yield ensureElementRemoval(div); }); + add_task_if_omta_enabled(function* change_duration_and_currenttime() { + var div = addDiv(null); + var animation = div.animate({ opacity: [ 0, 1 ] }, 10000); + + yield animation.ready; + ok(animation.isRunningOnCompositor); + + animation.currentTime = 50000; + + ok(!animation.isRunningOnCompositor); + + animation.effect.timing.duration = 100000; + var markers = yield observeStyling(5); + is(markers.length, 1, + 'Animations running on the compositor should update style' + + 'when timing.duration is made longer than the current time'); + + yield ensureElementRemoval(div); + }); + }); </script> </body>
--- a/dom/animation/test/chrome/test_running_on_compositor.html +++ b/dom/animation/test/chrome/test_running_on_compositor.html @@ -280,11 +280,53 @@ promise_test(function(t) { 'If an animation has a property that can run on the compositor and a ' + 'property that cannot (due to Gecko limitations) but where the latter' + 'property is overridden in the CSS cascade, the animation should ' + 'still report that it is running on the compositor'); })); }, 'isRunningOnCompositor is true when a property that would otherwise block ' + 'running on the compositor is overridden in the CSS cascade'); +promise_test(function(t) { + var div = addDiv(t); + var animation = div.animate({ opacity: [ 0, 1 ] }, 100000); + + return animation.ready.then(t.step_func(function() { + assert_equals(animation.isRunningOnCompositor, omtaEnabled, + 'Animation reports that it is running on the compositor'); + + animation.currentTime = 50000; + animation.effect.timing.duration = 10000; + + assert_equals(animation.isRunningOnCompositor, false, + 'Animation reports that it is NOT running on the compositor' + + ' when the animation is set a shorter duration than current time'); + })); +}, 'animation is immediately removed from compositor' + + 'when timing.duration is made shorter than the current time'); + +promise_test(function(t) { + var div = addDiv(t); + var animation = div.animate({ opacity: [ 0, 1 ] }, 10000); + + return animation.ready.then(t.step_func(function() { + assert_equals(animation.isRunningOnCompositor, omtaEnabled, + 'Animation reports that it is running on the compositor'); + + animation.currentTime = 50000; + + assert_equals(animation.isRunningOnCompositor, false, + 'Animation reports that it is NOT running on the compositor' + + ' when finished'); + + animation.effect.timing.duration = 100000; + return waitForFrame(); + })).then(t.step_func(function() { + assert_equals(animation.isRunningOnCompositor, omtaEnabled, + 'Animation reports that it is running on the compositor' + + ' when restarted'); + })); +}, 'animation is added to compositor' + + ' when timing.duration is made longer than the current time'); + </script> </script> </body>
new file mode 100644 --- /dev/null +++ b/dom/base/BodyUtil.cpp @@ -0,0 +1,574 @@ +/* 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 "BodyUtil.h" + +#include "nsError.h" +#include "nsString.h" +#include "nsIGlobalObject.h" +#include "nsIUnicodeDecoder.h" + +#include "nsCharSeparatedTokenizer.h" +#include "nsDOMString.h" +#include "nsNetUtil.h" +#include "nsReadableUtils.h" +#include "nsStreamUtils.h" +#include "nsStringStream.h" + +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/EncodingUtils.h" +#include "mozilla/dom/Exceptions.h" +#include "mozilla/dom/FetchUtil.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/FormData.h" +#include "mozilla/dom/Headers.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/URLSearchParams.h" + +namespace mozilla { +namespace dom { + +namespace { + +class StreamDecoder final +{ + nsCOMPtr<nsIUnicodeDecoder> mDecoder; + nsString mDecoded; + +public: + StreamDecoder() + : mDecoder(EncodingUtils::DecoderForEncoding("UTF-8")) + { + MOZ_ASSERT(mDecoder); + } + + nsresult + AppendText(const char* aSrcBuffer, uint32_t aSrcBufferLen) + { + int32_t destBufferLen; + nsresult rv = + mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen, &destBufferLen); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!mDecoded.SetCapacity(mDecoded.Length() + destBufferLen, fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + char16_t* destBuffer = mDecoded.BeginWriting() + mDecoded.Length(); + int32_t totalChars = mDecoded.Length(); + + int32_t srcLen = (int32_t) aSrcBufferLen; + int32_t outLen = destBufferLen; + rv = mDecoder->Convert(aSrcBuffer, &srcLen, destBuffer, &outLen); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + totalChars += outLen; + mDecoded.SetLength(totalChars); + + return NS_OK; + } + + nsString& + GetText() + { + return mDecoded; + } +}; + +// Reads over a CRLF and positions start after it. +static bool +PushOverLine(nsACString::const_iterator& aStart) +{ + if (*aStart == nsCRT::CR && (aStart.size_forward() > 1) && *(++aStart) == nsCRT::LF) { + ++aStart; // advance to after CRLF + return true; + } + + return false; +} + +class MOZ_STACK_CLASS FillFormIterator final + : public URLSearchParams::ForEachIterator +{ +public: + explicit FillFormIterator(FormData* aFormData) + : mFormData(aFormData) + { + MOZ_ASSERT(aFormData); + } + + bool URLParamsIterator(const nsString& aName, + const nsString& aValue) override + { + ErrorResult rv; + mFormData->Append(aName, aValue, rv); + MOZ_ASSERT(!rv.Failed()); + return true; + } + +private: + FormData* mFormData; +}; + +/** + * A simple multipart/form-data parser as defined in RFC 2388 and RFC 2046. + * This does not respect any encoding specified per entry, using UTF-8 + * throughout. This is as the Fetch spec states in the consume body algorithm. + * Borrows some things from Necko's nsMultiMixedConv, but is simpler since + * unlike Necko we do not have to deal with receiving incomplete chunks of data. + * + * This parser will fail the entire parse on any invalid entry, so it will + * never return a partially filled FormData. + * The content-disposition header is used to figure out the name and filename + * entries. The inclusion of the filename parameter decides if the entry is + * inserted into the FormData as a string or a File. + * + * File blobs are copies of the underlying data string since we cannot adopt + * char* chunks embedded within the larger body without significant effort. + * FIXME(nsm): Bug 1127552 - We should add telemetry to calls to formData() and + * friends to figure out if Fetch ends up copying big blobs to see if this is + * worth optimizing. + */ +class MOZ_STACK_CLASS FormDataParser +{ +private: + RefPtr<FormData> mFormData; + nsCString mMimeType; + nsCString mData; + + // Entry state, reset in START_PART. + nsCString mName; + nsCString mFilename; + nsCString mContentType; + + enum + { + START_PART, + PARSE_HEADER, + PARSE_BODY, + } mState; + + nsIGlobalObject* mParentObject; + + // Reads over a boundary and sets start to the position after the end of the + // boundary. Returns false if no boundary is found immediately. + bool + PushOverBoundary(const nsACString& aBoundaryString, + nsACString::const_iterator& aStart, + nsACString::const_iterator& aEnd) + { + // We copy the end iterator to keep the original pointing to the real end + // of the string. + nsACString::const_iterator end(aEnd); + const char* beginning = aStart.get(); + if (FindInReadable(aBoundaryString, aStart, end)) { + // We either should find the body immediately, or after 2 chars with the + // 2 chars being '-', everything else is failure. + if ((aStart.get() - beginning) == 0) { + aStart.advance(aBoundaryString.Length()); + return true; + } + + if ((aStart.get() - beginning) == 2) { + if (*(--aStart) == '-' && *(--aStart) == '-') { + aStart.advance(aBoundaryString.Length() + 2); + return true; + } + } + } + + return false; + } + + bool + ParseHeader(nsACString::const_iterator& aStart, + nsACString::const_iterator& aEnd, + bool* aWasEmptyHeader) + { + nsAutoCString headerName, headerValue; + if (!FetchUtil::ExtractHeader(aStart, aEnd, + headerName, headerValue, + aWasEmptyHeader)) { + return false; + } + if (*aWasEmptyHeader) { + return true; + } + + if (headerName.LowerCaseEqualsLiteral("content-disposition")) { + nsCCharSeparatedTokenizer tokenizer(headerValue, ';'); + bool seenFormData = false; + while (tokenizer.hasMoreTokens()) { + const nsDependentCSubstring& token = tokenizer.nextToken(); + if (token.IsEmpty()) { + continue; + } + + if (token.EqualsLiteral("form-data")) { + seenFormData = true; + continue; + } + + if (seenFormData && + StringBeginsWith(token, NS_LITERAL_CSTRING("name="))) { + mName = StringTail(token, token.Length() - 5); + mName.Trim(" \""); + continue; + } + + if (seenFormData && + StringBeginsWith(token, NS_LITERAL_CSTRING("filename="))) { + mFilename = StringTail(token, token.Length() - 9); + mFilename.Trim(" \""); + continue; + } + } + + if (mName.IsVoid()) { + // Could not parse a valid entry name. + return false; + } + } else if (headerName.LowerCaseEqualsLiteral("content-type")) { + mContentType = headerValue; + } + + return true; + } + + // The end of a body is marked by a CRLF followed by the boundary. So the + // CRLF is part of the boundary and not the body, but any prior CRLFs are + // part of the body. This will position the iterator at the beginning of the + // boundary (after the CRLF). + bool + ParseBody(const nsACString& aBoundaryString, + nsACString::const_iterator& aStart, + nsACString::const_iterator& aEnd) + { + const char* beginning = aStart.get(); + + // Find the boundary marking the end of the body. + nsACString::const_iterator end(aEnd); + if (!FindInReadable(aBoundaryString, aStart, end)) { + return false; + } + + // We found a boundary, strip the just prior CRLF, and consider + // everything else the body section. + if (aStart.get() - beginning < 2) { + // Only the first entry can have a boundary right at the beginning. Even + // an empty body will have a CRLF before the boundary. So this is + // a failure. + return false; + } + + // Check that there is a CRLF right before the boundary. + aStart.advance(-2); + + // Skip optional hyphens. + if (*aStart == '-' && *(aStart.get()+1) == '-') { + if (aStart.get() - beginning < 2) { + return false; + } + + aStart.advance(-2); + } + + if (*aStart != nsCRT::CR || *(aStart.get()+1) != nsCRT::LF) { + return false; + } + + nsAutoCString body(beginning, aStart.get() - beginning); + + // Restore iterator to after the \r\n as we promised. + // We do not need to handle the extra hyphens case since our boundary + // parser in PushOverBoundary() + aStart.advance(2); + + if (!mFormData) { + mFormData = new FormData(); + } + + NS_ConvertUTF8toUTF16 name(mName); + + if (mFilename.IsVoid()) { + ErrorResult rv; + mFormData->Append(name, NS_ConvertUTF8toUTF16(body), rv); + MOZ_ASSERT(!rv.Failed()); + } else { + // Unfortunately we've to copy the data first since all our strings are + // going to free it. We also need fallible alloc, so we can't just use + // ToNewCString(). + char* copy = static_cast<char*>(moz_xmalloc(body.Length())); + if (!copy) { + NS_WARNING("Failed to copy File entry body."); + return false; + } + nsCString::const_iterator bodyIter, bodyEnd; + body.BeginReading(bodyIter); + body.EndReading(bodyEnd); + char *p = copy; + while (bodyIter != bodyEnd) { + *p++ = *bodyIter++; + } + p = nullptr; + + RefPtr<Blob> file = + File::CreateMemoryFile(mParentObject, + reinterpret_cast<void *>(copy), body.Length(), + NS_ConvertUTF8toUTF16(mFilename), + NS_ConvertUTF8toUTF16(mContentType), /* aLastModifiedDate */ 0); + Optional<nsAString> dummy; + ErrorResult rv; + mFormData->Append(name, *file, dummy, rv); + if (NS_WARN_IF(rv.Failed())) { + return false; + } + } + + return true; + } + +public: + FormDataParser(const nsACString& aMimeType, const nsACString& aData, nsIGlobalObject* aParent) + : mMimeType(aMimeType), mData(aData), mState(START_PART), mParentObject(aParent) + { + } + + bool + Parse() + { + // Determine boundary from mimetype. + const char* boundaryId = nullptr; + boundaryId = strstr(mMimeType.BeginWriting(), "boundary"); + if (!boundaryId) { + return false; + } + + boundaryId = strchr(boundaryId, '='); + if (!boundaryId) { + return false; + } + + // Skip over '='. + boundaryId++; + + char *attrib = (char *) strchr(boundaryId, ';'); + if (attrib) *attrib = '\0'; + + nsAutoCString boundaryString(boundaryId); + if (attrib) *attrib = ';'; + + boundaryString.Trim(" \""); + + if (boundaryString.Length() == 0) { + return false; + } + + nsACString::const_iterator start, end; + mData.BeginReading(start); + // This should ALWAYS point to the end of data. + // Helpers make copies. + mData.EndReading(end); + + while (start != end) { + switch(mState) { + case START_PART: + mName.SetIsVoid(true); + mFilename.SetIsVoid(true); + mContentType = NS_LITERAL_CSTRING("text/plain"); + + // MUST start with boundary. + if (!PushOverBoundary(boundaryString, start, end)) { + return false; + } + + if (start != end && *start == '-') { + // End of data. + if (!mFormData) { + mFormData = new FormData(); + } + return true; + } + + if (!PushOverLine(start)) { + return false; + } + mState = PARSE_HEADER; + break; + + case PARSE_HEADER: + bool emptyHeader; + if (!ParseHeader(start, end, &emptyHeader)) { + return false; + } + + if (emptyHeader && !PushOverLine(start)) { + return false; + } + + mState = emptyHeader ? PARSE_BODY : PARSE_HEADER; + break; + + case PARSE_BODY: + if (mName.IsVoid()) { + NS_WARNING("No content-disposition header with a valid name was " + "found. Failing at body parse."); + return false; + } + + if (!ParseBody(boundaryString, start, end)) { + return false; + } + + mState = START_PART; + break; + + default: + MOZ_CRASH("Invalid case"); + } + } + + NS_NOTREACHED("Should never reach here."); + return false; + } + + already_AddRefed<FormData> GetFormData() + { + return mFormData.forget(); + } +}; +} + +// static +void +BodyUtil::ConsumeArrayBuffer(JSContext* aCx, + JS::MutableHandle<JSObject*> aValue, + uint32_t aInputLength, uint8_t* aInput, + ErrorResult& aRv) +{ + JS::Rooted<JSObject*> arrayBuffer(aCx); + arrayBuffer = JS_NewArrayBufferWithContents(aCx, aInputLength, + reinterpret_cast<void *>(aInput)); + if (!arrayBuffer) { + JS_ClearPendingException(aCx); + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + aValue.set(arrayBuffer); +} + +// static +already_AddRefed<Blob> +BodyUtil::ConsumeBlob(nsISupports* aParent, const nsString& aMimeType, + uint32_t aInputLength, uint8_t* aInput, + ErrorResult& aRv) +{ + RefPtr<Blob> blob = + Blob::CreateMemoryBlob(aParent, + reinterpret_cast<void *>(aInput), aInputLength, + aMimeType); + + if (!blob) { + aRv.Throw(NS_ERROR_DOM_UNKNOWN_ERR); + return nullptr; + } + return blob.forget(); +} + +// static +already_AddRefed<FormData> +BodyUtil::ConsumeFormData(nsIGlobalObject* aParent, const nsCString& aMimeType, + const nsCString& aStr, ErrorResult& aRv) +{ + NS_NAMED_LITERAL_CSTRING(formDataMimeType, "multipart/form-data"); + + // Allow semicolon separated boundary/encoding suffix like multipart/form-data; boundary= + // but disallow multipart/form-datafoobar. + bool isValidFormDataMimeType = StringBeginsWith(aMimeType, formDataMimeType); + + if (isValidFormDataMimeType && aMimeType.Length() > formDataMimeType.Length()) { + isValidFormDataMimeType = aMimeType[formDataMimeType.Length()] == ';'; + } + + if (isValidFormDataMimeType) { + FormDataParser parser(aMimeType, aStr, aParent); + if (!parser.Parse()) { + aRv.ThrowTypeError<MSG_BAD_FORMDATA>(); + return nullptr; + } + + RefPtr<FormData> fd = parser.GetFormData(); + MOZ_ASSERT(fd); + return fd.forget(); + } + + NS_NAMED_LITERAL_CSTRING(urlDataMimeType, "application/x-www-form-urlencoded"); + bool isValidUrlEncodedMimeType = StringBeginsWith(aMimeType, urlDataMimeType); + + if (isValidUrlEncodedMimeType && aMimeType.Length() > urlDataMimeType.Length()) { + isValidUrlEncodedMimeType = aMimeType[urlDataMimeType.Length()] == ';'; + } + + if (isValidUrlEncodedMimeType) { + URLParams params; + params.ParseInput(aStr); + + RefPtr<FormData> fd = new FormData(aParent); + FillFormIterator iterator(fd); + DebugOnly<bool> status = params.ForEach(iterator); + MOZ_ASSERT(status); + + return fd.forget(); + } + + aRv.ThrowTypeError<MSG_BAD_FORMDATA>(); + return nullptr; +} + +// static +nsresult +BodyUtil::ConsumeText(uint32_t aInputLength, uint8_t* aInput, + nsString& aText) +{ + StreamDecoder decoder; + nsresult rv = decoder.AppendText(reinterpret_cast<char*>(aInput), + aInputLength); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + aText = decoder.GetText(); + return NS_OK; +} + +// static +void +BodyUtil::ConsumeJson(JSContext* aCx, JS::MutableHandle<JS::Value> aValue, + const nsString& aStr, ErrorResult& aRv) +{ + aRv.MightThrowJSException(); + + AutoForceSetExceptionOnContext forceExn(aCx); + JS::Rooted<JS::Value> json(aCx); + if (!JS_ParseJSON(aCx, aStr.get(), aStr.Length(), &json)) { + if (!JS_IsExceptionPending(aCx)) { + aRv.Throw(NS_ERROR_DOM_UNKNOWN_ERR); + return; + } + + JS::Rooted<JS::Value> exn(aCx); + DebugOnly<bool> gotException = JS_GetPendingException(aCx, &exn); + MOZ_ASSERT(gotException); + + JS_ClearPendingException(aCx); + aRv.ThrowJSException(aCx, exn); + return; + } + + aValue.set(json); +} + +} // namespace dom +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/dom/base/BodyUtil.h @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_BodyUtil_h +#define mozilla_dom_BodyUtil_h + +#include "nsString.h" +#include "nsError.h" + +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/FormData.h" + +namespace mozilla { +namespace dom { + +class BodyUtil final +{ +private: + BodyUtil() = delete; + +public: + /** + * Creates an array buffer from an array, assigning the result to |aValue|. + * The array buffer takes ownership of |aInput|, which must be allocated + * by |malloc|. + */ + static void + ConsumeArrayBuffer(JSContext* aCx, JS::MutableHandle<JSObject*> aValue, + uint32_t aInputLength, uint8_t* aInput, ErrorResult& aRv); + + /** + * Creates an in-memory blob from an array. The blob takes ownership of + * |aInput|, which must be allocated by |malloc|. + */ + static already_AddRefed<Blob> + ConsumeBlob(nsISupports* aParent, const nsString& aMimeType, + uint32_t aInputLength, uint8_t* aInput, ErrorResult& aRv); + + /** + * Creates a form data object from a UTF-8 encoded |aStr|. Returns |nullptr| + * and sets |aRv| to MSG_BAD_FORMDATA if |aStr| contains invalid data. + */ + static already_AddRefed<FormData> + ConsumeFormData(nsIGlobalObject* aParent, const nsCString& aMimeType, + const nsCString& aStr, ErrorResult& aRv); + + /** + * UTF-8 decodes |aInput| into |aText|. The caller may free |aInput| + * once this method returns. + */ + static nsresult + ConsumeText(uint32_t aInputLength, uint8_t* aInput, nsString& aText); + + /** + * Parses a UTF-8 encoded |aStr| as JSON, assigning the result to |aValue|. + * Sets |aRv| to a syntax error if |aStr| contains invalid data. + */ + static void + ConsumeJson(JSContext* aCx, JS::MutableHandle<JS::Value> aValue, + const nsString& aStr, ErrorResult& aRv); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_BodyUtil_h
--- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -366,17 +366,17 @@ private: private: ~ConsoleReleaseRunnable() {} }; RefPtr<WorkerControlRunnable> runnable = new ConsoleReleaseRunnable(mWorkerPrivate, this); - runnable->Dispatch(nullptr); + runnable->Dispatch(); } void RunWithWindow(nsPIDOMWindowInner* aWindow) { AssertIsOnMainThread(); AutoJSAPI jsapi;
--- a/dom/base/Link.cpp +++ b/dom/base/Link.cpp @@ -6,16 +6,19 @@ #include "Link.h" #include "mozilla/EventStates.h" #include "mozilla/MemoryReporting.h" #include "mozilla/dom/Element.h" #include "nsIURL.h" #include "nsISizeOf.h" +#include "nsIDocShell.h" +#include "nsIPrefetchService.h" +#include "nsCPrefetchService.h" #include "nsEscape.h" #include "nsGkAtoms.h" #include "nsHTMLDNSPrefetch.h" #include "nsString.h" #include "mozAutoDocUpdate.h" #include "mozilla/Services.h" @@ -68,16 +71,80 @@ Link::CancelDNSPrefetch(nsWrapperCache:: mElement->UnsetFlags(aRequestedFlag); // Possible that hostname could have changed since binding, but since this // covers common cases, most DNS prefetch requests will be canceled nsHTMLDNSPrefetch::CancelPrefetchLow(this, NS_ERROR_ABORT); } } void +Link::TryDNSPrefetchPreconnectOrPrefetch() +{ + MOZ_ASSERT(mElement->IsInComposedDoc()); + if (!ElementHasHref()) { + return; + } + + nsAutoString rel; + if (!mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) { + return; + } + + if (!nsContentUtils::PrefetchEnabled(mElement->OwnerDoc()->GetDocShell())) { + return; + } + + uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, + mElement->NodePrincipal()); + + if ((linkTypes & nsStyleLinkElement::ePREFETCH) || + (linkTypes & nsStyleLinkElement::eNEXT)){ + nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID)); + if (prefetchService) { + nsCOMPtr<nsIURI> uri(GetURI()); + if (uri) { + nsCOMPtr<nsIDOMNode> domNode = GetAsDOMNode(mElement); + prefetchService->PrefetchURI(uri, + mElement->OwnerDoc()->GetDocumentURI(), + domNode, true); + return; + } + } + } + + if (linkTypes & nsStyleLinkElement::ePRECONNECT) { + nsCOMPtr<nsIURI> uri(GetURI()); + if (uri && mElement->OwnerDoc()) { + mElement->OwnerDoc()->MaybePreconnect(uri, + mElement->AttrValueToCORSMode(mElement->GetParsedAttr(nsGkAtoms::crossorigin))); + return; + } + } + + if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) { + if (nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) { + nsHTMLDNSPrefetch::PrefetchLow(this); + } + } +} + +void +Link::CancelPrefetch() +{ + nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID)); + if (prefetchService) { + nsCOMPtr<nsIURI> uri(GetURI()); + if (uri) { + nsCOMPtr<nsIDOMNode> domNode = GetAsDOMNode(mElement); + prefetchService->CancelPrefetchURI(uri, domNode); + } + } +} + +void Link::SetLinkState(nsLinkState aState) { NS_ASSERTION(mRegistered, "Setting the link state of an unregistered Link!"); NS_ASSERTION(mLinkState != aState, "Setting state to the currently set state!"); // Set our current state as appropriate.
--- a/dom/base/Link.h +++ b/dom/base/Link.h @@ -106,21 +106,25 @@ public: */ virtual bool HasDeferredDNSPrefetchRequest() { return true; } virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; bool ElementHasHref() const; + // This is called by HTMLAnchorElement. void TryDNSPrefetch(); - void CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag, nsWrapperCache::FlagsType aRequestedFlag); + // This is called by HTMLLinkElement. + void TryDNSPrefetchPreconnectOrPrefetch(); + void CancelPrefetch(); + protected: virtual ~Link(); /** * Return true if the link has associated URI. */ bool HasURI() const {
--- a/dom/base/WebSocket.cpp +++ b/dom/base/WebSocket.cpp @@ -2498,38 +2498,37 @@ public: : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) , mImpl(aImpl) { } bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { aWorkerPrivate->AssertIsOnWorkerThread(); - aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true); + aWorkerPrivate->ModifyBusyCountFromWorker(true); return !NS_FAILED(mImpl->CancelInternal()); } void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) override { - aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false); + aWorkerPrivate->ModifyBusyCountFromWorker(false); } bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { // We don't call WorkerRunnable::PreDispatch because it would assert the // wrong thing about which thread we're on. AssertIsOnMainThread(); return true; } void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) override + PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override { // We don't call WorkerRunnable::PostDispatch because it would assert the // wrong thing about which thread we're on. AssertIsOnMainThread(); } private: RefPtr<WebSocketImpl> mImpl; @@ -2542,17 +2541,17 @@ NS_IMETHODIMP WebSocketImpl::Cancel(nsresult aStatus) { AssertIsOnMainThread(); if (!mIsMainThread) { MOZ_ASSERT(mWorkerPrivate); RefPtr<CancelRunnable> runnable = new CancelRunnable(mWorkerPrivate, this); - if (!runnable->Dispatch(nullptr)) { + if (!runnable->Dispatch()) { return NS_ERROR_FAILURE; } return NS_OK; } return CancelInternal(); } @@ -2671,46 +2670,45 @@ public: , mWebSocketImpl(aImpl) , mEvent(aEvent) { } bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { aWorkerPrivate->AssertIsOnWorkerThread(); - aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true); + aWorkerPrivate->ModifyBusyCountFromWorker(true); // No messages when disconnected. if (mWebSocketImpl->mDisconnectingOrDisconnected) { NS_WARNING("Dispatching a WebSocket event after the disconnection!"); return true; } return !NS_FAILED(mEvent->Run()); } void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult) override { - aWorkerPrivate->ModifyBusyCountFromWorker(aCx, false); + aWorkerPrivate->ModifyBusyCountFromWorker(false); } bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { // We don't call WorkerRunnable::PreDispatch because it would assert the // wrong thing about which thread we're on. We're on whichever thread the // channel implementation is running on (probably the main thread or socket // transport thread). return true; } void - PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate, - bool aDispatchResult) override + PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override { // We don't call WorkerRunnable::PreDispatch because it would assert the // wrong thing about which thread we're on. We're on whichever thread the // channel implementation is running on (probably the main thread or socket // transport thread). } private: @@ -2746,17 +2744,17 @@ WebSocketImpl::Dispatch(already_AddRefed MOZ_ASSERT(HasFeatureRegistered()); #endif // If the target is a worker, we have to use a custom WorkerRunnableDispatcher // runnable. RefPtr<WorkerRunnableDispatcher> event = new WorkerRunnableDispatcher(this, mWorkerPrivate, event_ref.forget()); - if (!event->Dispatch(nullptr)) { + if (!event->Dispatch()) { return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP WebSocketImpl::IsOnCurrentThread(bool* aResult)
--- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -88,17 +88,16 @@ EXPORTS += [ 'nsIContent.h', 'nsIContentInlines.h', 'nsIContentIterator.h', 'nsIContentSerializer.h', 'nsIDocument.h', 'nsIDocumentInlines.h', 'nsIDocumentObserver.h', 'nsIDOMClassInfo.h', - 'nsIDOMScriptObjectFactory.h', 'nsIGlobalObject.h', 'nsImageLoadingContent.h', 'nsIMutationObserver.h', 'nsINode.h', 'nsINodeList.h', 'nsIScriptContext.h', 'nsIScriptElement.h', 'nsIScriptGlobalObject.h', @@ -152,16 +151,17 @@ EXPORTS.mozilla += [ ] EXPORTS.mozilla.dom += [ '!UseCounterList.h', 'AnonymousContent.h', 'Attr.h', 'BarProps.h', 'BlobSet.h', + 'BodyUtil.h', 'ChildIterator.h', 'ChromeNodeList.h', 'ChromeUtils.h', 'Comment.h', 'Console.h', 'DirectionalityUtils.h', 'DocumentFragment.h', 'DocumentType.h', @@ -219,16 +219,17 @@ EXPORTS.mozilla.dom += [ 'WebSocket.h', 'WindowOrientationObserver.h', ] UNIFIED_SOURCES += [ 'AnonymousContent.cpp', 'Attr.cpp', 'BarProps.cpp', + 'BodyUtil.cpp', 'ChildIterator.cpp', 'ChromeNodeList.cpp', 'ChromeUtils.cpp', 'Comment.cpp', 'Console.cpp', 'ConsoleReportCollector.cpp', 'Crypto.cpp', 'DirectionalityUtils.cpp', @@ -274,17 +275,16 @@ UNIFIED_SOURCES += [ 'nsDataDocumentContentPolicy.cpp', 'nsDocument.cpp', 'nsDocumentEncoder.cpp', 'nsDOMAttributeMap.cpp', 'nsDOMCaretPosition.cpp', 'nsDOMClassInfo.cpp', 'nsDOMMutationObserver.cpp', 'nsDOMNavigationTiming.cpp', - 'nsDOMScriptObjectFactory.cpp', 'nsDOMSerializer.cpp', 'nsDOMTokenList.cpp', 'nsDOMWindowList.cpp', 'nsFocusManager.cpp', 'nsFrameLoader.cpp', 'nsGenConImageContent.cpp', 'nsGenericDOMDataNode.cpp', 'nsGkAtoms.cpp',
--- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -687,17 +687,21 @@ nsContentSink::ProcessLink(const nsSubst // The link relation may apply to a different resource, specified // in the anchor parameter. For the link relations supported so far, // we simply abort if the link applies to a resource different to the // one we've loaded if (!LinkContextIsOurDocument(aAnchor)) { return NS_OK; } - + + if (!nsContentUtils::PrefetchEnabled(mDocShell)) { + return NS_OK; + } + bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH; // prefetch href if relation is "next" or "prefetch" if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) { PrefetchHref(aHref, mDocument, hasPrefetch); } if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::eDNS_PREFETCH)) { PrefetchDNS(aHref); @@ -822,45 +826,16 @@ nsContentSink::ProcessMETATag(nsIContent } void nsContentSink::PrefetchHref(const nsAString &aHref, nsINode *aSource, bool aExplicit) { - // - // SECURITY CHECK: disable prefetching from mailnews! - // - // walk up the docshell tree to see if any containing - // docshell are of type MAIL. - // - if (!mDocShell) - return; - - nsCOMPtr<nsIDocShell> docshell = mDocShell; - - nsCOMPtr<nsIDocShellTreeItem> parentItem; - do { - uint32_t appType = 0; - nsresult rv = docshell->GetAppType(&appType); - if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL) - return; // do not prefetch from mailnews - docshell->GetParent(getter_AddRefs(parentItem)); - if (parentItem) { - docshell = do_QueryInterface(parentItem); - if (!docshell) { - NS_ERROR("cannot get a docshell from a treeItem!"); - return; - } - } - } while (parentItem); - - // OK, we passed the security check... - nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID)); if (prefetchService) { // construct URI using document charset const nsACString &charset = mDocument->GetDocumentCharacterSet(); nsCOMPtr<nsIURI> uri; NS_NewURI(getter_AddRefs(uri), aHref, charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(), mDocument->GetDocBaseURI());
--- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -114,17 +114,16 @@ #include "nsIDOMDocument.h" #include "nsIDOMDocumentType.h" #include "nsIDOMEvent.h" #include "nsIDOMHTMLElement.h" #include "nsIDOMHTMLFormElement.h" #include "nsIDOMHTMLInputElement.h" #include "nsIDOMNode.h" #include "nsIDOMNodeList.h" -#include "nsIDOMScriptObjectFactory.h" #include "nsIDOMWindowUtils.h" #include "nsIDOMXULCommandEvent.h" #include "nsIDragService.h" #include "nsIEditor.h" #include "nsIFormControl.h" #include "nsIForm.h" #include "nsIFragmentContentSink.h" #include "nsContainerFrame.h" @@ -7228,16 +7227,53 @@ nsContentUtils::GenerateUUIDInPlace(nsID nsresult rv = sUUIDGenerator->GenerateUUIDInPlace(&aUUID); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; } +bool +nsContentUtils::PrefetchEnabled(nsIDocShell* aDocShell) +{ + // + // SECURITY CHECK: disable prefetching from mailnews! + // + // walk up the docshell tree to see if any containing + // docshell are of type MAIL. + // + + if (!aDocShell) { + return false; + } + + nsCOMPtr<nsIDocShell> docshell = aDocShell; + nsCOMPtr<nsIDocShellTreeItem> parentItem; + + do { + uint32_t appType = 0; + nsresult rv = docshell->GetAppType(&appType); + if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL) { + return false; // do not prefetch, preconnect from mailnews + } + + docshell->GetParent(getter_AddRefs(parentItem)); + if (parentItem) { + docshell = do_QueryInterface(parentItem); + if (!docshell) { + NS_ERROR("cannot get a docshell from a treeItem!"); + return false; + } + } + } while (parentItem); + + return true; +} + uint64_t nsContentUtils::GetInnerWindowID(nsIRequest* aRequest) { // can't do anything if there's no nsIRequest! if (!aRequest) { return 0; }
--- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -912,16 +912,17 @@ public: */ static uint32_t ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr); /** * Helper function that generates a UUID. */ static nsresult GenerateUUIDInPlace(nsID& aUUID); + static bool PrefetchEnabled(nsIDocShell* aDocShell); /** * Fill (with the parameters given) the localized string named |aKey| in * properties file |aFile|. */ private: static nsresult FormatLocalizedString(PropertiesFile aFile, const char* aKey,
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -21,16 +21,17 @@ #include "xpcprivate.h" #include "XPCWrapper.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/dom/RegisterBindings.h" #include "nscore.h" #include "nsDOMClassInfo.h" +#include "nsIDOMClassInfo.h" #include "nsCRT.h" #include "nsCRTGlue.h" #include "nsICategoryManager.h" #include "nsIComponentRegistrar.h" #include "nsXPCOM.h" #include "nsISimpleEnumerator.h" #include "nsISupportsPrimitives.h" #include "nsIXPConnect.h" @@ -112,18 +113,16 @@ #ifdef MOZ_TIME_MANAGER #include "TimeManager.h" #endif using namespace mozilla; using namespace mozilla::dom; -static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); - // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS // are defined in nsIDOMClassInfo.h. #define DOMCLASSINFO_STANDARD_FLAGS \ (nsIClassInfo::MAIN_THREAD_ONLY | \ nsIClassInfo::DOM_OBJECT | \ nsIClassInfo::SINGLETON_CLASSINFO) @@ -135,17 +134,17 @@ static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM #define NS_DEFINE_CLASSINFO_DATA_DEBUG(_class) \ // nothing #endif #define NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags, \ _chromeOnly, _allowXBL) \ { #_class, \ nullptr, \ - { _helper::doCreate }, \ + _helper::doCreate, \ nullptr, \ nullptr, \ nullptr, \ _flags, \ true, \ _chromeOnly, \ _allowXBL, \ false, \ @@ -347,25 +346,16 @@ nsDOMClassInfo::ObjectIsNativeWrapper(JS return xpc::WrapperFactory::IsXrayWrapper(obj) && xpc::AccessCheck::wrapperSubsumes(obj); } nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData) { } -nsDOMClassInfo::~nsDOMClassInfo() -{ - if (IS_EXTERNAL(mData->mCachedClassInfo)) { - // Some compilers don't like delete'ing a const nsDOMClassInfo* - nsDOMClassInfoData* data = const_cast<nsDOMClassInfoData*>(mData); - delete static_cast<nsExternalDOMClassInfoData*>(data); - } -} - NS_IMPL_ADDREF(nsDOMClassInfo) NS_IMPL_RELEASE(nsDOMClassInfo) NS_INTERFACE_MAP_BEGIN(nsDOMClassInfo) if (aIID.Equals(NS_GET_IID(nsXPCClassInfo))) foundInterface = static_cast<nsIClassInfo*>( static_cast<nsXPCClassInfo*>(this)); else @@ -443,68 +433,16 @@ nsDOMClassInfo::RegisterClassProtos(int3 nsCOMPtr<nsIInterfaceInfo> tmp(if_info); tmp->GetParent(getter_AddRefs(if_info)); } return NS_OK; } -// static -nsresult -nsDOMClassInfo::RegisterExternalClasses() -{ - nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); - NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); - - nsCOMPtr<nsIComponentRegistrar> registrar; - nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsICategoryManager> cm = - do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsISimpleEnumerator> e; - rv = cm->EnumerateCategory(JAVASCRIPT_DOM_CLASS, getter_AddRefs(e)); - NS_ENSURE_SUCCESS(rv, rv); - - nsXPIDLCString contractId; - nsAutoCString categoryEntry; - nsCOMPtr<nsISupports> entry; - - while (NS_SUCCEEDED(e->GetNext(getter_AddRefs(entry)))) { - nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry)); - - if (!category) { - NS_WARNING("Category entry not an nsISupportsCString!"); - continue; - } - - rv = category->GetData(categoryEntry); - - cm->GetCategoryEntry(JAVASCRIPT_DOM_CLASS, categoryEntry.get(), - getter_Copies(contractId)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCID *cid; - rv = registrar->ContractIDToCID(contractId, &cid); - if (NS_FAILED(rv)) { - NS_WARNING("Bad contract id registered with the script namespace manager"); - continue; - } - - rv = nameSpaceManager->RegisterExternalClassName(categoryEntry.get(), *cid); - free(cid); - NS_ENSURE_SUCCESS(rv, rv); - } - - return nameSpaceManager->RegisterExternalInterfaces(true); -} - #define _DOM_CLASSINFO_MAP_BEGIN(_class, _ifptr, _has_class_if) \ { \ nsDOMClassInfoData &d = sClassInfoData[eDOMClassInfo_##_class##_id]; \ d.mProtoChainInterface = _ifptr; \ d.mHasClassInterface = _has_class_if; \ static const nsIID *interface_list[] = { #define DOM_CLASSINFO_MAP_BEGIN(_class, _interface) \ @@ -705,17 +643,17 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_END static_assert(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount, "The number of items in sClassInfoData doesn't match the " "number of nsIDOMClassInfo ID's, this is bad! Fix it!"); #ifdef DEBUG for (size_t i = 0; i < eDOMClassInfoIDCount; i++) { - if (!sClassInfoData[i].u.mConstructorFptr || + if (!sClassInfoData[i].mConstructorFptr || sClassInfoData[i].mDebugID != i) { MOZ_CRASH("Class info data out of sync, you forgot to update " "nsDOMClassInfo.h and nsDOMClassInfo.cpp! Fix this, " "mozilla will not work without this fixed!"); } } for (size_t i = 0; i < eDOMClassInfoIDCount; i++) { @@ -740,18 +678,16 @@ nsDOMClassInfo::Init() nameSpaceManager->RegisterClassName(data.mName, i, data.mChromeOnly, data.mAllowXBL, &data.mNameUTF16); } for (i = 0; i < eDOMClassInfoIDCount; ++i) { RegisterClassProtos(i); } - RegisterExternalClasses(); - sIsInitialized = true; return NS_OK; } NS_IMETHODIMP nsDOMClassInfo::GetInterfaces(uint32_t *aCount, nsIID ***aArray) { @@ -974,51 +910,16 @@ nsDOMClassInfo::HasInstance(nsIXPConnect bool *_retval) { NS_WARNING("nsDOMClassInfo::HasInstance Don't call me!"); return NS_ERROR_UNEXPECTED; } static nsresult -GetExternalClassInfo(nsScriptNameSpaceManager *aNameSpaceManager, - const nsAString &aName, - const nsGlobalNameStruct *aStruct, - const nsGlobalNameStruct **aResult) -{ - NS_ASSERTION(aStruct->mType == - nsGlobalNameStruct::eTypeExternalClassInfoCreator, - "Wrong type!"); - - nsresult rv; - nsCOMPtr<nsIDOMCIExtension> creator(do_CreateInstance(aStruct->mCID, &rv)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID)); - NS_ENSURE_TRUE(sof, NS_ERROR_FAILURE); - - rv = creator->RegisterDOMCI(NS_ConvertUTF16toUTF8(aName).get(), sof); - NS_ENSURE_SUCCESS(rv, rv); - - const nsGlobalNameStruct *name_struct = aNameSpaceManager->LookupName(aName); - if (name_struct && - name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - *aResult = name_struct; - } - else { - NS_ERROR("Couldn't get the DOM ClassInfo data."); - - *aResult = nullptr; - } - - return NS_OK; -} - - -static nsresult ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, JS::Handle<JSObject*> obj, const char16_t *name, const nsDOMClassInfoData *ci_data, const nsGlobalNameStruct *name_struct, nsScriptNameSpaceManager *nameSpaceManager, JSObject *dot_prototype, JS::MutableHandle<JS::PropertyDescriptor> ctorDesc); @@ -1129,58 +1030,30 @@ NS_GetDOMClassInfoInstance(nsDOMClassInf } nsresult rv = RegisterDOMNames(); NS_ENSURE_SUCCESS(rv, nullptr); if (!sClassInfoData[aID].mCachedClassInfo) { nsDOMClassInfoData& data = sClassInfoData[aID]; - data.mCachedClassInfo = data.u.mConstructorFptr(&data); + data.mCachedClassInfo = data.mConstructorFptr(&data); NS_ENSURE_TRUE(data.mCachedClassInfo, nullptr); NS_ADDREF(data.mCachedClassInfo); } - NS_ASSERTION(!IS_EXTERNAL(sClassInfoData[aID].mCachedClassInfo), - "This is bad, internal class marked as external!"); - return sClassInfoData[aID].mCachedClassInfo; } // static -nsIClassInfo * -nsDOMClassInfo::GetClassInfoInstance(nsDOMClassInfoData* aData) -{ - NS_ASSERTION(IS_EXTERNAL(aData->mCachedClassInfo) - || !aData->mCachedClassInfo, - "This is bad, external class marked as internal!"); - - if (!aData->mCachedClassInfo) { - if (aData->u.mExternalConstructorFptr) { - aData->mCachedClassInfo = - aData->u.mExternalConstructorFptr(aData->mName); - } else { - aData->mCachedClassInfo = nsDOMGenericSH::doCreate(aData); - } - NS_ENSURE_TRUE(aData->mCachedClassInfo, nullptr); - - NS_ADDREF(aData->mCachedClassInfo); - aData->mCachedClassInfo = MARK_EXTERNAL(aData->mCachedClassInfo); - } - - return GET_CLEAN_CI_PTR(aData->mCachedClassInfo); -} - - -// static void nsDOMClassInfo::ShutDown() { - if (sClassInfoData[0].u.mConstructorFptr) { + if (sClassInfoData[0].mConstructorFptr) { uint32_t i; for (i = 0; i < eDOMClassInfoIDCount; i++) { NS_IF_RELEASE(sClassInfoData[i].mCachedClassInfo); } } sConstructor_id = JSID_VOID; @@ -1197,22 +1070,20 @@ BaseStubConstructor(nsIWeakReference* aW { MOZ_ASSERT(obj); MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext()); nsresult rv; nsCOMPtr<nsISupports> native; if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { rv = NS_ERROR_NOT_AVAILABLE; - } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) { + } else { + MOZ_ASSERT(name_struct->mType == + nsGlobalNameStruct::eTypeExternalConstructor); native = do_CreateInstance(name_struct->mCID, &rv); - } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { - native = do_CreateInstance(name_struct->mAlias->mCID, &rv); - } else { - native = do_CreateInstance(*name_struct->mData->mConstructorCID, &rv); } if (NS_FAILED(rv)) { NS_ERROR("Failed to create the object"); return rv; } js::AssertSameCompartment(cx, obj); return nsContentUtils::WrapNative(cx, native, args.rval(), true); @@ -1274,17 +1145,16 @@ protected: { } ~nsDOMConstructor() {} public: static nsresult Create(const char16_t* aName, - const nsDOMClassInfoData* aData, const nsGlobalNameStruct* aNameStruct, nsPIDOMWindowInner* aOwner, nsDOMConstructor** aResult); NS_DECL_ISUPPORTS NS_DECL_NSIDOMDOMCONSTRUCTOR nsresult PreCreate(JSContext *cx, JSObject *globalObj, JSObject **parentObj); @@ -1330,46 +1200,29 @@ private: } *aNameStruct = nameSpaceManager->LookupName(aName); // Return NS_OK here, aName just isn't a DOM class but nothing failed. return NS_OK; } - static bool IsConstructable(const nsDOMClassInfoData *aData) - { - if (IS_EXTERNAL(aData->mCachedClassInfo)) { - const nsExternalDOMClassInfoData* data = - static_cast<const nsExternalDOMClassInfoData*>(aData); - return data->mConstructorCID != nullptr; - } - - return false; - } static bool IsConstructable(const nsGlobalNameStruct *aNameStruct) { - return - (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor && - IsConstructable(&sClassInfoData[aNameStruct->mDOMClassInfoID])) || - (aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo && - IsConstructable(aNameStruct->mData)) || - aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructor || - aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias; + return aNameStruct->mType == nsGlobalNameStruct::eTypeExternalConstructor; } const char16_t* mClassName; const bool mConstructable; nsWeakPtr mWeakOwner; }; //static nsresult nsDOMConstructor::Create(const char16_t* aName, - const nsDOMClassInfoData* aData, const nsGlobalNameStruct* aNameStruct, nsPIDOMWindowInner* aOwner, nsDOMConstructor** aResult) { *aResult = nullptr; // Prevent creating a constructor if aOwner is inner window which doesn't have // an outer window. If the outer window doesn't have an inner window or the // caller can't access the outer window's current inner window then try to use @@ -1380,19 +1233,17 @@ nsDOMConstructor::Create(const char16_t* outerWindow ? outerWindow->GetCurrentInnerWindow() : aOwner; if (!currentInner || (aOwner != currentInner && !nsContentUtils::CanCallerAccess(currentInner) && !(currentInner = aOwner)->IsInnerWindow())) { return NS_ERROR_DOM_SECURITY_ERR; } - bool constructable = aNameStruct ? - IsConstructable(aNameStruct) : - IsConstructable(aData); + bool constructable = aNameStruct && IsConstructable(aNameStruct); *aResult = new nsDOMConstructor(aName, constructable, currentInner); NS_ADDREF(*aResult); return NS_OK; } NS_IMPL_ADDREF(nsDOMConstructor) NS_IMPL_RELEASE(nsDOMConstructor) @@ -1508,85 +1359,51 @@ nsDOMConstructor::HasInstance(nsIXPConne *bp = true; break; } } return NS_OK; } - if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor && - name_struct->mType != nsGlobalNameStruct::eTypeExternalClassInfo && - name_struct->mType != nsGlobalNameStruct::eTypeExternalConstructorAlias) { + if (name_struct->mType != nsGlobalNameStruct::eTypeClassConstructor) { // Doesn't have DOM interfaces. return NS_OK; } const nsGlobalNameStruct *class_name_struct = GetNameStruct(); NS_ENSURE_TRUE(class_name_struct, NS_ERROR_FAILURE); if (name_struct == class_name_struct) { *bp = true; return NS_OK; } - nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); - NS_ASSERTION(nameSpaceManager, "Can't get namespace manager?"); - const nsIID *class_iid; - if (class_name_struct->mType == nsGlobalNameStruct::eTypeInterface || - class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { + if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { class_iid = &class_name_struct->mIID; } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { class_iid = sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface; - } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - class_iid = class_name_struct->mData->mProtoChainInterface; - } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { - const nsGlobalNameStruct* alias_struct = - nameSpaceManager->GetConstructorProto(class_name_struct); - if (!alias_struct) { - NS_ERROR("Couldn't get constructor prototype."); - return NS_ERROR_UNEXPECTED; - } - - if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { - class_iid = - sClassInfoData[alias_struct->mDOMClassInfoID].mProtoChainInterface; - } else if (alias_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - class_iid = alias_struct->mData->mProtoChainInterface; - } else { - NS_ERROR("Expected eTypeClassConstructor or eTypeExternalClassInfo."); - return NS_ERROR_UNEXPECTED; - } } else { *bp = false; return NS_OK; } - if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { - name_struct = nameSpaceManager->GetConstructorProto(name_struct); - if (!name_struct) { - NS_ERROR("Couldn't get constructor prototype."); - return NS_ERROR_UNEXPECTED; - } - } - - NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor || - name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo, + NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor, "The constructor was set up with a struct of the wrong type."); - const nsDOMClassInfoData *ci_data = nullptr; + const nsDOMClassInfoData *ci_data; if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor && name_struct->mDOMClassInfoID >= 0) { ci_data = &sClassInfoData[name_struct->mDOMClassInfoID]; - } else if (name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - ci_data = name_struct->mData; + } else { + ci_data = nullptr; } nsCOMPtr<nsIInterfaceInfoManager> iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); if (!iim) { NS_ERROR("nsDOMConstructor::HasInstance can't get interface info mgr."); return NS_ERROR_UNEXPECTED; } @@ -1620,24 +1437,21 @@ nsDOMConstructor::HasInstance(nsIXPConne nsresult nsDOMConstructor::ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj) { const nsGlobalNameStruct *class_name_struct = GetNameStruct(); if (!class_name_struct) return NS_ERROR_UNEXPECTED; const nsIID *class_iid; - if (class_name_struct->mType == nsGlobalNameStruct::eTypeInterface || - class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { + if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { class_iid = &class_name_struct->mIID; } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { class_iid = sClassInfoData[class_name_struct->mDOMClassInfoID].mProtoChainInterface; - } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - class_iid = class_name_struct->mData->mProtoChainInterface; } else { return NS_OK; } nsresult rv = DefineInterfaceConstants(cx, obj, class_iid); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; @@ -1654,33 +1468,25 @@ nsDOMConstructor::ToString(nsAString &aR } static nsresult GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin, const nsGlobalNameStruct *aNameStruct, JS::MutableHandle<JSObject*> aProto) { - NS_ASSERTION(aNameStruct->mType == - nsGlobalNameStruct::eTypeClassConstructor || - aNameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo, + NS_ASSERTION(aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor, "Wrong type!"); - nsCOMPtr<nsIClassInfo> ci; - if (aNameStruct->mType == nsGlobalNameStruct::eTypeClassConstructor) { - int32_t id = aNameStruct->mDOMClassInfoID; - MOZ_ASSERT(id >= 0, "Negative DOM classinfo?!?"); + int32_t id = aNameStruct->mDOMClassInfoID; + MOZ_ASSERT(id >= 0, "Negative DOM classinfo?!?"); - nsDOMClassInfoID ci_id = (nsDOMClassInfoID)id; + nsDOMClassInfoID ci_id = (nsDOMClassInfoID)id; - ci = NS_GetDOMClassInfoInstance(ci_id); - } - else { - ci = nsDOMClassInfo::GetClassInfoInstance(aNameStruct->mData); - } + nsCOMPtr<nsIClassInfo> ci = NS_GetDOMClassInfoInstance(ci_id); NS_ENSURE_TRUE(ci, NS_ERROR_UNEXPECTED); nsresult rv = aXPConnect->GetWrappedNativePrototype(cx, aWin->GetGlobalJSObject(), ci, aProto.address()); NS_ENSURE_SUCCESS(rv, rv); return JS_WrapObject(cx, aProto) ? NS_OK : NS_ERROR_FAILURE; } @@ -1698,18 +1504,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec { JS::Rooted<JSObject*> dot_prototype(cx, aDot_prototype); NS_ASSERTION(ci_data || (name_struct && name_struct->mType == nsGlobalNameStruct::eTypeClassProto), "Wrong type or missing ci_data!"); RefPtr<nsDOMConstructor> constructor; - nsresult rv = nsDOMConstructor::Create(name, ci_data, name_struct, - aWin->AsInner(), + nsresult rv = nsDOMConstructor::Create(name, name_struct, aWin->AsInner(), getter_AddRefs(constructor)); NS_ENSURE_SUCCESS(rv, rv); JS::Rooted<JS::Value> v(cx); js::AssertSameCompartment(cx, obj); rv = nsContentUtils::WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), &v, @@ -1852,18 +1657,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec return NS_OK; } static bool OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct, nsGlobalWindow *aWin, JSContext *cx) { MOZ_ASSERT(aStruct->mType == nsGlobalNameStruct::eTypeProperty || - aStruct->mType == nsGlobalNameStruct::eTypeClassConstructor || - aStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo); + aStruct->mType == nsGlobalNameStruct::eTypeClassConstructor); // Don't expose chrome only constructors to content windows. if (aStruct->mChromeOnly) { bool expose; if (aStruct->mAllowXBL) { expose = IsChromeOrXBL(cx, nullptr); } else { expose = nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal()); @@ -1884,27 +1688,18 @@ LookupComponentsShim(JSContext *cx, JS:: // static bool nsWindowSH::NameStructEnabled(JSContext* aCx, nsGlobalWindow *aWin, const nsAString& aName, const nsGlobalNameStruct& aNameStruct) { const nsGlobalNameStruct* nameStruct = &aNameStruct; - if (nameStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) { - nsresult rv = GetExternalClassInfo(GetNameSpaceManager(), aName, nameStruct, - &nameStruct); - if (NS_FAILED(rv) || !nameStruct) { - return false; - } - } - return (nameStruct->mType != nsGlobalNameStruct::eTypeProperty && - nameStruct->mType != nsGlobalNameStruct::eTypeClassConstructor && - nameStruct->mType != nsGlobalNameStruct::eTypeExternalClassInfo) || + nameStruct->mType != nsGlobalNameStruct::eTypeClassConstructor) || OldBindingConstructorEnabled(nameStruct, aWin, aCx); } #ifdef RELEASE_BUILD #define USE_CONTROLLERS_SHIM #endif #ifdef USE_CONTROLLERS_SHIM @@ -1964,26 +1759,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow // The class_name had better match our name MOZ_ASSERT(name.Equals(class_name)); NS_ENSURE_TRUE(class_name, NS_ERROR_UNEXPECTED); nsresult rv = NS_OK; - if (name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) { - rv = GetExternalClassInfo(nameSpaceManager, name, name_struct, - &name_struct); - if (NS_FAILED(rv) || !name_struct) { - return rv; - } - } - if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding || - name_struct->mType == nsGlobalNameStruct::eTypeInterface || name_struct->mType == nsGlobalNameStruct::eTypeClassProto || name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { // Lookup new DOM bindings. DefineInterface getOrCreateInterfaceObject = name_struct->mDefineDOMInterface; if (getOrCreateInterfaceObject) { if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor && !OldBindingConstructorEnabled(name_struct, aWin, cx)) { @@ -2065,55 +1851,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow // doesn't matter what we pass for the "readonly" argument here. FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false); } return NS_OK; } } - if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) { - // We're resolving a name of a DOM interface for which there is no - // direct DOM class, create a constructor object... - RefPtr<nsDOMConstructor> constructor; - rv = nsDOMConstructor::Create(class_name, - nullptr, - name_struct, - aWin->AsInner(), - getter_AddRefs(constructor)); - NS_ENSURE_SUCCESS(rv, rv); - - JS::Rooted<JS::Value> v(cx); - js::AssertSameCompartment(cx, obj); - rv = nsContentUtils::WrapNative(cx, constructor, - &NS_GET_IID(nsIDOMDOMConstructor), &v, - false); - NS_ENSURE_SUCCESS(rv, rv); - - JS::Rooted<JSObject*> class_obj(cx, &v.toObject()); - - // ... and define the constants from the DOM interface on that - // constructor object. - - { - JSAutoCompartment ac(cx, class_obj); - rv = DefineInterfaceConstants(cx, class_obj, &name_struct->mIID); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (!JS_WrapValue(cx, &v)) { - return NS_ERROR_UNEXPECTED; - } - - FillPropertyDescriptor(desc, obj, 0, v); - return NS_OK; - } - - if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor || - name_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { + if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { if (!OldBindingConstructorEnabled(name_struct, aWin, cx)) { return NS_OK; } // Create the XPConnect prototype for our classinfo, PostCreateProto will // set up the prototype chain. This will go ahead and define things on the // actual window's global. JS::Rooted<JSObject*> dot_prototype(cx); @@ -2127,69 +1875,35 @@ nsWindowSH::GlobalResolve(nsGlobalWindow if (!isXray) { // GetXPCProto already defined the property for us FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false); return NS_OK; } // This is the Xray case. Look up the constructor object for this // prototype. - const nsDOMClassInfoData *ci_data; - if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { - ci_data = &sClassInfoData[name_struct->mDOMClassInfoID]; - } else { - ci_data = name_struct->mData; - } - return ResolvePrototype(nsDOMClassInfo::sXPConnect, aWin, cx, obj, - class_name, ci_data, + class_name, + &sClassInfoData[name_struct->mDOMClassInfoID], name_struct, nameSpaceManager, dot_prototype, desc); } if (name_struct->mType == nsGlobalNameStruct::eTypeClassProto) { // We don't have a XPConnect prototype object, let ResolvePrototype create // one. return ResolvePrototype(nsDOMClassInfo::sXPConnect, aWin, cx, obj, class_name, nullptr, name_struct, nameSpaceManager, nullptr, desc); } - if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { - const nsGlobalNameStruct *alias_struct = - nameSpaceManager->GetConstructorProto(name_struct); - NS_ENSURE_TRUE(alias_struct, NS_ERROR_UNEXPECTED); - - // We need to use the XPConnect prototype for the DOM class that this - // constructor is an alias for (for example for Image we need the prototype - // for HTMLImageElement). - JS::Rooted<JSObject*> dot_prototype(cx); - rv = GetXPCProto(nsDOMClassInfo::sXPConnect, cx, aWin, alias_struct, - &dot_prototype); - NS_ENSURE_SUCCESS(rv, rv); - MOZ_ASSERT(dot_prototype); - - const nsDOMClassInfoData *ci_data; - if (alias_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) { - ci_data = &sClassInfoData[alias_struct->mDOMClassInfoID]; - } else if (alias_struct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - ci_data = alias_struct->mData; - } else { - return NS_ERROR_UNEXPECTED; - } - - return ResolvePrototype(nsDOMClassInfo::sXPConnect, aWin, cx, obj, - class_name, ci_data, - name_struct, nameSpaceManager, nullptr, desc); - } - if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) { RefPtr<nsDOMConstructor> constructor; - rv = nsDOMConstructor::Create(class_name, nullptr, name_struct, - aWin->AsInner(), getter_AddRefs(constructor)); + rv = nsDOMConstructor::Create(class_name, name_struct, aWin->AsInner(), + getter_AddRefs(constructor)); NS_ENSURE_SUCCESS(rv, rv); JS::Rooted<JS::Value> val(cx); js::AssertSameCompartment(cx, obj); rv = nsContentUtils::WrapNative(cx, constructor, &NS_GET_IID(nsIDOMDOMConstructor), &val, true); NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -3,19 +3,19 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsDOMClassInfo_h___ #define nsDOMClassInfo_h___ #include "mozilla/Attributes.h" +#include "nsDOMClassInfoID.h" #include "nsIXPCScriptable.h" #include "nsIScriptGlobalObject.h" -#include "nsIDOMScriptObjectFactory.h" #include "js/Id.h" #include "nsIXPConnect.h" #ifdef XP_WIN #undef GetClassName #endif struct nsGlobalNameStruct; @@ -27,77 +27,49 @@ typedef nsIClassInfo* (*nsDOMClassInfoCo (nsDOMClassInfoData* aData); typedef nsresult (*nsDOMConstructorFunc)(nsISupports** aNewObject); struct nsDOMClassInfoData { const char *mName; const char16_t *mNameUTF16; - union { - nsDOMClassInfoConstructorFnc mConstructorFptr; - nsDOMClassInfoExternalConstructorFnc mExternalConstructorFptr; - } u; + nsDOMClassInfoConstructorFnc mConstructorFptr; - nsIClassInfo *mCachedClassInfo; // low bit is set to 1 if external, - // so be sure to mask if necessary! + nsIClassInfo *mCachedClassInfo; const nsIID *mProtoChainInterface; const nsIID **mInterfaces; uint32_t mScriptableFlags : 31; // flags must not use more than 31 bits! uint32_t mHasClassInterface : 1; bool mChromeOnly : 1; bool mAllowXBL : 1; bool mDisabled : 1; #ifdef DEBUG uint32_t mDebugID; #endif }; -struct nsExternalDOMClassInfoData : public nsDOMClassInfoData -{ - const nsCID *mConstructorCID; -}; - - -// To be used with the nsDOMClassInfoData::mCachedClassInfo pointer. -// The low bit is set when we created a generic helper for an external -// (which holds on to the nsDOMClassInfoData). -#define GET_CLEAN_CI_PTR(_ptr) (nsIClassInfo*)(uintptr_t(_ptr) & ~0x1) -#define MARK_EXTERNAL(_ptr) (nsIClassInfo*)(uintptr_t(_ptr) | 0x1) -#define IS_EXTERNAL(_ptr) (uintptr_t(_ptr) & 0x1) - class nsWindowSH; class nsDOMClassInfo : public nsXPCClassInfo { friend class nsWindowSH; protected: - virtual ~nsDOMClassInfo(); + virtual ~nsDOMClassInfo() {}; public: explicit nsDOMClassInfo(nsDOMClassInfoData* aData); NS_DECL_NSIXPCSCRIPTABLE NS_DECL_ISUPPORTS NS_DECL_NSICLASSINFO - // Helper method that returns a *non* refcounted pointer to a - // helper. So please note, don't release this pointer, if you do, - // you better make sure you've addreffed before release. - // - // Whaaaaa! I wanted to name this method GetClassInfo, but nooo, - // some of Microsoft devstudio's headers #defines GetClassInfo to - // GetClassInfoA so I can't, those $%#@^! bastards!!! What gives - // them the right to do that? - - static nsIClassInfo* GetClassInfoInstance(nsDOMClassInfoData* aData); - static nsresult Init(); static void ShutDown(); static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { return new nsDOMClassInfo(aData); } @@ -129,17 +101,16 @@ protected: const nsDOMClassInfoData* mData; virtual void PreserveWrapper(nsISupports *aNative) override { } static nsresult RegisterClassProtos(int32_t aDOMClassInfoID); - static nsresult RegisterExternalClasses(); static nsIXPConnect *sXPConnect; // nsIXPCScriptable code static nsresult DefineStaticJSVals(JSContext *cx); static bool sIsInitialized;
--- a/dom/base/nsDOMClassInfoID.h +++ b/dom/base/nsDOMClassInfoID.h @@ -55,15 +55,11 @@ NS_GetDOMClassInfoInstance(nsDOMClassInf aIID.Equals(NS_GET_IID(nsXPCClassInfo)))) { \ foundInterface = NS_GetDOMClassInfoInstance(eDOMClassInfo_##_class##_id); \ if (!foundInterface) { \ *aInstancePtr = nullptr; \ return NS_ERROR_OUT_OF_MEMORY; \ } \ } else -#else - -// See nsIDOMClassInfo.h - #endif // MOZILLA_INTERNAL_API #endif // nsDOMClassInfoID_h__
deleted file mode 100644 --- a/dom/base/nsDOMScriptObjectFactory.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- 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/. - * - * - * This Original Code has been modified by IBM Corporation. - * Modifications made by IBM described herein are - * Copyright (c) International Business Machines - * Corporation, 2000 - * - * Modifications to Mozilla code or documentation - * identified per MPL Section 3.3 - * - * Date Modified by Description of modification - * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink - * use in OS2 - */ - -#include "nsDOMScriptObjectFactory.h" -#include "nsScriptNameSpaceManager.h" -#include "nsIObserverService.h" -#include "nsJSEnvironment.h" -#include "nsGlobalWindow.h" -#include "nsCRT.h" -#ifdef MOZ_XUL -#include "nsXULPrototypeCache.h" -#endif -#include "nsThreadUtils.h" - -using mozilla::dom::GetNameSpaceManager; - -nsDOMScriptObjectFactory::nsDOMScriptObjectFactory() -{ - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (observerService) { - observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - } - -} - -NS_INTERFACE_MAP_BEGIN(nsDOMScriptObjectFactory) - NS_INTERFACE_MAP_ENTRY(nsIDOMScriptObjectFactory) - NS_INTERFACE_MAP_ENTRY(nsIObserver) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMScriptObjectFactory) -NS_INTERFACE_MAP_END - - -NS_IMPL_ADDREF(nsDOMScriptObjectFactory) -NS_IMPL_RELEASE(nsDOMScriptObjectFactory) - -NS_IMETHODIMP_(nsISupports *) -nsDOMScriptObjectFactory::GetClassInfoInstance(nsDOMClassInfoID aID) -{ - return NS_GetDOMClassInfoInstance(aID); -} - -NS_IMETHODIMP_(nsISupports *) -nsDOMScriptObjectFactory::GetExternalClassInfoInstance(const nsAString& aName) -{ - nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); - NS_ENSURE_TRUE(nameSpaceManager, nullptr); - - const nsGlobalNameStruct *globalStruct = nameSpaceManager->LookupName(aName); - if (globalStruct) { - if (globalStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfoCreator) { - nsresult rv; - nsCOMPtr<nsIDOMCIExtension> creator(do_CreateInstance(globalStruct->mCID, &rv)); - NS_ENSURE_SUCCESS(rv, nullptr); - - rv = creator->RegisterDOMCI(NS_ConvertUTF16toUTF8(aName).get(), this); - NS_ENSURE_SUCCESS(rv, nullptr); - - globalStruct = nameSpaceManager->LookupName(aName); - NS_ENSURE_TRUE(globalStruct, nullptr); - - NS_ASSERTION(globalStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo, - "The classinfo data for this class didn't get registered."); - } - if (globalStruct->mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - return nsDOMClassInfo::GetClassInfoInstance(globalStruct->mData); - } - } - return nullptr; -} - -NS_IMETHODIMP -nsDOMScriptObjectFactory::Observe(nsISupports *aSubject, - const char *aTopic, - const char16_t *someData) -{ - if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { -#ifdef MOZ_XUL - // Flush the XUL cache since it holds JS roots, and we're about to - // start the final GC. - nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance(); - - if (cache) - cache->Flush(); -#endif - } - - return NS_OK; -} - -NS_IMETHODIMP -nsDOMScriptObjectFactory::RegisterDOMClassInfo(const char *aName, - nsDOMClassInfoExternalConstructorFnc aConstructorFptr, - const nsIID *aProtoChainInterface, - const nsIID **aInterfaces, - uint32_t aScriptableFlags, - bool aHasClassInterface, - const nsCID *aConstructorCID) -{ - nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); - NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED); - - return nameSpaceManager->RegisterDOMCIData(aName, - aConstructorFptr, - aProtoChainInterface, - aInterfaces, - aScriptableFlags, - aHasClassInterface, - aConstructorCID); -}
deleted file mode 100644 --- a/dom/base/nsDOMScriptObjectFactory.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- 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/. - * - * - * This Original Code has been modified by IBM Corporation. - * Modifications made by IBM described herein are - * Copyright (c) International Business Machines - * Corporation, 2000 - * - * Modifications to Mozilla code or documentation - * identified per MPL Section 3.3 - * - * Date Modified by Description of modification - * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink - * use in OS2 - */ - -#include "nsIDOMScriptObjectFactory.h" -#include "nsIObserver.h" -#include "mozilla/Attributes.h" - -class nsDOMScriptObjectFactory final : public nsIDOMScriptObjectFactory, - public nsIObserver -{ - ~nsDOMScriptObjectFactory() {} - -public: - nsDOMScriptObjectFactory(); - - NS_DECL_ISUPPORTS - - // nsIObserver - NS_DECL_NSIOBSERVER - - // nsIDOMScriptObjectFactory - NS_IMETHOD_(nsISupports *) GetClassInfoInstance(nsDOMClassInfoID aID) override; - NS_IMETHOD_(nsISupports *) GetExternalClassInfoInstance(const nsAString& aName) override; - - NS_IMETHOD RegisterDOMClassInfo(const char *aName, - nsDOMClassInfoExternalConstructorFnc aConstructorFptr, - const nsIID *aProtoChainInterface, - const nsIID **aInterfaces, - uint32_t aScriptableFlags, - bool aHasClassInterface, - const nsCID *aConstructorCID) override; -}; -
--- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -6,16 +6,17 @@ #include "base/basictypes.h" #include "nsFrameMessageManager.h" #include "AppProcessChecker.h" #include "ContentChild.h" #include "nsContentUtils.h" +#include "nsDOMClassInfoID.h" #include "nsError.h" #include "nsIXPConnect.h" #include "jsapi.h" #include "jsfriendapi.h" #include "nsJSUtils.h" #include "nsJSPrincipals.h" #include "nsNetUtil.h" #include "nsScriptLoader.h"
--- a/dom/base/nsIDOMClassInfo.h +++ b/dom/base/nsIDOMClassInfo.h @@ -2,22 +2,17 @@ /* 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 nsIDOMClassInfo_h___ #define nsIDOMClassInfo_h___ -#include "nsIClassInfoImpl.h" -#include "nsDOMClassInfoID.h" #include "nsIXPCScriptable.h" -#include "nsIServiceManager.h" -#include "nsIDOMScriptObjectFactory.h" -#include "nsDOMCID.h" #define DOM_BASE_SCRIPTABLE_FLAGS \ (nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \ nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \ nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \ nsIXPCScriptable::ALLOW_PROP_MODS_TO_PROTOTYPE | \ nsIXPCScriptable::DONT_ASK_INSTANCE_FOR_SCRIPTABLE | \ nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES) @@ -27,158 +22,9 @@ nsIXPCScriptable::WANT_RESOLVE | \ nsIXPCScriptable::WANT_PRECREATE) #define DOM_DEFAULT_SCRIPTABLE_FLAGS \ (DEFAULT_SCRIPTABLE_FLAGS | \ nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \ nsIXPCScriptable::CLASSINFO_INTERFACES_ONLY) - -#ifdef MOZILLA_INTERNAL_API - -// See nsDOMClassInfoID.h - -#else - -#define NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(_class) \ - if (aIID.Equals(NS_GET_IID(nsIClassInfo)) || \ - aIID.Equals(NS_GET_IID(nsXPCClassInfo))) { \ - static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); \ - \ - nsresult rv; \ - nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID, \ - &rv)); \ - if (NS_FAILED(rv)) { \ - *aInstancePtr = nullptr; \ - return rv; \ - } \ - \ - foundInterface = \ - sof->GetClassInfoInstance(eDOMClassInfo_##_class##_id); \ - } else - -#endif /* MOZILLA_INTERNAL_API */ - -// Looks up the nsIClassInfo for a class name registered with the -// nsScriptNamespaceManager. Remember to release NS_CLASSINFO_NAME(_class) -// (eg. when your module unloads). -#define NS_INTERFACE_MAP_ENTRY_EXTERNAL_DOM_CLASSINFO(_class) \ - if (aIID.Equals(NS_GET_IID(nsIClassInfo)) || \ - aIID.Equals(NS_GET_IID(nsXPCClassInfo))) { \ - extern nsISupports *NS_CLASSINFO_NAME(_class); \ - if (NS_CLASSINFO_NAME(_class)) { \ - foundInterface = NS_CLASSINFO_NAME(_class); \ - } else { \ - static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); \ - \ - nsresult rv; \ - nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID, \ - &rv)); \ - if (NS_FAILED(rv)) { \ - *aInstancePtr = nullptr; \ - return rv; \ - } \ - \ - foundInterface = \ - sof->GetExternalClassInfoInstance(NS_LITERAL_STRING(#_class)); \ - \ - if (foundInterface) { \ - NS_CLASSINFO_NAME(_class) = foundInterface; \ - NS_CLASSINFO_NAME(_class)->AddRef(); \ - } \ - } \ - } else - - -#define NS_DECL_DOM_CLASSINFO(_class) \ - nsISupports *NS_CLASSINFO_NAME(_class) = nullptr; - -// {891a7b01-1b61-11d6-a7f2-f690b638899c} -#define NS_IDOMCI_EXTENSION_IID \ -{ 0x891a7b01, 0x1b61, 0x11d6, \ -{ 0xa7, 0xf2, 0xf6, 0x90, 0xb6, 0x38, 0x89, 0x9c } } - -class nsIDOMScriptObjectFactory; - -class nsIDOMCIExtension : public nsISupports { -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOMCI_EXTENSION_IID) - - NS_IMETHOD RegisterDOMCI(const char* aName, - nsIDOMScriptObjectFactory* aDOMSOFactory) = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMCIExtension, NS_IDOMCI_EXTENSION_IID) - -#define NS_DOMCI_EXTENSION_NAME(_module) ns##_module##DOMCIExtension -#define NS_DOMCI_EXTENSION_CONSTRUCTOR(_module) \ - ns##_module##DOMCIExtensionConstructor -#define NS_DOMCI_EXTENSION_CONSTRUCTOR_IMP(_extension) \ - NS_GENERIC_FACTORY_CONSTRUCTOR(_extension) - -#define NS_DOMCI_EXTENSION(_module) \ -class NS_DOMCI_EXTENSION_NAME(_module) : public nsIDOMCIExtension \ -{ \ -public: \ - NS_DOMCI_EXTENSION_NAME(_module)(); \ - virtual ~NS_DOMCI_EXTENSION_NAME(_module)(); \ - \ - NS_DECL_ISUPPORTS \ - \ - NS_IMETHOD RegisterDOMCI(const char* aName, \ - nsIDOMScriptObjectFactory* aDOMSOFactory); \ -}; \ - \ -NS_DOMCI_EXTENSION_CONSTRUCTOR_IMP(NS_DOMCI_EXTENSION_NAME(_module)) \ - \ -NS_DOMCI_EXTENSION_NAME(_module)::NS_DOMCI_EXTENSION_NAME(_module)() \ -{ \ -} \ - \ -NS_DOMCI_EXTENSION_NAME(_module)::~NS_DOMCI_EXTENSION_NAME(_module)() \ -{ \ -} \ - \ -NS_IMPL_ISUPPORTS(NS_DOMCI_EXTENSION_NAME(_module), nsIDOMCIExtension) \ - \ -NS_IMETHODIMP \ -NS_DOMCI_EXTENSION_NAME(_module)::RegisterDOMCI(const char* aName, \ - nsIDOMScriptObjectFactory* aDOMSOFactory) \ -{ - -#define NS_DOMCI_EXTENSION_ENTRY_BEGIN(_class) \ - if (nsCRT::strcmp(aName, #_class) == 0) { \ - static const nsIID* interfaces[] = { - -#define NS_DOMCI_EXTENSION_ENTRY_INTERFACE(_interface) \ - &NS_GET_IID(_interface), - -// Don't forget to register the primary interface (_proto) in the -// JAVASCRIPT_DOM_INTERFACE category, or prototypes for this class -// won't work (except if the interface name starts with nsIDOM). -#define NS_DOMCI_EXTENSION_ENTRY_END_HELPER(_class, _proto, _hasclassif, \ - _constructorcid) \ - nullptr \ - }; \ - aDOMSOFactory->RegisterDOMClassInfo(#_class, nullptr, _proto, \ - interfaces, \ - DOM_DEFAULT_SCRIPTABLE_FLAGS, \ - _hasclassif, _constructorcid); \ - return NS_OK; \ - } - -#define NS_DOMCI_EXTENSION_ENTRY_END(_class, _proto, _hasclassif, \ - _constructorcid) \ - NS_DOMCI_EXTENSION_ENTRY_END_HELPER(_class, &NS_GET_IID(_proto), \ - _hasclassif, _constructorcid) - -#define NS_DOMCI_EXTENSION_ENTRY_END_NO_PRIMARY_IF(_class, _hasclassif, \ - _constructorcid) \ - NS_DOMCI_EXTENSION_ENTRY_END_HELPER(_class, nullptr, _hasclassif, \ - _constructorcid) - -#define NS_DOMCI_EXTENSION_END \ - return NS_ERROR_FAILURE; \ -} - - #endif /* nsIDOMClassInfo_h___ */
deleted file mode 100644 --- a/dom/base/nsIDOMScriptObjectFactory.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsIDOMScriptObjectFactory_h__ -#define nsIDOMScriptObjectFactory_h__ - -#include "nsISupports.h" -#include "nsIDOMClassInfo.h" -#include "nsString.h" - -#define NS_IDOM_SCRIPT_OBJECT_FACTORY_IID \ -{ 0x2a50e17c, 0x46ff, 0x4150, \ - { 0xbb, 0x46, 0xd8, 0x07, 0xb3, 0x36, 0xde, 0xab } } - -typedef nsXPCClassInfo* (*nsDOMClassInfoExternalConstructorFnc) - (const char* aName); - -class nsIDOMScriptObjectFactory : public nsISupports { -public: - NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOM_SCRIPT_OBJECT_FACTORY_IID) - - NS_IMETHOD_(nsISupports *) GetClassInfoInstance(nsDOMClassInfoID aID) = 0; - NS_IMETHOD_(nsISupports *) GetExternalClassInfoInstance(const nsAString& aName) = 0; - - // Register the info for an external class. aName must be static - // data, it will not be deleted by the DOM code. aProtoChainInterface - // must be registered in the JAVASCRIPT_DOM_INTERFACE category, or - // prototypes for this class won't work (except if the interface - // name starts with nsIDOM). - NS_IMETHOD RegisterDOMClassInfo(const char *aName, - nsDOMClassInfoExternalConstructorFnc aConstructorFptr, - const nsIID *aProtoChainInterface, - const nsIID **aInterfaces, - uint32_t aScriptableFlags, - bool aHasClassInterface, - const nsCID *aConstructorCID) = 0; -}; - -NS_DEFINE_STATIC_IID_ACCESSOR(nsIDOMScriptObjectFactory, - NS_IDOM_SCRIPT_OBJECT_FACTORY_IID) - -#endif /* nsIDOMScriptObjectFactory_h__ */
--- a/dom/base/nsIScriptNameSpaceManager.h +++ b/dom/base/nsIScriptNameSpaceManager.h @@ -5,28 +5,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsIScriptNameSpaceManager_h__ #define nsIScriptNameSpaceManager_h__ #define JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY \ "JavaScript-global-constructor" -#define JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY \ - "JavaScript-global-constructor-prototype-alias" - #define JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY \ "JavaScript-global-property" // a global property that is only accessible to privileged script #define JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY \ "JavaScript-global-privileged-property" #define JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY \ "JavaScript-navigator-property" -#define JAVASCRIPT_DOM_CLASS \ - "JavaScript-DOM-class" - -#define JAVASCRIPT_DOM_INTERFACE \ - "JavaScript-DOM-interface" - #endif /* nsIScriptNameSpaceManager_h__ */
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -2557,18 +2557,16 @@ AsmJSCacheOpenEntryForWrite(JS::Handle<J intptr_t* aHandle) { nsIPrincipal* principal = nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aGlobal))); return asmjscache::OpenEntryForWrite(principal, aInstalled, aBegin, aEnd, aSize, aMemory, aHandle); } -static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); - void nsJSContext::EnsureStatics() { if (sIsInitialized) { if (!nsContentUtils::XPConnect()) { MOZ_CRASH(); } return; @@ -2690,25 +2688,16 @@ nsJSContext::EnsureStatics() nsIObserver* observer = new nsJSEnvironmentObserver(); obs->AddObserver(observer, "memory-pressure", false); obs->AddObserver(observer, "user-interaction-inactive", false); obs->AddObserver(observer, "user-interaction-active", false); obs->AddObserver(observer, "quit-application", false); obs->AddObserver(observer, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - // Bug 907848 - We need to explicitly get the nsIDOMScriptObjectFactory - // service in order to force its constructor to run, which registers a - // shutdown observer. It would be nice to make this more explicit and less - // side-effect-y. - nsCOMPtr<nsIDOMScriptObjectFactory> factory = do_GetService(kDOMScriptObjectFactoryCID); - if (!factory) { - MOZ_CRASH(); - } - sIsInitialized = true; } void nsJSContext::NotifyDidPaint() { sDidPaintAfterPreviousICCSlice = true; }
--- a/dom/base/nsScriptNameSpaceManager.cpp +++ b/dom/base/nsScriptNameSpaceManager.cpp @@ -56,31 +56,16 @@ GlobalNameHashMatchEntry(PLDHashTable *t static void GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) { GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry); // An entry is being cleared, let the key (nsString) do its own // cleanup. e->mKey.~nsString(); - if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalClassInfo) { - nsIClassInfo* ci = GET_CLEAN_CI_PTR(e->mGlobalName.mData->mCachedClassInfo); - - // If we constructed an internal helper, we'll let the helper delete - // the nsDOMClassInfoData structure, if not we do it here. - if (!ci || e->mGlobalName.mData->u.mExternalConstructorFptr) { - delete e->mGlobalName.mData; - } - - // Release our pointer to the helper. - NS_IF_RELEASE(ci); - } - else if (e->mGlobalName.mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) { - delete e->mGlobalName.mAlias; - } // This will set e->mGlobalName.mType to // nsGlobalNameStruct::eTypeNotInitialized memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct)); } static void GlobalNameHashInitEntry(PLDHashEntryHdr *entry, const void *key) @@ -146,31 +131,16 @@ nsScriptNameSpaceManager::AddToHash(PLDH void nsScriptNameSpaceManager::RemoveFromHash(PLDHashTable *aTable, const nsAString *aKey) { aTable->Remove(aKey); } -nsGlobalNameStruct* -nsScriptNameSpaceManager::GetConstructorProto(const nsGlobalNameStruct* aStruct) -{ - NS_ASSERTION(aStruct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias, - "This function only works on constructor aliases!"); - if (!aStruct->mAlias->mProto) { - auto proto = static_cast<GlobalNameMapEntry*> - (mGlobalNames.Search(&aStruct->mAlias->mProtoName)); - if (proto) { - aStruct->mAlias->mProto = &proto->mGlobalName; - } - } - return aStruct->mAlias->mProto; -} - nsresult nsScriptNameSpaceManager::FillHash(nsICategoryManager *aCategoryManager, const char *aCategory) { nsCOMPtr<nsISimpleEnumerator> e; nsresult rv = aCategoryManager->EnumerateCategory(aCategory, getter_AddRefs(e)); NS_ENSURE_SUCCESS(rv, rv); @@ -183,135 +153,22 @@ nsScriptNameSpaceManager::FillHash(nsICa } } return NS_OK; } nsresult -nsScriptNameSpaceManager::RegisterExternalInterfaces(bool aAsProto) -{ - nsresult rv; - nsCOMPtr<nsICategoryManager> cm = - do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIInterfaceInfoManager> - iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); - NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE); - - nsCOMPtr<nsISimpleEnumerator> enumerator; - rv = cm->EnumerateCategory(JAVASCRIPT_DOM_INTERFACE, - getter_AddRefs(enumerator)); - NS_ENSURE_SUCCESS(rv, rv); - - nsXPIDLCString IID_string; - nsAutoCString category_entry; - const char* if_name; - nsCOMPtr<nsISupports> entry; - nsCOMPtr<nsIInterfaceInfo> if_info; - bool found_old, dom_prefix; - - while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) { - nsCOMPtr<nsISupportsCString> category(do_QueryInterface(entry)); - - if (!category) { - NS_WARNING("Category entry not an nsISupportsCString!"); - - continue; - } - - rv = category->GetData(category_entry); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cm->GetCategoryEntry(JAVASCRIPT_DOM_INTERFACE, category_entry.get(), - getter_Copies(IID_string)); - NS_ENSURE_SUCCESS(rv, rv); - - nsIID primary_IID; - if (!primary_IID.Parse(IID_string) || - primary_IID.Equals(NS_GET_IID(nsISupports))) { - NS_ERROR("Invalid IID registered wi