diff --git a/.eslintignore b/.eslintignore index bd9ec81efb65..a676a160e1c7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -83,11 +83,9 @@ devtools/client/debugger/** devtools/client/framework/** !devtools/client/framework/selection.js !devtools/client/framework/toolbox.js -devtools/client/jsonview/lib/** devtools/client/netmonitor/test/** devtools/client/netmonitor/har/test/** devtools/client/projecteditor/** -devtools/client/promisedebugger/** devtools/client/responsivedesign/** devtools/client/scratchpad/** devtools/client/shadereditor/** @@ -104,17 +102,9 @@ devtools/client/webconsole/webconsole-connection-proxy.js devtools/client/webconsole/webconsole.js devtools/client/webide/** !devtools/client/webide/components/webideCli.js -devtools/server/*.js -devtools/server/*.jsm -!devtools/server/child.js -!devtools/server/css-logic.js -!devtools/server/main.js -!devtools/server/websocket-server.js -devtools/server/actors/** +devtools/server/actors/*.js !devtools/server/actors/csscoverage.js !devtools/server/actors/inspector.js -!devtools/server/actors/highlighters/css-grid.js -!devtools/server/actors/highlighters/eye-dropper.js !devtools/server/actors/layout.js !devtools/server/actors/string.js !devtools/server/actors/styles.js @@ -122,7 +112,6 @@ devtools/server/actors/** !devtools/server/actors/webbrowser.js !devtools/server/actors/webextension.js !devtools/server/actors/webextension-inspected-window.js -devtools/server/performance/** devtools/server/tests/browser/** !devtools/server/tests/browser/browser_webextension_inspected_window.js devtools/server/tests/mochitest/** @@ -134,7 +123,6 @@ devtools/shared/gcli/** !devtools/shared/gcli/templater.js devtools/shared/heapsnapshot/** devtools/shared/layout/** -devtools/shared/locales/** devtools/shared/performance/** !devtools/shared/platform/** devtools/shared/qrcode/** diff --git a/CLOBBER b/CLOBBER index b3e90652edb8..2fd2446034c8 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1142403 needs a clobber to force jemalloc to rerun configure. +Bug 1322938 needs a clobber for test_lowDiskSpace.html on Android diff --git a/accessible/aom/AccessibleNode.cpp b/accessible/aom/AccessibleNode.cpp index 966aa0f3df59..e899a04400e8 100644 --- a/accessible/aom/AccessibleNode.cpp +++ b/accessible/aom/AccessibleNode.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/DOMStringList.h" #include "nsIPersistentProperties2.h" +#include "nsISimpleEnumerator.h" #include "Accessible-inl.h" #include "nsAccessibilityService.h" @@ -77,6 +78,31 @@ AccessibleNode::GetStates(nsTArray& aStates) aStates.AppendElement(NS_LITERAL_STRING("defunct")); } +void +AccessibleNode::GetAttributes(nsTArray& aAttributes) +{ + if (!mIntl) { + return; + } + + nsCOMPtr attrs = mIntl->Attributes(); + + nsCOMPtr props; + attrs->Enumerate(getter_AddRefs(props)); + + bool hasMore = false; + while (NS_SUCCEEDED(props->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr supp; + props->GetNext(getter_AddRefs(supp)); + + nsCOMPtr prop(do_QueryInterface(supp)); + + nsAutoCString attr; + prop->GetKey(attr); + aAttributes.AppendElement(NS_ConvertUTF8toUTF16(attr)); + } +} + bool AccessibleNode::Is(const Sequence& aFlavors) { diff --git a/accessible/aom/AccessibleNode.h b/accessible/aom/AccessibleNode.h index 7a63221dfa23..71fc4609528f 100644 --- a/accessible/aom/AccessibleNode.h +++ b/accessible/aom/AccessibleNode.h @@ -38,6 +38,7 @@ public: void GetRole(nsAString& aRole); void GetStates(nsTArray& aStates); + void GetAttributes(nsTArray& aAttributes); nsINode* GetDOMNode(); bool Is(const Sequence& aFlavors); diff --git a/accessible/tests/mochitest/aom/test_general.html b/accessible/tests/mochitest/aom/test_general.html index a18ea905dab5..1a9c6911e21a 100644 --- a/accessible/tests/mochitest/aom/test_general.html +++ b/accessible/tests/mochitest/aom/test_general.html @@ -86,6 +86,21 @@ ok(anode.has('explicit-name'), 'object attributes are present'); + var attrs = [ 'explicit-name' ]; + if (anode.attributes.length > 1) { + attrs = [ + 'margin-left', 'text-align', 'text-indent', 'margin-right', + 'tag', 'margin-top', 'margin-bottom', 'display', + 'explicit-name' + ]; + } + + is(anode.attributes.length, attrs.length, 'correct number of attributes'); + for (var i = 0; i < attrs.length; i++) { + is(anode.attributes[i], attrs[i], + `${attrs[i]} attribute is expected at ${i}th index`); + } + finish(); } diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 8a4dd516e1be..cc5f8659bef0 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1215,12 +1215,7 @@ pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.ht pref("security.mixed_content.block_active_content", true); // Show degraded UI for http pages with password fields. -// Only for Nightly, Dev Edition and early beta, not for late beta or release. -#ifdef EARLY_BETA_OR_EARLIER pref("security.insecure_password.ui.enabled", true); -#else -pref("security.insecure_password.ui.enabled", false); -#endif pref("security.insecure_field_warning.contextual.enabled", false); diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index f63fe87a248a..f105ad15d024 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -2240,6 +2240,15 @@ this.tabContainer.updateVisibility(); + // If URI is about:blank and we don't have a preferred remote type, + // then we need to use the referrer, if we have one, to get the + // correct remote type for the new tab. + if (uriIsAboutBlank && !aPreferredRemoteType && aReferrerURI) { + aPreferredRemoteType = + E10SUtils.getRemoteTypeForURI(aReferrerURI.spec, + gMultiProcessBrowser); + } + // Currently in this incarnation of bug 906076, we are forcing the // browser to immediately be linked. In future incarnations of this // bug this will be removed so we can leave the tab in its "lazy" @@ -6456,44 +6465,58 @@ // to get a full-resolution drag image for use on HiDPI displays. let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils); let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom; - let canvas = this._dndCanvas ? this._dndCanvas - : document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); - canvas.mozOpaque = true; + let canvas = this._dndCanvas; + if (!canvas) { + this._dndCanvas = canvas = + document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); + canvas.style.width = "100%"; + canvas.style.height = "100%"; + canvas.mozOpaque = true; + } + canvas.width = 160 * scale; canvas.height = 90 * scale; - let toDrag; + let toDrag = canvas; let dragImageOffset = -16; if (gMultiProcessBrowser) { var context = canvas.getContext('2d'); context.fillStyle = "white"; context.fillRect(0, 0, canvas.width, canvas.height); - // Create a panel to use it in setDragImage - // which will tell xul to render a panel that follows - // the pointer while a dnd session is on. - if (!this._dndPanel) { - this._dndCanvas = canvas; - this._dndPanel = document.createElement("panel"); - this._dndPanel.className = "dragfeedback-tab"; - this._dndPanel.setAttribute("type", "drag"); - let wrapper = document.createElementNS("http://www.w3.org/1999/xhtml", "div"); - wrapper.style.width = "160px"; - wrapper.style.height = "90px"; - wrapper.appendChild(canvas); - canvas.style.width = "100%"; - canvas.style.height = "100%"; - this._dndPanel.appendChild(wrapper); - document.documentElement.appendChild(this._dndPanel); + + let captureListener; + let platform = this.tabbrowser.AppConstants.platform; + // On Windows and Mac we can update the drag image during a drag + // using updateDragImage. On Linux, we can use a panel. + if (platform == "win" || platform == "macosx") { + captureListener = function() { + dt.updateDragImage(canvas, dragImageOffset, dragImageOffset); + } + } + else { + // Create a panel to use it in setDragImage + // which will tell xul to render a panel that follows + // the pointer while a dnd session is on. + if (!this._dndPanel) { + this._dndCanvas = canvas; + this._dndPanel = document.createElement("panel"); + this._dndPanel.className = "dragfeedback-tab"; + this._dndPanel.setAttribute("type", "drag"); + let wrapper = document.createElementNS("http://www.w3.org/1999/xhtml", "div"); + wrapper.style.width = "160px"; + wrapper.style.height = "90px"; + wrapper.appendChild(canvas); + this._dndPanel.appendChild(wrapper); + document.documentElement.appendChild(this._dndPanel); + } + toDrag = this._dndPanel; } // PageThumb is async with e10s but that's fine - // since we can update the panel during the dnd. - PageThumbs.captureToCanvas(browser, canvas); - toDrag = this._dndPanel; + // since we can update the image during the dnd. + PageThumbs.captureToCanvas(browser, canvas, captureListener); } else { // For the non e10s case we can just use PageThumbs - // sync. No need for xul magic, the native dnd will - // be fine, so let's use the canvas for setDragImage. + // sync, so let's use the canvas for setDragImage. PageThumbs.captureToCanvas(browser, canvas); - toDrag = canvas; dragImageOffset = dragImageOffset * scale; } dt.setDragImage(toDrag, dragImageOffset, dragImageOffset); diff --git a/browser/base/content/test/tabs/browser.ini b/browser/base/content/test/tabs/browser.ini index a8f714dfd6bf..90df12f5b1fd 100644 --- a/browser/base/content/test/tabs/browser.ini +++ b/browser/base/content/test/tabs/browser.ini @@ -1,5 +1,10 @@ +[DEFAULT] +support-files = + dummy_page.html + [browser_tabSpinnerProbe.js] skip-if = !e10s # Tab spinner is e10s only. [browser_tabSwitchPrintPreview.js] skip-if = os == 'mac' [browser_navigatePinnedTab.js] +[browser_opened_file_tab_navigated_to_web.js] diff --git a/browser/base/content/test/tabs/browser_opened_file_tab_navigated_to_web.js b/browser/base/content/test/tabs/browser_opened_file_tab_navigated_to_web.js new file mode 100644 index 000000000000..3386c0a7034a --- /dev/null +++ b/browser/base/content/test/tabs/browser_opened_file_tab_navigated_to_web.js @@ -0,0 +1,38 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ + +const TEST_FILE = "dummy_page.html"; + +// Test for bug 1321020. +add_task(function* () { + let dir = getChromeDir(getResolvedURI(gTestPath)); + dir.append(TEST_FILE); + const uriString = Services.io.newFileURI(dir).spec; + const openedUriString = uriString + "?opened"; + + // Open first file:// page. + let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uriString); + registerCleanupFunction(function* () { + yield BrowserTestUtils.removeTab(tab); + }); + + // Open new file:// tab from JavaScript in first file:// page. + let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, openedUriString); + yield ContentTask.spawn(tab.linkedBrowser, openedUriString, uri => { + content.open(uri, "_blank"); + }); + + let openedTab = yield promiseTabOpened; + registerCleanupFunction(function* () { + yield BrowserTestUtils.removeTab(openedTab); + }); + + let openedBrowser = openedTab.linkedBrowser; + yield BrowserTestUtils.browserLoaded(openedBrowser); + + // Ensure that new file:// tab can be navigated to web content. + openedBrowser.loadURI("http://example.org/"); + let href = yield BrowserTestUtils.browserLoaded(openedBrowser); + is(href, "http://example.org/", + "Check that new file:// page has navigated successfully to web content"); +}); diff --git a/browser/base/content/test/tabs/dummy_page.html b/browser/base/content/test/tabs/dummy_page.html new file mode 100644 index 000000000000..1a87e28408d0 --- /dev/null +++ b/browser/base/content/test/tabs/dummy_page.html @@ -0,0 +1,9 @@ + + +Dummy test page + + + +

Dummy test page

+ + diff --git a/browser/config/mozconfigs/win32/clang b/browser/config/mozconfigs/win32/clang index 426958d45568..119a26ed3935 100644 --- a/browser/config/mozconfigs/win32/clang +++ b/browser/config/mozconfigs/win32/clang @@ -7,8 +7,7 @@ MOZ_AUTOMATION_L10N_CHECK=0 ac_add_options --enable-optimize -#Work to make the clang-plugin work on Windows is ongoing in bug 1316545. -#ac_add_options --enable-clang-plugin +ac_add_options --enable-clang-plugin . $topsrcdir/build/win32/mozconfig.vs-latest diff --git a/browser/config/mozconfigs/win32/clang-debug b/browser/config/mozconfigs/win32/clang-debug index b354d25acfbe..372e545838c8 100644 --- a/browser/config/mozconfigs/win32/clang-debug +++ b/browser/config/mozconfigs/win32/clang-debug @@ -8,8 +8,7 @@ MOZ_AUTOMATION_L10N_CHECK=0 ac_add_options --enable-optimize ac_add_options --enable-debug -#Work to make the clang-plugin work on Windows is ongoing in bug 1316545. -#ac_add_options --enable-clang-plugin +ac_add_options --enable-clang-plugin . $topsrcdir/build/win32/mozconfig.vs-latest diff --git a/browser/config/mozconfigs/win64/clang b/browser/config/mozconfigs/win64/clang index 8de249b45190..14f09b97a8fe 100644 --- a/browser/config/mozconfigs/win64/clang +++ b/browser/config/mozconfigs/win64/clang @@ -9,8 +9,7 @@ ac_add_options --host=x86_64-pc-mingw32 ac_add_options --enable-optimize -#Work to make the clang-plugin work on Windows is ongoing in bug 1316545. -#ac_add_options --enable-clang-plugin +ac_add_options --enable-clang-plugin . $topsrcdir/build/win64/mozconfig.vs-latest diff --git a/browser/config/mozconfigs/win64/clang-debug b/browser/config/mozconfigs/win64/clang-debug index ba416e22fc04..5565578fb2f7 100644 --- a/browser/config/mozconfigs/win64/clang-debug +++ b/browser/config/mozconfigs/win64/clang-debug @@ -10,8 +10,7 @@ ac_add_options --host=x86_64-pc-mingw32 ac_add_options --enable-optimize ac_add_options --enable-debug -#Work to make the clang-plugin work on Windows is ongoing in bug 1316545. -#ac_add_options --enable-clang-plugin +ac_add_options --enable-clang-plugin . $topsrcdir/build/win64/mozconfig.vs-latest diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index 61ec15c97565..7d6e507a2035 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -526,7 +526,30 @@ protected: // This doesn't check that it's really ::std::pair and not // ::std::something_else::pair, but should be good enough. StringRef Name = getNameChecked(D); - if (Name == "pair" || Name == "atomic" || Name == "__atomic_base") { + if (Name == "pair" || + Name == "atomic" || + // libstdc++ specific names + Name == "__atomic_base" || + Name == "atomic_bool" || + // MSVCRT specific names + Name == "_Atomic_impl" || + Name == "_Atomic_base" || + Name == "_Atomic_bool" || + Name == "_Atomic_char" || + Name == "_Atomic_schar" || + Name == "_Atomic_uchar" || + Name == "_Atomic_char16_t" || + Name == "_Atomic_char32_t" || + Name == "_Atomic_wchar_t" || + Name == "_Atomic_short" || + Name == "_Atomic_ushort" || + Name == "_Atomic_int" || + Name == "_Atomic_uint" || + Name == "_Atomic_long" || + Name == "_Atomic_ulong" || + Name == "_Atomic_llong" || + Name == "_Atomic_ullong" || + Name == "_Atomic_address") { return false; } return true; diff --git a/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp b/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp new file mode 100644 index 000000000000..b8aef2eacd31 --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp @@ -0,0 +1,30 @@ +// expected-no-diagnostics + +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) + +template +class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { T mForceInst; }; + +#include +#include +struct CustomType{}; +static struct { + Mover> m1; + Mover> m2; + Mover> m3; + Mover> m4; + Mover> m5; + Mover> m6; + Mover> m7; + Mover> m8; + Mover> m9; + Mover> m10; + Mover> m11; + Mover> m12; + Mover> m13; + Mover> m14; + Mover> m15; + Mover> m16; + Mover> m17; + Mover> m18; +} good; diff --git a/build/clang-plugin/tests/moz.build b/build/clang-plugin/tests/moz.build index 3f7bdcba18a7..1230a2aae1fa 100644 --- a/build/clang-plugin/tests/moz.build +++ b/build/clang-plugin/tests/moz.build @@ -30,6 +30,7 @@ SOURCES += [ 'TestNonHeapClass.cpp', 'TestNonMemMovable.cpp', 'TestNonMemMovableStd.cpp', + 'TestNonMemMovableStdAtomic.cpp', 'TestNonParameterChecker.cpp', 'TestNonTemporaryClass.cpp', 'TestNoRefcountedInsideLambdas.cpp', diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure index 3163f7e4cb2f..3193a060d0c5 100644 --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -702,9 +702,9 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None, # Check the compiler version here instead of in `compiler_version` so # that the `checking` message doesn't pretend the compiler can be used # to then bail out one line later. - if info.type == 'gcc' and info.version < '4.8.0': + if info.type == 'gcc' and info.version < '4.9.0': raise FatalCheckError( - 'Only GCC 4.8 or newer is supported (found version %s).' + 'Only GCC 4.9 or newer is supported (found version %s).' % info.version) # If you want to bump the version check here search for diff --git a/build/variables.py b/build/variables.py index d93335e93027..7761e6096c2e 100644 --- a/build/variables.py +++ b/build/variables.py @@ -9,6 +9,7 @@ import subprocess import sys from datetime import datetime +SOURCESTAMP_FILENAME = 'sourcestamp.txt' def buildid_header(output): buildid = os.environ.get('MOZ_BUILD_DATE') @@ -44,6 +45,26 @@ def get_hg_info(workdir): def get_hg_changeset(path): return get_program_output('hg', '-R', path, 'parent', '--template={node}') +def get_info_from_sourcestamp(sourcestamp_path): + """Read the repository and changelog information from the sourcestamp + file. This assumes that the file exists and returns the results as a list + (either strings or None in case of error). + """ + + # Load the content of the file. + lines = None + with open(sourcestamp_path) as f: + lines = f.read().splitlines() + + # Parse the repo and the changeset. The sourcestamp file is supposed to + # contain two lines: the first is the build id and the second is the source + # URL. + if len(lines) != 2 or not lines[1].startswith('http'): + # Just return if the file doesn't contain what we expect. + return None, None + + # Return the repo and the changeset. + return lines[1].split('/rev/') def source_repo_header(output): # We allow the source repo and changeset to be specified via the @@ -54,8 +75,11 @@ def source_repo_header(output): source = '' if not repo: + sourcestamp_path = os.path.join(buildconfig.topsrcdir, SOURCESTAMP_FILENAME) if os.path.exists(os.path.join(buildconfig.topsrcdir, '.hg')): repo, changeset = get_hg_info(buildconfig.topsrcdir) + elif os.path.exists(sourcestamp_path): + repo, changeset = get_info_from_sourcestamp(sourcestamp_path) elif not changeset: changeset = get_hg_changeset(buildconfig.topsrcdir) if not changeset: diff --git a/devtools/server/actors/highlighters/rulers.js b/devtools/server/actors/highlighters/rulers.js index 01e082e674e9..c7b58bc51c05 100644 --- a/devtools/server/actors/highlighters/rulers.js +++ b/devtools/server/actors/highlighters/rulers.js @@ -150,12 +150,10 @@ RulersHighlighter.prototype = { } else { dGraduations += `M${i} 0 L${i} ${graduationLength} `; } + } else if (i % 50 === 0) { + dMarkers += `M0 ${i} L${graduationLength} ${i}`; } else { - if (i % 50 === 0) { - dMarkers += `M0 ${i} L${graduationLength} ${i}`; - } else { - dGraduations += `M0 ${i} L${graduationLength} ${i}`; - } + dGraduations += `M0 ${i} L${graduationLength} ${i}`; } } diff --git a/devtools/server/actors/highlighters/utils/markup.js b/devtools/server/actors/highlighters/utils/markup.js index 8f7741eae49c..602ef280c828 100644 --- a/devtools/server/actors/highlighters/utils/markup.js +++ b/devtools/server/actors/highlighters/utils/markup.js @@ -245,7 +245,7 @@ function CanvasFrameAnonymousContentHelper(highlighterEnv, nodeBuilder) { this._insert(); } - this._onWindowReady= this._onWindowReady.bind(this); + this._onWindowReady = this._onWindowReady.bind(this); this.highlighterEnv.on("window-ready", this._onWindowReady); this.listeners = new Map(); diff --git a/devtools/server/actors/utils/TabSources.js b/devtools/server/actors/utils/TabSources.js index 56e862939fcb..8a845266dee3 100644 --- a/devtools/server/actors/utils/TabSources.js +++ b/devtools/server/actors/utils/TabSources.js @@ -4,7 +4,6 @@ "use strict"; -const { Ci, Cu } = require("chrome"); const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const { assert, fetch } = DevToolsUtils; const EventEmitter = require("devtools/shared/event-emitter"); @@ -137,18 +136,16 @@ TabSources.prototype = { // is the HTML url. originalUrl = source.url; source = null; - } - else if (this._sourceActors.has(source)) { + } else if (this._sourceActors.has(source)) { return this._sourceActors.get(source); } - } - else if (originalUrl) { + } else if (originalUrl) { // Not all "original" scripts are distinctly separate from the // generated script. Pretty-printed sources have a sourcemap for // themselves, so we need to make sure there a real source // doesn't already exist with this URL. - for (let [source, actor] of this._sourceActors) { - if (source.url === originalUrl) { + for (let [sourceData, actor] of this._sourceActors) { + if (sourceData.url === originalUrl) { return actor; } } @@ -168,7 +165,7 @@ TabSources.prototype = { }); let sourceActorStore = this._thread.sourceActorStore; - var id = sourceActorStore.getReusableActorId(source, originalUrl); + let id = sourceActorStore.getReusableActorId(source, originalUrl); if (id) { actor.actorID = id; } @@ -179,15 +176,13 @@ TabSources.prototype = { if (this._autoBlackBox && !this.neverAutoBlackBoxSources.has(actor.url) && this._isMinifiedURL(actor.url)) { - this.blackBox(actor.url); this.neverAutoBlackBoxSources.add(actor.url); } if (source) { this._sourceActors.set(source, actor); - } - else { + } else { this._sourceMappedSourceActors[originalUrl] = actor; } @@ -201,8 +196,7 @@ TabSources.prototype = { // it's something that has been sourcemapped, or it represents // the HTML file that contains inline sources. this.emit("newSource", actor); - } - else { + } else { // If sourcemapping is enabled and a source has sourcemaps, we // create `SourceActor` instances for both the original and // generated sources. The source actors for the generated @@ -246,30 +240,29 @@ TabSources.prototype = { } throw new Error("getSourceActorByURL: could not find source for " + url); - return null; }, /** * Returns true if the URL likely points to a minified resource, false * otherwise. * - * @param String aURL - * The URL to test. + * @param String uri + * The url to test. * @returns Boolean */ - _isMinifiedURL: function (aURL) { - if (!aURL) { + _isMinifiedURL: function (uri) { + if (!uri) { return false; } try { - let url = new URL(aURL); + let url = new URL(uri); let pathname = url.pathname; return MINIFIED_SOURCE_REGEXP.test(pathname.slice(pathname.lastIndexOf("/") + 1)); } catch (e) { // Not a valid URL so don't try to parse out the filename, just test the // whole thing with the minified source regexp. - return MINIFIED_SOURCE_REGEXP.test(aURL); + return MINIFIED_SOURCE_REGEXP.test(uri); } }, @@ -278,19 +271,19 @@ TabSources.prototype = { * source mapping and always returns an actor representing this real * source. Use `createSourceActors` if you want to respect source maps. * - * @param Debugger.Source aSource + * @param Debugger.Source source * The source instance to create an actor for. * @returns SourceActor */ - createNonSourceMappedActor: function (aSource) { + createNonSourceMappedActor: function (source) { // Don't use getSourceURL because we don't want to consider the // displayURL property if it's an eval source. We only want to // consider real URLs, otherwise if there is a URL but it's // invalid the code below will not set the content type, and we // will later try to fetch the contents of the URL to figure out // the content type, but it's a made up URL for eval sources. - let url = isEvalSource(aSource) ? null : aSource.url; - let spec = { source: aSource }; + let url = isEvalSource(source) ? null : source.url; + let spec = { source }; // XXX bug 915433: We can't rely on Debugger.Source.prototype.text // if the source is an HTML-embedded diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 30ba15eb3b91..98d4f86aab48 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -10047,22 +10047,6 @@ "n_values": 64, "description": "Count of scroll actions triggered by different input methods. See gfx/layers/apz/util/ScrollInputMethods.h for a list of possible values and their meanings." }, - "TOTAL_SCROLL_Y": { - "alert_emails": ["rhunt@mozilla.com"], - "bug_numbers": [1297867], - "expires_in_version": "58", - "kind": "count", - "description": "Count of the total number of CSS pixels scrolled up or down in the vertical axis of the root frame of all the pages visited in a subsession. This doesn't include any scrolling of nested scroll frames such as inputs, iframes, or scrollable divs." - }, - "PAGE_MAX_SCROLL_Y": { - "alert_emails": ["rhunt@mozilla.com"], - "bug_numbers": [1312881], - "expires_in_version": "58", - "kind": "exponential", - "high": 100000, - "n_buckets": 50, - "description": "Maximum distance in CSS pixels a user scrolls down the vertical axis of the root frame of a page. This doesn't include any scrolling of nested scroll frames such as inputs, iframes, or scrollable divs." - }, "WEB_NOTIFICATION_CLICKED": { "releaseChannelCollection": "opt-out", "alert_emails": ["firefox-dev@mozilla.org"], diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js index 8c8b7feddfbc..11fcd8f73bdc 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js @@ -305,11 +305,7 @@ function spoofPartnerInfo() { } function getAttributionFile() { - let file = Services.dirsvc.get("LocalAppData", Ci.nsIFile); - file.append("mozilla"); - file.append(AppConstants.MOZ_APP_NAME); - file.append("postSigningData"); - return file; + return FileUtils.getFile("LocalAppData", ["mozilla", AppConstants.MOZ_APP_NAME, "postSigningData"]); } function spoofAttributionData() { @@ -319,6 +315,7 @@ function spoofAttributionData() { createInstance(Ci.nsIFileOutputStream); stream.init(getAttributionFile(), -1, -1, 0); stream.write(ATTRIBUTION_CODE, ATTRIBUTION_CODE.length); + stream.close(); } } diff --git a/toolkit/components/url-classifier/tests/mochitest/test_classifier.html b/toolkit/components/url-classifier/tests/mochitest/test_classifier.html index 1a2f9f1b7bed..76a1a3a81a47 100644 --- a/toolkit/components/url-classifier/tests/mochitest/test_classifier.html +++ b/toolkit/components/url-classifier/tests/mochitest/test_classifier.html @@ -154,7 +154,8 @@ SpecialPowers.pushPrefEnv( {"set" : [["urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple"], ["urlclassifier.phishTable", "test-phish-simple"], ["urlclassifier.downloadBlockTable", "test-block-simple"], - ["urlclassifier.trackingTable", "test-track-simple"]]}, + ["urlclassifier.trackingTable", "test-track-simple"], + ["privacy.trackingprotection.annotate_channels", true]]}, function() { classifierHelper.waitForInit() .then(() => classifierHelper.addUrlToDB(testData)) diff --git a/toolkit/content/browser-content.js b/toolkit/content/browser-content.js index 39189d114ba9..458e7c0e935a 100644 --- a/toolkit/content/browser-content.js +++ b/toolkit/content/browser-content.js @@ -1761,37 +1761,3 @@ let DateTimePickerListener = { } DateTimePickerListener.init(); - -/* - * Telemetry probe to track the amount of scrolling a user does up and down the root frame - * of a page, and also the maximum distance a user scrolls down the root frame of a page. - * This doesn't include scrolling sub frames, but does include scrolling from JavaScript. - * See bug 1312881 and bug 1297867 for more details. - */ -addEventListener("DOMWindowCreated", function() { - if (event.target !== content.document || - content.location == "" || - content.location.protocol === "about:") { - return; - } - - let amountHistogram = Services.telemetry.getHistogramById("TOTAL_SCROLL_Y"); - let maxHistogram = Services.telemetry.getHistogramById("PAGE_MAX_SCROLL_Y"); - - let prevScrollY = 0; - let maxScrollY = 0; - - content.addEventListener("scroll", function() { - let amount = Math.abs(content.scrollY - prevScrollY); - amountHistogram.add(amount); - prevScrollY = content.scrollY; - - if (content.scrollY > maxScrollY) { - maxScrollY = content.scrollY; - } - }, { passive: true }); - - content.addEventListener("unload", function() { - maxHistogram.add(maxScrollY); - }); -}); diff --git a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm index 1b139f064c4e..c11fb00973aa 100644 --- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm +++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm @@ -874,6 +874,7 @@ var AddonTestUtils = { for (let part of entry.split("/")) target.append(part); zip.extract(entry, target); + target.permissions |= FileUtils.PERMS_FILE; } zip.close(); diff --git a/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm b/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm index 5dda49354b3f..7b9d49554491 100644 --- a/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm +++ b/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm @@ -432,6 +432,11 @@ const ProductAddonChecker = { * exception in case of error. */ getProductAddonList: function(url, allowNonBuiltIn = false, allowedCerts = null) { + if (!GMPPrefs.get(GMPPrefs.KEY_UPDATE_ENABLED, true)) { + logger.info("Updates are disabled via media.gmp-manager.updateEnabled"); + return Promise.resolve({usedFallback: true, gmpAddons: []}); + } + return downloadXML(url, allowNonBuiltIn, allowedCerts) .then(parseXML) .catch(downloadLocalConfig); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js index 071c3f7245ea..8b953d4741c3 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js @@ -352,11 +352,13 @@ function run_test_8() { zip.open(do_get_addon("test_dictionary")); dir.append("install.rdf"); zip.extract("install.rdf", dir); + dir.permissions |= FileUtils.PERMS_FILE; dir = dir.parent; dir.append("dictionaries"); dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0o755); dir.append("ab-CD.dic"); zip.extract("dictionaries/ab-CD.dic", dir); + dir.permissions |= FileUtils.PERMS_FILE; zip.close(); startupManager(false); @@ -485,11 +487,13 @@ function run_test_17() { zip.open(do_get_addon("test_dictionary")); dir.append("install.rdf"); zip.extract("install.rdf", dir); + dir.permissions |= FileUtils.PERMS_FILE; dir = dir.parent; dir.append("dictionaries"); dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0o755); dir.append("ab-CD.dic"); zip.extract("dictionaries/ab-CD.dic", dir); + dir.permissions |= FileUtils.PERMS_FILE; zip.close(); startupManager(); diff --git a/toolkit/mozapps/installer/packager.mk b/toolkit/mozapps/installer/packager.mk index a57b8d7fe329..902565c250cd 100644 --- a/toolkit/mozapps/installer/packager.mk +++ b/toolkit/mozapps/installer/packager.mk @@ -228,7 +228,17 @@ upload: checksum # source-package creates a source tarball from the files in MOZ_PKG_SRCDIR, # which is either set to a clean checkout or defaults to $topsrcdir source-package: + @echo 'Generate the sourcestamp file' + # Make sure to have repository information available and then generate the + # sourcestamp file. + $(MAKE) -C $(DEPTH) 'source-repo.h' + $(MAKE) make-sourcestamp-file @echo 'Packaging source tarball...' + # We want to include the sourcestamp file in the source tarball, so copy it + # in the root source directory. This is useful to enable telemetry submissions + # from builds made from the source package with the correct revision information. + # Don't bother removing it as this is only used by automation. + @cp $(MOZ_SOURCESTAMP_FILE) '$(MOZ_PKG_SRCDIR)/sourcestamp.txt' $(MKDIR) -p $(DIST)/$(PKG_SRCPACK_PATH) (cd $(MOZ_PKG_SRCDIR) && $(CREATE_SOURCE_TAR) - ./ ) | xz -9e > $(SOURCE_TAR) diff --git a/uriloader/exthandler/nsExternalProtocolHandler.cpp b/uriloader/exthandler/nsExternalProtocolHandler.cpp index 61ee3bec67a1..d92b6f89a96d 100644 --- a/uriloader/exthandler/nsExternalProtocolHandler.cpp +++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp @@ -401,6 +401,12 @@ NS_IMETHODIMP nsExtProtocolChannel::NotifyTrackingProtectionDisabled() return NS_OK; } +NS_IMETHODIMP nsExtProtocolChannel::NotifyTrackingResource() +{ + // nothing to do + return NS_OK; +} + NS_IMETHODIMP nsExtProtocolChannel::Delete() { // nothing to do diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 00306674fd24..ceef82f515f2 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -999,12 +999,12 @@ class AndroidBridge::DelayedTask using TimeDuration = mozilla::TimeDuration; public: - DelayedTask(already_AddRefed aTask) + DelayedTask(already_AddRefed aTask) : mTask(aTask) , mRunTime() // Null timestamp representing no delay. {} - DelayedTask(already_AddRefed aTask, int aDelayMs) + DelayedTask(already_AddRefed aTask, int aDelayMs) : mTask(aTask) , mRunTime(TimeStamp::Now() + TimeDuration::FromMilliseconds(aDelayMs)) {} @@ -1027,19 +1027,19 @@ public: return 0; } - already_AddRefed TakeTask() + already_AddRefed TakeTask() { return mTask.forget(); } private: - RefPtr mTask; + nsCOMPtr mTask; const TimeStamp mRunTime; }; void -AndroidBridge::PostTaskToUiThread(already_AddRefed aTask, int aDelayMs) +AndroidBridge::PostTaskToUiThread(already_AddRefed aTask, int aDelayMs) { // add the new task into the mUiTaskQueue, sorted with // the earliest task first in the queue @@ -1086,7 +1086,7 @@ AndroidBridge::RunDelayedUiThreadTasks() } // Retrieve task before unlocking/running. - RefPtr nextTask(mUiTaskQueue[0].TakeTask()); + nsCOMPtr nextTask(mUiTaskQueue[0].TakeTask()); mUiTaskQueue.RemoveElementAt(0); // Unlock to allow posting new tasks reentrantly. diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 1324562078d5..5fc0d5b8d7c0 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -42,16 +42,12 @@ class nsPIDOMWindowOuter; -namespace base { -class Thread; -} // end namespace base - typedef void* EGLSurface; +class nsIRunnable; namespace mozilla { class AutoLocalJNIFrame; -class Runnable; namespace hal { class BatteryInformation; @@ -239,7 +235,7 @@ private: mozilla::Mutex mUiTaskQueueLock; public: - void PostTaskToUiThread(already_AddRefed aTask, int aDelayMs); + void PostTaskToUiThread(already_AddRefed aTask, int aDelayMs); int64_t RunDelayedUiThreadTasks(); }; diff --git a/widget/android/AndroidContentController.cpp b/widget/android/AndroidContentController.cpp index 1df053afb2f6..003345f7670c 100644 --- a/widget/android/AndroidContentController.cpp +++ b/widget/android/AndroidContentController.cpp @@ -25,24 +25,6 @@ AndroidContentController::Destroy() ChromeProcessController::Destroy(); } -void -AndroidContentController::NotifyDefaultPrevented(IAPZCTreeManager* aManager, - uint64_t aInputBlockId, - bool aDefaultPrevented) -{ - if (!AndroidBridge::IsJavaUiThread()) { - // The notification must reach the APZ on the Java UI thread (aka the - // APZ "controller" thread) but we get it from the Gecko thread, so we - // have to throw it onto the other thread. - AndroidBridge::Bridge()->PostTaskToUiThread(NewRunnableMethod( - aManager, &IAPZCTreeManager::ContentReceivedInputBlock, - aInputBlockId, aDefaultPrevented), 0); - return; - } - - aManager->ContentReceivedInputBlock(aInputBlockId, aDefaultPrevented); -} - void AndroidContentController::DispatchSingleTapToObservers(const LayoutDevicePoint& aPoint, const ScrollableLayerGuid& aGuid) const @@ -101,11 +83,6 @@ AndroidContentController::HandleTap(TapType aType, const LayoutDevicePoint& aPoi ChromeProcessController::HandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId); } -void -AndroidContentController::PostDelayedTask(already_AddRefed aTask, int aDelayMs) -{ - AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs); -} void AndroidContentController::UpdateOverscrollVelocity(const float aX, const float aY, const bool aIsRootContent) { diff --git a/widget/android/AndroidContentController.h b/widget/android/AndroidContentController.h index 39674c939743..e6f2ca15260d 100644 --- a/widget/android/AndroidContentController.h +++ b/widget/android/AndroidContentController.h @@ -36,16 +36,12 @@ public: virtual void Destroy() override; void HandleTap(TapType aType, const LayoutDevicePoint& aPoint, Modifiers aModifiers, const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId) override; - void PostDelayedTask(already_AddRefed aTask, int aDelayMs) override; void UpdateOverscrollVelocity(const float aX, const float aY, const bool aIsRootContent) override; void UpdateOverscrollOffset(const float aX, const float aY, const bool aIsRootContent) override; void SetScrollingRootContent(const bool isRootContent) override; void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg) override; - - static void NotifyDefaultPrevented(mozilla::layers::IAPZCTreeManager* aManager, - uint64_t aInputBlockId, bool aDefaultPrevented); private: nsWindow* mAndroidWindow; diff --git a/widget/android/AndroidUiThread.cpp b/widget/android/AndroidUiThread.cpp new file mode 100644 index 000000000000..ed20f5c7a06a --- /dev/null +++ b/widget/android/AndroidUiThread.cpp @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AndroidBridge.h" +#include "base/message_loop.h" +#include "mozilla/Monitor.h" +#include "mozilla/RefPtr.h" +#include "mozilla/StaticPtr.h" +#include "nsThread.h" +#include "nsThreadManager.h" +#include "nsThreadUtils.h" + +using namespace mozilla; + +namespace { + +class AndroidUiThread; + +StaticRefPtr sThread; +static MessageLoop* sMessageLoop; + +/* + * The AndroidUiThread is derived from nsThread so that nsIRunnable objects that get + * dispatched may be intercepted. Only nsIRunnable objects that need to be synchronously + * executed are passed into the nsThread to be queued. All other nsIRunnable object + * are immediately dispatched to the Android UI thread via the AndroidBridge. + * AndroidUiThread is derived from nsThread instead of being an nsIEventTarget + * wrapper that contains an nsThread object because if nsIRunnable objects with a + * delay were dispatch directly to an nsThread object, such as obtained from + * nsThreadManager::GetCurrentThread(), the nsIRunnable could get stuck in the + * nsThread nsIRunnable queue. This is due to the fact that Android controls the + * event loop in the Android UI thread and has no knowledge of when the nsThread + * needs to be drained. +*/ + +class AndroidUiThread : public nsThread +{ +public: + NS_DECL_ISUPPORTS_INHERITED + AndroidUiThread() : nsThread(nsThread::NOT_MAIN_THREAD, 0) + {} + + nsresult Dispatch(already_AddRefed aEvent, uint32_t aFlags) override; + nsresult DelayedDispatch(already_AddRefed aEvent, uint32_t aDelayMs) override; + +private: + ~AndroidUiThread() + {} +}; + +NS_IMPL_ISUPPORTS_INHERITED0(AndroidUiThread, nsThread) + +NS_IMETHODIMP +AndroidUiThread::Dispatch(already_AddRefed aEvent, uint32_t aFlags) +{ + if (aFlags & NS_DISPATCH_SYNC) { + return nsThread::Dispatch(Move(aEvent), aFlags); + } else { + AndroidBridge::Bridge()->PostTaskToUiThread(Move(aEvent), 0); + return NS_OK; + } +} + +NS_IMETHODIMP +AndroidUiThread::DelayedDispatch(already_AddRefed aEvent, uint32_t aDelayMs) +{ + AndroidBridge::Bridge()->PostTaskToUiThread(Move(aEvent), aDelayMs); + return NS_OK; +} + +static void +PumpEvents() { + NS_ProcessPendingEvents(sThread.get()); +} + +class ThreadObserver : public nsIThreadObserver +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSITHREADOBSERVER + + ThreadObserver() + {} + +private: + virtual ~ThreadObserver() + {} +}; + +NS_IMPL_ISUPPORTS(ThreadObserver, nsIThreadObserver) + +NS_IMETHODIMP +ThreadObserver::OnDispatchedEvent(nsIThreadInternal *thread) +{ + AndroidBridge::Bridge()->PostTaskToUiThread(NS_NewRunnableFunction(&PumpEvents), 0); + return NS_OK; +} + +NS_IMETHODIMP +ThreadObserver::OnProcessNextEvent(nsIThreadInternal *thread, bool mayWait) +{ + return NS_OK; +} + +NS_IMETHODIMP +ThreadObserver::AfterProcessNextEvent(nsIThreadInternal *thread, bool eventWasProcessed) +{ + return NS_OK; +} + +class CreateOnUiThread : public Runnable { +public: + CreateOnUiThread() : mCreated(false), mThreadCreationMonitor("AndroidUiThreadCreationLock") + {} + + NS_IMETHOD Run() override { + MonitorAutoLock lock(mThreadCreationMonitor); + + sThread = new AndroidUiThread(); + sThread->InitCurrentThread(); + sThread->SetObserver(new ThreadObserver()); + sMessageLoop = new MessageLoop(MessageLoop::TYPE_MOZILLA_ANDROID_UI, sThread.get()); + mCreated = true; + lock.NotifyAll(); + return NS_OK; + } + + void WaitForCreation() + { + MonitorAutoLock lock(mThreadCreationMonitor); + while (!mCreated) { + lock.Wait(); + } + } + +private: + bool mCreated; + Monitor mThreadCreationMonitor; +}; + +class DestroyOnUiThread : public Runnable { +public: + DestroyOnUiThread() : mDestroyed(false), mThreadDestructionMonitor("AndroidUiThreadCreationLock") + {} + + NS_IMETHOD Run() override { + MonitorAutoLock lock(mThreadDestructionMonitor); + + delete sMessageLoop; + sMessageLoop = nullptr; + MOZ_ASSERT(sThread); + nsThreadManager::get().UnregisterCurrentThread(*sThread); + sThread = nullptr; + mDestroyed = true; + lock.NotifyAll(); + return NS_OK; + } + + void WaitForDestruction() + { + MonitorAutoLock lock(mThreadDestructionMonitor); + while (!mDestroyed) { + lock.Wait(); + } + } + +private: + bool mDestroyed; + Monitor mThreadDestructionMonitor; +}; + +} // namespace + +namespace mozilla { + +void +CreateAndroidUiThread() +{ + MOZ_ASSERT(!sThread); + RefPtr runnable = new CreateOnUiThread; + AndroidBridge::Bridge()->PostTaskToUiThread(do_AddRef(runnable), 0); + runnable->WaitForCreation(); +} + +void +DestroyAndroidUiThread() +{ + MOZ_ASSERT(sThread); + RefPtr runnable = new DestroyOnUiThread; + // Insure the Android bridge has not already been deconstructed. + MOZ_ASSERT(AndroidBridge::Bridge() != nullptr); + AndroidBridge::Bridge()->PostTaskToUiThread(do_AddRef(runnable), 0); + runnable->WaitForDestruction(); +} + +MessageLoop* +GetAndroidUiThreadMessageLoop() +{ + return sMessageLoop; +} + +} // namespace mozilla diff --git a/widget/android/AndroidUiThread.h b/widget/android/AndroidUiThread.h new file mode 100644 index 000000000000..4379b3f51169 --- /dev/null +++ b/widget/android/AndroidUiThread.h @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef AndroidUiThread_h__ +#define AndroidUiThread_h__ + +class MessageLoop; + +namespace mozilla { + +void CreateAndroidUiThread(); +void DestroyAndroidUiThread(); + +MessageLoop* GetAndroidUiThreadMessageLoop(); + +} // namespace mozilla + +#endif // AndroidUiThread_h__ diff --git a/widget/android/moz.build b/widget/android/moz.build index 1317a7e8c0d0..8f2e351badda 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -36,6 +36,7 @@ UNIFIED_SOURCES += [ 'AndroidJavaWrappers.cpp', 'AndroidJNI.cpp', 'AndroidJNIWrapper.cpp', + 'AndroidUiThread.cpp', 'ANRReporter.cpp', 'EventDispatcher.cpp', 'GeneratedJNIWrappers.cpp', @@ -64,6 +65,7 @@ LOCAL_INCLUDES += [ '/netwerk/base', '/netwerk/cache', '/widget', + '/xpcom/threads', ] CXXFLAGS += ['-Wno-error=shadow'] diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index 09e102d54466..777723d7a52c 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -61,6 +61,7 @@ #endif #include "AndroidAlerts.h" +#include "AndroidUiThread.h" #include "ANRReporter.h" #include "GeckoBatteryManager.h" #include "GeckoNetworkManager.h" @@ -395,6 +396,8 @@ nsAppShell::nsAppShell() } java::GeckoThread::SetState(java::GeckoThread::State::JNI_READY()); + + CreateAndroidUiThread(); } sPowerManagerService = do_GetService(POWERMANAGERSERVICE_CONTRACTID); @@ -425,6 +428,7 @@ nsAppShell::~nsAppShell() } if (jni::IsAvailable()) { + DestroyAndroidUiThread(); AndroidBridge::DeconstructBridge(); } } diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 00ac8b57fd6d..d9ac64ba70b2 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -73,6 +73,7 @@ using mozilla::Unused; #include "AndroidBridge.h" #include "AndroidBridgeUtilities.h" +#include "AndroidUiThread.h" #include "android_npapi.h" #include "FennecJNINatives.h" #include "GeneratedJNINatives.h" @@ -3560,7 +3561,7 @@ nsWindow::NeedsPaint() void nsWindow::ConfigureAPZControllerThread() { - APZThreadUtils::SetControllerThread(nullptr); + APZThreadUtils::SetControllerThread(mozilla::GetAndroidUiThreadMessageLoop()); } already_AddRefed diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index e5051dafde00..8185ca608cbb 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -5811,6 +5811,9 @@ GetIntegerDeltaForEvent(NSEvent* aEvent) if (mDragService) { // set the dragend point from the current mouse location nsDragService* dragService = static_cast(mDragService); + FlipCocoaScreenCoordinate(aPoint); + dragService->SetDragEndPoint(gfx::IntPoint::Round(aPoint.x, aPoint.y)); + NSPoint pnt = [NSEvent mouseLocation]; FlipCocoaScreenCoordinate(pnt); dragService->SetDragEndPoint(gfx::IntPoint::Round(pnt.x, pnt.y)); @@ -5856,11 +5859,8 @@ GetIntegerDeltaForEvent(NSEvent* aEvent) } if (dragService) { - NSPoint pnt = [NSEvent mouseLocation]; - FlipCocoaScreenCoordinate(pnt); - - LayoutDeviceIntPoint devPoint = mGeckoChild->CocoaPointsToDevPixels(pnt); - dragService->DragMoved(devPoint.x, devPoint.y); + nsDragService* ds = static_cast(dragService.get()); + ds->DragMovedWithView(aSession, aPoint); } NS_OBJC_END_TRY_ABORT_BLOCK; diff --git a/widget/cocoa/nsDragService.h b/widget/cocoa/nsDragService.h index 88cf7581917e..404df4057f2e 100644 --- a/widget/cocoa/nsDragService.h +++ b/widget/cocoa/nsDragService.h @@ -28,20 +28,34 @@ public: uint32_t aActionType); // nsIDragService NS_IMETHOD EndDragSession(bool aDoneDrag); + NS_IMETHOD UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY); // nsIDragSession NS_IMETHOD GetData(nsITransferable * aTransferable, uint32_t aItemIndex); NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval); NS_IMETHOD GetNumDropItems(uint32_t * aNumItems); + void DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint); + protected: virtual ~nsDragService(); private: + // Creates and returns the drag image for a drag. aImagePoint will be set to + // the origin of the drag relative to mNativeDragView. NSImage* ConstructDragImage(nsIDOMNode* aDOMNode, - mozilla::LayoutDeviceIntRect* aDragRect, - nsIScriptableRegion* aRegion); + nsIScriptableRegion* aRegion, + NSPoint* aImagePoint); + + // Creates and returns the drag image for a drag. aPoint should be the origin + // of the drag, for example the mouse coordinate of the mousedown event. + // aDragRect will be set the area of the drag relative to this. + NSImage* ConstructDragImage(nsIDOMNode* aDOMNode, + nsIScriptableRegion* aRegion, + mozilla::CSSIntPoint aPoint, + mozilla::LayoutDeviceIntRect* aDragRect); + bool IsValidType(NSString* availableType, bool allowFileURL); NSString* GetStringForType(NSPasteboardItem* item, const NSString* type, bool allowFileURL = false); @@ -51,6 +65,8 @@ private: nsCOMPtr mDataItems; // only valid for a drag started within gecko ChildView* mNativeDragView; NSEvent* mNativeDragEvent; + + bool mDragImageChanged; }; #endif // nsDragService_h_ diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm index 0439891c8d11..6d5154bce8a8 100644 --- a/widget/cocoa/nsDragService.mm +++ b/widget/cocoa/nsDragService.mm @@ -29,6 +29,7 @@ #include "nsCocoaUtils.h" #include "mozilla/gfx/2D.h" #include "gfxPlatform.h" +#include "nsDeviceContext.h" using namespace mozilla; using namespace mozilla::gfx; @@ -57,10 +58,8 @@ NSString* const kUTTypeURLName = @"public.url-name"; NSString* const kCustomTypesPboardType = @"org.mozilla.custom-clipdata"; nsDragService::nsDragService() + : mNativeDragView(nil), mNativeDragEvent(nil), mDragImageChanged(false) { - mNativeDragView = nil; - mNativeDragEvent = nil; - EnsureLogInitialized(); } @@ -70,22 +69,65 @@ nsDragService::~nsDragService() NSImage* nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode, - LayoutDeviceIntRect* aDragRect, - nsIScriptableRegion* aRegion) + nsIScriptableRegion* aRegion, + NSPoint* aDragPoint) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; - CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView); + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView); + + LayoutDeviceIntRect dragRect(0, 0, 20, 20); + NSImage* image = ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect); + if (!image) { + // if no image was returned, just draw a rectangle + NSSize size; + size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor); + size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor); + image = [[NSImage alloc] initWithSize:size]; + [image lockFocus]; + [[NSColor grayColor] set]; + NSBezierPath* path = [NSBezierPath bezierPath]; + [path setLineWidth:2.0]; + [path moveToPoint:NSMakePoint(0, 0)]; + [path lineToPoint:NSMakePoint(0, size.height)]; + [path lineToPoint:NSMakePoint(size.width, size.height)]; + [path lineToPoint:NSMakePoint(size.width, 0)]; + [path lineToPoint:NSMakePoint(0, 0)]; + [path stroke]; + [image unlockFocus]; + } + + LayoutDeviceIntPoint pt(dragRect.x, dragRect.YMost()); + NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor); + point.y = nsCocoaUtils::FlippedScreenY(point.y); + + point = nsCocoaUtils::ConvertPointFromScreen([mNativeDragView window], point); + *aDragPoint = [mNativeDragView convertPoint:point fromView:nil]; + + return image; + + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; +} + +NSImage* +nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode, + nsIScriptableRegion* aRegion, + CSSIntPoint aPoint, + LayoutDeviceIntRect* aDragRect) + { + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; + + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView); RefPtr surface; nsPresContext* pc; - nsresult rv = DrawDrag(aDOMNode, aRegion, mScreenPosition, + nsresult rv = DrawDrag(aDOMNode, aRegion, aPoint, aDragRect, &surface, &pc); if (pc && (!aDragRect->width || !aDragRect->height)) { // just use some suitable defaults int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor); - aDragRect->SetRect(pc->CSSPixelsToDevPixels(mScreenPosition.x), - pc->CSSPixelsToDevPixels(mScreenPosition.y), size, size); + aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x), + pc->CSSPixelsToDevPixels(aPoint.y), size, size); } if (NS_FAILED(rv) || !surface) @@ -291,38 +333,12 @@ nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray, } [pbItem setDataProvider:mNativeDragView forTypes:types]; - CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView); + NSPoint draggingPoint; + NSImage* image = ConstructDragImage(mSourceNode, aDragRgn, &draggingPoint); - LayoutDeviceIntRect dragRect(0, 0, 20, 20); - NSImage* image = ConstructDragImage(mSourceNode, &dragRect, aDragRgn); - if (!image) { - // if no image was returned, just draw a rectangle - NSSize size; - size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor); - size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor); - image = [[NSImage alloc] initWithSize:size]; - [image lockFocus]; - [[NSColor grayColor] set]; - NSBezierPath* path = [NSBezierPath bezierPath]; - [path setLineWidth:2.0]; - [path moveToPoint:NSMakePoint(0, 0)]; - [path lineToPoint:NSMakePoint(0, size.height)]; - [path lineToPoint:NSMakePoint(size.width, size.height)]; - [path lineToPoint:NSMakePoint(size.width, 0)]; - [path lineToPoint:NSMakePoint(0, 0)]; - [path stroke]; - [image unlockFocus]; - } - - // Make drag image appear in the right place under the cursor. - LayoutDeviceIntPoint pt(dragRect.x, dragRect.YMost()); - NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor); - point.y = nsCocoaUtils::FlippedScreenY(point.y); - point = nsCocoaUtils::ConvertPointFromScreen([gLastDragView window], point); - NSPoint localPoint = [gLastDragView convertPoint:point fromView:nil]; NSRect localDragRect = image.alignmentRect; - localDragRect.origin.x = localPoint.x; - localDragRect.origin.y = localPoint.y - localDragRect.size.height; + localDragRect.origin.x = draggingPoint.x; + localDragRect.origin.y = draggingPoint.y - localDragRect.size.height; NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem]; @@ -621,6 +637,72 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems) NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } +NS_IMETHODIMP +nsDragService::UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY) +{ + nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY); + mDragImageChanged = true; + return NS_OK; +} + +void +nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint) +{ + aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y); + + // XXX It feels like we should be using the backing scale factor at aPoint + // rather than the initial drag view, but I've seen no ill effects of this. + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView); + LayoutDeviceIntPoint devPoint = nsCocoaUtils::CocoaPointsToDevPixels(aPoint, scaleFactor); + + // If the image has changed, call enumerateDraggingItemsWithOptions to get + // the item being dragged and update its image. + if (mDragImageChanged && mNativeDragView) { + mDragImageChanged = false; + + nsPresContext* pc = nullptr; + nsCOMPtr content = do_QueryInterface(mImage); + if (content) { + nsCOMPtr document = content->OwnerDoc(); + if (document) { + nsIPresShell* shell = document->GetShell(); + pc = shell ? shell->GetPresContext() : nullptr; + } + } + + if (pc) { + void (^changeImageBlock) (NSDraggingItem*, NSInteger, BOOL*) = + ^(NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) { + // We never add more than one item right now, but check just in case. + if (idx > 0) { + return; + } + + nsPoint pt = LayoutDevicePixel::ToAppUnits(devPoint, + pc->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom()); + CSSIntPoint screenPoint = CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x), + nsPresContext::AppUnitsToIntCSSPixels(pt.y)); + + // Create a new image; if one isn't returned don't change the current one. + LayoutDeviceIntRect newRect; + NSImage* image = ConstructDragImage(mSourceNode, nullptr, screenPoint, &newRect); + if (image) { + NSRect draggingRect = nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor); + [draggingItem setDraggingFrame:draggingRect contents:image]; + } + }; + + [aSession enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent + forView:nil + classes:[NSArray arrayWithObject:[NSPasteboardItem class]] + searchOptions:nil + usingBlock:changeImageBlock]; + } + } + + DragMoved(devPoint.x, devPoint.y); +} + NS_IMETHODIMP nsDragService::EndDragSession(bool aDoneDrag) { diff --git a/widget/nsBaseDragService.cpp b/widget/nsBaseDragService.cpp index 7624bbbab35e..6c5150fb21f3 100644 --- a/widget/nsBaseDragService.cpp +++ b/widget/nsBaseDragService.cpp @@ -807,6 +807,19 @@ nsBaseDragService::UpdateDragEffect() return NS_OK; } +NS_IMETHODIMP +nsBaseDragService::UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY) +{ + // Don't change the image if this is a drag from another source or if there + // is a drag popup. + if (!mSourceNode || mDragPopup) + return NS_OK; + + mImage = aImage; + mImageOffset = CSSIntPoint(aImageX, aImageY); + return NS_OK; +} + NS_IMETHODIMP nsBaseDragService::DragEventDispatchedToChildProcess() { diff --git a/widget/nsIDragSession.idl b/widget/nsIDragSession.idl index 6b9f603a14f1..07ecb7edfa43 100644 --- a/widget/nsIDragSession.idl +++ b/widget/nsIDragSession.idl @@ -89,6 +89,10 @@ interface nsIDragSession : nsISupports // drag-and-drop based on the data got from the child process in response to // NS_DRAGDROP_OVER sent from parent process to child process. void updateDragEffect(); + + // Change the drag image, using similar arguments as + // nsIDragService::InvokeDragSessionWithImage. + void updateDragImage(in nsIDOMNode aImage, in long aImageX, in long aImageY); }; diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp index 0040f550f976..6ccc01a3d4d4 100644 --- a/widget/windows/nsDragService.cpp +++ b/widget/windows/nsDragService.cpp @@ -639,3 +639,29 @@ nsDragService::EndDragSession(bool aDoneDrag) return NS_OK; } + +NS_IMETHODIMP +nsDragService::UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY) +{ + if (!mDataObject) { + return NS_OK; + } + + nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY); + + IDragSourceHelper *pdsh; + if (SUCCEEDED(CoCreateInstance(CLSID_DragDropHelper, nullptr, + CLSCTX_INPROC_SERVER, + IID_IDragSourceHelper, (void**)&pdsh))) { + SHDRAGIMAGE sdi; + if (CreateDragImage(mSourceNode, nullptr, &sdi)) { + nsNativeDragTarget::DragImageChanged(); + if (FAILED(pdsh->InitializeFromBitmap(&sdi, mDataObject))) + DeleteObject(sdi.hbmpDragImage); + } + pdsh->Release(); + } + + return NS_OK; +} + diff --git a/widget/windows/nsDragService.h b/widget/windows/nsDragService.h index 7a2d297094b8..6aed563cd907 100644 --- a/widget/windows/nsDragService.h +++ b/widget/windows/nsDragService.h @@ -33,6 +33,7 @@ public: NS_IMETHOD GetNumDropItems(uint32_t * aNumItems); NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval); NS_IMETHOD EndDragSession(bool aDoneDrag); + NS_IMETHOD UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY); // native impl. NS_IMETHOD SetIDataObject(IDataObject * aDataObj); @@ -42,6 +43,8 @@ public: // A drop occurred within the application vs. outside of it. void SetDroppedLocal(); + IDataObject* GetDataObject() { return mDataObject; } + protected: nsDataObjCollection* GetDataObjCollection(IDataObject * aDataObj); diff --git a/widget/windows/nsNativeDragTarget.cpp b/widget/windows/nsNativeDragTarget.cpp index 1686642a3040..1507912086a7 100644 --- a/widget/windows/nsNativeDragTarget.cpp +++ b/widget/windows/nsNativeDragTarget.cpp @@ -28,6 +28,8 @@ static NS_DEFINE_IID(kIDragServiceIID, NS_IDRAGSERVICE_IID); // This is cached for Leave notification static POINTL gDragLastPoint; +bool nsNativeDragTarget::gDragImageChanged = false; + /* * class nsNativeDragTarget */ @@ -319,6 +321,9 @@ nsNativeDragTarget::DragOver(DWORD grfKeyState, return E_FAIL; } + bool dragImageChanged = gDragImageChanged; + gDragImageChanged = false; + // If a LINK effect could be generated previously from a DragEnter(), // then we should include it as an allowed effect. mEffectsAllowed = (*pdwEffect) | (mEffectsAllowed & DROPEFFECT_LINK); @@ -334,6 +339,14 @@ nsNativeDragTarget::DragOver(DWORD grfKeyState, // Drag and drop image helper if (GetDropTargetHelper()) { + if (dragImageChanged) { + // The drop helper only updates the image during DragEnter, so emulate + // a DragEnter if the image was changed. + POINT pt = { ptl.x, ptl.y }; + nsDragService* dragService = static_cast(mDragService); + GetDropTargetHelper()->DragEnter(mHWnd, dragService->GetDataObject(), &pt, *pdwEffect); + + } POINT pt = { ptl.x, ptl.y }; GetDropTargetHelper()->DragOver(&pt, *pdwEffect); } diff --git a/widget/windows/nsNativeDragTarget.h b/widget/windows/nsNativeDragTarget.h index 4989e44d4d9c..32b1e6f758f0 100644 --- a/widget/windows/nsNativeDragTarget.h +++ b/widget/windows/nsNativeDragTarget.h @@ -68,6 +68,8 @@ public: */ void DragCancel(); + static void DragImageChanged() { gDragImageChanged = true; } + protected: void GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect, @@ -95,6 +97,8 @@ protected: private: // Drag target helper IDropTargetHelper * mDropTargetHelper; + + static bool gDragImageChanged; }; #endif // _nsNativeDragTarget_h_ diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 7c7efd693839..f4c71f7cfa8e 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -210,12 +210,14 @@ #include "InputData.h" #include "mozilla/Telemetry.h" +#include "mozilla/plugins/PluginProcessParent.h" using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::gfx; using namespace mozilla::layers; using namespace mozilla::widget; +using namespace mozilla::plugins; /************************************************************** ************************************************************** @@ -3485,12 +3487,20 @@ nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal) { switch (aDataType) { case NS_NATIVE_CHILD_WINDOW: - SetChildStyleAndParent(reinterpret_cast(aVal), mWnd); - break; case NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW: - SetChildStyleAndParent(reinterpret_cast(aVal), - WinUtils::GetTopLevelHWND(mWnd)); - break; + { + HWND childHwnd = reinterpret_cast(aVal); + DWORD childProc = 0; + GetWindowThreadProcessId(childHwnd, &childProc); + if (!PluginProcessParent::IsPluginProcessId(static_cast(childProc))) { + MOZ_ASSERT_UNREACHABLE("SetNativeData window origin was not a plugin process."); + break; + } + HWND parentHwnd = + aDataType == NS_NATIVE_CHILD_WINDOW ? mWnd : WinUtils::GetTopLevelHWND(mWnd); + SetChildStyleAndParent(childHwnd, parentHwnd); + break; + } default: NS_ERROR("SetNativeData called with unsupported data type."); } diff --git a/xpcom/string/nsTSubstring.cpp b/xpcom/string/nsTSubstring.cpp index d5e0b2ed4d69..0eb5812b6194 100644 --- a/xpcom/string/nsTSubstring.cpp +++ b/xpcom/string/nsTSubstring.cpp @@ -417,13 +417,28 @@ nsTSubstring_CharT::AssignLiteral(const char_type* aData, size_type aLength) void nsTSubstring_CharT::Assign(const self_type& aStr) { - if (!Assign(aStr, mozilla::fallible)) { + if (!Assign(aStr, aStr.Length(), mozilla::fallible)) { AllocFailed(aStr.Length()); } } bool nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) +{ + return Assign(aStr, aStr.Length(), aFallible); +} + +void +nsTSubstring_CharT::Assign(const self_type& aStr, size_type aLength) +{ + if (!Assign(aStr, aLength, mozilla::fallible)) { + AllocFailed(aLength); + } +} + +bool +nsTSubstring_CharT::Assign(const self_type& aStr, size_type aLength, + const fallible_t& aFallible) { // |aStr| could be sharable. We need to check its flags to know how to // deal with it. @@ -432,7 +447,11 @@ nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) return true; } - if (!aStr.mLength) { + if (aStr.Length() < aLength) { + aLength = aStr.Length(); + } + + if (!aLength) { Truncate(); mFlags |= aStr.mFlags & F_VOIDED; return true; @@ -447,7 +466,7 @@ nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) ::ReleaseData(mData, mFlags); mData = aStr.mData; - mLength = aStr.mLength; + mLength = aLength; SetDataFlags(F_TERMINATED | F_SHARED); // get an owning reference to the mData @@ -456,12 +475,12 @@ nsTSubstring_CharT::Assign(const self_type& aStr, const fallible_t& aFallible) } else if (aStr.mFlags & F_LITERAL) { MOZ_ASSERT(aStr.mFlags & F_TERMINATED, "Unterminated literal"); - AssignLiteral(aStr.mData, aStr.mLength); + AssignLiteral(aStr.mData, aLength); return true; } // else, treat this like an ordinary assignment. - return Assign(aStr.Data(), aStr.Length(), aFallible); + return Assign(aStr.Data(), aLength, aFallible); } void diff --git a/xpcom/string/nsTSubstring.h b/xpcom/string/nsTSubstring.h index 7606d27baf19..6efbbecc9884 100644 --- a/xpcom/string/nsTSubstring.h +++ b/xpcom/string/nsTSubstring.h @@ -378,6 +378,20 @@ public: MOZ_MUST_USE bool NS_FASTCALL Assign(const substring_tuple_type&, const fallible_t&); + // Assign at most aLength characters of aStr to this, fallibly. + // If aLength is more than the number of characters in aStr.Length(), + // only assign aStr.Length() characters. + // + // Using this method is functionally equivalent to: + // + // str.Assign(other.BeginReading, other.Length(), fallible); + // + // but may enable string buffer sharing. + void NS_FASTCALL Assign(const self_type& aStr, size_type aLength); + MOZ_MUST_USE bool NS_FASTCALL Assign(const self_type& aStr, + size_type aLength, + const fallible_t&); + #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER) void Assign(char16ptr_t aData) { diff --git a/xpcom/threads/ThrottledEventQueue.cpp b/xpcom/threads/ThrottledEventQueue.cpp index 941566ef2e03..a82f15e4d70e 100644 --- a/xpcom/threads/ThrottledEventQueue.cpp +++ b/xpcom/threads/ThrottledEventQueue.cpp @@ -364,7 +364,7 @@ public: NS_IMPL_ISUPPORTS(ThrottledEventQueue::Inner, nsIObserver); -NS_IMPL_ISUPPORTS(ThrottledEventQueue, nsIEventTarget); +NS_IMPL_ISUPPORTS(ThrottledEventQueue, ThrottledEventQueue, nsIEventTarget); ThrottledEventQueue::ThrottledEventQueue(already_AddRefed aInner) : mInner(aInner) diff --git a/xpcom/threads/ThrottledEventQueue.h b/xpcom/threads/ThrottledEventQueue.h index e0762bcce6b6..90ae602ff823 100644 --- a/xpcom/threads/ThrottledEventQueue.h +++ b/xpcom/threads/ThrottledEventQueue.h @@ -11,6 +11,10 @@ #include "nsIEventTarget.h" +#define NS_THROTTLEDEVENTQUEUE_IID \ +{ 0x8f3cf7dc, 0xfc14, 0x4ad5, \ + { 0x9f, 0xd5, 0xdb, 0x79, 0xbc, 0xe6, 0xd5, 0x08 } } + namespace mozilla { // A ThrottledEventQueue is an event target that can be used to throttle @@ -87,8 +91,12 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIEVENTTARGET + + NS_DECLARE_STATIC_IID_ACCESSOR(NS_THROTTLEDEVENTQUEUE_IID); }; +NS_DEFINE_STATIC_IID_ACCESSOR(ThrottledEventQueue, NS_THROTTLEDEVENTQUEUE_IID); + } // namespace mozilla #endif // mozilla_ThrottledEventQueue_h