diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 38125ff5e08e..006bb72df03c 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -92,8 +92,8 @@ MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument) if (aContent->GetPrimaryFrame()->IsFocusable()) return true; - PRUint32 attrCount = aContent->GetAttrCount(); - for (PRUint32 attrIdx = 0; attrIdx < attrCount; attrIdx++) { + uint32_t attrCount = aContent->GetAttrCount(); + for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) { const nsAttrName* attr = aContent->GetAttrNameAt(attrIdx); if (attr->NamespaceEquals(kNameSpaceID_None)) { nsIAtom* attrAtom = attr->Atom(); diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 336012e5e8d2..91a084740fa3 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -328,9 +328,6 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); -// Randomize all UrlClassifier data with a per-client key. -pref("urlclassifier.randomizeclient", false); - // The list of tables that use the gethash request to confirm partial results. pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index f77e649d59d5..7125e78a5f65 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -974,15 +974,6 @@ window.addEventListener('ContentStart', function update_onContentStart() { }, "audio-channel-changed", false); })(); -(function audioChannelChangedTracker() { - Services.obs.addObserver(function(aSubject, aTopic, aData) { - shell.sendChromeEvent({ - type: 'audio-channel-changed', - channel: aData - }); -}, "audio-channel-changed", false); -})(); - (function recordingStatusTracker() { let gRecordingActiveCount = 0; diff --git a/b2g/components/ActivitiesGlue.js b/b2g/components/ActivitiesGlue.js index c6854572afc3..221aecb71436 100644 --- a/b2g/components/ActivitiesGlue.js +++ b/b2g/components/ActivitiesGlue.js @@ -24,7 +24,7 @@ ActivitiesDialog.prototype = { let choices = []; activity.list.forEach(function(item) { - choices.push({ title: item.title, icon: item.icon }); + choices.push({ manifest: item.manifest, icon: item.icon }); }); diff --git a/b2g/components/ContentPermissionPrompt.js b/b2g/components/ContentPermissionPrompt.js index fb67bc778e59..036e7b23a739 100644 --- a/b2g/components/ContentPermissionPrompt.js +++ b/b2g/components/ContentPermissionPrompt.js @@ -18,7 +18,7 @@ const Cr = Components.results; const Cu = Components.utils; const Cc = Components.classes; -const PROMPT_FOR_UNKNOWN = ['geolocation']; +const PROMPT_FOR_UNKNOWN = ['geolocation', 'desktop-notification']; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -88,12 +88,32 @@ ContentPermissionPrompt.prototype = { return false; }, - _id: 0, prompt: function(request) { // returns true if the request was handled if (this.handleExistingPermission(request)) return; + // If the request was initiated from a hidden iframe + // we don't forward it to content and cancel it right away + let frame = request.element; + + if (!frame) { + this.delegatePrompt(request); + } + + var self = this; + frame.wrappedJSObject.getVisible().onsuccess = function gv_success(evt) { + if (!evt.target.result) { + request.cancel(); + return; + } + + self.delegatePrompt(request); + }; + }, + + _id: 0, + delegatePrompt: function(request) { let browser = Services.wm.getMostRecentWindow("navigator:browser"); let content = browser.getContentWindow(); if (!content) diff --git a/b2g/components/UpdatePrompt.js b/b2g/components/UpdatePrompt.js index 4118a9721e55..f62d5893d4f1 100644 --- a/b2g/components/UpdatePrompt.js +++ b/b2g/components/UpdatePrompt.js @@ -460,11 +460,20 @@ UpdatePrompt.prototype = { // nsIRequestObserver + _startedSent: false, + onStartRequest: function UP_onStartRequest(aRequest, aContext) { - this.sendChromeEvent("update-downloading"); + // Wait until onProgress to send the update-download-started event, in case + // this request turns out to fail for some reason + this._startedSent = false; }, onStopRequest: function UP_onStopRequest(aRequest, aContext, aStatusCode) { + let paused = !Components.isSuccessCode(aStatusCode); + this.sendChromeEvent("update-download-stopped", { + paused: paused + }); + Services.aus.removeDownloadListener(this); }, @@ -472,7 +481,14 @@ UpdatePrompt.prototype = { onProgress: function UP_onProgress(aRequest, aContext, aProgress, aProgressMax) { - this.sendChromeEvent("update-progress", { + if (!this._startedSent) { + this.sendChromeEvent("update-download-started", { + total: aProgressMax + }); + this._startedSent = true; + } + + this.sendChromeEvent("update-download-progress", { progress: aProgress, total: aProgressMax }); diff --git a/b2g/components/YoutubeProtocolHandler.js b/b2g/components/YoutubeProtocolHandler.js index 189a6d9889f7..d9e1498c27b1 100644 --- a/b2g/components/YoutubeProtocolHandler.js +++ b/b2g/components/YoutubeProtocolHandler.js @@ -31,155 +31,27 @@ YoutubeProtocolHandler.prototype = { // Sample URL: // vnd.youtube:iNuKL2Gy_QM?vndapp=youtube_mobile&vndclient=mv-google&vndel=watch&vnddnc=1 + // Note that there is no hostname, so we use URLTYPE_NO_AUTHORITY newURI: function yt_phNewURI(aSpec, aOriginCharset, aBaseURI) { let uri = Cc["@mozilla.org/network/standard-url;1"] .createInstance(Ci.nsIStandardURL); - let id = aSpec.substring(this.scheme.length + 1); - id = id.substring(0, id.indexOf('?')); - uri.init(Ci.nsIStandardURL.URLTYPE_STANDARD, -1, this.scheme + "://dummy_host/" + id, aOriginCharset, - aBaseURI); + uri.init(Ci.nsIStandardURL.URLTYPE_NO_AUTHORITY, this.defaultPort, + aSpec, aOriginCharset, aBaseURI); return uri.QueryInterface(Ci.nsIURI); }, newChannel: function yt_phNewChannel(aURI) { - // Get a list of streams for this video id. - let infoURI = "http://www.youtube.com/get_video_info?&video_id=" + - aURI.path.substring(1); - - let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Ci.nsIXMLHttpRequest); - xhr.open("GET", infoURI, true); - xhr.addEventListener("load", function() { - try { - let info = parseYoutubeVideoInfo(xhr.responseText); - cpmm.sendAsyncMessage("content-handler", info); - } - catch(e) { - // If parseYoutubeVideoInfo() can't find a video URL, it - // throws an Error. We report the error message here and do - // nothing. This shouldn't happen often. But if it does, the user - // will find that clicking on a video doesn't do anything. - log(e.message); - } + /* + * This isn't a real protocol handler. Instead of creating a channel + * we just send a message and throw an exception. This 'content-handler' + * message is handled in b2g/chrome/content/shell.js where it starts + * an activity request that will open the Video app. The video app + * includes code to handle this fake 'video/youtube' mime type + */ + cpmm.sendAsyncMessage("content-handler", { + type: 'video/youtube', // A fake MIME type for the activity handler + url: aURI.spec // The path component of this URL is the video id }); - xhr.send(null); - - function log(msg) { - msg = "YoutubeProtocolHandler.js: " + (msg.join ? msg.join(" ") : msg); - Cc["@mozilla.org/consoleservice;1"] - .getService(Ci.nsIConsoleService) - .logStringMessage(msg); - } - - // - // Parse the response from a youtube get_video_info query. - // - // If youtube's response is a failure, this function returns an object - // with status, errorcode, type and reason properties. Otherwise, it returns - // an object with status, url, and type properties, and optional - // title, poster, and duration properties. - // - function parseYoutubeVideoInfo(response) { - // Splits parameters in a query string. - function extractParameters(q) { - let params = q.split("&"); - let result = {}; - for(let i = 0, n = params.length; i < n; i++) { - let param = params[i]; - let pos = param.indexOf('='); - if (pos === -1) - continue; - let name = param.substring(0, pos); - let value = param.substring(pos+1); - result[name] = decodeURIComponent(value); - } - return result; - } - - let params = extractParameters(response); - - // If the request failed, return an object with an error code - // and an error message - if (params.status === 'fail') { - // - // Hopefully this error message will be properly localized. - // Do we need to add any parameters to the XMLHttpRequest to - // specify the language we want? - // - // Note that we include fake type and url properties in the returned - // object. This is because we still need to trigger the video app's - // view activity handler to display the error message from youtube, - // and those parameters are required. - // - return { - status: params.status, - errorcode: params.errorcode, - reason: (params.reason || '').replace(/\+/g, ' '), - type: 'video/3gpp', - url: 'https://m.youtube.com' - } - } - - // Otherwise, the query was successful - let result = { - status: params.status, - }; - - // Now parse the available streams - let streamsText = params.url_encoded_fmt_stream_map; - if (!streamsText) - throw Error("No url_encoded_fmt_stream_map parameter"); - let streams = streamsText.split(','); - for(let i = 0, n = streams.length; i < n; i++) { - streams[i] = extractParameters(streams[i]); - } - - // This is the list of youtube video formats, ordered from worst - // (but playable) to best. These numbers are values used as the - // itag parameter of each stream description. See - // https://en.wikipedia.org/wiki/YouTube#Quality_and_codecs - let formats = [ - "17", // 144p 3GP - "36", // 240p 3GP - "43", // 360p WebM -#ifdef MOZ_WIDGET_GONK - "18", // 360p H.264 -#endif - ]; - - // Sort the array of stream descriptions in order of format - // preference, so that the first item is the most preferred one - streams.sort(function(a, b) { - let x = a.itag ? formats.indexOf(a.itag) : -1; - let y = b.itag ? formats.indexOf(b.itag) : -1; - return y - x; - }); - - let bestStream = streams[0]; - - // If the best stream is a format we don't support just return - if (formats.indexOf(bestStream.itag) === -1) - throw Error("No supported video formats"); - - result.url = bestStream.url + '&signature=' + (bestStream.sig || ''); - result.type = bestStream.type; - // Strip codec information off of the mime type - if (result.type && result.type.indexOf(';') !== -1) { - result.type = result.type.split(';',1)[0]; - } - - if (params.title) { - result.title = params.title.replace(/\+/g, ' '); - } - if (params.length_seconds) { - result.duration = params.length_seconds; - } - if (params.thumbnail_url) { - result.poster = params.thumbnail_url; - } - - return result; - } throw Components.results.NS_ERROR_ILLEGAL_VALUE; }, diff --git a/browser/app/profile/extensions/Makefile.in b/browser/app/profile/extensions/Makefile.in index fff217f4abee..9e96bbd395da 100644 --- a/browser/app/profile/extensions/Makefile.in +++ b/browser/app/profile/extensions/Makefile.in @@ -27,14 +27,6 @@ all_xpis = $(foreach dir,$(EXTENSIONS),$(DISTROEXT)/$(dir).xpi) libs:: $(all_xpis) GARBAGE += $(all_xpis) -$(all_xpis): $(DISTROEXT)/%.xpi: $(call mkdir_deps,$(DISTROEXT)) libs-% - cd $* && \ - $(ZIP) -r9XD $@ * -x \*.in -x \*.mkdir.done - cd $(call core_abspath,$(srcdir)/$*) && \ - $(ZIP) -r9XD $@ * -x \*.in -x \*.mkdir.done - -.PHONY: $(all_xpis:.xpi=) - define pp_one $(2) := $(2) $(2)_PATH := $(dir $(2)) @@ -50,3 +42,11 @@ $(foreach d,$(EXTENSIONS), \ endif include $(topsrcdir)/config/rules.mk + +$(all_xpis): $(DISTROEXT)/%.xpi: $(call mkdir_deps,$(DISTROEXT)) libs-% + cd $* && \ + $(ZIP) -r9XD $@ * -x \*.in -x \*.mkdir.done + cd $(call core_abspath,$(srcdir)/$*) && \ + $(ZIP) -r9XD $@ * -x \*.in -x \*.mkdir.done + +.PHONY: $(all_xpis:.xpi=) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 2606af4a99f6..04e711f52a0a 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -736,9 +736,6 @@ pref("urlclassifier.alternate_error_page", "blocked"); // The number of random entries to send with a gethash request. pref("urlclassifier.gethashnoise", 4); -// Randomize all UrlClassifier data with a per-client key. -pref("urlclassifier.randomizeclient", false); - // The list of tables that use the gethash request to confirm partial results. pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index ad8be8ad39e0..80e0df19e4b8 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -280,8 +280,7 @@ var gPluginHandler = { let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser); if (notification && plugins.length > 0 && !haveVisibleCTPPlugin && !this._notificationDisplayedOnce) { - notification.dismissed = false; - PopupNotifications._update(notification.anchorElement); + notification.reshow(); this._notificationDisplayedOnce = true; } diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js index fba887531322..1b2561acf46b 100644 --- a/browser/base/content/browser-social.js +++ b/browser/base/content/browser-social.js @@ -132,7 +132,7 @@ let SocialUI = { break; } } catch (e) { - Components.utils.reportError(e + e.stack); + Components.utils.reportError(e + "\n" + e.stack); throw e; } }, @@ -719,6 +719,8 @@ var SocialToolbar = { if (!Social.provider) return; this.button.style.listStyleImage = "url(" + Social.provider.iconURL + ")"; + this.button.setAttribute("label", Social.provider.name); + this.button.setAttribute("tooltiptext", Social.provider.name); this.updateButton(); this.updateProfile(); this.populateProviderMenus(); @@ -779,7 +781,6 @@ var SocialToolbar = { let provider = Social.provider; let icons = provider.ambientNotificationIcons; let iconNames = Object.keys(icons); - let iconBox = document.getElementById("social-toolbar-item"); let panel = document.getElementById("social-notification-panel"); panel.hidden = false; @@ -824,7 +825,7 @@ var SocialToolbar = { str); } - let iconContainers = document.createDocumentFragment(); + let toolbarButtons = document.createDocumentFragment(); let createdFrames = []; @@ -835,7 +836,6 @@ var SocialToolbar = { let notificationFrame = document.getElementById(notificationFrameId); if (!notificationFrame) { - notificationFrame = SharedFrame.createFrame( notificationFrameId, /* frame name */ panel, /* parent */ @@ -860,56 +860,41 @@ var SocialToolbar = { SharedFrame.updateURL(notificationFrameId, icon.contentPanel); } - let iconId = "social-notification-icon-" + icon.name; - let imageId = iconId + "-image"; - let labelId = iconId + "-label"; - let stackId = iconId + "-stack"; - let stack = document.getElementById(stackId); - let image, label; - if (stack) { - image = document.getElementById(imageId); - label = document.getElementById(labelId); - } else { - let box = document.createElement("box"); - box.classList.add("toolbarbutton-1"); - box.setAttribute("id", iconId); - // Use the accessibility menuitem label as tooltiptext. - if (icon.label) - box.setAttribute("tooltiptext", icon.label); - box.addEventListener("mousedown", function (e) { - if (e.button == 0) - SocialToolbar.showAmbientPopup(box); - }, false); - box.setAttribute("notificationFrameId", notificationFrameId); - stack = document.createElement("stack"); - stack.setAttribute("id", stackId); - stack.classList.add("social-notification-icon-stack"); - stack.classList.add("toolbarbutton-icon"); - image = document.createElement("image"); - image.setAttribute("id", imageId); - image.classList.add("social-notification-icon-image"); - image = stack.appendChild(image); - label = document.createElement("label"); - label.setAttribute("id", labelId); - label.classList.add("social-notification-icon-label"); - let hbox = document.createElement("hbox"); - hbox.classList.add("social-notification-icon-hbox"); - hbox.setAttribute("align", "start"); - hbox.setAttribute("pack", "end"); - label = hbox.appendChild(label); - stack.appendChild(hbox); - box.appendChild(stack); - iconContainers.appendChild(box); + let toolbarButtonContainerId = "social-notification-container-" + icon.name; + let toolbarButtonId = "social-notification-icon-" + icon.name; + let toolbarButtonContainer = document.getElementById(toolbarButtonContainerId); + let toolbarButton = document.getElementById(toolbarButtonId); + if (!toolbarButtonContainer) { + // The container is used to fix an issue with position:absolute on + // generated content not being constrained to the bounding box of a + // parent toolbarbutton that has position:relative. + toolbarButtonContainer = document.createElement("toolbaritem"); + toolbarButtonContainer.classList.add("social-notification-container"); + toolbarButtonContainer.setAttribute("id", toolbarButtonContainerId); + + toolbarButton = document.createElement("toolbarbutton"); + toolbarButton.classList.add("toolbarbutton-1"); + toolbarButton.setAttribute("id", toolbarButtonId); + toolbarButton.setAttribute("notificationFrameId", notificationFrameId); + toolbarButton.addEventListener("mousedown", function (event) { + if (event.button == 0) + SocialToolbar.showAmbientPopup(toolbarButton); + }); + + toolbarButtonContainer.appendChild(toolbarButton); + toolbarButtons.appendChild(toolbarButtonContainer); } - let labelValue = icon.counter || ""; - // Only update the value attribute if it has changed to reduce layout changes. - if (!label.hasAttribute("value") || label.getAttribute("value") != labelValue) - label.setAttribute("value", labelValue); + toolbarButton.style.listStyleImage = "url(" + icon.iconURL + ")"; + toolbarButton.setAttribute("label", icon.label); + toolbarButton.setAttribute("tooltiptext", icon.label); - image.style.listStyleImage = "url(" + icon.iconURL + ")"; + let badge = icon.counter || ""; + if (toolbarButton.getAttribute("badge") != badge) + toolbarButton.setAttribute("badge", badge); } - iconBox.appendChild(iconContainers); + let socialToolbarItem = document.getElementById("social-toolbar-item"); + socialToolbarItem.appendChild(toolbarButtons); for (let frame of createdFrames) { if (frame.docShell) { @@ -923,12 +908,12 @@ var SocialToolbar = { } }, - showAmbientPopup: function SocialToolbar_showAmbientPopup(aToolbarButtonBox) { + showAmbientPopup: function SocialToolbar_showAmbientPopup(aToolbarButton) { // Hide any other social panels that may be open. SocialFlyout.panel.hidePopup(); let panel = document.getElementById("social-notification-panel"); - let notificationFrameId = aToolbarButtonBox.getAttribute("notificationFrameId"); + let notificationFrameId = aToolbarButton.getAttribute("notificationFrameId"); let notificationFrame = document.getElementById(notificationFrameId); let wasAlive = SharedFrame.isGroupAlive(notificationFrameId); @@ -951,7 +936,8 @@ var SocialToolbar = { let dynamicResizer = this._dynamicResizer; panel.addEventListener("popuphidden", function onpopuphiding() { panel.removeEventListener("popuphidden", onpopuphiding); - aToolbarButtonBox.removeAttribute("open"); + aToolbarButton.removeAttribute("open"); + aToolbarButton.parentNode.removeAttribute("open"); dynamicResizer.stop(); notificationFrame.docShell.isActive = false; dispatchPanelEvent("socialFrameHide"); @@ -959,7 +945,13 @@ var SocialToolbar = { panel.addEventListener("popupshown", function onpopupshown() { panel.removeEventListener("popupshown", onpopupshown); - aToolbarButtonBox.setAttribute("open", "true"); + // This attribute is needed on both the button and the + // containing toolbaritem since the buttons on OS X have + // moz-appearance:none, while their container gets + // moz-appearance:toolbarbutton due to the way that toolbar buttons + // get combined on OS X. + aToolbarButton.setAttribute("open", "true"); + aToolbarButton.parentNode.setAttribute("open", "true"); notificationFrame.docShell.isActive = true; notificationFrame.docShell.isAppTab = true; if (notificationFrame.contentDocument.readyState == "complete" && wasAlive) { @@ -977,9 +969,8 @@ var SocialToolbar = { } }); - let imageId = aToolbarButtonBox.getAttribute("id") + "-image"; - let toolbarButtonImage = document.getElementById(imageId); - panel.openPopup(toolbarButtonImage, "bottomcenter topright", 0, 0, false, false); + let toolbarButtonIcon = document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-icon"); + panel.openPopup(toolbarButtonIcon, "bottomcenter topright", 0, 0, false, false); }, setPanelErrorMessage: function SocialToolbar_setPanelErrorMessage(aNotificationFrame) { diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index 404b6273eec2..4f2f1d2744ee 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -618,6 +618,10 @@ html|*#gcli-output-frame, transition: none; } +.social-notification-container > .toolbarbutton-1[badge]:not([badge=""])::after { + content: attr(badge); +} + chatbox { -moz-binding: url("chrome://browser/content/socialchat.xml#chatbox"); } diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 646a1e703f37..67abe5c76a51 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -6925,6 +6925,12 @@ let gPrivateBrowsingUI = { return; } +#ifdef XP_MACOSX + if (!PrivateBrowsingUtils.permanentPrivateBrowsing) { + document.documentElement.setAttribute("drawintitlebar", true); + } +#endif + // Disable the Clear Recent History... menu item when in PB mode // temporary fix until bug 463607 is fixed document.getElementById("Tools:Sanitize").setAttribute("disabled", "true"); @@ -6936,7 +6942,8 @@ let gPrivateBrowsingUI = { docElement.getAttribute("title_privatebrowsing")); docElement.setAttribute("titlemodifier", docElement.getAttribute("titlemodifier_privatebrowsing")); - docElement.setAttribute("privatebrowsingmode", "temporary"); + docElement.setAttribute("privatebrowsingmode", + PrivateBrowsingUtils.permanentPrivateBrowsing ? "permanent" : "temporary"); gBrowser.updateTitlebar(); } diff --git a/browser/base/content/test/browser_pluginnotification.js b/browser/base/content/test/browser_pluginnotification.js index 54b117d4b9f9..bf9fd5ab606f 100644 --- a/browser/base/content/test/browser_pluginnotification.js +++ b/browser/base/content/test/browser_pluginnotification.js @@ -827,9 +827,8 @@ function test21a() { } // we have to actually show the panel to get the bindings to instantiate - notification.options.dismissed = false; notification.options.eventCallback = test21b; - PopupNotifications._showPanel([notification], notification.anchorElement); + notification.reshow(); } function test21b() { @@ -887,9 +886,8 @@ function test21c() { } // we have to actually show the panel to get the bindings to instantiate - notification.options.dismissed = false; notification.options.eventCallback = test21d; - PopupNotifications._showPanel([notification], notification.anchorElement); + notification.reshow(); } function test21d() { diff --git a/browser/base/content/test/social/browser_social_mozSocial_API.js b/browser/base/content/test/social/browser_social_mozSocial_API.js index fbe9c7a8211e..215f55a8ae79 100644 --- a/browser/base/content/test/social/browser_social_mozSocial_API.js +++ b/browser/base/content/test/social/browser_social_mozSocial_API.js @@ -28,10 +28,10 @@ var tests = { } function triggerIconPanel() { - let statusIcon = document.querySelector("#social-toolbar-item > box"); + let statusIcon = document.querySelector("#social-toolbar-item > .social-notification-container > .toolbarbutton-1"); info("status icon is " + statusIcon); waitForCondition(function() { - statusIcon = document.querySelector("#social-toolbar-item > box"); + statusIcon = document.querySelector("#social-toolbar-item > .social-notification-container > .toolbarbutton-1"); info("status icon is " + statusIcon); return !!statusIcon; }, function() { diff --git a/browser/base/content/test/social/browser_social_toolbar.js b/browser/base/content/test/social/browser_social_toolbar.js index f28bbc1717a9..b5162f61c948 100644 --- a/browser/base/content/test/social/browser_social_toolbar.js +++ b/browser/base/content/test/social/browser_social_toolbar.js @@ -103,17 +103,18 @@ var tests = { Social.provider.setAmbientNotification(ambience2); Social.provider.setAmbientNotification(ambience3); - let statusIcon = document.querySelector("#social-toolbar-item > box"); + let statusIcon = document.querySelector("#social-toolbar-item > .social-notification-container > .toolbarbutton-1"); waitForCondition(function() { - statusIcon = document.querySelector("#social-toolbar-item > box"); + statusIcon = document.querySelector("#social-toolbar-item > .social-notification-container > .toolbarbutton-1"); return !!statusIcon; }, function () { - let statusIconLabel = statusIcon.querySelector("label"); - is(statusIconLabel.value, "42", "status value is correct"); + let badge = statusIcon.getAttribute("badge"); + is(badge, "42", "status value is correct"); ambience.counter = 0; Social.provider.setAmbientNotification(ambience); - is(statusIconLabel.value, "", "status value is correct"); + badge = statusIcon.getAttribute("badge"); + is(badge, "", "status value is correct"); // The menu bar isn't as easy to instrument on Mac. if (navigator.platform.contains("Mac")) diff --git a/browser/components/Makefile.in b/browser/components/Makefile.in index 07ca3eb9a96a..a9caa5a5f1e2 100644 --- a/browser/components/Makefile.in +++ b/browser/components/Makefile.in @@ -17,8 +17,11 @@ XPIDLSRCS = \ nsIBrowserHandler.idl \ $(NULL) -EXTRA_PP_COMPONENTS = \ +EXTRA_COMPONENTS = \ BrowserComponents.manifest \ + $(NULL) + +EXTRA_PP_COMPONENTS = \ nsBrowserContentHandler.js \ nsBrowserGlue.js \ $(NULL) diff --git a/browser/components/downloads/content/allDownloadsViewOverlay.css b/browser/components/downloads/content/allDownloadsViewOverlay.css index 45c511881548..71e56b96b9fc 100644 --- a/browser/components/downloads/content/allDownloadsViewOverlay.css +++ b/browser/components/downloads/content/allDownloadsViewOverlay.css @@ -1,8 +1,8 @@ /* 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/. */ - -richlistitem.download { + +richlistitem.download[active] { -moz-binding: url('chrome://browser/content/downloads/download.xml#download-full-ui'); } @@ -13,12 +13,12 @@ richlistitem.download { .download-state:not(:-moz-any([state="2"], /* Failed */ [state="4"]) /* Paused */) .downloadCancelMenuItem, -.download-state:not(:-moz-any([state="1"], /* Finished */ - [state="2"], /* Failed */ - [state="3"], /* Canceled */ - [state="6"], /* Blocked (parental) */ - [state="8"], /* Blocked (dirty) */ - [state="9"]) /* Blocked (policy) */) +.download-state[state]:not(:-moz-any([state="1"], /* Finished */ + [state="2"], /* Failed */ + [state="3"], /* Canceled */ + [state="6"], /* Blocked (parental) */ + [state="8"], /* Blocked (dirty) */ + [state="9"]) /* Blocked (policy) */) .downloadRemoveFromHistoryMenuItem, .download-state:not(:-moz-any([state="-1"],/* Starting (initial) */ [state="0"], /* Downloading */ @@ -26,8 +26,7 @@ richlistitem.download { [state="4"], /* Paused */ [state="5"]) /* Starting (queued) */) .downloadShowMenuItem, -.download-state[state="7"] .downloadCommandsSeparator, -.download-state:not([state]) .downloadCommandsSeparator +.download-state[state="7"] .downloadCommandsSeparator { display: none; } diff --git a/browser/components/downloads/content/allDownloadsViewOverlay.js b/browser/components/downloads/content/allDownloadsViewOverlay.js index 21a54362c9a7..f0e298760c75 100644 --- a/browser/components/downloads/content/allDownloadsViewOverlay.js +++ b/browser/components/downloads/content/allDownloadsViewOverlay.js @@ -78,7 +78,7 @@ function DownloadElementShell(aDataItem, aPlacesNode, aAnnotations) { this._element.classList.add("download"); this._element.classList.add("download-state"); - if (aAnnotations) + if (aAnnotations) this._annotations = aAnnotations; if (aDataItem) this.dataItem = aDataItem; @@ -90,12 +90,30 @@ DownloadElementShell.prototype = { // The richlistitem for the download get element() this._element, + /** + * Manages the "active" state of the shell. By default all the shells + * without a dataItem are inactive, thus their UI is not updated. They must + * be activated when entering the visible area. Session downloads are + * always active since they always have a dataItem. + */ + ensureActive: function DES_ensureActive() { + if (this._active) + return; + this._active = true; + this._element.setAttribute("active", true); + this._updateStatusUI(); + this._fetchTargetFileInfo(); + }, + get active() !!this._active, + // The data item for the download _dataItem: null, get dataItem() this._dataItem, set dataItem(aValue) { - if ((this._dataItem = aValue)) { + this._dataItem = aValue; + if (this._dataItem) { + this._active = true; this._wasDone = this._dataItem.done; this._wasInProgress = this._dataItem.inProgress; this._targetFileInfoFetched = false; @@ -105,10 +123,12 @@ DownloadElementShell.prototype = { this._wasInProgress = false; this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED; this._targetFileInfoFetched = false; - this._fetchTargetFileInfo(); + if (this.active) + this._fetchTargetFileInfo(); } - this._updateStatusUI(); + it (this.active) + this._updateStatusUI(); return aValue; }, @@ -129,8 +149,10 @@ DownloadElementShell.prototype = { this._wasInProgress = false; this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED; this._targetFileInfoFetched = false; - this._updateStatusUI(); - this._fetchTargetFileInfo(); + if (this.active) { + this._updateStatusUI(); + this._fetchTargetFileInfo(); + } } } return aNode; @@ -154,8 +176,13 @@ DownloadElementShell.prototype = { get _icon() { if (this._targetFileURI) return "moz-icon://" + this._targetFileURI + "?size=32"; - if (this._placesNode) - return this.placesNode.icon; + if (this._placesNode) { + // Try to extract an extension from the uri. + let ext = this._downloadURIObj.QueryInterface(Ci.nsIURL).fileExtension; + if (ext) + return "moz-icon://." + ext + "?size=32"; + return this._placesNode.icon || "moz-icon://.unknown?size=32"; + } if (this._dataItem) throw new Error("Session-download items should always have a target file uri"); throw new Error("Unexpected download element state"); @@ -223,6 +250,8 @@ DownloadElementShell.prototype = { _fetchTargetFileInfo: function DES__fetchTargetFileInfo() { if (this._targetFileInfoFetched) throw new Error("_fetchTargetFileInfo should not be called if the information was already fetched"); + if (!this.active) + throw new Error("Trying to _fetchTargetFileInfo on an inactive download shell"); let path = this._targetFilePath; @@ -406,6 +435,8 @@ DownloadElementShell.prototype = { }, _updateStatusUI: function DES__updateStatusUI() { + if (!this.active) + throw new Error("Trying to _updateStatusUI on an inactive download shell"); this._element.setAttribute("displayName", this._displayName); this._element.setAttribute("image", this._icon); this._updateDownloadStatusUI(); @@ -446,7 +477,8 @@ DownloadElementShell.prototype = { this._element.setAttribute("image", this._icon + "&state=normal"); this._targetFileInfoFetched = false; - this._fetchTargetFileInfo(); + if (this.active) + this._fetchTargetFileInfo(); } this._wasDone = this._dataItem.done; @@ -471,6 +503,9 @@ DownloadElementShell.prototype = { /* nsIController */ isCommandEnabled: function DES_isCommandEnabled(aCommand) { + // The only valid command for inactive elements is cmd_delete. + if (!this.active && aCommand != "cmd_delete") + return false; switch (aCommand) { case "downloadsCmd_open": { // We cannot open a session dowload file unless it's done ("openable"). @@ -574,7 +609,8 @@ DownloadElementShell.prototype = { // show up in the search results for the given term. Both the display // name for the download and the url are searched. matchesSearchTerm: function DES_matchesSearchTerm(aTerm) { - // Stub implemention until we figure out something better + if (!aTerm) + return true; aTerm = aTerm.toLowerCase(); return this._displayName.toLowerCase().indexOf(aTerm) != -1 || this.downloadURI.toLowerCase().indexOf(aTerm) != -1; @@ -623,7 +659,7 @@ DownloadElementShell.prototype = { * as they exist they "collapses" their history "counterpart" (So we don't show two * items for every download). */ -function DownloadsPlacesView(aRichListBox) { +function DownloadsPlacesView(aRichListBox, aActive = true) { this._richlistbox = aRichListBox; this._richlistbox._placesView = this; this._richlistbox.controllers.appendController(this); @@ -640,6 +676,8 @@ function DownloadsPlacesView(aRichListBox) { this._searchTerm = ""; + this._active = aActive; + // Register as a downloads view. The places data will be initialized by // the places setter. let downloadsData = DownloadsCommon.getData(window.opener || window); @@ -651,11 +689,23 @@ function DownloadsPlacesView(aRichListBox) { downloadsData.removeView(this); this.result = null; }.bind(this), true); + // Resizing the window may change items visibility. + window.addEventListener("resize", function() { + this._ensureVisibleElementsAreActive(); + }.bind(this), true); } DownloadsPlacesView.prototype = { get associatedElement() this._richlistbox, + get active() this._active, + set active(val) { + this._active = val; + if (this._active) + this._ensureVisibleElementsAreActive(); + return this._active; + }, + _forEachDownloadElementShellForURI: function DPV__forEachDownloadElementShellForURI(aURI, aCallback) { if (this._downloadElementsShellsForURI.has(aURI)) { @@ -811,6 +861,11 @@ DownloadsPlacesView.prototype = { !newOrUpdatedShell.element._shell.matchesSearchTerm(this.searchTerm); } } + + // If aDocumentFragment is defined this is a batch change, so it's up to + // the caller to append the fragment and activate the visible shells. + if (!aDocumentFragment) + this._ensureVisibleElementsAreActive(); }, _removeElement: function DPV__removeElement(aElement) { @@ -823,6 +878,7 @@ DownloadsPlacesView.prototype = { this._richlistbox.selectItem(aElement.nextSibling); } this._richlistbox.removeChild(aElement); + this._ensureVisibleElementsAreActive(); }, _removeHistoryDownloadFromView: @@ -879,6 +935,38 @@ DownloadsPlacesView.prototype = { } }, + _ensureVisibleElementsAreActive: + function DPV__ensureVisibleElementsAreActive() { + if (!this.active || this._ensureVisibleTimer || !this._richlistbox.firstChild) + return; + + this._ensureVisibleTimer = setTimeout(function() { + delete this._ensureVisibleTimer; + + let rlRect = this._richlistbox.getBoundingClientRect(); + let fcRect = this._richlistbox.firstChild.getBoundingClientRect(); + // For simplicity assume border and padding are the same across all sides. + // This works as far as there isn't an horizontal scrollbar since fcRect + // is relative to the scrolled area. + let offset = fcRect.left - rlRect.left + 1; + + let firstVisible = document.elementFromPoint(fcRect.left, rlRect.top + offset); + if (!firstVisible || firstVisible.localName != "richlistitem") + throw new Error("_ensureVisibleElementsAreActive invoked on the wrong view"); + + let lastVisible = document.elementFromPoint(fcRect.left, rlRect.bottom - offset); + // If the last visible child found is not a richlistitem, then there are + // less items than the available space, thus just proceed to the last child. + if (!lastVisible || lastVisible.localName != "richlistitem") + lastVisible = this._richlistbox.lastChild; + + for (let elt = firstVisible; elt != lastVisible.nextSibling; elt = elt.nextSibling) { + if (elt._shell) + elt._shell.ensureActive(); + } + }.bind(this), 10); + }, + _place: "", get place() this._place, set place(val) { @@ -975,6 +1063,7 @@ DownloadsPlacesView.prototype = { } this._richlistbox.appendChild(elementsToAppendFragment); + this._ensureVisibleElementsAreActive(); }, nodeInserted: function DPV_nodeInserted(aParent, aPlacesNode) { @@ -1022,6 +1111,7 @@ DownloadsPlacesView.prototype = { for (let element of this._richlistbox.childNodes) { element.hidden = !element._shell.matchesSearchTerm(aValue); } + this._ensureVisibleElementsAreActive(); } return this._searchTerm = aValue; }, @@ -1198,6 +1288,10 @@ DownloadsPlacesView.prototype = { let element = selectedElements[0]; if (element._shell) element._shell.doDefaultCommand(); + }, + + onScroll: function DPV_onScroll() { + this._ensureVisibleElementsAreActive(); } }; diff --git a/browser/components/downloads/content/allDownloadsViewOverlay.xul b/browser/components/downloads/content/allDownloadsViewOverlay.xul index a4221cf4e01e..bad89005996c 100644 --- a/browser/components/downloads/content/allDownloadsViewOverlay.xul +++ b/browser/components/downloads/content/allDownloadsViewOverlay.xul @@ -42,6 +42,7 @@ diff --git a/browser/components/places/content/places.js b/browser/components/places/content/places.js index 38110aa3b13a..55c6483e7d6d 100644 --- a/browser/components/places/content/places.js +++ b/browser/components/places/content/places.js @@ -274,13 +274,8 @@ var PlacesOrganizer = { * Handle focus changes on the places list and the current content view. */ updateDetailsPane: function PO_updateDetailsPane() { - let detailsDeck = document.getElementById("detailsDeck"); - let detailsPaneDisabled = detailsDeck.hidden = - !ContentArea.currentViewOptions.showDetailsPane; - if (detailsPaneDisabled) { + if (!ContentArea.currentViewOptions.showDetailsPane) return; - } - let view = PlacesUIUtils.getViewForNode(document.activeElement); if (view) { let selectedNodes = view.selectedNode ? @@ -1278,7 +1273,7 @@ let ContentArea = { } } catch(ex) { - Cu.reportError(ex); + Components.utils.reportError(ex); } return ContentTree.view; }, @@ -1314,23 +1309,38 @@ let ContentArea = { get currentPlace() this.currentView.place, set currentPlace(aQueryString) { - this.currentView = this.getContentViewForQueryString(aQueryString); - this.currentView.place = aQueryString; - this._updateToolbarSet(); + let oldView = this.currentView; + let newView = this.getContentViewForQueryString(aQueryString); + newView.place = aQueryString; + if (oldView != newView) { + oldView.active = false; + this.currentView = newView; + this._setupView(); + newView.active = true; + } return aQueryString; }, - _updateToolbarSet: function CA__updateToolbarSet() { - let toolbarSet = this.currentViewOptions.toolbarSet; + /** + * Applies view options. + */ + _setupView: function CA__setupView() { + let options = this.currentViewOptions; + + // showDetailsPane. + let detailsDeck = document.getElementById("detailsDeck"); + detailsDeck.hidden = !options.showDetailsPane; + + // toolbarSet. for (let elt of this._toolbar.childNodes) { // On Windows and Linux the menu buttons are menus wrapped in a menubar. if (elt.id == "placesMenu") { for (let menuElt of elt.childNodes) { - menuElt.hidden = toolbarSet.indexOf(menuElt.id) == -1; + menuElt.hidden = options.toolbarSet.indexOf(menuElt.id) == -1; } } else { - elt.hidden = toolbarSet.indexOf(elt.id) == -1; + elt.hidden = options.toolbarSet.indexOf(elt.id) == -1; } } }, diff --git a/browser/components/places/content/tree.xml b/browser/components/places/content/tree.xml index 235f4bc68bf1..b0f995750650 100644 --- a/browser/components/places/content/tree.xml +++ b/browser/components/places/content/tree.xml @@ -674,6 +674,12 @@ + + true + + .toolbarbutton-1 { - margin: 0; - padding: 0; - -moz-appearance: toolbarbutton; -} - -.social-notification-icon-hbox { - pointer-events: none; -} - -.social-status-button { - list-style-image: none; -} - -#social-provider-button { - -moz-image-region: rect(0, 16px, 16px, 0); -} - -#social-provider-button > image { +#social-toolbar-item > .toolbarbutton-1 > .toolbarbutton-icon, +.social-notification-container > .toolbarbutton-1 > .toolbarbutton-icon { margin: 5px 3px; } @@ -2374,33 +2353,32 @@ html|*#gcli-output-frame { display: none; } -.social-notification-icon-stack { - padding: 0; +.social-notification-container { + /* position:relative on .toolbarbutton-1 does not get position:absolute + to work as expected on .toolbarbutton-1 generated content. Placing a + simple container outside of .toolbarbutton-1 and setting position:relative + on the simple container however will work. */ + position: relative; } -.social-notification-icon-image { - margin: 5px 3px; - -moz-image-region: rect(0, 16px, 16px, 0); -} - -.social-notification-icon-hbox { - padding: 0; -} - -.social-notification-icon-label { - background-color: rgb(240,61,37); - border: 1px solid rgb(216,55,34); - box-shadow: 0px 1px 0px rgba(0,39,121,0.77); - padding-right: 1px; - padding-left: 1px; - color: white; +.social-notification-container > .toolbarbutton-1[badge]:not([badge=""])::after { + /* The |content| property is set in the content stylesheet. */ font-size: 9px; font-weight: bold; - margin: 0; + padding: 0 1px; + color: #fff; + background-color: rgb(240,61,37); + border: 1px solid rgb(216,55,34); + border-radius: 2px; + box-shadow: 0 1px 0 rgba(0,39,121,0.77); + position: absolute; + top: 2px; + right: 2px; } -.social-notification-icon-label[value=""] { - display: none; +.social-notification-container > .toolbarbutton-1[badge]:not([badge=""]):-moz-locale-dir(rtl)::after { + left: 2px; + right: auto; } /* social toolbar provider menu */ diff --git a/browser/themes/gnomestripe/preferences/preferences.css b/browser/themes/gnomestripe/preferences/preferences.css index 0e644dabbdec..55cc2c8fd152 100644 --- a/browser/themes/gnomestripe/preferences/preferences.css +++ b/browser/themes/gnomestripe/preferences/preferences.css @@ -60,11 +60,11 @@ radio[pane=paneSync] { /* styles for the link elements copied from .text-link in global.css */ .inline-link { color: -moz-nativehyperlinktext; - text-decoration: underline; + text-decoration: none; } - -.inline-link:not(:focus) { - outline: 1px dotted transparent; + +.inline-link:hover { + text-decoration: underline; } /* Modeless Window Dialogs */ diff --git a/browser/themes/pinstripe/browser.css b/browser/themes/pinstripe/browser.css index 48648df5778c..f13de6ceaa42 100644 --- a/browser/themes/pinstripe/browser.css +++ b/browser/themes/pinstripe/browser.css @@ -2392,7 +2392,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { text-shadow: inherit; } -#navigator-toolbox[tabsontop="true"]:not(:-moz-lwtheme)::before { +#main-window:not([privatebrowsingmode=temporary]) #navigator-toolbox[tabsontop="true"]:not(:-moz-lwtheme)::before { /* We want the titlebar to be unified, but we still want to be able * to give #TabsToolbar a background. So we can't set -moz-appearance: * toolbar on #TabsToolbar itself. Instead, we set it on a box of the @@ -3002,11 +3002,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { } } -#notification-popup .text-link, .panel-arrowcontent .text-link { - color: #0073e6; - text-decoration: none; -} - #geolocation-learnmore-link { -moz-margin-start: 0; /* override default label margin to match description margin */ } @@ -3100,7 +3095,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { .popup-notification-icon[popupid="geolocation"] { list-style-image: url(chrome://browser/skin/Geolocation-64.png); } - @media (min-resolution: 2dppx) { .popup-notification-icon[popupid="geolocation"] { list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png); @@ -3171,6 +3165,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { .popup-notification-icon[popupid="webRTC-shareDevices"] { list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png); } +@media (min-resolution: 2dppx) { + .popup-notification-icon[popupid="webRTC-sharingDevices"], + .popup-notification-icon[popupid="webRTC-shareDevices"] { + list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64@2x.png); + } +} /* Popup Buttons */ #identity-popup-more-info-button { @@ -3803,30 +3803,16 @@ html|*#gcli-output-frame { /* === social toolbar button === */ -/* button icon for the service */ +toolbar[mode="icons"] > *|* > .social-notification-container { + -moz-appearance: toolbarbutton; +} + +.social-notification-container > .toolbarbutton-1 { + -moz-appearance: none; +} + #social-toolbar-item { - -moz-box-orient: horizontal; -} - -#social-toolbar-item > .toolbarbutton-1:not(:first-child):not(:last-child) { - margin-left: 0; - margin-right: 0; -} - -#social-toolbar-item > .toolbarbutton-1:first-child { - -moz-margin-end: 0; -} - -#social-toolbar-item > .toolbarbutton-1:last-child { - -moz-margin-start: 0; -} - -.social-notification-icon-hbox { - pointer-events: none; -} - -.social-status-button { - list-style-image: none; + margin: 0 4px; } #social-provider-button { @@ -3837,39 +3823,40 @@ html|*#gcli-output-frame { display: none; } -.social-notification-icon-stack { - padding: 0; +.social-notification-container { + /* position:relative on .toolbarbutton-1 does not get position:absolute + to work as expected on .toolbarbutton-1 generated content. Placing a + simple container outside of .toolbarbutton-1 and setting position:relative + on the simple container however will work. */ + position: relative; } -.social-notification-icon-hbox { - padding: 0; -} -.social-notification-icon-label { - text-align: end; +.social-notification-container > .toolbarbutton-1[badge]:not([badge=""])::after { + /* The |content| property is set in the content stylesheet. */ font-size: 9px; font-weight: bold; padding: 0 1px; - color: white; - margin: 0; + color: #fff; background-color: rgb(240,61,37); border: 1px solid rgb(216,55,34); + border-radius: 2px; box-shadow: 0 1px 0 rgba(0,39,121,0.77); - -moz-margin-end: -4px; - margin-top: -4px; + position: absolute; + top: 2px; + right: 0; } -.social-notification-icon-label[value=""] { - display: none; +.social-notification-container > .toolbarbutton-1[badge]:not([badge=""]):-moz-locale-dir(rtl)::after { + left: 0; + right: auto; } -@media (-moz-mac-lion-theme) { - .social-notification-icon-stack > image:-moz-window-inactive { - opacity: .5; - } +toolbar[mode="icons"] > *|* > .social-notification-container > .toolbarbutton-1[badge]:not([badge=""])::after { + right: -2px; } -.social-notification-icon-image { - -moz-image-region: rect(0, 16px, 16px, 0); +toolbar[mode="icons"] > *|* > .social-notification-container > .toolbarbutton-1[badge]:not([badge=""]):-moz-locale-dir(rtl)::after { + left: -2px; } /* === end of social toolbar button === */ @@ -4161,3 +4148,27 @@ panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > . .center-item-button { min-width: 0; } + +%ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING +#main-window[privatebrowsingmode=temporary] { + background-image: url("chrome://browser/skin/privatebrowsing-mask.png"); + background-position: top right; + background-repeat: no-repeat; + background-color: -moz-mac-chrome-active; +} + +@media (-moz-mac-lion-theme) { + #main-window[privatebrowsingmode=temporary] { + background-position: top right 40px; + } + + #main-window[privatebrowsingmode=temporary]:-moz-locale-dir(rtl) { + background-position: top left 70px; + } +} + +#main-window[privatebrowsingmode=temporary]:-moz-window-inactive { + background-color: -moz-mac-chrome-inactive; +} +%endif + diff --git a/browser/themes/pinstripe/jar.mn b/browser/themes/pinstripe/jar.mn index 965bd2a44c52..62723370d0a1 100644 --- a/browser/themes/pinstripe/jar.mn +++ b/browser/themes/pinstripe/jar.mn @@ -48,6 +48,7 @@ browser.jar: skin/classic/browser/pageInfo.css skin/classic/browser/Privacy-16.png skin/classic/browser/Privacy-48.png + skin/classic/browser/privatebrowsing-mask.png skin/classic/browser/reload-stop-go.png skin/classic/browser/reload-stop-go@2x.png skin/classic/browser/searchbar-dropmarker.png @@ -70,6 +71,7 @@ browser.jar: skin/classic/browser/webRTC-shareDevice-16.png skin/classic/browser/webRTC-shareDevice-16@2x.png skin/classic/browser/webRTC-shareDevice-64.png + skin/classic/browser/webRTC-shareDevice-64@2x.png skin/classic/browser/downloads/buttons.png (downloads/buttons.png) skin/classic/browser/downloads/download-glow.png (downloads/download-glow.png) skin/classic/browser/downloads/download-glow@2x.png (downloads/download-glow@2x.png) diff --git a/browser/themes/pinstripe/preferences/preferences.css b/browser/themes/pinstripe/preferences/preferences.css index d5846c77a209..043534fc16b3 100644 --- a/browser/themes/pinstripe/preferences/preferences.css +++ b/browser/themes/pinstripe/preferences/preferences.css @@ -163,11 +163,11 @@ caption { /* styles for the link elements copied from .text-link in global.css */ .inline-link { color: -moz-nativehyperlinktext; - text-decoration: underline; + text-decoration: none; } - -.inline-link:not(:focus) { - outline: 1px dotted transparent; + +.inline-link:hover { + text-decoration: underline; } /** diff --git a/browser/themes/pinstripe/privatebrowsing-mask.png b/browser/themes/pinstripe/privatebrowsing-mask.png new file mode 100644 index 000000000000..92f60e29f9fd Binary files /dev/null and b/browser/themes/pinstripe/privatebrowsing-mask.png differ diff --git a/browser/themes/pinstripe/webRTC-shareDevice-64@2x.png b/browser/themes/pinstripe/webRTC-shareDevice-64@2x.png new file mode 100644 index 000000000000..82e591f614f8 Binary files /dev/null and b/browser/themes/pinstripe/webRTC-shareDevice-64@2x.png differ diff --git a/browser/themes/winstripe/browser.css b/browser/themes/winstripe/browser.css index 9325e8c69ab6..a06fd09865d6 100644 --- a/browser/themes/winstripe/browser.css +++ b/browser/themes/winstripe/browser.css @@ -727,7 +727,8 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button { } @navbarLargeIcons@ .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before, -@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:not(:hover) + .toolbarbutton-1:not(:hover)::before { +@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:not(:hover) + .social-notification-container:not(:hover) > .toolbarbutton-1::before, +@navbarLargeIcons@ > #social-toolbar-item > .social-notification-container:not(:hover) + .social-notification-container:not(:hover) > .toolbarbutton-1::before { content: ""; display: -moz-box; width: 1px; @@ -3028,6 +3029,7 @@ html|*#gcli-output-frame { } /* Social toolbar item */ + #social-provider-button { -moz-image-region: rect(0, 16px, 16px, 0); } @@ -3036,47 +3038,47 @@ html|*#gcli-output-frame { display: none; } -#social-toolbar-item > .toolbarbutton-1 { - padding: 5px; - -moz-appearance: toolbarbutton; +@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1, +@navbarLargeIcons@ > #social-toolbar-item > .social-notification-container > .toolbarbutton-1 { + padding-left: 0; + padding-right: 0; } -@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1 { - padding: 6px 0; +@navbarLargeIcons@ > #social-toolbar-item { + margin-left: 5px; + margin-right: 5px; } -@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:first-child { - -moz-padding-start: 5px; +.social-notification-container { + /* position:relative on .toolbarbutton-1 does not get position:absolute + to work as expected on .toolbarbutton-1 generated content. Placing a + simple container outside of .toolbarbutton-1 and setting position:relative + on the simple container however will work. */ + position: relative; } -@navbarLargeIcons@ > #social-toolbar-item > .toolbarbutton-1:last-child { - -moz-padding-end: 5px; -} - -.social-notification-icon-hbox { - pointer-events: none; - margin-top: -5px; - -moz-margin-end: -12px; -} - -.social-notification-icon-label { - text-align: end; +.social-notification-container > .toolbarbutton-1[badge]:not([badge=""])::after { + /* The |content| property is set in the content stylesheet. */ font-size: 9px; font-weight: bold; padding: 0 1px; - color: white; + color: #fff; background-color: rgb(240,61,37); border: 1px solid rgb(216,55,34); border-radius: 2px; box-shadow: 0 1px 0 rgba(0,39,121,0.77); + position: absolute; + top: 2px; + right: 2px; } -.social-notification-icon-label[value=""] { - display: none; +@navbarLargeIcons@ > *|* > .social-notification-container > .toolbarbutton-1[badge]:not([badge=""])::after { + top: 7px; } -.social-notification-icon-image { - -moz-image-region: rect(0, 16px, 16px, 0); +.social-notification-container > .toolbarbutton-1[badge]:not([badge=""]):-moz-locale-dir(rtl)::after { + left: 2px; + right: auto; } /* social toolbar provider menu */ @@ -3377,3 +3379,20 @@ chatbox[minimized="true"] { .center-item-button { min-width: 0; } + +%ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING +#main-window[privatebrowsingmode=temporary] #toolbar-menubar { + background-image: url("chrome://browser/skin/privatebrowsing-dark.png"); + background-position: top right; + background-repeat: no-repeat; +} + +#main-window[privatebrowsingmode=temporary] #toolbar-menubar:-moz-locale-dir(rtl) { + background-position: top left; +} + +#main-window[privatebrowsingmode=temporary] #appmenu-button { + list-style-image: url("chrome://browser/skin/privatebrowsing-light.png"); +} +%endif + diff --git a/browser/themes/winstripe/jar.mn b/browser/themes/winstripe/jar.mn index 0204bb3bfa1a..44565cab0984 100644 --- a/browser/themes/winstripe/jar.mn +++ b/browser/themes/winstripe/jar.mn @@ -44,6 +44,8 @@ browser.jar: skin/classic/browser/page-livemarks.png (feeds/feedIcon16.png) skin/classic/browser/Privacy-16.png skin/classic/browser/Privacy-48.png + skin/classic/browser/privatebrowsing-light.png + skin/classic/browser/privatebrowsing-dark.png skin/classic/browser/reload-stop-go.png skin/classic/browser/searchbar.css skin/classic/browser/searchbar-dropdown-arrow.png @@ -266,6 +268,8 @@ browser.jar: skin/classic/aero/browser/page-livemarks.png (feeds/feedIcon16-aero.png) skin/classic/aero/browser/Privacy-16.png (Privacy-16-aero.png) skin/classic/aero/browser/Privacy-48.png (Privacy-48-aero.png) + skin/classic/aero/browser/privatebrowsing-light.png + skin/classic/aero/browser/privatebrowsing-dark.png skin/classic/aero/browser/reload-stop-go.png skin/classic/aero/browser/searchbar.css skin/classic/aero/browser/searchbar-dropdown-arrow.png (searchbar-dropdown-arrow-aero.png) diff --git a/browser/themes/winstripe/preferences/preferences.css b/browser/themes/winstripe/preferences/preferences.css index ddfeb9977cda..5067fe635123 100644 --- a/browser/themes/winstripe/preferences/preferences.css +++ b/browser/themes/winstripe/preferences/preferences.css @@ -59,11 +59,11 @@ radio[pane=paneSync] { /* styles for the link elements copied from .text-link in global.css */ .inline-link { color: -moz-nativehyperlinktext; - text-decoration: underline; + text-decoration: none; } -.inline-link:not(:focus) { - outline: 1px dotted transparent; +.inline-link:hover { + text-decoration: underline; } /* Modeless Window Dialogs */ diff --git a/browser/themes/winstripe/privatebrowsing-dark.png b/browser/themes/winstripe/privatebrowsing-dark.png new file mode 100644 index 000000000000..9eaf3aec7e71 Binary files /dev/null and b/browser/themes/winstripe/privatebrowsing-dark.png differ diff --git a/browser/themes/winstripe/privatebrowsing-light.png b/browser/themes/winstripe/privatebrowsing-light.png new file mode 100644 index 000000000000..c12f50779858 Binary files /dev/null and b/browser/themes/winstripe/privatebrowsing-light.png differ diff --git a/build/mobile/sutagent/android/DoCommand.java b/build/mobile/sutagent/android/DoCommand.java index a3fc0d260e5e..e5200a78dcea 100755 --- a/build/mobile/sutagent/android/DoCommand.java +++ b/build/mobile/sutagent/android/DoCommand.java @@ -107,7 +107,7 @@ public class DoCommand { String ffxProvider = "org.mozilla.ffxcp"; String fenProvider = "org.mozilla.fencp"; - private final String prgVersion = "SUTAgentAndroid Version 1.15"; + private final String prgVersion = "SUTAgentAndroid Version 1.16"; public enum Command { @@ -3414,7 +3414,7 @@ private void CancelNotification() else prgIntent.setAction(Intent.ACTION_MAIN); - if (sArgs[0].contains("fennec")) + if (sArgs[0].contains("fennec") || sArgs[0].contains("firefox")) { sArgList = ""; sUrl = ""; diff --git a/build/win32/mozconfig.vs2010-win64 b/build/win32/mozconfig.vs2010-win64 index a9156a28aac2..8fbe98f8ff3c 100644 --- a/build/win32/mozconfig.vs2010-win64 +++ b/build/win32/mozconfig.vs2010-win64 @@ -1,9 +1,18 @@ -export INCLUDE=/c/tools/msvs10/vc/include:/c/tools/msvs10/vc/atlmfc/include:/c/tools/sdks/v7.0/include:/c/tools/sdks/v7.0/include/atl:/c/tools/sdks/dx10/include -export LIBPATH=/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib -export LIB=/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib:/c/tools/sdks/v7.0/lib:/c/tools/sdks/dx10/lib +## SDK redist ## export WIN32_REDIST_DIR=/c/tools/msvs10/VC/redist/x86/Microsoft.VC100.CRT + +## moz tools location for 64-bit builders ## export MOZ_TOOLS=C:/mozilla-build/moztools -export PATH="/c/tools/msvs10/Common7/IDE:/c/tools/msvs10/VC/BIN:/c/tools/msvs10/Common7/Tools:/c/tools/msvs10/VC/VCPackages:/c/mozilla-build/moztools:/c/Tools/sdks/v7.0/bin:${PATH}" + +## includes: win8 sdk includes, winrt headers for metro, msvc 10 std library, directx sdk for d3d9 ## +export INCLUDE=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/shared:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/um:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl/wrappers:/c/tools/msvs10/vc/include:/c/tools/msvs10/vc/atlmfc/include:/c/tools/sdks/dx10/include + +## libs: win8 sdk x86 (32-bit) libs, msvc 10 (32-bit) std library, msvc 10 atl libs, directx sdk (32-bit) for d3d9 ## +export LIBPATH=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x86:/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib:/c/tools/sdks/dx10/lib +export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x86:/c/tools/msvs10/vc/lib:/c/tools/msvs10/vc/atlmfc/lib:/c/tools/sdks/dx10/lib + +## paths: win8 sdk x86 (32-bit) tools, msvc 10 (32-bit) build toolchain, moz tools ## +export PATH="/c/Program Files (x86)/Windows Kits/8.0/bin/x86:/c/tools/msvs10/Common7/IDE:/c/tools/msvs10/VC/BIN:/c/tools/msvs10/Common7/Tools:/c/tools/msvs10/VC/VCPackages:/c/mozilla-build/moztools:${PATH}" . $topsrcdir/build/mozconfig.vs2010-common diff --git a/build/win64/mozconfig.vs2010 b/build/win64/mozconfig.vs2010 index fe9093be4b10..d82bada4c438 100644 --- a/build/win64/mozconfig.vs2010 +++ b/build/win64/mozconfig.vs2010 @@ -1,9 +1,16 @@ -export INCLUDE=/c/tools/msvs10/vc/include:/c/tools/msvs10/vc/atlmfc/include:/c/tools/sdks/v7.0/include:/c/tools/sdks/v7.0/include/atl:/c/tools/sdks/dx10/include -export LIBPATH=/c/tools/msvs10/vc/lib/amd64:/c/tools/msvs10/vc/atlmfc/lib/amd64 -export LIB=/c/tools/msvs10/vc/lib/amd64:/c/tools/msvs10/vc/atlmfc/lib/amd64:/c/tools/sdks/v7.0/lib/x64:/c/tools/sdks/dx10/lib/x64 -export PATH="/c/tools/msvs10/Common7/IDE:/c/tools/msvs10/VC/BIN/amd64:/c/tools/msvs10/VC/BIN/x86_amd64:/c/tools/msvs10/VC/BIN:/c/tools/msvs10/Common7/Tools:/c/tools/msvs10/VC/VCPackages:${PATH}" +## SDK redist ## export WIN32_REDIST_DIR=/c/tools/msvs10/VC/redist/x64/Microsoft.VC100.CRT +## includes: win8 sdk includes, winrt headers for metro, msvc 10 std library, directx sdk for d3d9 ## +export INCLUDE=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/shared:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/um:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl:/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/include/winrt/wrl/wrappers:/c/tools/msvs10/vc/include:/c/tools/msvs10/vc/atlmfc/include:/c/tools/sdks/dx10/include + +## libs: win8 sdk x64 (64-bit) libs, msvc 10 (64-bit) std library, msvc 10 atl libs, directx sdk (64-bit) for d3d9 ## +export LIBPATH=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x64:/c/tools/msvs10/vc/lib/amd64:/c/tools/msvs10/vc/atlmfc/lib/amd64:/c/tools/sdks/dx10/lib/x64 +export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/8.0/Lib/win8/um/x64:/c/tools/msvs10/vc/lib/amd64:/c/tools/msvs10/vc/atlmfc/lib/amd64:/c/tools/sdks/dx10/lib/x64 + +## paths: win8 sdk x64 (64-bit) tools, msvc 10 (64-bit) build toolchain, moz tools ## +export PATH="/c/Program Files (x86)/Windows Kits/8.0/bin/x64:/c/tools/msvs10/Common7/IDE:/c/tools/msvs10/VC/BIN/amd64:/c/tools/msvs10/VC/BIN/x86_amd64:/c/tools/msvs10/VC/BIN:/c/tools/msvs10/Common7/Tools:/c/tools/msvs10/VC/VCPackages:${PATH}" + # Use 32bit linker for PGO crash bug. # https://connect.microsoft.com/VisualStudio/feedback/details/686117/ export LD=c:/tools/msvs10/VC/BIN/x86_amd64/link.exe diff --git a/caps/idl/nsIPrincipal.idl b/caps/idl/nsIPrincipal.idl index 8f009f996dcc..640e957904fe 100644 --- a/caps/idl/nsIPrincipal.idl +++ b/caps/idl/nsIPrincipal.idl @@ -21,7 +21,7 @@ interface nsIContentSecurityPolicy; [ptr] native JSPrincipals(JSPrincipals); [ptr] native PrincipalArray(nsTArray >); -[scriptable, builtinclass, uuid(011966C0-8564-438D-B37A-08D7E1195E5A)] +[scriptable, builtinclass, uuid(dbda8bb0-3023-4aec-ad98-8e9931a29d70)] interface nsIPrincipal : nsISerializable { /** @@ -153,6 +153,13 @@ interface nsIPrincipal : nsISerializable */ readonly attribute AUTF8String extendedOrigin; + /** + * The base domain of the codebase URI to which this principal pertains + * (generally the document URI), handling null principals and + * non-hierarchical schemes correctly. + */ + readonly attribute ACString baseDomain; + const short APP_STATUS_NOT_INSTALLED = 0; const short APP_STATUS_INSTALLED = 1; const short APP_STATUS_PRIVILEGED = 2; diff --git a/caps/include/nsPrincipal.h b/caps/include/nsPrincipal.h index 53255826086d..46c6510560c2 100644 --- a/caps/include/nsPrincipal.h +++ b/caps/include/nsPrincipal.h @@ -72,6 +72,7 @@ public: NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement); NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId); NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal); + NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain); #ifdef DEBUG virtual void dumpImpl(); #endif @@ -154,6 +155,7 @@ public: NS_IMETHOD GetIsInBrowserElement(bool* aIsInBrowserElement); NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId); NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal); + NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain); #ifdef DEBUG virtual void dumpImpl(); #endif diff --git a/caps/src/nsNullPrincipal.cpp b/caps/src/nsNullPrincipal.cpp index c1996efeff99..3f710d84e431 100644 --- a/caps/src/nsNullPrincipal.cpp +++ b/caps/src/nsNullPrincipal.cpp @@ -298,6 +298,13 @@ nsNullPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) return NS_OK; } +NS_IMETHODIMP +nsNullPrincipal::GetBaseDomain(nsACString& aBaseDomain) +{ + // For a null principal, we use our unique uuid as the base domain. + return mURI->GetPath(aBaseDomain); +} + /** * nsISerializable implementation */ diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp index 575467183f64..082d22a9e253 100644 --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -4,6 +4,7 @@ * 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 "mozIThirdPartyUtil.h" #include "nscore.h" #include "nsScriptSecurityManager.h" #include "nsString.h" @@ -441,7 +442,7 @@ nsPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport, bool aAllowIfInheritsPrinc nsScriptSecurityManager::ReportError( nullptr, NS_LITERAL_STRING("CheckSameOriginError"), mCodebase, aURI); } - + return NS_ERROR_DOM_BAD_URI; } @@ -485,7 +486,7 @@ nsPrincipal::SetDomain(nsIURI* aDomain) { mDomain = NS_TryToMakeImmutable(aDomain); mDomainImmutable = URIIsImmutable(mDomain); - + // Domain has changed, forget cached security policy SetSecurityPolicy(nullptr); @@ -556,6 +557,29 @@ nsPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) return NS_OK; } +NS_IMETHODIMP +nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) +{ + // For a file URI, we return the file path. + if (URIIsLocalFile(mCodebase)) { + nsCOMPtr url = do_QueryInterface(mCodebase); + + if (url) { + return url->GetFilePath(aBaseDomain); + } + } + + // For everything else, we ask the TLD service via + // the ThirdPartyUtil. + nsCOMPtr thirdPartyUtil = + do_GetService(THIRDPARTYUTIL_CONTRACTID); + if (thirdPartyUtil) { + return thirdPartyUtil->GetBaseDomain(mCodebase, aBaseDomain); + } + + return NS_OK; +} + NS_IMETHODIMP nsPrincipal::Read(nsIObjectInputStream* aStream) { @@ -688,20 +712,20 @@ nsExpandedPrincipal::nsExpandedPrincipal(nsTArray > &aWh nsExpandedPrincipal::~nsExpandedPrincipal() { } -NS_IMETHODIMP +NS_IMETHODIMP nsExpandedPrincipal::GetDomain(nsIURI** aDomain) { *aDomain = nullptr; return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsExpandedPrincipal::SetDomain(nsIURI* aDomain) { return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsExpandedPrincipal::GetOrigin(char** aOrigin) { *aOrigin = ToNewCString(NS_LITERAL_CSTRING(EXPANDED_PRINCIPAL_SPEC)); @@ -713,10 +737,10 @@ typedef nsresult (NS_STDCALL nsIPrincipal::*nsIPrincipalMemFn)(nsIPrincipal* aOt #define CALL_MEMBER_FUNCTION(THIS,MEM_FN) ((THIS)->*(MEM_FN)) // nsExpandedPrincipal::Equals and nsExpandedPrincipal::EqualsIgnoringDomain -// shares the same logic. The difference only that Equals requires 'this' -// and 'aOther' to Subsume each other while EqualsIgnoringDomain requires +// shares the same logic. The difference only that Equals requires 'this' +// and 'aOther' to Subsume each other while EqualsIgnoringDomain requires // bidirectional SubsumesIgnoringDomain. -static nsresult +static nsresult Equals(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, bool* aResult) { @@ -750,14 +774,14 @@ nsExpandedPrincipal::EqualsIgnoringDomain(nsIPrincipal* aOther, bool* aResult) // nsExpandedPrincipal::Subsumes and nsExpandedPrincipal::SubsumesIgnoringDomain // shares the same logic. The difference only that Subsumes calls are replaced //with SubsumesIgnoringDomain calls in the second case. -static nsresult -Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, +static nsresult +Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther, bool* aResult) { nsresult rv; - nsCOMPtr expanded = do_QueryInterface(aOther); + nsCOMPtr expanded = do_QueryInterface(aOther); if (expanded) { - // If aOther is an ExpandedPrincipal too, check if all of its + // If aOther is an ExpandedPrincipal too, check if all of its // principals are subsumed. nsTArray< nsCOMPtr >* otherList; expanded->GetWhiteList(&otherList); @@ -766,7 +790,7 @@ Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther NS_ENSURE_SUCCESS(rv, rv); if (!*aResult) { // If we don't subsume at least one principal of aOther, return false. - return NS_OK; + return NS_OK; } } } else { @@ -826,7 +850,7 @@ nsExpandedPrincipal::GetURI(nsIURI** aURI) return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsExpandedPrincipal::GetWhiteList(nsTArray >** aWhiteList) { *aWhiteList = &mPrincipals; @@ -874,6 +898,12 @@ nsExpandedPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) return NS_OK; } +NS_IMETHODIMP +nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) +{ + return NS_ERROR_NOT_AVAILABLE; +} + void nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) { diff --git a/caps/src/nsSystemPrincipal.cpp b/caps/src/nsSystemPrincipal.cpp index ddc310c908a0..3003dd4b0f7b 100644 --- a/caps/src/nsSystemPrincipal.cpp +++ b/caps/src/nsSystemPrincipal.cpp @@ -205,6 +205,13 @@ nsSystemPrincipal::GetIsNullPrincipal(bool* aIsNullPrincipal) return NS_OK; } +NS_IMETHODIMP +nsSystemPrincipal::GetBaseDomain(nsACString& aBaseDomain) +{ + // No base domain for chrome. + return NS_OK; +} + ////////////////////////////////////////// // Methods implementing nsISerializable // ////////////////////////////////////////// diff --git a/configure.in b/configure.in index b21073581bfc..0417559c25ef 100644 --- a/configure.in +++ b/configure.in @@ -7296,7 +7296,7 @@ dnl our own linker. if test "$OS_TARGET" = Android; then WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue" WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror" - WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl--wrap=PR_GetEnv,--wrap=PR_SetEnv" + WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv" if test -z "$gonkdir"; then WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise" WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=memccpy,--wrap=memchr,--wrap=memrchr,--wrap=memcmp,--wrap=memcpy,--wrap=memmove,--wrap=memset,--wrap=memmem,--wrap=memswap,--wrap=index,--wrap=strchr,--wrap=strrchr,--wrap=strlen,--wrap=strcmp,--wrap=strcpy,--wrap=strcat,--wrap=strcasecmp,--wrap=strncasecmp,--wrap=strstr,--wrap=strcasestr,--wrap=strtok,--wrap=strtok_r,--wrap=strerror,--wrap=strerror_r,--wrap=strnlen,--wrap=strncat,--wrap=strncmp,--wrap=strncpy,--wrap=strlcat,--wrap=strlcpy,--wrap=strcspn,--wrap=strpbrk,--wrap=strsep,--wrap=strspn,--wrap=strcoll,--wrap=strxfrm" diff --git a/content/base/crashtests/824719.html b/content/base/crashtests/824719.html new file mode 100644 index 000000000000..3749b0ec08e0 --- /dev/null +++ b/content/base/crashtests/824719.html @@ -0,0 +1,26 @@ + + +
+
+
+a +
+
+
+
+ + + + + diff --git a/content/base/crashtests/crashtests.list b/content/base/crashtests/crashtests.list index a00756b41ce4..b749f29a93c7 100644 --- a/content/base/crashtests/crashtests.list +++ b/content/base/crashtests/crashtests.list @@ -123,3 +123,4 @@ load 815500.html load 816253.html load 822691.html load 822723.html +load 824719.html diff --git a/content/base/public/Element.h b/content/base/public/Element.h index 5fabce8920db..39573f609b12 100644 --- a/content/base/public/Element.h +++ b/content/base/public/Element.h @@ -873,6 +873,29 @@ public: */ nsIEditor* GetEditorInternal(); + /** + * Helper method for NS_IMPL_BOOL_ATTR macro. + * Gets value of boolean attribute. Only works for attributes in null + * namespace. + * + * @param aAttr name of attribute. + * @param aValue Boolean value of attribute. + */ + NS_HIDDEN_(bool) GetBoolAttr(nsIAtom* aAttr) const + { + return HasAttr(kNameSpaceID_None, aAttr); + } + + /** + * Helper method for NS_IMPL_BOOL_ATTR macro. + * Sets value of boolean attribute by removing attribute or setting it to + * the empty string. Only works for attributes in null namespace. + * + * @param aAttr name of attribute. + * @param aValue Boolean value of attribute. + */ + NS_HIDDEN_(nsresult) SetBoolAttr(nsIAtom* aAttr, bool aValue); + protected: /* * Named-bools for use with SetAttrAndNotify to make call sites easier to @@ -1215,6 +1238,24 @@ _elementName::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const \ return SetAttr(kNameSpaceID_None, nsGkAtoms::_atom, nullptr, aValue, true); \ } +/** + * A macro to implement the getter and setter for a given boolean + * valued content property. The method uses the GetBoolAttr and + * SetBoolAttr methods. + */ +#define NS_IMPL_BOOL_ATTR(_class, _method, _atom) \ + NS_IMETHODIMP \ + _class::Get##_method(bool* aValue) \ + { \ + *aValue = GetBoolAttr(nsGkAtoms::_atom); \ + return NS_OK; \ + } \ + NS_IMETHODIMP \ + _class::Set##_method(bool aValue) \ + { \ + return SetBoolAttr(nsGkAtoms::_atom, aValue); \ + } + #define NS_FORWARD_NSIDOMELEMENT_TO_GENERIC \ typedef mozilla::dom::Element Element; \ NS_IMETHOD GetTagName(nsAString& aTagName) MOZ_FINAL \ diff --git a/content/base/public/nsContentPolicyUtils.h b/content/base/public/nsContentPolicyUtils.h index 595707b11f21..3c9e785d068c 100644 --- a/content/base/public/nsContentPolicyUtils.h +++ b/content/base/public/nsContentPolicyUtils.h @@ -144,7 +144,7 @@ NS_CP_ContentTypeName(uint32_t contentType) * * Note: requestOrigin is scoped outside the PR_BEGIN_MACRO/PR_END_MACRO on * purpose */ -#define CHECK_PRINCIPAL \ +#define CHECK_PRINCIPAL_AND_DATA(action) \ nsCOMPtr requestOrigin; \ PR_BEGIN_MACRO \ if (originPrincipal) { \ @@ -153,12 +153,32 @@ NS_CP_ContentTypeName(uint32_t contentType) secMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); \ } \ if (secMan) { \ - bool isSystem; \ + bool isSystem; \ nsresult rv = secMan->IsSystemPrincipal(originPrincipal, \ &isSystem); \ NS_ENSURE_SUCCESS(rv, rv); \ if (isSystem) { \ *decision = nsIContentPolicy::ACCEPT; \ + nsCOMPtr n = do_QueryInterface(context); \ + if (!n) { \ + nsCOMPtr win = do_QueryInterface(context); \ + n = win ? win->GetExtantDoc() : nullptr; \ + } \ + if (n) { \ + nsIDocument* d = n->OwnerDoc(); \ + if (d->IsLoadedAsData() || d->IsBeingUsedAsImage() || \ + d->IsResourceDoc()) { \ + nsCOMPtr dataPolicy = \ + do_GetService( \ + "@mozilla.org/data-document-content-policy;1"); \ + if (dataPolicy) { \ + dataPolicy-> action (contentType, contentLocation, \ + requestOrigin, context, \ + mimeType, extra, \ + originPrincipal, decision); \ + } \ + } \ + } \ return NS_OK; \ } \ } \ @@ -187,7 +207,7 @@ NS_CheckContentLoadPolicy(uint32_t contentType, nsIContentPolicy *policyService = nullptr, nsIScriptSecurityManager* aSecMan = nullptr) { - CHECK_PRINCIPAL; + CHECK_PRINCIPAL_AND_DATA(ShouldLoad); if (policyService) { CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldLoad, policyService); } @@ -214,7 +234,7 @@ NS_CheckContentProcessPolicy(uint32_t contentType, nsIContentPolicy *policyService = nullptr, nsIScriptSecurityManager* aSecMan = nullptr) { - CHECK_PRINCIPAL; + CHECK_PRINCIPAL_AND_DATA(ShouldProcess); if (policyService) { CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldProcess, policyService); } diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index a8c45d36846e..73af8b9e30a8 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -46,7 +46,6 @@ class nsIDocumentObserver; class nsIDOMDocument; class nsIDOMDocumentFragment; class nsIDOMDocumentType; -class nsXMLProcessingInstruction; class nsIDOMElement; class nsIDOMEventTarget; class nsIDOMNodeList; @@ -74,6 +73,7 @@ class nsStyleSet; class nsTextNode; class nsWindowSizes; class nsSmallVoidArray; +class nsDOMCaretPosition; namespace mozilla { class ErrorResult; @@ -84,12 +84,14 @@ class ImageLoader; } // namespace css namespace dom { +class CDATASection; class Comment; class DocumentFragment; class DocumentType; class DOMImplementation; class Element; class Link; +class ProcessingInstruction; class UndoManager; template class Sequence; } // namespace dom @@ -1825,7 +1827,7 @@ public: mozilla::ErrorResult& rv) const; already_AddRefed CreateComment(const nsAString& aData, mozilla::ErrorResult& rv) const; - already_AddRefed + already_AddRefed CreateProcessingInstruction(const nsAString& target, const nsAString& data, mozilla::ErrorResult& rv) const; already_AddRefed @@ -1842,7 +1844,7 @@ public: nsIDOMNodeFilter* aFilter, mozilla::ErrorResult& rv) const; // Deprecated WebIDL bits - already_AddRefed + already_AddRefed CreateCDATASection(const nsAString& aData, mozilla::ErrorResult& rv); already_AddRefed CreateAttribute(const nsAString& aName, mozilla::ErrorResult& rv); @@ -1916,6 +1918,19 @@ public: virtual nsIDOMDOMStringList* StyleSheetSets() = 0; virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0; Element* ElementFromPoint(float aX, float aY); + + /** + * Retrieve the location of the caret position (DOM node and character + * offset within that node), given a point. + * + * @param aX Horizontal point at which to determine the caret position, in + * page coordinates. + * @param aY Vertical point at which to determine the caret position, in + * page coordinates. + */ + already_AddRefed + CaretPositionFromPoint(float aX, float aY); + // QuerySelector and QuerySelectorAll already defined on nsINode nsINodeList* GetAnonymousNodes(Element& aElement); Element* GetAnonymousElementByAttribute(Element& aElement, diff --git a/content/base/public/nsIMessageManager.idl b/content/base/public/nsIMessageManager.idl index 766f8aacedf7..fc8cb671d26f 100644 --- a/content/base/public/nsIMessageManager.idl +++ b/content/base/public/nsIMessageManager.idl @@ -336,8 +336,8 @@ interface nsIFrameScriptLoader : nsISupports void removeDelayedFrameScript(in AString aURL); }; -[scriptable, builtinclass, uuid(5f552699-01a2-4f17-833b-ddb3fa0d98b2)] -interface nsIPermissionChecker : nsISupports +[scriptable, builtinclass, uuid(e2ccdade-4c16-11e2-9ae0-23151c6d6e1d)] +interface nsIProcessChecker : nsISupports { /** @@ -361,4 +361,25 @@ interface nsIPermissionChecker : nsISupports */ boolean assertPermission(in DOMString aPermission); + /** + * Return true iff the "remote" process has |aManifestURL|. This is + * intended to be used by JS implementations of cross-process DOM + * APIs, like so + * + * recvFooRequest: function(message) { + * if (!message.target.assertContainApp("foo")) { + * return false; + * } + * // service foo request + * + * This interface only returns meaningful data when our content is + * in a separate process. If it shares the same OS process as us, + * then applying this manifest URL check doesn't add any security, + * though it doesn't hurt anything either. + * + * Note: If the remote content process does *not* contain |aManifestURL|, + * it will be killed as a precaution. + */ + boolean assertContainApp(in DOMString aManifestURL); + }; diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index 4b7772a05bfd..c59d8d31e2b5 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -1319,6 +1319,11 @@ private: NodeHasDirAuto, // Set if a node in the node's parent chain has dir=auto. NodeAncestorHasDirAuto, + // Set if the element is in the scope of a scoped style sheet; this flag is + // only accurate for elements bounds to a document + ElementIsInStyleScope, + // Set if the element is a scoped style sheet root + ElementIsScopedStyleRoot, // Guard value BooleanFlagCount }; @@ -1435,6 +1440,24 @@ public: bool NodeOrAncestorHasDirAuto() const { return HasDirAuto() || AncestorHasDirAuto(); } + + void SetIsElementInStyleScope(bool aValue) { + MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node"); + SetBoolFlag(ElementIsInStyleScope, aValue); + } + void SetIsElementInStyleScope() { + MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node"); + SetBoolFlag(ElementIsInStyleScope); + } + void ClearIsElementInStyleScope() { + MOZ_ASSERT(IsElement(), "ClearIsInStyleScope on a non-Element node"); + ClearBoolFlag(ElementIsInStyleScope); + } + bool IsElementInStyleScope() const { return GetBoolFlag(ElementIsInStyleScope); } + + void SetIsScopedStyleRoot() { SetBoolFlag(ElementIsScopedStyleRoot); } + void ClearIsScopedStyleRoot() { ClearBoolFlag(ElementIsScopedStyleRoot); } + bool IsScopedStyleRoot() { return GetBoolFlag(ElementIsScopedStyleRoot); } protected: void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); } void SetInDocument() { SetBoolFlag(IsInDocument); } @@ -1455,7 +1478,7 @@ protected: bool HasLockedStyleStates() const { return GetBoolFlag(ElementHasLockedStyleStates); } - void SetSubtreeRootPointer(nsINode* aSubtreeRoot) + void SetSubtreeRootPointer(nsINode* aSubtreeRoot) { NS_ASSERTION(aSubtreeRoot, "aSubtreeRoot can never be null!"); NS_ASSERTION(!(IsNodeOfType(eCONTENT) && IsInDoc()), "Shouldn't be here!"); diff --git a/content/base/src/Element.cpp b/content/base/src/Element.cpp index c179df81afd9..2871ee368886 100644 --- a/content/base/src/Element.cpp +++ b/content/base/src/Element.cpp @@ -1155,6 +1155,9 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent, NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES | // And the restyle bits ELEMENT_ALL_RESTYLE_FLAGS); + + // Propagate scoped style sheet tracking bit. + SetIsElementInStyleScope(mParent->IsElementInStyleScope()); } else { // If we're not in the doc, update our subtree pointer. SetSubtreeRootPointer(aParent->SubtreeRoot()); @@ -3595,3 +3598,13 @@ Element::GetEditorInternal() nsCOMPtr textCtrl = do_QueryInterface(this); return textCtrl ? textCtrl->GetTextEditor() : nullptr; } + +nsresult +Element::SetBoolAttr(nsIAtom* aAttr, bool aValue) +{ + if (aValue) { + return SetAttr(kNameSpaceID_None, aAttr, EmptyString(), true); + } + + return UnsetAttr(kNameSpaceID_None, aAttr, true); +} diff --git a/content/base/src/nsCCUncollectableMarker.cpp b/content/base/src/nsCCUncollectableMarker.cpp index d26608e7549d..3041f991ab6f 100644 --- a/content/base/src/nsCCUncollectableMarker.cpp +++ b/content/base/src/nsCCUncollectableMarker.cpp @@ -368,12 +368,16 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic, MarkDocShell(shellTreeNode, cleanupJS, prepareForCC); } #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING - appShell->GetHiddenPrivateWindow(getter_AddRefs(hw)); - if (hw) { - nsCOMPtr shell; - hw->GetDocShell(getter_AddRefs(shell)); - nsCOMPtr shellTreeNode = do_QueryInterface(shell); - MarkDocShell(shellTreeNode, cleanupJS, prepareForCC); + bool hasHiddenPrivateWindow = false; + appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow); + if (hasHiddenPrivateWindow) { + appShell->GetHiddenPrivateWindow(getter_AddRefs(hw)); + if (hw) { + nsCOMPtr shell; + hw->GetDocShell(getter_AddRefs(shell)); + nsCOMPtr shellTreeNode = do_QueryInterface(shell); + MarkDocShell(shellTreeNode, cleanupJS, prepareForCC); + } } #endif } diff --git a/content/base/src/nsDataDocumentContentPolicy.cpp b/content/base/src/nsDataDocumentContentPolicy.cpp index dcf420bc27df..843b3430aaec 100644 --- a/content/base/src/nsDataDocumentContentPolicy.cpp +++ b/content/base/src/nsDataDocumentContentPolicy.cpp @@ -30,6 +30,9 @@ HasFlags(nsIURI* aURI, uint32_t aURIFlags) return NS_SUCCEEDED(rv) && hasFlags; } +// If you change DataDocumentContentPolicy, make sure to check that +// CHECK_PRINCIPAL_AND_DATA in nsContentPolicyUtils is still valid. +// nsContentPolicyUtils may not pass all the parameters to ShouldLoad. NS_IMETHODIMP nsDataDocumentContentPolicy::ShouldLoad(uint32_t aContentType, nsIURI *aContentLocation, @@ -123,6 +126,10 @@ nsDataDocumentContentPolicy::ShouldLoad(uint32_t aContentType, *aDecision = nsIContentPolicy::REJECT_TYPE; } + // If you add more restrictions here, make sure to check that + // CHECK_PRINCIPAL_AND_DATA in nsContentPolicyUtils is still valid. + // nsContentPolicyUtils may not pass all the parameters to ShouldLoad + return NS_OK; } diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 3cf1e8bd782f..56438fa7c0db 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -45,8 +45,8 @@ #include "nsIDOMDocumentXBL.h" #include "mozilla/dom/Element.h" #include "nsGenericHTMLElement.h" -#include "nsIDOMCDATASection.h" -#include "nsIDOMProcessingInstruction.h" +#include "mozilla/dom/CDATASection.h" +#include "mozilla/dom/ProcessingInstruction.h" #include "nsDOMString.h" #include "nsNodeUtils.h" #include "nsLayoutUtils.h" // for GetFrameForPoint @@ -170,7 +170,6 @@ #include "mozilla/dom/DOMImplementation.h" #include "mozilla/dom/Comment.h" #include "nsTextNode.h" -#include "nsXMLProcessingInstruction.h" #include "mozilla/dom/Link.h" #include "nsXULAppAPI.h" #include "nsDOMTouchEvent.h" @@ -2027,6 +2026,25 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup, } } +void +nsDocument::RemoveDocStyleSheetsFromStyleSets() +{ + // The stylesheets should forget us + int32_t indx = mStyleSheets.Count(); + while (--indx >= 0) { + nsIStyleSheet* sheet = mStyleSheets[indx]; + sheet->SetOwningDocument(nullptr); + + if (sheet->IsApplicable()) { + nsCOMPtr shell = GetShell(); + if (shell) { + shell->StyleSet()->RemoveDocStyleSheet(sheet); + } + } + // XXX Tell observers? + } +} + void nsDocument::RemoveStyleSheetsFromStyleSets(nsCOMArray& aSheets, nsStyleSet::sheetType aType) { @@ -2054,7 +2072,7 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) NS_PRECONDITION(aURI, "Null URI passed to ResetStylesheetsToURI"); mozAutoDocUpdate upd(this, UPDATE_STYLE, true); - RemoveStyleSheetsFromStyleSets(mStyleSheets, nsStyleSet::eDocSheet); + RemoveDocStyleSheetsFromStyleSets(); RemoveStyleSheetsFromStyleSets(mCatalogSheets, nsStyleSet::eAgentSheet); RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], nsStyleSet::eAgentSheet); RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], nsStyleSet::eUserSheet); @@ -3503,7 +3521,7 @@ nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet) { nsCOMPtr shell = GetShell(); if (shell) { - shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet); + shell->StyleSet()->RemoveDocStyleSheet(aSheet); } } @@ -4610,7 +4628,7 @@ nsDocument::CreateCDATASection(const nsAString& aData, return rv.ErrorCode(); } -already_AddRefed +already_AddRefed nsIDocument::CreateCDATASection(const nsAString& aData, ErrorResult& rv) { @@ -4635,8 +4653,7 @@ nsIDocument::CreateCDATASection(const nsAString& aData, // Don't notify; this node is still being created. content->SetText(aData, false); - nsCOMPtr section = do_QueryInterface(content); - return section.forget(); + return static_cast(content.forget().get()); } NS_IMETHODIMP @@ -4649,7 +4666,7 @@ nsDocument::CreateProcessingInstruction(const nsAString& aTarget, return rv.ErrorCode(); } -already_AddRefed +already_AddRefed nsIDocument::CreateProcessingInstruction(const nsAString& aTarget, const nsAString& aData, mozilla::ErrorResult& rv) const @@ -4673,7 +4690,7 @@ nsIDocument::CreateProcessingInstruction(const nsAString& aTarget, return nullptr; } - return static_cast(content.forget().get()); + return static_cast(content.forget().get()); } NS_IMETHODIMP @@ -8853,32 +8870,29 @@ ResetFullScreen(nsIDocument* aDocument, void* aData) return true; } -NS_IMETHODIMP -nsDocument::CaretPositionFromPoint(float aX, float aY, nsISupports** aCaretPos) +already_AddRefed +nsIDocument::CaretPositionFromPoint(float aX, float aY) { - NS_ENSURE_ARG_POINTER(aCaretPos); - *aCaretPos = nullptr; - nscoord x = nsPresContext::CSSPixelsToAppUnits(aX); nscoord y = nsPresContext::CSSPixelsToAppUnits(aY); nsPoint pt(x, y); nsIPresShell *ps = GetShell(); if (!ps) { - return NS_OK; + return nullptr; } nsIFrame *rootFrame = ps->GetRootFrame(); // XUL docs, unlike HTML, have no frame tree until everything's done loading if (!rootFrame) { - return NS_OK; // return null to premature XUL callers as a reminder to wait + return nullptr; } nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, true, false); if (!ptFrame) { - return NS_OK; + return nullptr; } // GetContentOffsetsFromPoint requires frame-relative coordinates, so we need @@ -8906,8 +8920,15 @@ nsDocument::CaretPositionFromPoint(float aX, float aY, nsISupports** aCaretPos) } } - *aCaretPos = new nsDOMCaretPosition(node, offset); - NS_ADDREF(*aCaretPos); + nsRefPtr aCaretPos = new nsDOMCaretPosition(node, offset); + return aCaretPos.forget(); +} + +NS_IMETHODIMP +nsDocument::CaretPositionFromPoint(float aX, float aY, nsISupports** aCaretPos) +{ + NS_ENSURE_ARG_POINTER(aCaretPos); + *aCaretPos = nsIDocument::CaretPositionFromPoint(aX, aY).get(); return NS_OK; } diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 9da0d22572f2..4185f9f224f0 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -1080,6 +1080,7 @@ protected: nsCompatibility aCompatMode, nsIPresShell** aInstancePtrResult); + void RemoveDocStyleSheetsFromStyleSets(); void RemoveStyleSheetsFromStyleSets(nsCOMArray& aSheets, nsStyleSet::sheetType aType); nsresult ResetStylesheetsToURI(nsIURI* aURI); diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 084e9c957414..b5cc1f171b37 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -77,7 +77,7 @@ #include "Layers.h" -#include "AppProcessPermissions.h" +#include "AppProcessChecker.h" #include "ContentParent.h" #include "TabParent.h" #include "mozilla/GuardObjects.h" @@ -2314,6 +2314,13 @@ nsFrameLoader::CheckPermission(const nsAString& aPermission) NS_ConvertUTF16toUTF8(aPermission).get()); } +bool +nsFrameLoader::CheckManifestURL(const nsAString& aManifestURL) +{ + return AssertAppProcessManifestURL(GetRemoteBrowser(), + NS_ConvertUTF16toUTF8(aManifestURL).get()); +} + NS_IMETHODIMP nsFrameLoader::GetMessageManager(nsIMessageSender** aManager) { @@ -2550,6 +2557,12 @@ nsFrameLoader::AttributeChanged(nsIDocument* aDocument, void nsFrameLoader::ResetPermissionManagerStatus() { + // The resetting of the permissions status can run only + // in the main process. + if (XRE_GetProcessType() == GeckoProcessType_Content) { + return; + } + // Finding the new app Id: // . first we check if the owner is an app frame // . second, we check if the owner is a browser frame diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h index b52a1899dc8e..f6883f121426 100644 --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -189,7 +189,7 @@ public: virtual bool DoSendAsyncMessage(const nsAString& aMessage, const mozilla::dom::StructuredCloneData& aData); virtual bool CheckPermission(const nsAString& aPermission); - + virtual bool CheckManifestURL(const nsAString& aManifestURL); /** * Called from the layout frame associated with this frame loader; diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 4023f9508c06..e2fd1d62c8dd 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -7,7 +7,7 @@ #include "nsFrameMessageManager.h" -#include "AppProcessPermissions.h" +#include "AppProcessChecker.h" #include "ContentChild.h" #include "ContentParent.h" #include "nsContentUtils.h" @@ -107,8 +107,8 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameMessageManager) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFrameScriptLoader, mChrome && !mIsProcessManager) - /* Message senders in the chrome process support nsIPermissionChecker. */ - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPermissionChecker, + /* Message senders in the chrome process support nsIProcessChecker. */ + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIProcessChecker, mChrome && !mIsBroadcaster) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageBroadcaster, @@ -423,12 +423,14 @@ nsFrameMessageManager::Atob(const nsAString& aAsciiString, return NS_OK; } -// nsIPermissionChecker +// nsIProcessChecker -NS_IMETHODIMP -nsFrameMessageManager::AssertPermission(const nsAString& aPermission, bool* aHasPermission) +nsresult +nsFrameMessageManager::AssertProcessInternal(ProcessCheckerType aType, + const nsAString& aCapability, + bool* aValid) { - *aHasPermission = false; + *aValid = false; // This API is only supported for message senders in the chrome process. if (!mChrome || mIsBroadcaster) { @@ -437,10 +439,37 @@ nsFrameMessageManager::AssertPermission(const nsAString& aPermission, bool* aHas if (!mCallback) { return NS_ERROR_NOT_AVAILABLE; } - *aHasPermission = mCallback->CheckPermission(aPermission); + switch (aType) { + case PROCESS_CHECKER_PERMISSION: + *aValid = mCallback->CheckPermission(aCapability); + break; + case PROCESS_CHECKER_MANIFEST_URL: + *aValid = mCallback->CheckManifestURL(aCapability); + break; + default: + break; + } return NS_OK; } +NS_IMETHODIMP +nsFrameMessageManager::AssertPermission(const nsAString& aPermission, + bool* aHasPermission) +{ + return AssertProcessInternal(PROCESS_CHECKER_PERMISSION, + aPermission, + aHasPermission); +} + +NS_IMETHODIMP +nsFrameMessageManager::AssertContainApp(const nsAString& aManifestURL, + bool* aHasManifestURL) +{ + return AssertProcessInternal(PROCESS_CHECKER_MANIFEST_URL, + aManifestURL, + aHasManifestURL); +} + class MMListenerRemover { public: @@ -1100,6 +1129,11 @@ public: return true; } + bool CheckManifestURL(const nsAString& aManifestURL) + { + // In a single-process scenario, the child always has all capabilities. + return true; + } }; diff --git a/content/base/src/nsFrameMessageManager.h b/content/base/src/nsFrameMessageManager.h index ae0825b3ed86..6ca9124372c4 100644 --- a/content/base/src/nsFrameMessageManager.h +++ b/content/base/src/nsFrameMessageManager.h @@ -66,6 +66,11 @@ public: { return false; } + + virtual bool CheckManifestURL(const nsAString& aManifestURL) + { + return false; + } }; } // namespace ipc @@ -86,7 +91,7 @@ struct nsMessageListenerInfo class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager, public nsIMessageBroadcaster, public nsIFrameScriptLoader, - public nsIPermissionChecker + public nsIProcessChecker { typedef mozilla::dom::StructuredCloneData StructuredCloneData; public: @@ -152,7 +157,7 @@ public: NS_DECL_NSISYNCMESSAGESENDER NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER NS_DECL_NSIFRAMESCRIPTLOADER - NS_DECL_NSIPERMISSIONCHECKER + NS_DECL_NSIPROCESSCHECKER static nsFrameMessageManager* NewProcessMessageManager(mozilla::dom::ContentParent* aProcess); @@ -226,6 +231,14 @@ public: static nsFrameMessageManager* sChildProcessManager; static nsFrameMessageManager* sSameProcessParentManager; static nsTArray >* sPendingSameProcessAsyncMessages; +private: + enum ProcessCheckerType { + PROCESS_CHECKER_PERMISSION, + PROCESS_CHECKER_MANIFEST_URL + }; + nsresult AssertProcessInternal(ProcessCheckerType aType, + const nsAString& aCapability, + bool* aValid); }; void diff --git a/content/base/src/nsStyleLinkElement.cpp b/content/base/src/nsStyleLinkElement.cpp index d7294adc26d4..48e9ed03a0eb 100644 --- a/content/base/src/nsStyleLinkElement.cpp +++ b/content/base/src/nsStyleLinkElement.cpp @@ -12,9 +12,10 @@ #include "nsStyleLinkElement.h" -#include "nsIContent.h" #include "mozilla/css/Loader.h" +#include "mozilla/dom/Element.h" #include "nsCSSStyleSheet.h" +#include "nsIContent.h" #include "nsIDocument.h" #include "nsIDOMComment.h" #include "nsIDOMNode.h" @@ -26,6 +27,9 @@ #include "nsUnicharInputStream.h" #include "nsContentUtils.h" +using namespace mozilla; +using namespace mozilla::dom; + nsStyleLinkElement::nsStyleLinkElement() : mDontLoadStyle(false) , mUpdatesEnabled(true) @@ -203,6 +207,87 @@ nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument, aForceUpdate); } +static bool +IsScopedStyleElement(nsIContent* aContent) +{ + // This is quicker than, say, QIing aContent to nsStyleLinkElement + // and then calling its virtual GetStyleSheetInfo method to find out + // if it is scoped. + return aContent->IsHTML(nsGkAtoms::style) && + aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scoped); +} + +static void +SetIsElementInStyleScopeFlagOnSubtree(Element* aElement) +{ + if (aElement->IsElementInStyleScope()) { + return; + } + + aElement->SetIsElementInStyleScope(); + + nsIContent* n = aElement->GetNextNode(aElement); + while (n) { + if (n->IsElementInStyleScope()) { + n = n->GetNextNonChildNode(aElement); + } else { + if (n->IsElement()) { + n->SetIsElementInStyleScope(); + } + n = n->GetNextNode(aElement); + } + } +} + +static bool +HasScopedStyleSheetChild(nsIContent* aContent) +{ + for (nsIContent* n = aContent->GetFirstChild(); n; n = n->GetNextSibling()) { + if (IsScopedStyleElement(n)) { + return true; + } + } + return false; +} + +// Called when aElement has had a + + + + +
+dddddd dddddd dddddd +
+
+
+
+ + diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index 305e7308aec5..1dcf3956e16c 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -725,6 +725,7 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, ClearContainer(mContainer); mContainer->SetPreScale(1.0f, 1.0f); mContainer->SetPostScale(1.0f, 1.0f); + mContainer->SetInheritedScale(1.0f, 1.0f); } ContainerLayer* shadowRoot = GetRootLayer(); diff --git a/layout/mathml/nsMathMLContainerFrame.cpp b/layout/mathml/nsMathMLContainerFrame.cpp index 6ada551e9cd9..8eaa7a2946ec 100644 --- a/layout/mathml/nsMathMLContainerFrame.cpp +++ b/layout/mathml/nsMathMLContainerFrame.cpp @@ -1522,7 +1522,7 @@ nsMathMLContainerFrame::TransmitAutomaticDataForMrowLikeElement() nsresult nsMathMLContainerFrame::ReportErrorToConsole(const char* errorMsgId, const PRUnichar** aParams, - PRUint32 aParamCount) + uint32_t aParamCount) { return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, "MathML", mContent->OwnerDoc(), diff --git a/layout/mathml/nsMathMLContainerFrame.h b/layout/mathml/nsMathMLContainerFrame.h index f9bb697492e0..b3d0b027eab3 100644 --- a/layout/mathml/nsMathMLContainerFrame.h +++ b/layout/mathml/nsMathMLContainerFrame.h @@ -267,7 +267,7 @@ public: nsresult ReportErrorToConsole(const char* aErrorMsgId, const PRUnichar** aParams = nullptr, - PRUint32 aParamCount = 0); + uint32_t aParamCount = 0); // helper method to reflow a child frame. We are inline frames, and we don't // know our positions until reflow is finished. That's why we ask the diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp index 02f7bbb10932..f3822bfd0d00 100644 --- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -411,6 +411,7 @@ nsPrintEngine::CommonPrint(bool aIsPrintPreview, nsIPrintSettings* aPrintSettings, nsIWebProgressListener* aWebProgressListener, nsIDOMDocument* aDoc) { + nsRefPtr kungfuDeathGrip = this; nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings, aWebProgressListener, aDoc); if (NS_FAILED(rv)) { diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list index fa8472a446ce..7a9061fe752e 100644 --- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -238,6 +238,9 @@ include position-dynamic-changes/reftest.list include printing/reftest.list include pagination/reftest.list +# + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-002-ref.html b/layout/reftests/scoped-style/scoped-style-002-ref.html new file mode 100644 index 000000000000..9b30be20fbc5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-002-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-002.html b/layout/reftests/scoped-style/scoped-style-002.html new file mode 100644 index 000000000000..0acaa4dfb547 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-002.html @@ -0,0 +1,14 @@ + + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-003-ref.html b/layout/reftests/scoped-style/scoped-style-003-ref.html new file mode 100644 index 000000000000..9b30be20fbc5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-003-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-003.html b/layout/reftests/scoped-style/scoped-style-003.html new file mode 100644 index 000000000000..b1db050db91b --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-003.html @@ -0,0 +1,14 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-004-ref.html b/layout/reftests/scoped-style/scoped-style-004-ref.html new file mode 100644 index 000000000000..9b30be20fbc5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-004-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-004.html b/layout/reftests/scoped-style/scoped-style-004.html new file mode 100644 index 000000000000..61f05c18a2f2 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-004.html @@ -0,0 +1,14 @@ + + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-005-ref.html b/layout/reftests/scoped-style/scoped-style-005-ref.html new file mode 100644 index 000000000000..9b30be20fbc5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-005-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-005.html b/layout/reftests/scoped-style/scoped-style-005.html new file mode 100644 index 000000000000..b555dfd3c35c --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-005.html @@ -0,0 +1,14 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-006-ref.html b/layout/reftests/scoped-style/scoped-style-006-ref.html new file mode 100644 index 000000000000..9b30be20fbc5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-006-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-006.html b/layout/reftests/scoped-style/scoped-style-006.html new file mode 100644 index 000000000000..9789c510ebed --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-006.html @@ -0,0 +1,14 @@ + + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-007-ref.html b/layout/reftests/scoped-style/scoped-style-007-ref.html new file mode 100644 index 000000000000..9b30be20fbc5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-007-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-007.html b/layout/reftests/scoped-style/scoped-style-007.html new file mode 100644 index 000000000000..5f3185cea386 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-007.html @@ -0,0 +1,14 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-008-ref.html b/layout/reftests/scoped-style/scoped-style-008-ref.html new file mode 100644 index 000000000000..6e7f33bf4afa --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-008-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-008.html b/layout/reftests/scoped-style/scoped-style-008.html new file mode 100644 index 000000000000..99fa4300e1fd --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-008.html @@ -0,0 +1,11 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-009-ref.html b/layout/reftests/scoped-style/scoped-style-009-ref.html new file mode 100644 index 000000000000..6e7f33bf4afa --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-009-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-009.html b/layout/reftests/scoped-style/scoped-style-009.html new file mode 100644 index 000000000000..48528c368e5a --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-009.html @@ -0,0 +1,11 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-010-ref.html b/layout/reftests/scoped-style/scoped-style-010-ref.html new file mode 100644 index 000000000000..4f6e81bc5350 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-010-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-010.html b/layout/reftests/scoped-style/scoped-style-010.html new file mode 100644 index 000000000000..d996503457f8 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-010.html @@ -0,0 +1,17 @@ + + +

First

+

+ + + Second + +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-011-ref.html b/layout/reftests/scoped-style/scoped-style-011-ref.html new file mode 100644 index 000000000000..57f7c5377b6e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-011-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-011.html b/layout/reftests/scoped-style/scoped-style-011.html new file mode 100644 index 000000000000..778a9dbd784e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-011.html @@ -0,0 +1,13 @@ + + +

First

+
+ +

+ Second +

+
+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-012-ref.html b/layout/reftests/scoped-style/scoped-style-012-ref.html new file mode 100644 index 000000000000..f4bc63d0943a --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-012-ref.html @@ -0,0 +1,8 @@ + + +
First
+
+ Second +
Third
+
+ diff --git a/layout/reftests/scoped-style/scoped-style-012.html b/layout/reftests/scoped-style/scoped-style-012.html new file mode 100644 index 000000000000..5803e9dc49f0 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-012.html @@ -0,0 +1,16 @@ + + +
First
+
+ + Second +
+ + Third +
+
+ diff --git a/layout/reftests/scoped-style/scoped-style-013-ref.html b/layout/reftests/scoped-style/scoped-style-013-ref.html new file mode 100644 index 000000000000..7a2f780e07f4 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-013-ref.html @@ -0,0 +1,9 @@ + + +
+

First

+
+
+

Second

+
+ diff --git a/layout/reftests/scoped-style/scoped-style-013.html b/layout/reftests/scoped-style/scoped-style-013.html new file mode 100644 index 000000000000..7b9f97f51af5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-013.html @@ -0,0 +1,12 @@ + + +
+

First

+
+
+ +

Second

+
+ diff --git a/layout/reftests/scoped-style/scoped-style-014-ref.html b/layout/reftests/scoped-style/scoped-style-014-ref.html new file mode 100644 index 000000000000..54cab8795a13 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-014-ref.html @@ -0,0 +1,15 @@ + + +
+

First

+
+
+
+
+
+

Second

+
+
+
+
+ diff --git a/layout/reftests/scoped-style/scoped-style-014.html b/layout/reftests/scoped-style/scoped-style-014.html new file mode 100644 index 000000000000..9c2fb88164e1 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-014.html @@ -0,0 +1,18 @@ + + +
+

First

+
+
+ +
+
+
+

Second

+
+
+
+
+ diff --git a/layout/reftests/scoped-style/scoped-style-015-ref.html b/layout/reftests/scoped-style/scoped-style-015-ref.html new file mode 100644 index 000000000000..109d197982b6 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-015-ref.html @@ -0,0 +1,8 @@ + + +

First

+
+

Second

+
+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-015.html b/layout/reftests/scoped-style/scoped-style-015.html new file mode 100644 index 000000000000..8948f58f113a --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-015.html @@ -0,0 +1,11 @@ + + +

First

+
+ +

Second

+
+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-016-ref.html b/layout/reftests/scoped-style/scoped-style-016-ref.html new file mode 100644 index 000000000000..28f64c59a529 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-016-ref.html @@ -0,0 +1,8 @@ + + +

First

+
+

Second

+

Third

+
+ diff --git a/layout/reftests/scoped-style/scoped-style-016.html b/layout/reftests/scoped-style/scoped-style-016.html new file mode 100644 index 000000000000..658140c4e56d --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-016.html @@ -0,0 +1,11 @@ + + +

First

+
+ +

Second

+

Third

+
+ diff --git a/layout/reftests/scoped-style/scoped-style-017-ref.html b/layout/reftests/scoped-style/scoped-style-017-ref.html new file mode 100644 index 000000000000..902861abb320 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-017-ref.html @@ -0,0 +1,8 @@ + + +

First

+
+

Second

+

Third

+
+ diff --git a/layout/reftests/scoped-style/scoped-style-017.html b/layout/reftests/scoped-style/scoped-style-017.html new file mode 100644 index 000000000000..eb35174dbc8a --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-017.html @@ -0,0 +1,16 @@ + + +

First

+
+ +

+ + Second +

+

Third

+
+ diff --git a/layout/reftests/scoped-style/scoped-style-018-ref.html b/layout/reftests/scoped-style/scoped-style-018-ref.html new file mode 100644 index 000000000000..ea87d4a7abc5 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-018-ref.html @@ -0,0 +1,8 @@ + + +
+
+

This should be green.

+
+
+ diff --git a/layout/reftests/scoped-style/scoped-style-018.html b/layout/reftests/scoped-style/scoped-style-018.html new file mode 100644 index 000000000000..f51d3b30c83c --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-018.html @@ -0,0 +1,14 @@ + + +
+
+

This should be green.

+ +
+ +
+ diff --git a/layout/reftests/scoped-style/scoped-style-019-ref.svg b/layout/reftests/scoped-style/scoped-style-019-ref.svg new file mode 100644 index 000000000000..4f729794739e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-019-ref.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-019.svg b/layout/reftests/scoped-style/scoped-style-019.svg new file mode 100644 index 000000000000..161ebc7e79f3 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-019.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-020-ref.html b/layout/reftests/scoped-style/scoped-style-020-ref.html new file mode 100644 index 000000000000..ef5bf0cb05bb --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-020-ref.html @@ -0,0 +1,4 @@ + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-020.html b/layout/reftests/scoped-style/scoped-style-020.html new file mode 100644 index 000000000000..818e8da05796 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-020.html @@ -0,0 +1,9 @@ + + +

+ + Hello +

+ diff --git a/layout/reftests/scoped-style/scoped-style-021-ref.html b/layout/reftests/scoped-style/scoped-style-021-ref.html new file mode 100644 index 000000000000..ef5bf0cb05bb --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-021-ref.html @@ -0,0 +1,4 @@ + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-021.html b/layout/reftests/scoped-style/scoped-style-021.html new file mode 100644 index 000000000000..406bd9e280bc --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-021.html @@ -0,0 +1,7 @@ + + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-charset-ref.html b/layout/reftests/scoped-style/scoped-style-charset-ref.html new file mode 100644 index 000000000000..f1d8460a1b97 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-charset-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-charset.html b/layout/reftests/scoped-style/scoped-style-charset.html new file mode 100644 index 000000000000..921148692c0d --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-charset.html @@ -0,0 +1,12 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-document-ref.html b/layout/reftests/scoped-style/scoped-style-document-ref.html new file mode 100644 index 000000000000..f1d8460a1b97 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-document-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-document.html b/layout/reftests/scoped-style/scoped-style-document.html new file mode 100644 index 000000000000..cb02becd645e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-document.html @@ -0,0 +1,13 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-001-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-001-ref.html new file mode 100644 index 000000000000..3f763ef4beed --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-001-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-001.html b/layout/reftests/scoped-style/scoped-style-dynamic-001.html new file mode 100644 index 000000000000..08251ea81953 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-001.html @@ -0,0 +1,15 @@ + + +

First

+

Second

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-002-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-002-ref.html new file mode 100644 index 000000000000..4f6e81bc5350 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-002-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-002.html b/layout/reftests/scoped-style/scoped-style-dynamic-002.html new file mode 100644 index 000000000000..6d96511a134e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-002.html @@ -0,0 +1,20 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-003-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-003-ref.html new file mode 100644 index 000000000000..3f763ef4beed --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-003-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-003.html b/layout/reftests/scoped-style/scoped-style-dynamic-003.html new file mode 100644 index 000000000000..048688cdf4b2 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-003.html @@ -0,0 +1,20 @@ + + +

First

+

+ + + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-004-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-004-ref.html new file mode 100644 index 000000000000..c0b77f52a3ba --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-004-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-004.html b/layout/reftests/scoped-style/scoped-style-dynamic-004.html new file mode 100644 index 000000000000..de11bf92813a --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-004.html @@ -0,0 +1,20 @@ + + +

First

+

+ + + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-005-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-005-ref.html new file mode 100644 index 000000000000..9993e6f3125b --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-005-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-005.html b/layout/reftests/scoped-style/scoped-style-dynamic-005.html new file mode 100644 index 000000000000..38e8b56d2fd3 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-005.html @@ -0,0 +1,17 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-006-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-006-ref.html new file mode 100644 index 000000000000..3f763ef4beed --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-006-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-006.html b/layout/reftests/scoped-style/scoped-style-dynamic-006.html new file mode 100644 index 000000000000..8947b08aa830 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-006.html @@ -0,0 +1,17 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-007-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-007-ref.html new file mode 100644 index 000000000000..52e5060f8bea --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-007-ref.html @@ -0,0 +1,6 @@ + + +

First

+
+

Second

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-007.html b/layout/reftests/scoped-style/scoped-style-dynamic-007.html new file mode 100644 index 000000000000..6403cc5296e9 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-007.html @@ -0,0 +1,16 @@ + + +

First

+
+ +

Second

+
+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-008-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-008-ref.html new file mode 100644 index 000000000000..9ce53f8911bd --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-008-ref.html @@ -0,0 +1,7 @@ + + +
+

First

+
+

Second

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-008.html b/layout/reftests/scoped-style/scoped-style-dynamic-008.html new file mode 100644 index 000000000000..a19ebeb82885 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-008.html @@ -0,0 +1,17 @@ + + +

First

+
+ +
+

Second

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-009-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-009-ref.html new file mode 100644 index 000000000000..3f763ef4beed --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-009-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-009.html b/layout/reftests/scoped-style/scoped-style-dynamic-009.html new file mode 100644 index 000000000000..726cf672fc0d --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-009.html @@ -0,0 +1,17 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-010-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-010-ref.html new file mode 100644 index 000000000000..9993e6f3125b --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-010-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-010.html b/layout/reftests/scoped-style/scoped-style-dynamic-010.html new file mode 100644 index 000000000000..940cc717cb1a --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-010.html @@ -0,0 +1,17 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-011-ref.html b/layout/reftests/scoped-style/scoped-style-dynamic-011-ref.html new file mode 100644 index 000000000000..aa6dce1a4929 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-011-ref.html @@ -0,0 +1,5 @@ + + +

First

+

Second

+ diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-011.html b/layout/reftests/scoped-style/scoped-style-dynamic-011.html new file mode 100644 index 000000000000..e5223e19db75 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-011.html @@ -0,0 +1,17 @@ + + +

+ + First +

+

Second

+ + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-012-ref.svg b/layout/reftests/scoped-style/scoped-style-dynamic-012-ref.svg new file mode 100644 index 000000000000..5a1db3c2c09e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-012-ref.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-012.svg b/layout/reftests/scoped-style/scoped-style-dynamic-012.svg new file mode 100644 index 000000000000..1ecfb0e4ca93 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-012.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-013-ref.svg b/layout/reftests/scoped-style/scoped-style-dynamic-013-ref.svg new file mode 100644 index 000000000000..4f729794739e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-013-ref.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-013.svg b/layout/reftests/scoped-style/scoped-style-dynamic-013.svg new file mode 100644 index 000000000000..fc5f00111ad1 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-013.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-014-ref.svg b/layout/reftests/scoped-style/scoped-style-dynamic-014-ref.svg new file mode 100644 index 000000000000..5a1db3c2c09e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-014-ref.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-014.svg b/layout/reftests/scoped-style/scoped-style-dynamic-014.svg new file mode 100644 index 000000000000..b19318ca4f6c --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-014.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-015-ref.svg b/layout/reftests/scoped-style/scoped-style-dynamic-015-ref.svg new file mode 100644 index 000000000000..4f729794739e --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-015-ref.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-dynamic-015.svg b/layout/reftests/scoped-style/scoped-style-dynamic-015.svg new file mode 100644 index 000000000000..f6d2c7a57c46 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-dynamic-015.svg @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/layout/reftests/scoped-style/scoped-style-font-face-ref.html b/layout/reftests/scoped-style/scoped-style-font-face-ref.html new file mode 100644 index 000000000000..a2943b30a699 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-font-face-ref.html @@ -0,0 +1,13 @@ + + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-font-face.html b/layout/reftests/scoped-style/scoped-style-font-face.html new file mode 100644 index 000000000000..0fe34db057f6 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-font-face.html @@ -0,0 +1,23 @@ + + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-import-ref.html b/layout/reftests/scoped-style/scoped-style-import-ref.html new file mode 100644 index 000000000000..f1d8460a1b97 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-import-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-import.html b/layout/reftests/scoped-style/scoped-style-import.html new file mode 100644 index 000000000000..414b4b157a9d --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-import.html @@ -0,0 +1,11 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-001-ref.html b/layout/reftests/scoped-style/scoped-style-important-001-ref.html new file mode 100644 index 000000000000..eadaf600dacc --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-001-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-001.html b/layout/reftests/scoped-style/scoped-style-important-001.html new file mode 100644 index 000000000000..1fd9f202e145 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-001.html @@ -0,0 +1,14 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-important-002-ref.html b/layout/reftests/scoped-style/scoped-style-important-002-ref.html new file mode 100644 index 000000000000..f1d8460a1b97 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-002-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-002.html b/layout/reftests/scoped-style/scoped-style-important-002.html new file mode 100644 index 000000000000..3e2d1526e165 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-002.html @@ -0,0 +1,11 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-003-ref.html b/layout/reftests/scoped-style/scoped-style-important-003-ref.html new file mode 100644 index 000000000000..9993e6f3125b --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-003-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-003.html b/layout/reftests/scoped-style/scoped-style-important-003.html new file mode 100644 index 000000000000..410867d491e0 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-003.html @@ -0,0 +1,14 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-important-004-ref.html b/layout/reftests/scoped-style/scoped-style-important-004-ref.html new file mode 100644 index 000000000000..9993e6f3125b --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-004-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-004.html b/layout/reftests/scoped-style/scoped-style-important-004.html new file mode 100644 index 000000000000..546a8748c130 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-004.html @@ -0,0 +1,14 @@ + + +

First

+

+ + Second +

+

Third

+ + diff --git a/layout/reftests/scoped-style/scoped-style-important-005-ref.html b/layout/reftests/scoped-style/scoped-style-important-005-ref.html new file mode 100644 index 000000000000..ef5bf0cb05bb --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-005-ref.html @@ -0,0 +1,4 @@ + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-005.html b/layout/reftests/scoped-style/scoped-style-important-005.html new file mode 100644 index 000000000000..de5b3bd6f2e3 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-005.html @@ -0,0 +1,7 @@ + + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-006-ref.html b/layout/reftests/scoped-style/scoped-style-important-006-ref.html new file mode 100644 index 000000000000..ef5bf0cb05bb --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-006-ref.html @@ -0,0 +1,4 @@ + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-006.html b/layout/reftests/scoped-style/scoped-style-important-006.html new file mode 100644 index 000000000000..352bd6c9b7f1 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-006.html @@ -0,0 +1,9 @@ + + +

+ + Hello +

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-007-ref.html b/layout/reftests/scoped-style/scoped-style-important-007-ref.html new file mode 100644 index 000000000000..ef5bf0cb05bb --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-007-ref.html @@ -0,0 +1,4 @@ + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-important-007.html b/layout/reftests/scoped-style/scoped-style-important-007.html new file mode 100644 index 000000000000..fe69a6b638ca --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-important-007.html @@ -0,0 +1,7 @@ + + + +

Hello

+ diff --git a/layout/reftests/scoped-style/scoped-style-imported.css b/layout/reftests/scoped-style/scoped-style-imported.css new file mode 100644 index 000000000000..d964925b6a23 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-imported.css @@ -0,0 +1 @@ +p { color: blue } diff --git a/layout/reftests/scoped-style/scoped-style-keyframes-ref.html b/layout/reftests/scoped-style/scoped-style-keyframes-ref.html new file mode 100644 index 000000000000..af12e6108b00 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-keyframes-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-keyframes.html b/layout/reftests/scoped-style/scoped-style-keyframes.html new file mode 100644 index 000000000000..18e9c6670501 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-keyframes.html @@ -0,0 +1,28 @@ + + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-media-ref.html b/layout/reftests/scoped-style/scoped-style-media-ref.html new file mode 100644 index 000000000000..f1d8460a1b97 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-media-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-media.html b/layout/reftests/scoped-style/scoped-style-media.html new file mode 100644 index 000000000000..6cebeb6da2e1 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-media.html @@ -0,0 +1,16 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-namespace-ref.html b/layout/reftests/scoped-style/scoped-style-namespace-ref.html new file mode 100644 index 000000000000..f1d8460a1b97 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-namespace-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-namespace.html b/layout/reftests/scoped-style/scoped-style-namespace.html new file mode 100644 index 000000000000..714fea5e46ea --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-namespace.html @@ -0,0 +1,12 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-supports-ref.html b/layout/reftests/scoped-style/scoped-style-supports-ref.html new file mode 100644 index 000000000000..f1d8460a1b97 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-supports-ref.html @@ -0,0 +1,6 @@ + + +

First

+

Second

+

Third

+ diff --git a/layout/reftests/scoped-style/scoped-style-supports.html b/layout/reftests/scoped-style/scoped-style-supports.html new file mode 100644 index 000000000000..2e25340582d6 --- /dev/null +++ b/layout/reftests/scoped-style/scoped-style-supports.html @@ -0,0 +1,16 @@ + + +

First

+

+ + Second +

+

Third

+ diff --git a/layout/reftests/svg/conditions-08-ref.svg b/layout/reftests/svg/conditions-08-ref.svg new file mode 100644 index 000000000000..50406bddb9c2 --- /dev/null +++ b/layout/reftests/svg/conditions-08-ref.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/conditions-08.svg b/layout/reftests/svg/conditions-08.svg new file mode 100644 index 000000000000..573533d00f83 --- /dev/null +++ b/layout/reftests/svg/conditions-08.svg @@ -0,0 +1,42 @@ + + + Test that clipPath, mask, filter, gradients and patterns ignore failing conditionals + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/mask-basic-03.svg b/layout/reftests/svg/mask-basic-03.svg new file mode 100644 index 000000000000..95727570c870 --- /dev/null +++ b/layout/reftests/svg/mask-basic-03.svg @@ -0,0 +1,19 @@ + + + + + + Test that the x/y/width/height attributes work on the mask element + + + + + + + + + + diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 035415e49fc4..ad99b3a0d06e 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -46,6 +46,7 @@ fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),1,2) == clipPath-and-shape-re == conditions-05.svg about:blank == conditions-06.svg pass.svg == conditions-07.svg pass.svg +== conditions-08.svg conditions-08-ref.svg == currentColor-01.svg pass.svg == currentColor-02.svg pass.svg == currentColor-03.svg pass.svg @@ -175,6 +176,7 @@ fuzzy-if(Android,9,980) == gradient-live-01d.svg gradient-live-01-ref.svg == marker-orientation-01.svg marker-orientation-01-ref.svg == mask-basic-01.svg pass.svg == mask-basic-02.svg mask-basic-02-ref.svg +#== mask-basic-03.svg pass.svg == mask-extref-dataURI-01.svg pass.svg == mask-containing-masked-content-01.svg pass.svg == mask-transformed-01.svg mask-transformed-01-ref.svg diff --git a/layout/reftests/text-svgglyphs/reftest.list b/layout/reftests/text-svgglyphs/reftest.list index 71349ef27d4d..02d27a607666 100644 --- a/layout/reftests/text-svgglyphs/reftest.list +++ b/layout/reftests/text-svgglyphs/reftest.list @@ -6,6 +6,7 @@ pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-invalid.html pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectfill-solid.svg svg-glyph-objectfill-solid-ref.svg pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectstroke-solid.svg svg-glyph-objectstroke-solid-ref.svg pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectgradient.svg svg-glyph-objectgradient-ref.svg +pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectgradient-zoom.svg svg-glyph-objectgradient-zoom-ref.svg pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectpattern.svg svg-glyph-objectpattern-ref.svg pref(gfx.font_rendering.opentype_svg.enabled,true) == clip.html clip-ref.html pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectopacity.svg svg-glyph-objectopacity-ref.svg diff --git a/layout/reftests/text-svgglyphs/svg-glyph-objectgradient-zoom-ref.svg b/layout/reftests/text-svgglyphs/svg-glyph-objectgradient-zoom-ref.svg new file mode 100644 index 000000000000..95f3d1bb7049 --- /dev/null +++ b/layout/reftests/text-svgglyphs/svg-glyph-objectgradient-zoom-ref.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/text-svgglyphs/svg-glyph-objectgradient-zoom.svg b/layout/reftests/text-svgglyphs/svg-glyph-objectgradient-zoom.svg new file mode 100644 index 000000000000..cebc4fb04cfb --- /dev/null +++ b/layout/reftests/text-svgglyphs/svg-glyph-objectgradient-zoom.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + N + O + P + Q + diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index 111c8c3b6700..70341a90df88 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -18,6 +18,7 @@ #include "mozilla/Util.h" +#include "mozilla/dom/Element.h" #include "mozilla/css/Loader.h" #include "nsIRunnable.h" #include "nsIUnicharStreamLoader.h" @@ -70,6 +71,8 @@ #include "mozilla/dom/EncodingUtils.h" using mozilla::dom::EncodingUtils; +using namespace mozilla::dom; + /** * OVERALL ARCHITECTURE * @@ -1206,6 +1209,7 @@ Loader::PrepareSheet(nsCSSStyleSheet* aSheet, const nsSubstring& aTitle, const nsSubstring& aMediaString, nsMediaList* aMediaList, + Element* aScopeElement, bool isAlternate) { NS_PRECONDITION(aSheet, "Must have a sheet!"); @@ -1232,6 +1236,7 @@ Loader::PrepareSheet(nsCSSStyleSheet* aSheet, aSheet->SetTitle(aTitle); aSheet->SetEnabled(! isAlternate); + aSheet->SetScopeElement(aScopeElement); return NS_OK; } @@ -1794,6 +1799,7 @@ Loader::LoadInlineStyle(nsIContent* aElement, uint32_t aLineNumber, const nsAString& aTitle, const nsAString& aMedia, + Element* aScopeElement, nsICSSLoaderObserver* aObserver, bool* aCompleted, bool* aIsAlternate) @@ -1826,7 +1832,8 @@ Loader::LoadInlineStyle(nsIContent* aElement, LOG((" Sheet is alternate: %d", *aIsAlternate)); - rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate); + rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, + *aIsAlternate); NS_ENSURE_SUCCESS(rv, rv); rv = InsertSheetInDoc(sheet, aElement, mDocument); @@ -1899,7 +1906,7 @@ Loader::LoadStyleLink(nsIContent* aElement, LOG((" Sheet is alternate: %d", *aIsAlternate)); - rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, *aIsAlternate); + rv = PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate); NS_ENSURE_SUCCESS(rv, rv); rv = InsertSheetInDoc(sheet, aElement, mDocument); @@ -2057,7 +2064,7 @@ Loader::LoadChildSheet(nsCSSStyleSheet* aParentSheet, false, empty, state, &isAlternate, getter_AddRefs(sheet)); NS_ENSURE_SUCCESS(rv, rv); - rv = PrepareSheet(sheet, empty, empty, aMedia, isAlternate); + rv = PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate); NS_ENSURE_SUCCESS(rv, rv); rv = InsertChildSheet(sheet, aParentSheet, aParentRule); @@ -2168,7 +2175,7 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL, empty, state, &isAlternate, getter_AddRefs(sheet)); NS_ENSURE_SUCCESS(rv, rv); - rv = PrepareSheet(sheet, empty, empty, nullptr, isAlternate); + rv = PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate); NS_ENSURE_SUCCESS(rv, rv); if (state == eSheetComplete) { diff --git a/layout/style/Loader.h b/layout/style/Loader.h index fddfc145fa2f..034fed5e88f0 100644 --- a/layout/style/Loader.h +++ b/layout/style/Loader.h @@ -31,6 +31,12 @@ class nsMediaList; class nsIStyleSheetLinkingElement; class nsCycleCollectionTraversalCallback; +namespace mozilla { +namespace dom { +class Element; +} +} + namespace mozilla { class URIPrincipalAndCORSModeHashKey : public nsURIHashKey @@ -160,6 +166,7 @@ public: uint32_t aLineNumber, const nsAString& aTitle, const nsAString& aMedia, + mozilla::dom::Element* aScopeElement, nsICSSLoaderObserver* aObserver, bool* aCompleted, bool* aIsAlternate); @@ -395,6 +402,7 @@ private: const nsAString& aTitle, const nsAString& aMediaString, nsMediaList* aMediaList, + mozilla::dom::Element* aScopeElement, bool isAlternate); nsresult InsertSheetInDoc(nsCSSStyleSheet* aSheet, diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index a08f5f21e7eb..2cd09e783ec7 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -579,7 +579,7 @@ protected: bool ParseCursor(); bool ParseFont(); bool ParseFontWeight(nsCSSValue& aValue); - bool ParseOneFamily(nsAString& aValue); + bool ParseOneFamily(nsAString& aFamily, bool& aOneKeyword); bool ParseFamily(nsCSSValue& aValue); bool ParseFontFeatureSettings(nsCSSValue& aValue); bool ParseFontSrc(nsCSSValue& aValue); @@ -8356,20 +8356,23 @@ CSSParserImpl::ParseFontWeight(nsCSSValue& aValue) } bool -CSSParserImpl::ParseOneFamily(nsAString& aFamily) +CSSParserImpl::ParseOneFamily(nsAString& aFamily, bool& aOneKeyword) { if (!GetToken(true)) return false; nsCSSToken* tk = &mToken; + aOneKeyword = false; if (eCSSToken_Ident == tk->mType) { + aOneKeyword = true; aFamily.Append(tk->mIdent); for (;;) { if (!GetToken(false)) break; if (eCSSToken_Ident == tk->mType) { + aOneKeyword = false; aFamily.Append(tk->mIdent); } else if (eCSSToken_WhiteSpace == tk->mType) { // Lookahead one token and drop whitespace if we are ending the @@ -8401,444 +8404,28 @@ CSSParserImpl::ParseOneFamily(nsAString& aFamily) } } -/////////////////////////////////////////////////////// -// transform Parsing Implementation - -/* Reads a function list of arguments. Do not call this function - * directly; it's mean to be caled from ParseFunction. - */ -bool -CSSParserImpl::ParseFunctionInternals(const int32_t aVariantMask[], - uint16_t aMinElems, - uint16_t aMaxElems, - InfallibleTArray &aOutput) -{ - for (uint16_t index = 0; index < aMaxElems; ++index) { - nsCSSValue newValue; - if (!ParseVariant(newValue, aVariantMask[index], nullptr)) - return false; - - aOutput.AppendElement(newValue); - - // See whether to continue or whether to look for end of function. - if (!ExpectSymbol(',', true)) { - // We need to read the closing parenthesis, and also must take care - // that we haven't read too few symbols. - return ExpectSymbol(')', true) && (index + 1) >= aMinElems; - } - } - - // If we're here, we finished looping without hitting the end, so we read too - // many elements. - return false; -} - -/* Parses a function [ input of the form (a [, b]*) ] and stores it - * as an nsCSSValue that holds a function of the form - * function-name arg1 arg2 ... argN - * - * On error, the return value is false. - * - * @param aFunction The name of the function that we're reading. - * @param aAllowedTypes An array of values corresponding to the legal - * types for each element in the function. The zeroth element in the - * array corresponds to the first function parameter, etc. The length - * of this array _must_ be greater than or equal to aMaxElems or the - * behavior is undefined. - * @param aMinElems Minimum number of elements to read. Reading fewer than - * this many elements will result in the function failing. - * @param aMaxElems Maximum number of elements to read. Reading more than - * this many elements will result in the function failing. - * @param aValue (out) The value that was parsed. - */ -bool -CSSParserImpl::ParseFunction(const nsString &aFunction, - const int32_t aAllowedTypes[], - uint16_t aMinElems, uint16_t aMaxElems, - nsCSSValue &aValue) -{ - typedef InfallibleTArray::size_type arrlen_t; - - /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1 - * elements stored in the the nsCSSValue::Array. - */ - static const arrlen_t MAX_ALLOWED_ELEMS = 0xFFFE; - - /* Make a copy of the function name, since the reference is _probably_ to - * mToken.mIdent, which is going to get overwritten during the course of this - * function. - */ - nsString functionName(aFunction); - - /* Read in a list of values as an array, failing if we can't or if - * it's out of bounds. - */ - InfallibleTArray foundValues; - if (!ParseFunctionInternals(aAllowedTypes, aMinElems, aMaxElems, - foundValues)) - return false; - - /* Now, convert this array into an nsCSSValue::Array object. - * We'll need N + 1 spots, one for the function name and the rest for the - * arguments. In case the user has given us more than 2^16 - 2 arguments, - * we'll truncate them at 2^16 - 2 arguments. - */ - uint16_t numElements = (foundValues.Length() <= MAX_ALLOWED_ELEMS ? - foundValues.Length() + 1 : MAX_ALLOWED_ELEMS); - nsRefPtr convertedArray = - nsCSSValue::Array::Create(numElements); - - /* Copy things over. */ - convertedArray->Item(0).SetStringValue(functionName, eCSSUnit_Ident); - for (uint16_t index = 0; index + 1 < numElements; ++index) - convertedArray->Item(index + 1) = foundValues[static_cast(index)]; - - /* Fill in the outparam value with the array. */ - aValue.SetArrayValue(convertedArray, eCSSUnit_Function); - - /* Return it! */ - return true; -} - -/** - * Given a token, determines the minimum and maximum number of function - * parameters to read, along with the mask that should be used to read - * those function parameters. If the token isn't a transform function, - * returns an error. - * - * @param aToken The token identifying the function. - * @param aMinElems [out] The minimum number of elements to read. - * @param aMaxElems [out] The maximum number of elements to read - * @param aVariantMask [out] The variant mask to use during parsing - * @return Whether the information was loaded successfully. - */ -static bool GetFunctionParseInformation(nsCSSKeyword aToken, - bool aIsPrefixed, - uint16_t &aMinElems, - uint16_t &aMaxElems, - const int32_t *& aVariantMask, - bool &aIs3D) -{ -/* These types represent the common variant masks that will be used to - * parse out the individual functions. The order in the enumeration - * must match the order in which the masks are declared. - */ - enum { eLengthPercentCalc, - eLengthCalc, - eTwoLengthPercentCalcs, - eTwoLengthPercentCalcsOneLengthCalc, - eAngle, - eTwoAngles, - eNumber, - ePositiveLength, - eTwoNumbers, - eThreeNumbers, - eThreeNumbersOneAngle, - eMatrix, - eMatrixPrefixed, - eMatrix3d, - eMatrix3dPrefixed, - eNumVariantMasks }; - static const int32_t kMaxElemsPerFunction = 16; - static const int32_t kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = { - {VARIANT_LPCALC}, - {VARIANT_LENGTH|VARIANT_CALC}, - {VARIANT_LPCALC, VARIANT_LPCALC}, - {VARIANT_LPCALC, VARIANT_LPCALC, VARIANT_LENGTH|VARIANT_CALC}, - {VARIANT_ANGLE_OR_ZERO}, - {VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO}, - {VARIANT_NUMBER}, - {VARIANT_LENGTH|VARIANT_POSITIVE_DIMENSION}, - {VARIANT_NUMBER, VARIANT_NUMBER}, - {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}, - {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO}, - {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_NUMBER, VARIANT_NUMBER}, - {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_LPNCALC, VARIANT_LPNCALC}, - {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}, - {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, - VARIANT_LPNCALC, VARIANT_LPNCALC, VARIANT_LNCALC, VARIANT_NUMBER}}; - -#ifdef DEBUG - static const uint8_t kVariantMaskLengths[eNumVariantMasks] = - {1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 6, 16, 16}; -#endif - - int32_t variantIndex = eNumVariantMasks; - - aIs3D = false; - - switch (aToken) { - case eCSSKeyword_translatex: - case eCSSKeyword_translatey: - /* Exactly one length or percent. */ - variantIndex = eLengthPercentCalc; - aMinElems = 1U; - aMaxElems = 1U; - break; - case eCSSKeyword_translatez: - /* Exactly one length */ - variantIndex = eLengthCalc; - aMinElems = 1U; - aMaxElems = 1U; - aIs3D = true; - break; - case eCSSKeyword_translate3d: - /* Exactly two lengthds or percents and a number */ - variantIndex = eTwoLengthPercentCalcsOneLengthCalc; - aMinElems = 3U; - aMaxElems = 3U; - aIs3D = true; - break; - case eCSSKeyword_scalez: - aIs3D = true; - case eCSSKeyword_scalex: - case eCSSKeyword_scaley: - /* Exactly one scale factor. */ - variantIndex = eNumber; - aMinElems = 1U; - aMaxElems = 1U; - break; - case eCSSKeyword_scale3d: - /* Exactly three scale factors. */ - variantIndex = eThreeNumbers; - aMinElems = 3U; - aMaxElems = 3U; - aIs3D = true; - break; - case eCSSKeyword_rotatex: - case eCSSKeyword_rotatey: - aIs3D = true; - case eCSSKeyword_rotate: - case eCSSKeyword_rotatez: - /* Exactly one angle. */ - variantIndex = eAngle; - aMinElems = 1U; - aMaxElems = 1U; - break; - case eCSSKeyword_rotate3d: - variantIndex = eThreeNumbersOneAngle; - aMinElems = 4U; - aMaxElems = 4U; - aIs3D = true; - break; - case eCSSKeyword_translate: - /* One or two lengths or percents. */ - variantIndex = eTwoLengthPercentCalcs; - aMinElems = 1U; - aMaxElems = 2U; - break; - case eCSSKeyword_skew: - /* Exactly one or two angles. */ - variantIndex = eTwoAngles; - aMinElems = 1U; - aMaxElems = 2U; - break; - case eCSSKeyword_scale: - /* One or two scale factors. */ - variantIndex = eTwoNumbers; - aMinElems = 1U; - aMaxElems = 2U; - break; - case eCSSKeyword_skewx: - /* Exactly one angle. */ - variantIndex = eAngle; - aMinElems = 1U; - aMaxElems = 1U; - break; - case eCSSKeyword_skewy: - /* Exactly one angle. */ - variantIndex = eAngle; - aMinElems = 1U; - aMaxElems = 1U; - break; - case eCSSKeyword_matrix: - /* Six values, all numbers. */ - variantIndex = aIsPrefixed ? eMatrixPrefixed : eMatrix; - aMinElems = 6U; - aMaxElems = 6U; - break; - case eCSSKeyword_matrix3d: - /* 16 matrix values, all numbers */ - variantIndex = aIsPrefixed ? eMatrix3dPrefixed : eMatrix3d; - aMinElems = 16U; - aMaxElems = 16U; - aIs3D = true; - break; - case eCSSKeyword_perspective: - /* Exactly one scale number. */ - variantIndex = ePositiveLength; - aMinElems = 1U; - aMaxElems = 1U; - aIs3D = true; - break; - default: - /* Oh dear, we didn't match. Report an error. */ - return false; - } - - NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!"); - NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!"); - NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!"); - NS_ASSERTION(variantIndex >= 0, "Invalid variant mask!"); - NS_ASSERTION(variantIndex < eNumVariantMasks, "Invalid variant mask!"); -#ifdef DEBUG - NS_ASSERTION(aMaxElems <= kVariantMaskLengths[variantIndex], - "Invalid aMaxElems for this variant mask."); -#endif - - // Convert the index into a mask. - aVariantMask = kVariantMasks[variantIndex]; - - return true; -} - -/* Reads a single transform function from the tokenizer stream, reporting an - * error if something goes wrong. - */ -bool -CSSParserImpl::ParseSingleTransform(bool aIsPrefixed, - nsCSSValue& aValue, bool& aIs3D) -{ - if (!GetToken(true)) - return false; - - if (mToken.mType != eCSSToken_Function) { - UngetToken(); - return false; - } - - const int32_t* variantMask; - uint16_t minElems, maxElems; - nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); - - if (!GetFunctionParseInformation(keyword, aIsPrefixed, - minElems, maxElems, variantMask, aIs3D)) - return false; - - // Bug 721136: Normalize the identifier to lowercase, except that things - // like scaleX should have the last character capitalized. This matches - // what other browsers do. - nsContentUtils::ASCIIToLower(mToken.mIdent); - switch (keyword) { - case eCSSKeyword_rotatex: - case eCSSKeyword_scalex: - case eCSSKeyword_skewx: - case eCSSKeyword_translatex: - mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('X')); - break; - - case eCSSKeyword_rotatey: - case eCSSKeyword_scaley: - case eCSSKeyword_skewy: - case eCSSKeyword_translatey: - mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Y')); - break; - - case eCSSKeyword_rotatez: - case eCSSKeyword_scalez: - case eCSSKeyword_translatez: - mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Z')); - break; - - default: - break; - } - - return ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, aValue); -} - -/* Parses a transform property list by continuously reading in properties - * and constructing a matrix from it. - */ -bool CSSParserImpl::ParseTransform(bool aIsPrefixed) -{ - nsCSSValue value; - if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { - // 'inherit', 'initial', and 'none' must be alone - if (!ExpectEndProperty()) { - return false; - } - } else { - nsCSSValueList* cur = value.SetListValue(); - for (;;) { - bool is3D; - if (!ParseSingleTransform(aIsPrefixed, cur->mValue, is3D)) { - return false; - } - if (is3D && !nsLayoutUtils::Are3DTransformsEnabled()) { - return false; - } - if (CheckEndProperty()) { - break; - } - cur->mNext = new nsCSSValueList; - cur = cur->mNext; - } - } - AppendValue(eCSSProperty_transform, value); - return true; -} - -bool CSSParserImpl::ParseTransformOrigin(bool aPerspective) -{ - nsCSSValuePair position; - if (!ParseBoxPositionValues(position, true)) - return false; - - nsCSSProperty prop = eCSSProperty_transform_origin; - if (aPerspective) { - if (!ExpectEndProperty()) { - return false; - } - prop = eCSSProperty_perspective_origin; - } - - // Unlike many other uses of pairs, this position should always be stored - // as a pair, even if the values are the same, so it always serializes as - // a pair, and to keep the computation code simple. - if (position.mXValue.GetUnit() == eCSSUnit_Inherit || - position.mXValue.GetUnit() == eCSSUnit_Initial) { - NS_ABORT_IF_FALSE(position.mXValue == position.mYValue, - "inherit/initial only half?"); - AppendValue(prop, position.mXValue); - } else { - nsCSSValue value; - if (aPerspective) { - value.SetPairValue(position.mXValue, position.mYValue); - } else { - nsCSSValue depth; - if (!nsLayoutUtils::Are3DTransformsEnabled() || - // only try parsing if 3-D transforms are enabled - !ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nullptr)) { - depth.SetFloatValue(0.0f, eCSSUnit_Pixel); - } - value.SetTripletValue(position.mXValue, position.mYValue, depth); - } - - AppendValue(prop, value); - } - return true; -} - bool CSSParserImpl::ParseFamily(nsCSSValue& aValue) { - if (!GetToken(true)) + nsAutoString family; + bool single; + + // keywords only have meaning in the first position + if (!ParseOneFamily(family, single)) return false; - if (eCSSToken_Ident == mToken.mType) { - nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); + // check for keywords, but only when keywords appear by themselves + // i.e. not in compounds such as font-family: default blah; + if (single) { + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(family); if (keyword == eCSSKeyword_inherit) { aValue.SetInheritValue(); return true; } + // 605231 - don't parse unquoted 'default' reserved keyword + if (keyword == eCSSKeyword_default) { + return false; + } if (keyword == eCSSKeyword__moz_initial || keyword == eCSSKeyword_initial) { aValue.SetInitialValue(); return true; @@ -8850,17 +8437,33 @@ CSSParserImpl::ParseFamily(nsCSSValue& aValue) } } - UngetToken(); - - nsAutoString family; for (;;) { - if (!ParseOneFamily(family)) - return false; - if (!ExpectSymbol(',', true)) break; family.Append(PRUnichar(',')); + + nsAutoString nextFamily; + if (!ParseOneFamily(nextFamily, single)) + return false; + + // at this point unquoted keywords are not allowed + // as font family names but can appear within names + if (single) { + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(nextFamily); + switch (keyword) { + case eCSSKeyword_inherit: + case eCSSKeyword_initial: + case eCSSKeyword_default: + case eCSSKeyword__moz_initial: + case eCSSKeyword__moz_use_system_font: + return false; + default: + break; + } + } + + family.Append(nextFamily); } if (family.IsEmpty()) { @@ -8899,7 +8502,8 @@ CSSParserImpl::ParseFontSrc(nsCSSValue& aValue) // , possibly surrounded by whitespace. nsAutoString family; - if (!ParseOneFamily(family)) { + bool single; + if (!ParseOneFamily(family, single)) { SkipUntil(')'); return false; } @@ -9492,7 +9096,433 @@ CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue) } return true; } - + +/////////////////////////////////////////////////////// +// transform Parsing Implementation + +/* Reads a function list of arguments. Do not call this function + * directly; it's mean to be caled from ParseFunction. + */ +bool +CSSParserImpl::ParseFunctionInternals(const int32_t aVariantMask[], + uint16_t aMinElems, + uint16_t aMaxElems, + InfallibleTArray &aOutput) +{ + for (uint16_t index = 0; index < aMaxElems; ++index) { + nsCSSValue newValue; + if (!ParseVariant(newValue, aVariantMask[index], nullptr)) + return false; + + aOutput.AppendElement(newValue); + + // See whether to continue or whether to look for end of function. + if (!ExpectSymbol(',', true)) { + // We need to read the closing parenthesis, and also must take care + // that we haven't read too few symbols. + return ExpectSymbol(')', true) && (index + 1) >= aMinElems; + } + } + + // If we're here, we finished looping without hitting the end, so we read too + // many elements. + return false; +} + +/* Parses a function [ input of the form (a [, b]*) ] and stores it + * as an nsCSSValue that holds a function of the form + * function-name arg1 arg2 ... argN + * + * On error, the return value is false. + * + * @param aFunction The name of the function that we're reading. + * @param aAllowedTypes An array of values corresponding to the legal + * types for each element in the function. The zeroth element in the + * array corresponds to the first function parameter, etc. The length + * of this array _must_ be greater than or equal to aMaxElems or the + * behavior is undefined. + * @param aMinElems Minimum number of elements to read. Reading fewer than + * this many elements will result in the function failing. + * @param aMaxElems Maximum number of elements to read. Reading more than + * this many elements will result in the function failing. + * @param aValue (out) The value that was parsed. + */ +bool +CSSParserImpl::ParseFunction(const nsString &aFunction, + const int32_t aAllowedTypes[], + uint16_t aMinElems, uint16_t aMaxElems, + nsCSSValue &aValue) +{ + typedef InfallibleTArray::size_type arrlen_t; + + /* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1 + * elements stored in the the nsCSSValue::Array. + */ + static const arrlen_t MAX_ALLOWED_ELEMS = 0xFFFE; + + /* Make a copy of the function name, since the reference is _probably_ to + * mToken.mIdent, which is going to get overwritten during the course of this + * function. + */ + nsString functionName(aFunction); + + /* Read in a list of values as an array, failing if we can't or if + * it's out of bounds. + */ + InfallibleTArray foundValues; + if (!ParseFunctionInternals(aAllowedTypes, aMinElems, aMaxElems, + foundValues)) + return false; + + /* Now, convert this array into an nsCSSValue::Array object. + * We'll need N + 1 spots, one for the function name and the rest for the + * arguments. In case the user has given us more than 2^16 - 2 arguments, + * we'll truncate them at 2^16 - 2 arguments. + */ + uint16_t numElements = (foundValues.Length() <= MAX_ALLOWED_ELEMS ? + foundValues.Length() + 1 : MAX_ALLOWED_ELEMS); + nsRefPtr convertedArray = + nsCSSValue::Array::Create(numElements); + + /* Copy things over. */ + convertedArray->Item(0).SetStringValue(functionName, eCSSUnit_Ident); + for (uint16_t index = 0; index + 1 < numElements; ++index) + convertedArray->Item(index + 1) = foundValues[static_cast(index)]; + + /* Fill in the outparam value with the array. */ + aValue.SetArrayValue(convertedArray, eCSSUnit_Function); + + /* Return it! */ + return true; +} + +/** + * Given a token, determines the minimum and maximum number of function + * parameters to read, along with the mask that should be used to read + * those function parameters. If the token isn't a transform function, + * returns an error. + * + * @param aToken The token identifying the function. + * @param aMinElems [out] The minimum number of elements to read. + * @param aMaxElems [out] The maximum number of elements to read + * @param aVariantMask [out] The variant mask to use during parsing + * @return Whether the information was loaded successfully. + */ +static bool GetFunctionParseInformation(nsCSSKeyword aToken, + bool aIsPrefixed, + uint16_t &aMinElems, + uint16_t &aMaxElems, + const int32_t *& aVariantMask, + bool &aIs3D) +{ +/* These types represent the common variant masks that will be used to + * parse out the individual functions. The order in the enumeration + * must match the order in which the masks are declared. + */ + enum { eLengthPercentCalc, + eLengthCalc, + eTwoLengthPercentCalcs, + eTwoLengthPercentCalcsOneLengthCalc, + eAngle, + eTwoAngles, + eNumber, + ePositiveLength, + eTwoNumbers, + eThreeNumbers, + eThreeNumbersOneAngle, + eMatrix, + eMatrixPrefixed, + eMatrix3d, + eMatrix3dPrefixed, + eNumVariantMasks }; + static const int32_t kMaxElemsPerFunction = 16; + static const int32_t kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = { + {VARIANT_LPCALC}, + {VARIANT_LENGTH|VARIANT_CALC}, + {VARIANT_LPCALC, VARIANT_LPCALC}, + {VARIANT_LPCALC, VARIANT_LPCALC, VARIANT_LENGTH|VARIANT_CALC}, + {VARIANT_ANGLE_OR_ZERO}, + {VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO}, + {VARIANT_NUMBER}, + {VARIANT_LENGTH|VARIANT_POSITIVE_DIMENSION}, + {VARIANT_NUMBER, VARIANT_NUMBER}, + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}, + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO}, + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_NUMBER, VARIANT_NUMBER}, + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_LPNCALC, VARIANT_LPNCALC}, + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}, + {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, + VARIANT_LPNCALC, VARIANT_LPNCALC, VARIANT_LNCALC, VARIANT_NUMBER}}; + +#ifdef DEBUG + static const uint8_t kVariantMaskLengths[eNumVariantMasks] = + {1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 6, 16, 16}; +#endif + + int32_t variantIndex = eNumVariantMasks; + + aIs3D = false; + + switch (aToken) { + case eCSSKeyword_translatex: + case eCSSKeyword_translatey: + /* Exactly one length or percent. */ + variantIndex = eLengthPercentCalc; + aMinElems = 1U; + aMaxElems = 1U; + break; + case eCSSKeyword_translatez: + /* Exactly one length */ + variantIndex = eLengthCalc; + aMinElems = 1U; + aMaxElems = 1U; + aIs3D = true; + break; + case eCSSKeyword_translate3d: + /* Exactly two lengthds or percents and a number */ + variantIndex = eTwoLengthPercentCalcsOneLengthCalc; + aMinElems = 3U; + aMaxElems = 3U; + aIs3D = true; + break; + case eCSSKeyword_scalez: + aIs3D = true; + case eCSSKeyword_scalex: + case eCSSKeyword_scaley: + /* Exactly one scale factor. */ + variantIndex = eNumber; + aMinElems = 1U; + aMaxElems = 1U; + break; + case eCSSKeyword_scale3d: + /* Exactly three scale factors. */ + variantIndex = eThreeNumbers; + aMinElems = 3U; + aMaxElems = 3U; + aIs3D = true; + break; + case eCSSKeyword_rotatex: + case eCSSKeyword_rotatey: + aIs3D = true; + case eCSSKeyword_rotate: + case eCSSKeyword_rotatez: + /* Exactly one angle. */ + variantIndex = eAngle; + aMinElems = 1U; + aMaxElems = 1U; + break; + case eCSSKeyword_rotate3d: + variantIndex = eThreeNumbersOneAngle; + aMinElems = 4U; + aMaxElems = 4U; + aIs3D = true; + break; + case eCSSKeyword_translate: + /* One or two lengths or percents. */ + variantIndex = eTwoLengthPercentCalcs; + aMinElems = 1U; + aMaxElems = 2U; + break; + case eCSSKeyword_skew: + /* Exactly one or two angles. */ + variantIndex = eTwoAngles; + aMinElems = 1U; + aMaxElems = 2U; + break; + case eCSSKeyword_scale: + /* One or two scale factors. */ + variantIndex = eTwoNumbers; + aMinElems = 1U; + aMaxElems = 2U; + break; + case eCSSKeyword_skewx: + /* Exactly one angle. */ + variantIndex = eAngle; + aMinElems = 1U; + aMaxElems = 1U; + break; + case eCSSKeyword_skewy: + /* Exactly one angle. */ + variantIndex = eAngle; + aMinElems = 1U; + aMaxElems = 1U; + break; + case eCSSKeyword_matrix: + /* Six values, all numbers. */ + variantIndex = aIsPrefixed ? eMatrixPrefixed : eMatrix; + aMinElems = 6U; + aMaxElems = 6U; + break; + case eCSSKeyword_matrix3d: + /* 16 matrix values, all numbers */ + variantIndex = aIsPrefixed ? eMatrix3dPrefixed : eMatrix3d; + aMinElems = 16U; + aMaxElems = 16U; + aIs3D = true; + break; + case eCSSKeyword_perspective: + /* Exactly one scale number. */ + variantIndex = ePositiveLength; + aMinElems = 1U; + aMaxElems = 1U; + aIs3D = true; + break; + default: + /* Oh dear, we didn't match. Report an error. */ + return false; + } + + NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!"); + NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!"); + NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!"); + NS_ASSERTION(variantIndex >= 0, "Invalid variant mask!"); + NS_ASSERTION(variantIndex < eNumVariantMasks, "Invalid variant mask!"); +#ifdef DEBUG + NS_ASSERTION(aMaxElems <= kVariantMaskLengths[variantIndex], + "Invalid aMaxElems for this variant mask."); +#endif + + // Convert the index into a mask. + aVariantMask = kVariantMasks[variantIndex]; + + return true; +} + +/* Reads a single transform function from the tokenizer stream, reporting an + * error if something goes wrong. + */ +bool +CSSParserImpl::ParseSingleTransform(bool aIsPrefixed, + nsCSSValue& aValue, bool& aIs3D) +{ + if (!GetToken(true)) + return false; + + if (mToken.mType != eCSSToken_Function) { + UngetToken(); + return false; + } + + const int32_t* variantMask; + uint16_t minElems, maxElems; + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); + + if (!GetFunctionParseInformation(keyword, aIsPrefixed, + minElems, maxElems, variantMask, aIs3D)) + return false; + + // Bug 721136: Normalize the identifier to lowercase, except that things + // like scaleX should have the last character capitalized. This matches + // what other browsers do. + nsContentUtils::ASCIIToLower(mToken.mIdent); + switch (keyword) { + case eCSSKeyword_rotatex: + case eCSSKeyword_scalex: + case eCSSKeyword_skewx: + case eCSSKeyword_translatex: + mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('X')); + break; + + case eCSSKeyword_rotatey: + case eCSSKeyword_scaley: + case eCSSKeyword_skewy: + case eCSSKeyword_translatey: + mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Y')); + break; + + case eCSSKeyword_rotatez: + case eCSSKeyword_scalez: + case eCSSKeyword_translatez: + mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Z')); + break; + + default: + break; + } + + return ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, aValue); +} + +/* Parses a transform property list by continuously reading in properties + * and constructing a matrix from it. + */ +bool CSSParserImpl::ParseTransform(bool aIsPrefixed) +{ + nsCSSValue value; + if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) { + // 'inherit', 'initial', and 'none' must be alone + if (!ExpectEndProperty()) { + return false; + } + } else { + nsCSSValueList* cur = value.SetListValue(); + for (;;) { + bool is3D; + if (!ParseSingleTransform(aIsPrefixed, cur->mValue, is3D)) { + return false; + } + if (is3D && !nsLayoutUtils::Are3DTransformsEnabled()) { + return false; + } + if (CheckEndProperty()) { + break; + } + cur->mNext = new nsCSSValueList; + cur = cur->mNext; + } + } + AppendValue(eCSSProperty_transform, value); + return true; +} + +bool CSSParserImpl::ParseTransformOrigin(bool aPerspective) +{ + nsCSSValuePair position; + if (!ParseBoxPositionValues(position, true)) + return false; + + nsCSSProperty prop = eCSSProperty_transform_origin; + if (aPerspective) { + if (!ExpectEndProperty()) { + return false; + } + prop = eCSSProperty_perspective_origin; + } + + // Unlike many other uses of pairs, this position should always be stored + // as a pair, even if the values are the same, so it always serializes as + // a pair, and to keep the computation code simple. + if (position.mXValue.GetUnit() == eCSSUnit_Inherit || + position.mXValue.GetUnit() == eCSSUnit_Initial) { + NS_ABORT_IF_FALSE(position.mXValue == position.mYValue, + "inherit/initial only half?"); + AppendValue(prop, position.mXValue); + } else { + nsCSSValue value; + if (aPerspective) { + value.SetPairValue(position.mXValue, position.mYValue); + } else { + nsCSSValue depth; + if (!nsLayoutUtils::Are3DTransformsEnabled() || + // only try parsing if 3-D transforms are enabled + !ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nullptr)) { + depth.SetFloatValue(0.0f, eCSSUnit_Pixel); + } + value.SetTripletValue(position.mXValue, position.mYValue, depth); + } + + AppendValue(prop, value); + } + return true; +} + bool CSSParserImpl::ParseTransitionProperty() { diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index cc5869f86f71..4b1e97c5a1d5 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -1051,12 +1051,17 @@ RuleCascadeData::AttributeListFor(nsIAtom* aAttribute) // nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets, - uint8_t aSheetType) + uint8_t aSheetType, + Element* aScopeElement) : mSheets(aSheets) , mRuleCascades(nullptr) , mLastPresContext(nullptr) , mSheetType(aSheetType) + , mScopeElement(aScopeElement) { + NS_ASSERTION(!!mScopeElement == (aSheetType == nsStyleSet::eScopedDocSheet), + "aScopeElement must be specified iff aSheetType is " + "eScopedDocSheet"); for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) { mSheets[i]->AddRuleProcessor(this); } @@ -2197,6 +2202,13 @@ static bool SelectorMatchesTree(Element* aPrevElement, selector->mNext->mOperator != PRUnichar(0), "compound selector without combinator"); + // If after the previous selector match we are now outside the + // current style scope, we don't need to match any further. + if (aTreeMatchContext.mForScopedStyle && + !aTreeMatchContext.IsWithinStyleScopeForSelectorMatching()) { + return false; + } + // for adjacent sibling combinators, the content to test against the // selector is the previous sibling *element* Element* element = nullptr; @@ -2227,6 +2239,13 @@ static bool SelectorMatchesTree(Element* aPrevElement, // element parents. if (content && content->IsElement()) { element = content->AsElement(); + if (aTreeMatchContext.mForScopedStyle) { + // We are moving up to the parent element; tell the + // TreeMatchContext, so that in case this element is the + // style scope element, selector matching stops before we + // traverse further up the tree. + aTreeMatchContext.PopStyleScopeForSelectorMatching(element); + } } } if (!element) { @@ -2298,6 +2317,12 @@ void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector, // We won't match; nothing else to do here return; } + if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement, + data->mScope)) { + // The selector is for a rule in a scoped style sheet, and the subject + // of the selector matching is not in its scope. + return; + } if (SelectorMatches(data->mElement, aSelector, nodeContext, data->mTreeMatchContext)) { nsCSSSelector *next = aSelector->mNext; @@ -2482,6 +2507,13 @@ AttributeEnumFunc(nsCSSSelector* aSelector, AttributeEnumData* aData) { AttributeRuleProcessorData *data = aData->data; + if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement, + data->mScope)) { + // The selector is for a rule in a scoped style sheet, and the subject + // of the selector matching is not in its scope. + return; + } + nsRestyleHint possibleChange = RestyleHintForOp(aSelector->mOperator); // If enumData->change already includes all the bits of possibleChange, don't @@ -3256,14 +3288,14 @@ nsCSSRuleProcessor::SelectorListMatches(Element* aElement, return false; } -// AncestorFilter out of line methods +// TreeMatchContext and AncestorFilter out of line methods void -AncestorFilter::Init(Element *aElement) +TreeMatchContext::InitAncestors(Element *aElement) { - MOZ_ASSERT(!mFilter); - MOZ_ASSERT(mHashes.IsEmpty()); + MOZ_ASSERT(!mAncestorFilter.mFilter); + MOZ_ASSERT(mAncestorFilter.mHashes.IsEmpty()); - mFilter = new Filter(); + mAncestorFilter.mFilter = new AncestorFilter::Filter(); if (MOZ_LIKELY(aElement)) { MOZ_ASSERT(aElement->IsInDoc(), @@ -3284,7 +3316,8 @@ AncestorFilter::Init(Element *aElement) // Now push them in reverse order. for (uint32_t i = ancestors.Length(); i-- != 0; ) { - PushAncestor(ancestors[i]); + mAncestorFilter.PushAncestor(ancestors[i]); + PushStyleScope(ancestors[i]); } } } diff --git a/layout/style/nsCSSRuleProcessor.h b/layout/style/nsCSSRuleProcessor.h index 905eb47deefb..f0167930dd10 100644 --- a/layout/style/nsCSSRuleProcessor.h +++ b/layout/style/nsCSSRuleProcessor.h @@ -43,7 +43,11 @@ class nsCSSRuleProcessor: public nsIStyleRuleProcessor { public: typedef nsTArray > sheet_array_type; - nsCSSRuleProcessor(const sheet_array_type& aSheets, uint8_t aSheetType); + // aScopeElement must be non-null iff aSheetType is + // nsStyleSet::eScopedDocSheet. + nsCSSRuleProcessor(const sheet_array_type& aSheets, + uint8_t aSheetType, + mozilla::dom::Element* aScopeElement); virtual ~nsCSSRuleProcessor(); NS_DECL_ISUPPORTS @@ -124,6 +128,13 @@ public: bool AppendPageRules(nsPresContext* aPresContext, nsTArray& aArray); + /** + * Returns the scope element for the scoped style sheets this rule + * processor is for. If this is not a rule processor for scoped style + * sheets, it returns null. + */ + mozilla::dom::Element* GetScopeElement() const { return mScopeElement; } + #ifdef DEBUG void AssertQuirksChangeOK() { NS_ASSERTION(!mRuleCascades, "can't toggle quirks style sheet without " @@ -163,7 +174,11 @@ private: // The last pres context for which GetRuleCascades was called. nsPresContext *mLastPresContext; - + + // The scope element for this rule processor's scoped style sheets. + // Only used if mSheetType == nsStyleSet::eScopedDocSheet. + nsRefPtr mScopeElement; + // type of stylesheet using this processor uint8_t mSheetType; // == nsStyleSet::sheetType diff --git a/layout/style/nsCSSStyleSheet.cpp b/layout/style/nsCSSStyleSheet.cpp index 762325faaee1..4df5106da4cc 100644 --- a/layout/style/nsCSSStyleSheet.cpp +++ b/layout/style/nsCSSStyleSheet.cpp @@ -11,6 +11,7 @@ #include "nsCRT.h" #include "nsIAtom.h" #include "nsCSSRuleProcessor.h" +#include "mozilla/dom/Element.h" #include "mozilla/css/NameSpaceRule.h" #include "mozilla/css/GroupRule.h" #include "mozilla/css/ImportRule.h" @@ -41,6 +42,7 @@ #include "mozilla/Likely.h" using namespace mozilla; +using namespace mozilla::dom; // ------------------------------- @@ -1033,6 +1035,7 @@ nsCSSStyleSheet::nsCSSStyleSheet(CORSMode aCORSMode) mOwningNode(nullptr), mDisabled(false), mDirty(false), + mScopeElement(nullptr), mRuleProcessors(nullptr) { @@ -1051,6 +1054,7 @@ nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet& aCopy, mOwningNode(aOwningNodeToUse), mDisabled(aCopy.mDisabled), mDirty(aCopy.mDirty), + mScopeElement(nullptr), mInner(aCopy.mInner), mRuleProcessors(nullptr) { @@ -1197,12 +1201,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSStyleSheet) // unlinked before it does. tmp->DropRuleCollection(); tmp->UnlinkInner(); + tmp->mScopeElement = nullptr; NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSStyleSheet) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia) // We do not traverse mNext; our parent will handle that. See // comments in Unlink for why. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement) tmp->TraverseInner(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/layout/style/nsCSSStyleSheet.h b/layout/style/nsCSSStyleSheet.h index 3227ca1fc454..309670b35495 100644 --- a/layout/style/nsCSSStyleSheet.h +++ b/layout/style/nsCSSStyleSheet.h @@ -10,6 +10,7 @@ #define nsCSSStyleSheet_h_ #include "mozilla/Attributes.h" +#include "mozilla/dom/Element.h" #include "nscore.h" #include "nsCOMPtr.h" @@ -247,6 +248,12 @@ public: // Get this style sheet's CORS mode mozilla::CORSMode GetCORSMode() const { return mInner->mCORSMode; } + mozilla::dom::Element* GetScopeElement() const { return mScopeElement; } + void SetScopeElement(mozilla::dom::Element* aScopeElement) + { + mScopeElement = aScopeElement; + } + private: nsCSSStyleSheet(const nsCSSStyleSheet& aCopy, nsCSSStyleSheet* aParentToUse, @@ -297,6 +304,7 @@ protected: nsIDOMNode* mOwningNode; // weak ref bool mDisabled; bool mDirty; // has been modified + nsRefPtr mScopeElement; nsCSSStyleSheetInner* mInner; diff --git a/layout/style/nsRuleData.cpp b/layout/style/nsRuleData.cpp index 66051e48ae31..fd0324c1fe9d 100644 --- a/layout/style/nsRuleData.cpp +++ b/layout/style/nsRuleData.cpp @@ -32,7 +32,6 @@ nsRuleData::nsRuleData(uint32_t aSIDs, nsCSSValue* aValueStorage, mCanStoreInRuleTree(true), mPresContext(aContext), mStyleContext(aStyleContext), - mPostResolveCallback(nullptr), mValueStorage(aValueStorage) { #ifndef MOZ_VALGRIND diff --git a/layout/style/nsRuleData.h b/layout/style/nsRuleData.h index db5ac9c4a927..5b9cea03ebd1 100644 --- a/layout/style/nsRuleData.h +++ b/layout/style/nsRuleData.h @@ -25,10 +25,9 @@ struct nsRuleData const uint32_t mSIDs; bool mCanStoreInRuleTree; bool mIsImportantRule; - uint8_t mLevel; // an nsStyleSet::sheetType + uint16_t mLevel; // an nsStyleSet::sheetType nsPresContext* const mPresContext; nsStyleContext* const mStyleContext; - const nsPostResolveFunc mPostResolveCallback; // We store nsCSSValues needed to compute the data for one or more // style structs (specified by the bitfield mSIDs). These are stored diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index f48588f70133..4f203875e8c6 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -2008,7 +2008,7 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID, detail = eRulePartialMixed; // Treat as though some data is specified to avoid // the optimizations and force data computation. - if (detail == eRuleNone && startStruct && !ruleData.mPostResolveCallback) { + if (detail == eRuleNone && startStruct) { // We specified absolutely no rule information, but a parent rule in the tree // specified all the rule information. We set a bit along the branch from our // node in the tree to the node that specified the data that tells nodes on that @@ -2017,7 +2017,6 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID, PropagateDependentBit(aSID, ruleNode, startStruct); return startStruct; } - // FIXME Do we need to check for mPostResolveCallback? if ((!startStruct && !isReset && (detail == eRuleNone || detail == eRulePartialInherited)) || detail == eRuleFullInherited) { @@ -2072,10 +2071,6 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID, #undef STYLE_STRUCT #undef STYLE_STRUCT_TEST - // If we have a post-resolve callback, handle that now. - if (ruleData.mPostResolveCallback && (MOZ_LIKELY(res != nullptr))) - (*ruleData.mPostResolveCallback)(const_cast(res), &ruleData); - // Now return the result. return res; } @@ -3450,11 +3445,6 @@ nsRuleNode::SetGenericFont(nsPresContext* aPresContext, aGenericFontID, &ruleData, &parentFont, aFont, false, dummy); - // XXX Not sure if we need to do this here - // If we have a post-resolve callback, handle that now. - if (ruleData.mPostResolveCallback) - (ruleData.mPostResolveCallback)(aFont, &ruleData); - parentFont = *aFont; } } diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h index 8544c35b6fee..87b2f3f8d175 100644 --- a/layout/style/nsRuleNode.h +++ b/layout/style/nsRuleNode.h @@ -645,7 +645,7 @@ public: nsRuleNode* GetParent() const { return mParent; } bool IsRoot() const { return mParent == nullptr; } - // These PRUint8s are really nsStyleSet::sheetType values. + // These uint8_ts are really nsStyleSet::sheetType values. uint8_t GetLevel() const { NS_ASSERTION(!IsRoot(), "can't call on root"); return (mDependentBits & NS_RULE_NODE_LEVEL_MASK) >> diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index deddac717842..368f0d58ccbc 100644 --- a/layout/style/nsRuleProcessorData.h +++ b/layout/style/nsRuleProcessorData.h @@ -26,6 +26,7 @@ class nsIStyleSheet; class nsIAtom; class nsICSSPseudoComparator; class nsAttrValue; +struct TreeMatchContext; /** * An AncestorFilter is used to keep track of ancestors so that we can @@ -33,44 +34,12 @@ class nsAttrValue; * element. */ class NS_STACK_CLASS AncestorFilter { + friend struct TreeMatchContext; public: - /** - * Initialize the filter. If aElement is not null, it and all its - * ancestors will be passed to PushAncestor, starting from the root - * and going down the tree. - */ - void Init(mozilla::dom::Element *aElement); - /* Maintenance of our ancestor state */ void PushAncestor(mozilla::dom::Element *aElement); void PopAncestor(); - /* Helper class for maintaining the ancestor state */ - class NS_STACK_CLASS AutoAncestorPusher { - public: - AutoAncestorPusher(bool aDoPush, - AncestorFilter &aFilter, - mozilla::dom::Element *aElement - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mPushed(aDoPush && aElement), mFilter(aFilter) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - if (mPushed) { - mFilter.PushAncestor(aElement); - } - } - ~AutoAncestorPusher() { - if (mPushed) { - mFilter.PopAncestor(); - } - } - - private: - bool mPushed; - AncestorFilter &mFilter; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - }; - /* Check whether we might have an ancestor matching one of the given atom hashes. |hashes| must have length hashListLength */ template @@ -164,6 +133,114 @@ struct NS_STACK_CLASS TreeMatchContext { return mHaveSpecifiedScope; } + /** + * Initialize the ancestor filter and list of style scopes. If aElement is + * not null, it and all its ancestors will be passed to + * mAncestorFilter.PushAncestor and PushStyleScope, starting from the root and + * going down the tree. + */ + void InitAncestors(mozilla::dom::Element *aElement); + + void PushStyleScope(mozilla::dom::Element* aElement) + { + NS_PRECONDITION(aElement, "aElement must not be null"); + if (aElement->IsScopedStyleRoot()) { + mStyleScopes.AppendElement(aElement); + } + } + + void PopStyleScope(mozilla::dom::Element* aElement) + { + NS_PRECONDITION(aElement, "aElement must not be null"); + if (mStyleScopes.SafeLastElement(nullptr) == aElement) { + mStyleScopes.TruncateLength(mStyleScopes.Length() - 1); + } + } + + bool PopStyleScopeForSelectorMatching(mozilla::dom::Element* aElement) + { + NS_ASSERTION(mForScopedStyle, "only call PopScopeForSelectorMatching when " + "mForScopedStyle is true"); + + if (!mCurrentStyleScope) { + return false; + } + if (mCurrentStyleScope == aElement) { + mCurrentStyleScope = nullptr; + } + return true; + } + + bool SetStyleScopeForSelectorMatching(mozilla::dom::Element* aSubject, + mozilla::dom::Element* aScope) + { + mForScopedStyle = !!aScope; + if (!aScope) { + // This is not for a scoped style sheet; return true, as we want + // selector matching to proceed. + mCurrentStyleScope = nullptr; + return true; + } + if (aScope == aSubject) { + // Although the subject is the same element as the scope, as soon + // as we continue with selector matching up the tree we don't want + // to match any more elements. So we return true to indicate that + // we want to do the initial selector matching, but set + // mCurrentStyleScope to null so that no ancestor elements will match. + mCurrentStyleScope = nullptr; + return true; + } + if (mStyleScopes.Contains(aScope)) { + // mStyleScopes contains all of the scope elements that are ancestors of + // aSubject, so if aScope is in mStyleScopes, then we do want selector + // matching to proceed. + mCurrentStyleScope = aScope; + return true; + } + // Otherwise, we're not in the scope, and we don't want to proceed + // with selector matching. + mCurrentStyleScope = nullptr; + return false; + } + + bool IsWithinStyleScopeForSelectorMatching() const + { + NS_ASSERTION(mForScopedStyle, "only call IsWithinScopeForSelectorMatching " + "when mForScopedStyle is true"); + return mCurrentStyleScope; + } + + /* Helper class for maintaining the ancestor state */ + class NS_STACK_CLASS AutoAncestorPusher { + public: + AutoAncestorPusher(bool aDoPush, + TreeMatchContext &aTreeMatchContext, + mozilla::dom::Element *aElement + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : mPushed(aDoPush && aElement), + mTreeMatchContext(aTreeMatchContext), + mElement(aElement) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (mPushed) { + mTreeMatchContext.mAncestorFilter.PushAncestor(aElement); + mTreeMatchContext.PushStyleScope(aElement); + } + } + ~AutoAncestorPusher() { + if (mPushed) { + mTreeMatchContext.mAncestorFilter.PopAncestor(); + mTreeMatchContext.PopStyleScope(mElement); + } + } + + private: + bool mPushed; + TreeMatchContext& mTreeMatchContext; + mozilla::dom::Element* mElement; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + }; + // Is this matching operation for the creation of a style context? // (If it is, we need to set slow selector bits on nodes indicating // that certain restyling needs to happen.) @@ -213,11 +290,22 @@ struct NS_STACK_CLASS TreeMatchContext { // Whether this document is using PB mode bool mUsingPrivateBrowsing; + // Whether this TreeMatchContext is being used with an nsCSSRuleProcessor + // for an HTML5 scoped style sheet. + bool mForScopedStyle; + enum MatchVisited { eNeverMatchVisited, eMatchVisitedDefault }; + // List of ancestor elements that define a style scope (due to having a + // + + +
+

+
+
+
+
+
diff --git a/layout/style/test/test_garbage_at_end_of_declarations.html b/layout/style/test/test_garbage_at_end_of_declarations.html
index 4042cc32ffe5..c9c8dd757618 100644
--- a/layout/style/test/test_garbage_at_end_of_declarations.html
+++ b/layout/style/test/test_garbage_at_end_of_declarations.html
@@ -71,6 +71,7 @@ var gAllowsExtraUnusual = {
                  "ease-in-out": true, "2s ease-in": true,
                  "ease-out 2s": true, "1s bounce, 2s": true,
                  "1s bounce, 2s none": true },
+  "font-family": { "inherit": true, "initial": true }
 };
 
 gAllowsExtraUnusual["-moz-transition"] = gAllowsExtraUnusual["transition"];
diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html
index b0c8fb34e49e..88f2d0ea3b28 100644
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -49,6 +49,7 @@ function any_unit_to_num(str)
 }
 
 var FUNC_NEGATIVE = "cubic-bezier(0.25, -2, 0.75, 1)";
+var FUNC_OVERONE = "cubic-bezier(0.25, 0, 0.75, 3)";
 
 var supported_properties = {
     "border-bottom-left-radius": [ test_radius_transition ],
@@ -1131,38 +1132,74 @@ function test_rect_transition(prop) {
 }
 
 function test_visibility_transition(prop) {
-  div.style.setProperty("transition-property", "none", "");
-  div.style.setProperty(prop, "visible", "");
-  is(cs.getPropertyValue(prop), "visible",
-     "visibility property " + prop + ": computed value before transition");
-  div.style.setProperty("transition-property", prop, "");
-  div.style.setProperty(prop, "hidden", "");
-  is(cs.getPropertyValue(prop), "visible",
-     "visibility property " + prop + ": interpolation of visibility");
+  function do_test(from_value, to_value, interp_value) {
+    div.style.setProperty("transition-property", "none", "");
+    div.style.setProperty(prop, from_value, "");
+    is(cs.getPropertyValue(prop), from_value,
+       "visibility property " + prop + ": computed value before transition");
+    div.style.setProperty("transition-property", prop, "");
+    div.style.setProperty(prop, to_value, "");
+    is(cs.getPropertyValue(prop), interp_value,
+       "visibility property " + prop + ": interpolation of visibility");
+  }
+
+  do_test("visible", "hidden", "visible");
+  do_test("hidden", "visible", "visible");
+  do_test("hidden", "collapse", "collapse"); /* not interpolable */
+  do_test("collapse", "hidden", "hidden"); /* not interpolable */
+  do_test("visible", "collapse", "visible");
+  do_test("collapse", "visible", "visible");
+
   isnot(get_distance(prop, "visible", "hidden"), 0,
         "distance between visible and hidden should not be zero");
+  isnot(get_distance(prop, "visible", "collapse"), 0,
+        "distance between visible and collapse should not be zero");
   is(get_distance(prop, "visible", "visible"), 0,
      "distance between visible and visible should not be zero");
   is(get_distance(prop, "hidden", "hidden"), 0,
      "distance between hidden and hidden should not be zero");
+  is(get_distance(prop, "collapse", "collapse"), 0,
+     "distance between collapse and collapse should not be zero");
 
   div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
-  div.style.setProperty("transition-property", "none", "");
-  div.style.setProperty(prop, "visible", "");
-  is(cs.getPropertyValue(prop), "visible",
-     "visibility property " + prop + ": flush before clamping test");
-  div.style.setProperty("transition-property", prop, "");
-  div.style.setProperty(prop, "hidden", "");
-  is(cs.getPropertyValue(prop), "visible",
-     "visibility property " + prop + ": clamping of negatives");
-  div.style.setProperty("transition-property", "none", "");
-  div.style.setProperty(prop, "hidden", "");
-  is(cs.getPropertyValue(prop), "hidden",
-     "visibility property " + prop + ": flush before clamping test");
-  div.style.setProperty("transition-property", prop, "");
-  div.style.setProperty(prop, "visible", "");
-  is(cs.getPropertyValue(prop), "hidden",
-     "visibility property " + prop + ": clamping of negatives");
+  function do_negative_test(from_value, to_value, interpolable) {
+    div.style.setProperty("transition-property", "none", "");
+    div.style.setProperty(prop, from_value, "");
+    is(cs.getPropertyValue(prop), from_value,
+       "visibility property " + prop + ": flush before clamping test");
+    div.style.setProperty("transition-property", prop, "");
+    div.style.setProperty(prop, to_value, "");
+    is(cs.getPropertyValue(prop), interpolable ? from_value : to_value,
+       "visibility property " + prop + ": clamping of negatives");
+  }
+  do_negative_test("visible", "hidden", true);
+  do_negative_test("hidden", "visible", true);
+  do_negative_test("hidden", "collapse", false);
+  do_negative_test("collapse", "hidden", false);
+  do_negative_test("visible", "collapse", true);
+  do_negative_test("collapse", "visible", true);
+
+  div.style.setProperty("transition-delay", "-3s", "");
+  div.style.setProperty("transition-timing-function", FUNC_OVERONE, "");
+
+  function do_overone_test(from_value, to_value) {
+    div.style.setProperty("transition-property", "none", "");
+    div.style.setProperty(prop, from_value, "");
+    is(cs.getPropertyValue(prop), from_value,
+       "visibility property " + prop + ": flush before clamping test");
+    div.style.setProperty("transition-property", prop, "");
+    div.style.setProperty(prop, to_value, "");
+    is(cs.getPropertyValue(prop), to_value,
+       "visibility property " + prop + ": clamping of over-ones");
+  }
+  do_overone_test("visible", "hidden");
+  do_overone_test("hidden", "visible");
+  do_overone_test("hidden", "collapse");
+  do_overone_test("collapse", "hidden");
+  do_overone_test("visible", "collapse");
+  do_overone_test("collapse", "visible");
+
+  div.style.setProperty("transition-delay", "-1s", "");
   div.style.setProperty("transition-timing-function", "linear", "");
 }
 
diff --git a/layout/svg/SVGFEImageFrame.cpp b/layout/svg/SVGFEImageFrame.cpp
index 79fed0c165c8..7d5140dd00d9 100644
--- a/layout/svg/SVGFEImageFrame.cpp
+++ b/layout/svg/SVGFEImageFrame.cpp
@@ -98,12 +98,9 @@ SVGFEImageFrame::Init(nsIContent* aContent,
                         nsIFrame* aParent,
                         nsIFrame* aPrevInFlow)
 {
-#ifdef DEBUG
-  nsCOMPtr elem = do_QueryInterface(aContent);
-  NS_ASSERTION(elem,
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::feImage),
                "Trying to construct an SVGFEImageFrame for a "
                "content element that doesn't support the right interfaces");
-#endif /* DEBUG */
 
   SVGFEImageFrameBase::Init(aContent, aParent, aPrevInFlow);
   nsCOMPtr imageLoader =
diff --git a/layout/svg/SVGViewFrame.cpp b/layout/svg/SVGViewFrame.cpp
index 7fc41443f73a..ad42d6b74b97 100644
--- a/layout/svg/SVGViewFrame.cpp
+++ b/layout/svg/SVGViewFrame.cpp
@@ -8,7 +8,7 @@
 #include "nsGkAtoms.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsSVGSVGElement.h"
-#include "nsSVGViewElement.h"
+#include "mozilla/dom/SVGViewElement.h"
 
 typedef nsFrame SVGViewFrameBase;
 
@@ -81,8 +81,8 @@ SVGViewFrame::Init(nsIContent* aContent,
                    nsIFrame* aParent,
                    nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr elem = do_QueryInterface(aContent);
-  NS_ASSERTION(elem, "Content is not an SVG view");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::view),
+               "Content is not an SVG view");
 
   return SVGViewFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGAFrame.cpp b/layout/svg/nsSVGAFrame.cpp
index ffdaf2fa6e5d..6ff9c54973bb 100644
--- a/layout/svg/nsSVGAFrame.cpp
+++ b/layout/svg/nsSVGAFrame.cpp
@@ -91,8 +91,7 @@ nsSVGAFrame::Init(nsIContent* aContent,
                   nsIFrame* aParent,
                   nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr elem = do_QueryInterface(aContent);
-  NS_ASSERTION(elem,
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::a),
                "Trying to construct an SVGAFrame for a "
                "content element that doesn't support the right interfaces");
 
diff --git a/layout/svg/nsSVGClipPathFrame.cpp b/layout/svg/nsSVGClipPathFrame.cpp
index 01e8d66d46c3..af0a64f96640 100644
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -9,7 +9,6 @@
 // Keep others in (case-insensitive) order:
 #include "gfxContext.h"
 #include "nsGkAtoms.h"
-#include "nsIDOMSVGClipPathElement.h"
 #include "nsRenderingContext.h"
 #include "nsSVGClipPathElement.h"
 #include "nsSVGEffects.h"
@@ -298,10 +297,8 @@ nsSVGClipPathFrame::Init(nsIContent* aContent,
                          nsIFrame* aParent,
                          nsIFrame* aPrevInFlow)
 {
-#ifdef DEBUG
-  nsCOMPtr clipPath = do_QueryInterface(aContent);
-  NS_ASSERTION(clipPath, "Content is not an SVG clipPath!");
-#endif
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::clipPath),
+               "Content is not an SVG clipPath!");
 
   AddStateBits(NS_STATE_SVG_CLIPPATH_CHILD);
   return nsSVGClipPathFrameBase::Init(aContent, aParent, aPrevInFlow);
diff --git a/layout/svg/nsSVGFilterFrame.cpp b/layout/svg/nsSVGFilterFrame.cpp
index 7ba89b4de107..4e4d7bd6da99 100644
--- a/layout/svg/nsSVGFilterFrame.cpp
+++ b/layout/svg/nsSVGFilterFrame.cpp
@@ -523,15 +523,15 @@ nsSVGFilterFrame::GetPostFilterBounds(nsIFrame *aFilteredFrame,
   }
   return nsRect();
 }
-  
+
 #ifdef DEBUG
 NS_IMETHODIMP
 nsSVGFilterFrame::Init(nsIContent* aContent,
                        nsIFrame* aParent,
                        nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr filter = do_QueryInterface(aContent);
-  NS_ASSERTION(filter, "Content is not an SVG filter");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::filter),
+               "Content is not an SVG filter");
 
   return nsSVGFilterFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp
index a25a8c357a56..db698451abfd 100644
--- a/layout/svg/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/nsSVGForeignObjectFrame.cpp
@@ -10,7 +10,6 @@
 #include "gfxContext.h"
 #include "gfxMatrix.h"
 #include "nsGkAtoms.h"
-#include "nsIDOMSVGForeignObjectElem.h"
 #include "nsINameSpaceManager.h"
 #include "nsLayoutUtils.h"
 #include "nsRegion.h"
@@ -58,10 +57,8 @@ nsSVGForeignObjectFrame::Init(nsIContent* aContent,
                               nsIFrame*   aParent,
                               nsIFrame*   aPrevInFlow)
 {
-#ifdef DEBUG
-  nsCOMPtr foreignObject = do_QueryInterface(aContent);
-  NS_ASSERTION(foreignObject, "Content is not an SVG foreignObject!");
-#endif
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::foreignObject),
+               "Content is not an SVG foreignObject!");
 
   nsresult rv = nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
   AddStateBits(aParent->GetStateBits() &
diff --git a/layout/svg/nsSVGGlyphFrame.cpp b/layout/svg/nsSVGGlyphFrame.cpp
index ee363b1c60af..9c9ed59ab04b 100644
--- a/layout/svg/nsSVGGlyphFrame.cpp
+++ b/layout/svg/nsSVGGlyphFrame.cpp
@@ -972,9 +972,6 @@ nsSVGGlyphFrame::SetupCairoStroke(gfxContext *aContext,
     return false;
   }
 
-  gfxContextMatrixAutoSaveRestore matrixRestore(aContext);
-  aContext->IdentityMatrix();
-
   nsSVGUtils::SetupCairoStrokeHitGeometry(this, aContext, aOuterObjectPaint);
   float opacity = nsSVGUtils::GetOpacity(style->mStrokeOpacitySource,
                                          style->mStrokeOpacity,
diff --git a/layout/svg/nsSVGGradientFrame.cpp b/layout/svg/nsSVGGradientFrame.cpp
index 52feb638f84c..efb59103e191 100644
--- a/layout/svg/nsSVGGradientFrame.cpp
+++ b/layout/svg/nsSVGGradientFrame.cpp
@@ -10,12 +10,13 @@
 #include "gfxPattern.h"
 #include "nsContentUtils.h"
 #include "nsIDOMSVGAnimatedNumber.h"
-#include "nsIDOMSVGStopElement.h"
 #include "nsSVGEffects.h"
 #include "nsSVGGradientElement.h"
 #include "SVGAnimatedTransformList.h"
+#include "mozilla/dom/SVGStopElement.h"
 
-using mozilla::SVGAnimatedTransformList;
+using namespace mozilla;
+using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // Helper classes
@@ -103,12 +104,14 @@ nsSVGGradientFrame::GetStopInformation(int32_t aIndex,
 
   nsIFrame *stopFrame = nullptr;
   GetStopFrame(aIndex, &stopFrame);
-  nsCOMPtr stopElement =
-    do_QueryInterface(stopFrame->GetContent());
 
-  if (stopElement) {
-    nsCOMPtr aNum;
-    stopElement->GetOffset(getter_AddRefs(aNum));
+  nsIContent* stopContent = stopFrame->GetContent();
+
+  if (stopContent) {
+    MOZ_ASSERT(stopContent->IsSVG(nsGkAtoms::stop));
+    SVGStopElement* stopElement = nullptr;
+    stopElement = static_cast(stopContent);
+    nsCOMPtr aNum = stopElement->Offset();
 
     aNum->GetAnimVal(aOffset);
     if (*aOffset < 0.0f)
@@ -419,8 +422,8 @@ nsSVGLinearGradientFrame::Init(nsIContent* aContent,
                                nsIFrame* aParent,
                                nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr grad = do_QueryInterface(aContent);
-  NS_ASSERTION(grad, "Content is not an SVG linearGradient");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::linearGradient),
+               "Content is not an SVG linearGradient");
 
   return nsSVGLinearGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
@@ -532,8 +535,8 @@ nsSVGRadialGradientFrame::Init(nsIContent* aContent,
                                nsIFrame* aParent,
                                nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr grad = do_QueryInterface(aContent);
-  NS_ASSERTION(grad, "Content is not an SVG radialGradient");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::radialGradient),
+               "Content is not an SVG radialGradient");
 
   return nsSVGRadialGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGImageFrame.cpp b/layout/svg/nsSVGImageFrame.cpp
index 4fed47425e33..312cc7fb3f41 100644
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -8,7 +8,6 @@
 #include "gfxMatrix.h"
 #include "gfxPlatform.h"
 #include "imgIContainer.h"
-#include "nsIDOMSVGImageElement.h"
 #include "nsIImageLoadingContent.h"
 #include "nsLayoutUtils.h"
 #include "nsRenderingContext.h"
@@ -133,14 +132,12 @@ nsSVGImageFrame::Init(nsIContent* aContent,
                       nsIFrame* aParent,
                       nsIFrame* aPrevInFlow)
 {
-#ifdef DEBUG
-  nsCOMPtr image = do_QueryInterface(aContent);
-  NS_ASSERTION(image, "Content is not an SVG image!");
-#endif
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::image),
+               "Content is not an SVG image!");
 
   nsresult rv = nsSVGImageFrameBase::Init(aContent, aParent, aPrevInFlow);
   if (NS_FAILED(rv)) return rv;
-  
+
   mListener = new nsSVGImageListener(this);
   if (!mListener) return NS_ERROR_OUT_OF_MEMORY;
   nsCOMPtr imageLoader = do_QueryInterface(mContent);
diff --git a/layout/svg/nsSVGInnerSVGFrame.cpp b/layout/svg/nsSVGInnerSVGFrame.cpp
index 40d1360411a5..a4e1ad38177c 100644
--- a/layout/svg/nsSVGInnerSVGFrame.cpp
+++ b/layout/svg/nsSVGInnerSVGFrame.cpp
@@ -37,8 +37,8 @@ nsSVGInnerSVGFrame::Init(nsIContent* aContent,
                          nsIFrame* aParent,
                          nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr svg = do_QueryInterface(aContent);
-  NS_ASSERTION(svg, "Content is not an SVG 'svg' element!");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::svg),
+               "Content is not an SVG 'svg' element!");
 
   return nsSVGInnerSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp
index b000634b1a60..aa99674dc45d 100644
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -356,8 +356,13 @@ nsSVGIntegrationUtils::HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& a
   nsIFrame* firstFrame =
     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
   // Convert aPt to user space:
-  nsPoint toUserSpace =
-    aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame);
+  nsPoint toUserSpace;
+  if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
+    toUserSpace = aFrame->GetPosition();
+  } else {
+    toUserSpace =
+      aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame);
+  }
   nsPoint pt = aPt + toUserSpace;
   return nsSVGUtils::HitTestClip(firstFrame, pt);
 }
diff --git a/layout/svg/nsSVGMaskFrame.cpp b/layout/svg/nsSVGMaskFrame.cpp
index c5113385de6b..05dd0cc636dc 100644
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -183,8 +183,8 @@ nsSVGMaskFrame::Init(nsIContent* aContent,
                      nsIFrame* aParent,
                      nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr mask = do_QueryInterface(aContent);
-  NS_ASSERTION(mask, "Content is not an SVG mask");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::mask),
+               "Content is not an SVG mask");
 
   return nsSVGMaskFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp
index 7fd623293f73..e2c734985359 100644
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -11,7 +11,6 @@
 #include "gfxMatrix.h"
 #include "nsDisplayList.h"
 #include "nsIDocument.h"
-#include "nsIDOMSVGSVGElement.h"
 #include "nsIDOMWindow.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIObjectLoadingContent.h"
@@ -21,7 +20,7 @@
 #include "nsSVGForeignObjectFrame.h"
 #include "nsSVGSVGElement.h"
 #include "nsSVGTextFrame.h"
-#include "nsSVGViewElement.h"
+#include "mozilla/dom/SVGViewElement.h"
 #include "nsSubDocumentFrame.h"
 
 namespace dom = mozilla::dom;
@@ -150,10 +149,8 @@ nsSVGOuterSVGFrame::Init(nsIContent* aContent,
                          nsIFrame* aParent,
                          nsIFrame* aPrevInFlow)
 {
-#ifdef DEBUG
-  nsCOMPtr svgElement = do_QueryInterface(aContent);
-  NS_ASSERTION(svgElement, "Content is not an SVG 'svg' element!");
-#endif
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::svg),
+               "Content is not an SVG 'svg' element!");
 
   AddStateBits(NS_STATE_IS_OUTER_SVG |
                NS_FRAME_FONT_INFLATION_CONTAINER |
@@ -286,7 +283,7 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio()
     return ratio;
   }
 
-  nsSVGViewElement* viewElement = content->GetCurrentViewElement();
+  dom::SVGViewElement* viewElement = content->GetCurrentViewElement();
   const nsSVGViewBoxRect* viewbox = nullptr;
 
   // The logic here should match HasViewBox().
diff --git a/layout/svg/nsSVGPatternFrame.cpp b/layout/svg/nsSVGPatternFrame.cpp
index 9ccdfde5fcdc..5a0a3487f97b 100644
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -105,8 +105,7 @@ nsSVGPatternFrame::Init(nsIContent* aContent,
                         nsIFrame* aParent,
                         nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr patternElement = do_QueryInterface(aContent);
-  NS_ASSERTION(patternElement, "Content is not an SVG pattern");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::pattern), "Content is not an SVG pattern");
 
   return nsSVGPatternFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGStopFrame.cpp b/layout/svg/nsSVGStopFrame.cpp
index 9179c3fb258f..01f2388202c1 100644
--- a/layout/svg/nsSVGStopFrame.cpp
+++ b/layout/svg/nsSVGStopFrame.cpp
@@ -6,7 +6,6 @@
 // Keep in (case-insensitive) order:
 #include "nsFrame.h"
 #include "nsGkAtoms.h"
-#include "nsIDOMSVGStopElement.h"
 #include "nsStyleContext.h"
 #include "nsSVGEffects.h"
 
@@ -83,8 +82,8 @@ nsSVGStopFrame::Init(nsIContent* aContent,
                      nsIFrame* aParent,
                      nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr grad = do_QueryInterface(aContent);
-  NS_ASSERTION(grad, "Content doesn't support nsIDOMSVGStopElement");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::stop),
+               "Content doesn't support nsIDOMSVGStopElement");
 
   return nsSVGStopFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGSwitchFrame.cpp b/layout/svg/nsSVGSwitchFrame.cpp
index 5f124ab6d08c..d354f815c11e 100644
--- a/layout/svg/nsSVGSwitchFrame.cpp
+++ b/layout/svg/nsSVGSwitchFrame.cpp
@@ -79,8 +79,8 @@ nsSVGSwitchFrame::Init(nsIContent* aContent,
                        nsIFrame* aParent,
                        nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr svgSwitch = do_QueryInterface(aContent);
-  NS_ASSERTION(svgSwitch, "Content is not an SVG switch\n");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::svgSwitch),
+               "Content is not an SVG switch\n");
 
   return nsSVGSwitchFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGTSpanFrame.cpp b/layout/svg/nsSVGTSpanFrame.cpp
index dfefc2852c16..363e8a62f739 100644
--- a/layout/svg/nsSVGTSpanFrame.cpp
+++ b/layout/svg/nsSVGTSpanFrame.cpp
@@ -7,8 +7,6 @@
 #include "nsSVGTSpanFrame.h"
 
 // Keep others in (case-insensitive) order:
-#include "nsIDOMSVGTSpanElement.h"
-#include "nsIDOMSVGAltGlyphElement.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGUtils.h"
 
@@ -60,9 +58,9 @@ nsSVGTSpanFrame::Init(nsIContent* aContent,
                  "trying to construct an SVGTSpanFrame for an invalid "
                  "container");
 
-    nsCOMPtr tspan = do_QueryInterface(aContent);
-    nsCOMPtr altGlyph = do_QueryInterface(aContent);
-    NS_ASSERTION(tspan || altGlyph, "Content is not an SVG tspan or altGlyph");
+    NS_ASSERTION(aContent->IsSVG() && (aContent->Tag() == nsGkAtoms::altGlyph ||
+                                       aContent->Tag() == nsGkAtoms::tspan),
+                 "Content is not an SVG tspan or altGlyph");
   }
 
   return nsSVGTSpanFrameBase::Init(aContent, aParent, aPrevInFlow);
diff --git a/layout/svg/nsSVGTextFrame.cpp b/layout/svg/nsSVGTextFrame.cpp
index da501afc4c9d..ab5d22e45e47 100644
--- a/layout/svg/nsSVGTextFrame.cpp
+++ b/layout/svg/nsSVGTextFrame.cpp
@@ -9,7 +9,6 @@
 // Keep others in (case-insensitive) order:
 #include "nsGkAtoms.h"
 #include "nsIDOMSVGRect.h"
-#include "nsIDOMSVGTextElement.h"
 #include "nsISVGGlyphFragmentNode.h"
 #include "nsSVGGlyphFrame.h"
 #include "nsSVGIntegrationUtils.h"
@@ -40,8 +39,8 @@ nsSVGTextFrame::Init(nsIContent* aContent,
                      nsIFrame* aParent,
                      nsIFrame* aPrevInFlow)
 {
-  nsCOMPtr text = do_QueryInterface(aContent);
-  NS_ASSERTION(text, "Content is not an SVG text");
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::text),
+               "Content is not an SVG text");
 
   return nsSVGTextFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGTextPathFrame.cpp b/layout/svg/nsSVGTextPathFrame.cpp
index f5177e2459a4..a30d7a98f6f2 100644
--- a/layout/svg/nsSVGTextPathFrame.cpp
+++ b/layout/svg/nsSVGTextPathFrame.cpp
@@ -8,7 +8,6 @@
 
 // Keep others in (case-insensitive) order:
 #include "nsContentUtils.h"
-#include "nsIDOMSVGTextPathElement.h"
 #include "nsSVGEffects.h"
 #include "nsSVGLength2.h"
 #include "nsSVGPathElement.h"
@@ -43,9 +42,9 @@ nsSVGTextPathFrame::Init(nsIContent* aContent,
   NS_ASSERTION(ancestorFrame->GetType() == nsGkAtoms::svgTextFrame,
                "trying to construct an SVGTextPathFrame for an invalid "
                "container");
-  
-  nsCOMPtr textPath = do_QueryInterface(aContent);
-  NS_ASSERTION(textPath, "Content is not an SVG textPath");
+
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::textPath),
+               "Content is not an SVG textPath");
 
   return nsSVGTextPathFrameBase::Init(aContent, aParent, aPrevInFlow);
 }
diff --git a/layout/svg/nsSVGUseFrame.cpp b/layout/svg/nsSVGUseFrame.cpp
index fb489c0377ea..be1768249a62 100644
--- a/layout/svg/nsSVGUseFrame.cpp
+++ b/layout/svg/nsSVGUseFrame.cpp
@@ -5,7 +5,6 @@
 
 // Keep in (case-insensitive) order:
 #include "nsIAnonymousContentCreator.h"
-#include "nsIDOMSVGUseElement.h"
 #include "nsSVGGFrame.h"
 #include "nsSVGUseElement.h"
 #include "nsContentList.h"
@@ -101,10 +100,8 @@ nsSVGUseFrame::Init(nsIContent* aContent,
                     nsIFrame* aParent,
                     nsIFrame* aPrevInFlow)
 {
-#ifdef DEBUG
-  nsCOMPtr use = do_QueryInterface(aContent);
-  NS_ASSERTION(use, "Content is not an SVG use!");
-#endif /* DEBUG */
+  NS_ASSERTION(aContent->IsSVG(nsGkAtoms::use),
+               "Content is not an SVG use!");
 
   mHasValidDimensions =
     static_cast(aContent)->HasValidDimensions();
diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py
index 1111c6310a8d..88adde9d621f 100644
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -109,6 +109,10 @@ class B2GOptions(ReftestOptions):
                         type="string", dest="logcat_dir",
                         help="directory to store logcat dump files")
         defaults["logcat_dir"] = None
+        self.add_option('--busybox', action='store',
+                        type='string', dest='busybox',
+                        help="Path to busybox binary to install on device")
+        defaults['busybox'] = None
         defaults["remoteTestRoot"] = "/data/local/tests"
         defaults["logFile"] = "reftest.log"
         defaults["autorun"] = True
@@ -484,6 +488,8 @@ def main(args=sys.argv[1:]):
             kwargs['gecko_path'] = options.geckoPath
         if options.logcat_dir:
             kwargs['logcat_dir'] = options.logcat_dir
+        if options.busybox:
+            kwargs['busybox'] = options.busybox
     if options.emulator_res:
         kwargs['emulator_res'] = options.emulator_res
     if options.b2gPath:
diff --git a/media/omx-plugin/OmxPlugin.cpp b/media/omx-plugin/OmxPlugin.cpp
index 0e286ee93279..5f90863bbf31 100644
--- a/media/omx-plugin/OmxPlugin.cpp
+++ b/media/omx-plugin/OmxPlugin.cpp
@@ -84,6 +84,11 @@ ssize_t MediaStreamSource::readAt(MOZ_STAGEFRIGHT_OFF_T offset, void *data, size
     if (!mPluginHost->Read(mDecoder, ptr, offset, todo, &bytesRead)) {
       return ERROR_IO;
     }
+
+    if (bytesRead == 0) {
+      return size - todo;
+    }
+
     offset += bytesRead;
     todo -= bytesRead;
     ptr += bytesRead;
diff --git a/media/webrtc/signaling/src/sipcc/core/includes/ccapi.h b/media/webrtc/signaling/src/sipcc/core/includes/ccapi.h
index 454044baf644..2f902f2f2db6 100755
--- a/media/webrtc/signaling/src/sipcc/core/includes/ccapi.h
+++ b/media/webrtc/signaling/src/sipcc/core/includes/ccapi.h
@@ -5,7 +5,9 @@
 #ifndef _CCAPI_H_
 #define _CCAPI_H_
 
-#include "prtypes.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Util.h"
+
 #include "cpr_types.h"
 #include "cpr_memory.h"
 #include "phone_types.h"
@@ -106,7 +108,7 @@ typedef enum {
 /* please update the following cc_feature_names whenever this feature list is changed */
 
 #ifdef __CC_FEATURE_STRINGS__
-static const char *cc_feature_names[] = {
+static const char *const cc_feature_names[] = {
     "NONE",
     "HOLD",
     "RESUME",
@@ -170,7 +172,8 @@ static const char *cc_feature_names[] = {
 /* This checks at compile-time that the cc_feature_names list
  * is the same size as the cc_group_feature_t enum
  */
-PR_STATIC_ASSERT(PR_ARRAY_SIZE(cc_feature_names) == CC_FEATURE_MAX + 1);
+MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(cc_feature_names) == CC_FEATURE_MAX + 1,
+                  "cc_feature_names size == cc_group_feature_t size?");
 
 #endif
 
@@ -250,7 +253,7 @@ typedef enum cc_msgs_t_ {
 } cc_msgs_t;
 
 #ifdef __CC_MESSAGES_STRINGS__
-static const char *cc_msg_names[] = {
+static const char *const cc_msg_names[] = {
     "SETUP",
     "SETUP_ACK",
     "PROCEEDING",
@@ -292,7 +295,8 @@ static const char *cc_msg_names[] = {
 /* This checks at compile-time that the cc_msg_names list
  * is the same size as the cc_msgs_t enum
  */
-PR_STATIC_ASSERT(PR_ARRAY_SIZE(cc_msg_names) == CC_MSG_MAX + 1);
+MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(cc_msg_names) == CC_MSG_MAX + 1,
+                  "cc_msg_names size == cc_msgs_t size?");
 
 #endif //__CC_MESSAGES_STRINGS__
 
diff --git a/media/webrtc/signaling/src/sipcc/core/sipstack/sip_platform_task.c b/media/webrtc/signaling/src/sipcc/core/sipstack/sip_platform_task.c
index d639f1d8e542..0efe423fe7f8 100644
--- a/media/webrtc/signaling/src/sipcc/core/sipstack/sip_platform_task.c
+++ b/media/webrtc/signaling/src/sipcc/core/sipstack/sip_platform_task.c
@@ -153,7 +153,7 @@ sip_platform_task_init (void)
  * @return            The length of the written output not including the NULL
  *                    terminator, or -1 if an error occurs.
  */
-static PRUint32 sip_get_sock_dir_tmpl(char *out, PRUint32 outlen,
+static uint32_t sip_get_sock_dir_tmpl(char *out, uint32_t outlen,
                                       const char *suffix) {
 
     char *tmpdir;
diff --git a/media/webrtc/trunk/src/common_audio/signal_processing/signal_processing.gypi b/media/webrtc/trunk/src/common_audio/signal_processing/signal_processing.gypi
index 57310f90cffc..de50904f84a8 100644
--- a/media/webrtc/trunk/src/common_audio/signal_processing/signal_processing.gypi
+++ b/media/webrtc/trunk/src/common_audio/signal_processing/signal_processing.gypi
@@ -75,7 +75,7 @@
                 'filter_ar_fast_q12.c',
               ],
               'conditions': [
-                ['arm_neon==1', {
+                ['0==1 and arm_neon==1', {
                   'sources': [
                     'cross_correlation_neon.s',
                     'downsample_fast_neon.s',
@@ -88,6 +88,9 @@
                   ],
                 }],
               ],
+              'defines!': [
+                'WEBRTC_ARCH_ARM_NEON'
+              ],
             }],
           ],
         }],
diff --git a/memory/replace/dmd/DMD.cpp b/memory/replace/dmd/DMD.cpp
index 222761395077..035ab8fe1bef 100644
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -770,6 +770,9 @@ typedef js::HashSet
         StackTraceTable;
 static StackTraceTable* gStackTraceTable = nullptr;
 
+// We won't GC the stack trace table until it this many elements.
+static uint32_t gGCStackTraceTableWhenSizeExceeds = 4 * 1024;
+
 void
 StackTrace::Print(const Writer& aWriter, LocationService* aLocService) const
 {
@@ -1017,6 +1020,61 @@ public:
 typedef js::HashSet BlockTable;
 static BlockTable* gBlockTable = nullptr;
 
+typedef js::HashSet,
+                    InfallibleAllocPolicy>
+        StackTraceSet;
+
+// Add a pointer to each live stack trace into the given StackTraceSet.  (A
+// stack trace is live if it's used by one of the live blocks.)
+static void
+GatherUsedStackTraces(StackTraceSet& aStackTraces)
+{
+  MOZ_ASSERT(gStateLock->IsLocked());
+  MOZ_ASSERT(Thread::Fetch()->InterceptsAreBlocked());
+
+  aStackTraces.finish();
+  aStackTraces.init(1024);
+
+  for (BlockTable::Range r = gBlockTable->all(); !r.empty(); r.popFront()) {
+    const Block& b = r.front();
+    aStackTraces.put(b.AllocStackTrace());
+    aStackTraces.put(b.ReportStackTrace1());
+    aStackTraces.put(b.ReportStackTrace2());
+  }
+
+  // Any of the stack traces added above may have been null.  For the sake of
+  // cleanliness, don't leave the null pointer in the set.
+  aStackTraces.remove(nullptr);
+}
+
+// Delete stack traces that we aren't using, and compact our hashtable.
+static void
+GCStackTraces()
+{
+  MOZ_ASSERT(gStateLock->IsLocked());
+  MOZ_ASSERT(Thread::Fetch()->InterceptsAreBlocked());
+
+  StackTraceSet usedStackTraces;
+  GatherUsedStackTraces(usedStackTraces);
+
+  // Delete all unused stack traces from gStackTraceTable.  The Enum destructor
+  // will automatically rehash and compact the table.
+  for (StackTraceTable::Enum e(*gStackTraceTable);
+       !e.empty();
+       e.popFront()) {
+    StackTrace* const& st = e.front();
+
+    if (!usedStackTraces.has(st)) {
+      e.removeFront();
+      InfallibleAllocPolicy::delete_(st);
+    }
+  }
+
+  // Schedule a GC when we have twice as many stack traces as we had right after
+  // this GC finished.
+  gGCStackTraceTableWhenSizeExceeds = 2 * gStackTraceTable->count();
+}
+
 //---------------------------------------------------------------------------
 // malloc/free callbacks
 //---------------------------------------------------------------------------
@@ -1070,6 +1128,10 @@ FreeCallback(void* aPtr, Thread* aT)
   AutoBlockIntercepts block(aT);
 
   gBlockTable->remove(aPtr);
+
+  if (gStackTraceTable->count() > gGCStackTraceTableWhenSizeExceeds) {
+    GCStackTraces();
+  }
 }
 
 //---------------------------------------------------------------------------
@@ -1886,16 +1948,8 @@ SizeOfInternal(Sizes* aSizes)
     return;
   }
 
-  js::HashSet,
-              InfallibleAllocPolicy> usedStackTraces;
-  usedStackTraces.init(1024);
-
-  for(BlockTable::Range r = gBlockTable->all(); !r.empty(); r.popFront()) {
-    const Block& b = r.front();
-    usedStackTraces.put(b.AllocStackTrace());
-    usedStackTraces.put(b.ReportStackTrace1());
-    usedStackTraces.put(b.ReportStackTrace2());
-  }
+  StackTraceSet usedStackTraces;
+  GatherUsedStackTraces(usedStackTraces);
 
   for (StackTraceTable::Range r = gStackTraceTable->all();
        !r.empty();
diff --git a/mfbt/RangedPtr.h b/mfbt/RangedPtr.h
index adecf7c1a097..ecc8063410e6 100644
--- a/mfbt/RangedPtr.h
+++ b/mfbt/RangedPtr.h
@@ -60,6 +60,8 @@ class RangedPtr
 #endif
     }
 
+    uintptr_t asUintptr() const { return uintptr_t(ptr); }
+
   public:
     RangedPtr(T* p, T* start, T* end)
       : ptr(p)
@@ -128,13 +130,13 @@ class RangedPtr
 
     RangedPtr operator+(size_t inc) {
       MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
-      MOZ_ASSERT(ptr + inc >= ptr);
+      MOZ_ASSERT(asUintptr() + inc * sizeof(T) >= asUintptr());
       return create(ptr + inc);
     }
 
     RangedPtr operator-(size_t dec) {
       MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
-      MOZ_ASSERT(ptr - dec <= ptr);
+      MOZ_ASSERT(asUintptr() - dec * sizeof(T) <= asUintptr());
       return create(ptr - dec);
     }
 
diff --git a/mfbt/Util.h b/mfbt/Util.h
index bff7e7b17f46..dcfec6a7c7b9 100644
--- a/mfbt/Util.h
+++ b/mfbt/Util.h
@@ -269,4 +269,11 @@ ArrayEnd(T (&arr)[N])
 
 #endif /* __cplusplus */
 
+/*
+ * MOZ_ARRAY_LENGTH() is an alternative to mozilla::ArrayLength() for C files
+ * that can't use C++ template functions and for MOZ_STATIC_ASSERT() calls that
+ * can't call ArrayLength() when it is not a C++11 constexpr function.
+ */
+#define MOZ_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0]))
+
 #endif  /* mozilla_Util_h_ */
diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js
index 65395735702b..edbeb27194c8 100644
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -575,9 +575,6 @@ pref("urlclassifier.alternate_error_page", "blocked");
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
 
-// Randomize all UrlClassifier data with a per-client key.
-pref("urlclassifier.randomizeclient", false);
-
 // The list of tables that use the gethash request to confirm partial results.
 pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
 
diff --git a/mobile/android/base/AboutHomeContent.java b/mobile/android/base/AboutHomeContent.java
index f28fb6a7dc09..1214cc6e3345 100644
--- a/mobile/android/base/AboutHomeContent.java
+++ b/mobile/android/base/AboutHomeContent.java
@@ -163,7 +163,10 @@ public class AboutHomeContent extends ScrollView
         mRemoteTabClickListener = new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                Tabs.getInstance().loadUrl((String) v.getTag(), Tabs.LOADURL_NEW_TAB);
+                int flags = Tabs.LOADURL_NEW_TAB;
+                if (Tabs.getInstance().getSelectedTab().isPrivate())
+                    flags |= Tabs.LOADURL_PRIVATE;
+                Tabs.getInstance().loadUrl((String) v.getTag(), flags);
             }
         };
 
@@ -676,7 +679,10 @@ public class AboutHomeContent extends ScrollView
 
                         container.setOnClickListener(new View.OnClickListener() {
                             public void onClick(View v) {
-                                Tabs.getInstance().loadUrlInTab(url);
+                                int flags = Tabs.LOADURL_NEW_TAB;
+                                if (Tabs.getInstance().getSelectedTab().isPrivate())
+                                    flags |= Tabs.LOADURL_PRIVATE;
+                                Tabs.getInstance().loadUrl(url, flags);
                             }
                         });
 
@@ -694,8 +700,11 @@ public class AboutHomeContent extends ScrollView
                         mLastTabs.showMoreText();
                         mLastTabs.setOnMoreTextClickListener(new View.OnClickListener() {
                             public void onClick(View v) {
+                                int flags = Tabs.LOADURL_NEW_TAB;
+                                if (Tabs.getInstance().getSelectedTab().isPrivate())
+                                    flags |= Tabs.LOADURL_PRIVATE;
                                 for (String url : lastTabUrlsList) {
-                                    Tabs.getInstance().loadUrlInTab(url);
+                                    Tabs.getInstance().loadUrl(url, flags);
                                 }
                             }
                         });
diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java
index 6812a1b3f857..5211f8f8ea20 100644
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -500,7 +500,7 @@ abstract public class BrowserApp extends GeckoApp
     }
 
     public void addPrivateTab() {
-        Tabs.getInstance().loadUrl("about:home", Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_PRIVATE);
+        Tabs.getInstance().loadUrl("about:privatebrowsing", Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_PRIVATE);
     }
 
     public void showNormalTabs() {
diff --git a/mobile/android/base/BrowserToolbar.java b/mobile/android/base/BrowserToolbar.java
index 7cfce26b7a18..0077c9b12f22 100644
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -944,9 +944,10 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
         if (tab != null && tab.isEnteringReaderMode())
             return;
 
-        // Setting a null title for about:home will ensure we just see
+        // Setting a null title will ensure we just see
         // the "Enter Search or Address" placeholder text
-        if (tab != null && "about:home".equals(tab.getURL()))
+        if (tab != null && ("about:home".equals(tab.getURL()) ||
+                            "about:privatebrowsing".equals(tab.getURL())))
             title = null;
 
         mTitle.setText(title);
diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java
index a4897eddc740..b99b62e64f7d 100644
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -629,52 +629,8 @@ abstract public class GeckoApp
         if (ReaderModeUtils.isAboutReader(url))
             url = ReaderModeUtils.getUrlFromAboutReader(url);
 
-        if (Build.VERSION.SDK_INT >= 11) {
-            final Intent shareIntent = new Intent(Intent.ACTION_SEND);
-            shareIntent.putExtra(Intent.EXTRA_TEXT, url);
-            shareIntent.putExtra(Intent.EXTRA_SUBJECT, tab.getDisplayTitle());
-            shareIntent.setType("text/plain");
-
-            PackageManager pm = getPackageManager();
-            List activities = pm.queryIntentActivities(shareIntent, 0);
-            Collections.sort(activities, new Comparator() {
-                @Override
-                public int compare(ResolveInfo one, ResolveInfo two) {
-                    return one.preferredOrder - two.preferredOrder;
-                }
-
-                @Override
-                public boolean equals(Object info) {
-                    return this.equals(info);
-                }
-            });
-
-            GeckoSubMenu menu = new GeckoSubMenu(mAppContext, null);
-
-            GeckoMenu parent = (GeckoMenu) mMenu;
-            menu.setCallback(parent.getCallback());
-            menu.setMenuPresenter(parent.getMenuPresenter());
-
-            for (ResolveInfo activity : activities) {
-                 final ActivityInfo activityInfo = activity.activityInfo;
-
-                 MenuItem item = menu.add(activity.loadLabel(pm));
-                 item.setIcon(activity.loadIcon(pm));
-                 item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-                     @Override
-                     public boolean onMenuItemClick(MenuItem item) {
-                         shareIntent.setComponent(new ComponentName(activityInfo.packageName, activityInfo.name));
-                         startActivity(shareIntent);
-                         return true;
-                     }
-                 });
-            }
-
-            showMenu(menu);
-        } else {
-            GeckoAppShell.openUriExternal(url, "text/plain", "", "",
-                                          Intent.ACTION_SEND, tab.getDisplayTitle());
-        }
+        GeckoAppShell.openUriExternal(url, "text/plain", "", "",
+                                      Intent.ACTION_SEND, tab.getDisplayTitle());
     }
 
     protected void onSaveInstanceState(Bundle outState) {
diff --git a/mobile/android/base/awesomebar/AllPagesTab.java b/mobile/android/base/awesomebar/AllPagesTab.java
index 90044c7455ec..db33155f20bf 100644
--- a/mobile/android/base/awesomebar/AllPagesTab.java
+++ b/mobile/android/base/awesomebar/AllPagesTab.java
@@ -602,7 +602,9 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
         mSuggestionsOptInPrompt = LayoutInflater.from(mContext).inflate(R.layout.awesomebar_suggestion_prompt, (LinearLayout)getView(), false);
         GeckoTextView promptText = (GeckoTextView) mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_title);
         promptText.setText(getResources().getString(R.string.suggestions_prompt, mSearchEngines.get(0).name));
-        promptText.setPrivateMode(Tabs.getInstance().getSelectedTab().isPrivate());
+        Tab tab = Tabs.getInstance().getSelectedTab();
+        if (tab != null)
+            promptText.setPrivateMode(tab.isPrivate());
 
         final View yesButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_yes);
         final View noButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_no);
diff --git a/mobile/android/chrome/content/aboutPrivateBrowsing.xhtml b/mobile/android/chrome/content/aboutPrivateBrowsing.xhtml
new file mode 100644
index 000000000000..770c5a953fa9
--- /dev/null
+++ b/mobile/android/chrome/content/aboutPrivateBrowsing.xhtml
@@ -0,0 +1,49 @@
+
+
+
+  %htmlDTD;
+  
+  %brandDTD;
+  
+  %globalDTD;
+  
+  %privatebrowsingpageDTD;
+]>
+
+
+  
+    
+    
+    
+    
+  
+
+  
+    
+    

&privatebrowsingpage.title;

+

&privatebrowsingpage.issueDesc.normal;

+ +
+

&privatebrowsingpage.description.private;

+

&privatebrowsingpage.description;

+ +

&privatebrowsingpage.moreInfo;

+
+ + diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index b7d2ae2bab65..af3094f08a96 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1874,6 +1874,10 @@ var SelectionHandler = { break; } case "Tab:Selected": + if (this._activeType == this.TYPE_CURSOR) { + this.hideThumb(); + } + // fall through case "Window:Resize": { if (this._activeType == this.TYPE_SELECTION) { // Knowing when the page is done drawing is hard, so let's just cancel diff --git a/mobile/android/chrome/jar.mn b/mobile/android/chrome/jar.mn index 6f0de473883d..c153f6d19a6a 100644 --- a/mobile/android/chrome/jar.mn +++ b/mobile/android/chrome/jar.mn @@ -15,6 +15,7 @@ chrome.jar: content/aboutDownloads.xhtml (content/aboutDownloads.xhtml) content/aboutDownloads.js (content/aboutDownloads.js) content/aboutFeedback.xhtml (content/aboutFeedback.xhtml) + content/aboutPrivateBrowsing.xhtml (content/aboutPrivateBrowsing.xhtml) content/aboutReader.html (content/aboutReader.html) content/aboutReader.js (content/aboutReader.js) content/Readability.js (content/Readability.js) diff --git a/mobile/android/components/AboutRedirector.js b/mobile/android/components/AboutRedirector.js index 60172575a9ac..6819cd0a88df 100644 --- a/mobile/android/components/AboutRedirector.js +++ b/mobile/android/components/AboutRedirector.js @@ -67,6 +67,10 @@ let modules = { feedback: { uri: "chrome://browser/content/aboutFeedback.xhtml", privileged: true + }, + privatebrowsing: { + uri: "chrome://browser/content/aboutPrivateBrowsing.xhtml", + privileged: true } } diff --git a/mobile/android/components/MobileComponents.manifest b/mobile/android/components/MobileComponents.manifest index fef83dca9d87..74238a0dd7c0 100644 --- a/mobile/android/components/MobileComponents.manifest +++ b/mobile/android/components/MobileComponents.manifest @@ -11,6 +11,7 @@ contract @mozilla.org/network/protocol/about;1?what=apps {322ba47e-7047-4f71-aeb contract @mozilla.org/network/protocol/about;1?what=downloads {322ba47e-7047-4f71-aebf-cb7d69325cd9} contract @mozilla.org/network/protocol/about;1?what=reader {322ba47e-7047-4f71-aebf-cb7d69325cd9} contract @mozilla.org/network/protocol/about;1?what=feedback {322ba47e-7047-4f71-aebf-cb7d69325cd9} +contract @mozilla.org/network/protocol/about;1?what=privatebrowsing {322ba47e-7047-4f71-aebf-cb7d69325cd9} #ifdef MOZ_SAFE_BROWSING contract @mozilla.org/network/protocol/about;1?what=blocked {322ba47e-7047-4f71-aebf-cb7d69325cd9} #endif diff --git a/mobile/android/config/mozconfigs/android-x86/debug b/mobile/android/config/mozconfigs/android-x86/debug index 0e5a24cf7e6c..8c9de9588da9 100644 --- a/mobile/android/config/mozconfigs/android-x86/debug +++ b/mobile/android/config/mozconfigs/android-x86/debug @@ -14,9 +14,6 @@ ac_add_options --with-android-gnu-compiler-version=4.6 ac_add_options --with-android-version=9 ac_add_options --with-system-zlib -# IonMonkey disabled in bug 789373 -ac_add_options --disable-ion - export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android-x86/l10n-nightly b/mobile/android/config/mozconfigs/android-x86/l10n-nightly index d2391b1b4436..e8c73da2a8bf 100644 --- a/mobile/android/config/mozconfigs/android-x86/l10n-nightly +++ b/mobile/android/config/mozconfigs/android-x86/l10n-nightly @@ -22,9 +22,6 @@ ac_add_options --with-system-zlib ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -# IonMonkey disabled in bug 789373 -ac_add_options --disable-ion - export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 diff --git a/mobile/android/config/mozconfigs/android-x86/l10n-release b/mobile/android/config/mozconfigs/android-x86/l10n-release index 1abf16d78df1..f85f7505ca02 100644 --- a/mobile/android/config/mozconfigs/android-x86/l10n-release +++ b/mobile/android/config/mozconfigs/android-x86/l10n-release @@ -19,9 +19,6 @@ ac_add_options --with-system-zlib ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -# IonMonkey disabled in bug 789373 -ac_add_options --disable-ion - export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 diff --git a/mobile/android/config/mozconfigs/android-x86/nightly b/mobile/android/config/mozconfigs/android-x86/nightly index 3fcc8a8c777d..c05ae70e1d38 100644 --- a/mobile/android/config/mozconfigs/android-x86/nightly +++ b/mobile/android/config/mozconfigs/android-x86/nightly @@ -12,9 +12,6 @@ ac_add_options --with-android-version=9 ac_add_options --with-system-zlib ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -# IonMonkey disabled in bug 789373 -ac_add_options --disable-ion - export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/config/mozconfigs/android-x86/release b/mobile/android/config/mozconfigs/android-x86/release index 304e74113dca..177db0de86d5 100644 --- a/mobile/android/config/mozconfigs/android-x86/release +++ b/mobile/android/config/mozconfigs/android-x86/release @@ -13,9 +13,6 @@ ac_add_options --with-system-zlib ac_add_options --enable-updater ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -# IonMonkey disabled in bug 789373 -ac_add_options --disable-ion - export JAVA_HOME=/tools/jdk6 export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 diff --git a/mobile/android/themes/core/aboutPrivateBrowsing.css b/mobile/android/themes/core/aboutPrivateBrowsing.css new file mode 100644 index 000000000000..e90b733a0173 --- /dev/null +++ b/mobile/android/themes/core/aboutPrivateBrowsing.css @@ -0,0 +1,71 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +body { + font-family: Roboto,"Droid Sans",helvetica,arial,clean,sans-serif; + font-size: 14px; +} + +body.normal .showPrivate, +body.private .showNormal { + display: none; +} + +div.contentSection { + width: 92%; + max-width: 400px; + margin: 0 auto; +} + +body.private { + color: #9ba3ab; + background-image: url("chrome://browser/skin/images/privatebrowsing-bg-textured.png"); +} + +body.normal { + color: #222; + background-image: url("chrome://browser/skin/images/about-bg-lightblue.png"); +} + +h1 { + font-size: 24px; + font-weight: 100; + text-align: center; + margin: 0; +} + +body.private h1 { + color: #d06bff; +} + +img { + display: block; + width: 125px; + height: 125px; + margin: -30px auto; +} + +@media all and (max-height: 399px) { + body { + margin-top: 25px; + } +} + +@media all and (min-height: 400px) and (max-height: 599px) { + body { + margin-top: 50px; + } +} + +@media all and (min-height: 600px) and (max-height: 799px) { + body { + margin-top: 150px; + } +} + +@media all and (min-height: 800px) { + body { + margin-top: 250px; + } +} diff --git a/mobile/android/themes/core/images/privatebrowsing-bg-textured.png b/mobile/android/themes/core/images/privatebrowsing-bg-textured.png new file mode 100644 index 000000000000..f9ab48016f6a Binary files /dev/null and b/mobile/android/themes/core/images/privatebrowsing-bg-textured.png differ diff --git a/mobile/android/themes/core/images/privatebrowsing-mask.png b/mobile/android/themes/core/images/privatebrowsing-mask.png new file mode 100644 index 000000000000..8acc2985ad3f Binary files /dev/null and b/mobile/android/themes/core/images/privatebrowsing-mask.png differ diff --git a/mobile/android/themes/core/jar.mn b/mobile/android/themes/core/jar.mn index bf0d167484bd..ed3d5e005398 100644 --- a/mobile/android/themes/core/jar.mn +++ b/mobile/android/themes/core/jar.mn @@ -13,6 +13,7 @@ chrome.jar: * skin/aboutDownloads.css (aboutDownloads.css) skin/aboutFeedback.css (aboutFeedback.css) skin/aboutMemory.css (aboutMemory.css) +* skin/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css) skin/aboutReader.css (aboutReader.css) skin/aboutSupport.css (aboutSupport.css) * skin/browser.css (browser.css) @@ -123,3 +124,5 @@ chrome.jar: skin/images/reader-toolbar-bg-port-xhdpi.png (images/reader-toolbar-bg-port-xhdpi.png) skin/images/reader-toolbar-bg-land-xhdpi.png (images/reader-toolbar-bg-land-xhdpi.png) skin/images/reader-toolbar-bg-xlarge-xhdpi.png (images/reader-toolbar-bg-xlarge-xhdpi.png) + skin/images/privatebrowsing-mask.png (images/privatebrowsing-mask.png) + skin/images/privatebrowsing-bg-textured.png (images/privatebrowsing-bg-textured.png) diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index cdf0654b41b0..8b188cf766e7 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -2664,12 +2664,12 @@ pref("font.name-list.monospace.x-western", "Courier,Courier New"); pref("font.name-list.cursive.x-western", "Apple Chancery"); pref("font.name-list.fantasy.x-western", "Papyrus"); -pref("font.name.serif.zh-CN", "STSong"); -pref("font.name.sans-serif.zh-CN", "STHeiti"); -pref("font.name.monospace.zh-CN", "STHeiti"); -pref("font.name-list.serif.zh-CN", "STSong,Heiti SC"); -pref("font.name-list.sans-serif.zh-CN", "STHeiti,Heiti SC"); -pref("font.name-list.monospace.zh-CN", "STHeiti,Heiti SC"); +pref("font.name.serif.zh-CN", "Times"); +pref("font.name.sans-serif.zh-CN", "Helvetica"); +pref("font.name.monospace.zh-CN", "Courier"); +pref("font.name-list.serif.zh-CN", "Times,STSong,Heiti SC"); +pref("font.name-list.sans-serif.zh-CN", "Helvetica,STHeiti,Heiti SC"); +pref("font.name-list.monospace.zh-CN", "Courier,STHeiti,Heiti SC"); pref("font.name.serif.zh-TW", "Times"); pref("font.name.sans-serif.zh-TW", "Helvetica"); @@ -3915,6 +3915,18 @@ pref("dom.mozApps.dev_mode", false); // Lowest localId for apps. pref("dom.mozApps.maxLocalId", 1000); +// XXX Security: You CANNOT safely add a new app store for +// installing privileged apps just by modifying this pref and +// adding the signing cert for that store to the cert trust +// database. *Any* origin listed can install apps signed with +// *any* certificate trusted; we don't try to maintain a strong +// association between certificate with installOrign. The +// expectation here is that in production builds the pref will +// contain exactly one origin. However, in custom development +// builds it may contain more than one origin so we can test +// different stages (dev, staging, prod) of the same app store. +pref("dom.mozApps.signed_apps_installable_from", "https://marketplace.firefox.com"); + // Minimum delay in milliseconds between network activity notifications (0 means // no notifications). The delay is the same for both download and upload, though // they are handled separately. This pref is only read once at startup: diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index aec4391f82fd..67f780698551 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -370,8 +370,8 @@ NeckoParent::AllocPRemoteOpenFile(const URIParams& aURI, if (PL_strnstr(requestedPath.BeginReading(), "/../", requestedPath.Length())) { printf_stderr("NeckoParent::AllocPRemoteOpenFile: " - "FATAL error: requested file URI contains '/../' " - "KILLING CHILD PROCESS\n"); + "FATAL error: requested file URI '%s' contains '/../' " + "KILLING CHILD PROCESS\n", requestedPath.get()); return nullptr; } } else { @@ -391,8 +391,10 @@ NeckoParent::AllocPRemoteOpenFile(const URIParams& aURI, NS_LossyConvertUTF16toASCII(uuid).get()); if (!requestedPath.Equals(mustMatch)) { printf_stderr("NeckoParent::AllocPRemoteOpenFile: " - "FATAL error: requesting file other than application.zip: " - "KILLING CHILD PROCESS\n"); + "FATAL error: app without webapps-manage permission is " + "requesting file '%s' but is only allowed to open its " + "own application.zip: KILLING CHILD PROCESS\n", + requestedPath.get()); return nullptr; } } diff --git a/netwerk/ipc/PRemoteOpenFile.ipdl b/netwerk/ipc/PRemoteOpenFile.ipdl index 89d22079d72a..5fc5db4bb662 100644 --- a/netwerk/ipc/PRemoteOpenFile.ipdl +++ b/netwerk/ipc/PRemoteOpenFile.ipdl @@ -26,8 +26,10 @@ parent: __delete__(); child: - // success/failure code, and if NS_SUCCEEDED(rv), an open file descriptor - FileOpened(FileDescriptor fd, nsresult rv); + // Your file handle is ready, Sir... + FileOpened(FileDescriptor fd); + // Trying to send invalid fd crashes, so we need separate method for failure + FileDidNotOpen(); }; diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp index ecd9afc3a647..89749abdd695 100644 --- a/netwerk/ipc/RemoteOpenFileChild.cpp +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -138,26 +138,39 @@ RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags, //----------------------------------------------------------------------------- bool -RemoteOpenFileChild::RecvFileOpened(const FileDescriptor& aFD, - const nsresult& aRV) +RemoteOpenFileChild::RecvFileOpened(const FileDescriptor& aFD) { #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) NS_NOTREACHED("osX and Windows shouldn't be doing IPDL here"); #else - if (NS_SUCCEEDED(aRV)) { - mNSPRFileDesc = PR_AllocFileDesc(aFD.PlatformHandle(), PR_GetFileMethods()); - } + mNSPRFileDesc = PR_AllocFileDesc(aFD.PlatformHandle(), PR_GetFileMethods()); MOZ_ASSERT(mListener); - - mListener->OnRemoteFileOpenComplete(aRV); - + mListener->OnRemoteFileOpenComplete(NS_OK); mListener = nullptr; // release ref to listener // This calls NeckoChild::DeallocPRemoteOpenFile(), which deletes |this| if // IPDL holds the last reference. Don't rely on |this| existing after here! Send__delete__(this); +#endif + return true; +} + +bool +RemoteOpenFileChild::RecvFileDidNotOpen() +{ +#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) + NS_NOTREACHED("osX and Windows shouldn't be doing IPDL here"); +#else + MOZ_ASSERT(mListener); + printf_stderr("RemoteOpenFileChild: file was not opened!\n"); + mListener->OnRemoteFileOpenComplete(NS_ERROR_FILE_NOT_FOUND); + mListener = nullptr; // release ref to listener + + // This calls NeckoChild::DeallocPRemoteOpenFile(), which deletes |this| if + // IPDL holds the last reference. Don't rely on |this| existing after here! + Send__delete__(this); #endif return true; diff --git a/netwerk/ipc/RemoteOpenFileChild.h b/netwerk/ipc/RemoteOpenFileChild.h index 260718572d91..44877d6d14ff 100644 --- a/netwerk/ipc/RemoteOpenFileChild.h +++ b/netwerk/ipc/RemoteOpenFileChild.h @@ -68,7 +68,8 @@ private: RemoteOpenFileChild(const RemoteOpenFileChild& other); protected: - virtual bool RecvFileOpened(const FileDescriptor&, const nsresult&); + virtual bool RecvFileOpened(const FileDescriptor&); + virtual bool RecvFileDidNotOpen(); // regular nsIFile object, that we forward most calls to. nsCOMPtr mFile; diff --git a/netwerk/ipc/RemoteOpenFileParent.cpp b/netwerk/ipc/RemoteOpenFileParent.cpp index 645b69b462ce..d8492bf30942 100644 --- a/netwerk/ipc/RemoteOpenFileParent.cpp +++ b/netwerk/ipc/RemoteOpenFileParent.cpp @@ -50,7 +50,7 @@ RemoteOpenFileParent::RecvAsyncOpenFile() if (NS_SUCCEEDED(rv)) { int fd = open(path.get(), O_RDONLY); if (fd != -1) { - unused << SendFileOpened(FileDescriptor(fd), NS_OK); + unused << SendFileOpened(FileDescriptor(fd)); // file handle needs to stay open until it's shared with child (and IPDL // is async, so hasn't happened yet). Close in destructor. mFd = fd; @@ -60,7 +60,8 @@ RemoteOpenFileParent::RecvAsyncOpenFile() // Note: sending an invalid file descriptor currently kills the child process: // but that's ok for our use case (failing to open application.jar). - unused << SendFileOpened(FileDescriptor(mFd), NS_ERROR_NOT_AVAILABLE); + printf_stderr("RemoteOpenFileParent: file '%s' was not found!\n", path.get()); + unused << SendFileDidNotOpen(); #endif // OS_TYPE return true; diff --git a/netwerk/mime/nsMimeTypes.h b/netwerk/mime/nsMimeTypes.h index 3356f0694c28..c4c1b12a303a 100644 --- a/netwerk/mime/nsMimeTypes.h +++ b/netwerk/mime/nsMimeTypes.h @@ -16,6 +16,7 @@ instead, to help catch typos, and make central management of them easier. */ +#define ANY_WILDCARD "*/*" #define AUDIO_WILDCARD "audio/*" #define IMAGE_WILDCARD "image/*" @@ -81,9 +82,11 @@ #define BINARY_OCTET_STREAM "binary/octet-stream" #define IMAGE_GIF "image/gif" -#define IMAGE_JPG "image/jpeg" -#define IMAGE_PJPG "image/pjpeg" +#define IMAGE_JPEG "image/jpeg" +#define IMAGE_JPG "image/jpg" +#define IMAGE_PJPEG "image/pjpeg" #define IMAGE_PNG "image/png" +#define IMAGE_X_PNG "image/x-png" #define IMAGE_PPM "image/x-portable-pixmap" #define IMAGE_XBM "image/x-xbitmap" #define IMAGE_XBM2 "image/x-xbm" @@ -91,7 +94,10 @@ #define IMAGE_ART "image/x-jg" #define IMAGE_TIFF "image/tiff" #define IMAGE_BMP "image/bmp" +#define IMAGE_BMP_MS "image/x-ms-bmp" #define IMAGE_ICO "image/x-icon" +#define IMAGE_ICO_MS "image/vnd.microsoft.icon" +#define IMAGE_ICON_MS "image/icon" #define IMAGE_MNG "video/x-mng" #define IMAGE_JNG "image/x-jng" #define IMAGE_SVG_XML "image/svg+xml" diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index b6328c6964f6..ea99f1466e45 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -632,7 +632,7 @@ nsHttpHandler::InitUserAgentComponents() ); #endif -#if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) +#if defined(ANDROID) || defined(MOZ_PLATFORM_MAEMO) || defined(MOZ_B2G) nsCOMPtr infoService = do_GetService("@mozilla.org/system-info;1"); NS_ASSERTION(infoService, "Could not find a system info service"); diff --git a/parser/htmlparser/public/nsHTMLTagList.h b/parser/htmlparser/public/nsHTMLTagList.h index 525023aa748a..898336f05f76 100644 --- a/parser/htmlparser/public/nsHTMLTagList.h +++ b/parser/htmlparser/public/nsHTMLTagList.h @@ -70,7 +70,7 @@ HTML_TAG(del, Mod) HTML_HTMLELEMENT_TAG(dfn) HTML_TAG(dir, Shared) HTML_TAG(div, Div) -HTML_TAG(dl, SharedList) +HTML_TAG(dl, DList) HTML_HTMLELEMENT_TAG(dt) HTML_HTMLELEMENT_TAG(em) HTML_TAG(embed, SharedObject) @@ -120,7 +120,7 @@ HTML_HTMLELEMENT_TAG(noembed) HTML_HTMLELEMENT_TAG(noframes) HTML_HTMLELEMENT_TAG(noscript) HTML_TAG(object, Object) -HTML_TAG(ol, SharedList) +HTML_TAG(ol, OList) HTML_TAG(optgroup, OptGroup) HTML_TAG(option, Option) HTML_TAG(output, Output) @@ -156,7 +156,7 @@ HTML_TAG(title, Title) HTML_TAG(tr, TableRow) HTML_HTMLELEMENT_TAG(tt) HTML_HTMLELEMENT_TAG(u) -HTML_TAG(ul, SharedList) +HTML_TAG(ul, UList) HTML_HTMLELEMENT_TAG(var) #if defined(MOZ_MEDIA) HTML_TAG(video, Video) diff --git a/security/build/b2g-app-root-cert.der b/security/build/b2g-app-root-cert.der index 490b8682b75c..9a7247c7e056 100644 Binary files a/security/build/b2g-app-root-cert.der and b/security/build/b2g-app-root-cert.der differ diff --git a/security/build/b2g-certdata.txt b/security/build/b2g-certdata.txt index 0e1984481432..2db616fe7a2c 100644 --- a/security/build/b2g-certdata.txt +++ b/security/build/b2g-certdata.txt @@ -2,13 +2,13 @@ # # Certificate "b2g-app-root-cert" # -# Issuer: C=US,ST=CA,L=Mountain View,O=Examplla Corporation,OU=Examplla CA,CN=Examplla Root CA 1 +# Issuer: C=US,ST=CA,L=Mountain View,O=MarketplaceTest Corporation,OU=MarketplaceTest CA,CN=MarketplaceTest Root CA 1 # Serial Number: 1 (0x1) -# Subject: C=US,ST=CA,L=Mountain View,O=Examplla Corporation,OU=Examplla CA,CN=Examplla Root CA 1 -# Not Valid Before: Wed Nov 21 23:00:03 2012 -# Not Valid After : Sat Nov 19 23:00:03 2022 -# Fingerprint (MD5): 05:14:37:02:CC:6B:3B:0F:EB:40:2D:FA:C7:CF:D3:B6 -# Fingerprint (SHA1): 33:F8:4F:CB:0C:1F:CE:35:32:6A:8C:A1:C3:CB:C9:BE:1F:B8:ED:9E +# Subject: C=US,ST=CA,L=Mountain View,O=MarketplaceTest Corporation,OU=MarketplaceTest CA,CN=MarketplaceTest Root CA 1 +# Not Valid Before: Thu Dec 13 20:14:18 2012 +# Not Valid After : Sun Dec 11 20:14:18 2022 +# Fingerprint (MD5): 16:FA:62:5A:EB:A6:E0:35:72:EB:95:B0:7D:58:EE:79 +# Fingerprint (SHA1): 36:C7:33:40:5E:5C:53:8E:BD:31:B9:0F:4A:6C:30:86:64:F2:D2:E1 CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE CKA_TOKEN CK_BBOOL CK_TRUE CKA_PRIVATE CK_BBOOL CK_FALSE @@ -16,125 +16,130 @@ CKA_MODIFIABLE CK_BBOOL CK_FALSE CKA_LABEL UTF8 "b2g-app-root-cert" CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 CKA_SUBJECT MULTILINE_OCTAL -\060\201\204\061\033\060\031\006\003\125\004\003\023\022\105\170 -\141\155\160\154\154\141\040\122\157\157\164\040\103\101\040\061 -\061\024\060\022\006\003\125\004\013\023\013\105\170\141\155\160 -\154\154\141\040\103\101\061\035\060\033\006\003\125\004\012\023 -\024\105\170\141\155\160\154\154\141\040\103\157\162\160\157\162 -\141\164\151\157\156\061\026\060\024\006\003\125\004\007\023\015 -\115\157\165\156\164\141\151\156\040\126\151\145\167\061\013\060 -\011\006\003\125\004\010\023\002\103\101\061\013\060\011\006\003 -\125\004\006\023\002\125\123 +\060\201\231\061\042\060\040\006\003\125\004\003\023\031\115\141 +\162\153\145\164\160\154\141\143\145\124\145\163\164\040\122\157 +\157\164\040\103\101\040\061\061\033\060\031\006\003\125\004\013 +\023\022\115\141\162\153\145\164\160\154\141\143\145\124\145\163 +\164\040\103\101\061\044\060\042\006\003\125\004\012\023\033\115 +\141\162\153\145\164\160\154\141\143\145\124\145\163\164\040\103 +\157\162\160\157\162\141\164\151\157\156\061\026\060\024\006\003 +\125\004\007\023\015\115\157\165\156\164\141\151\156\040\126\151 +\145\167\061\013\060\011\006\003\125\004\010\023\002\103\101\061 +\013\060\011\006\003\125\004\006\023\002\125\123 END CKA_ID UTF8 "0" CKA_ISSUER MULTILINE_OCTAL -\060\201\204\061\033\060\031\006\003\125\004\003\023\022\105\170 -\141\155\160\154\154\141\040\122\157\157\164\040\103\101\040\061 -\061\024\060\022\006\003\125\004\013\023\013\105\170\141\155\160 -\154\154\141\040\103\101\061\035\060\033\006\003\125\004\012\023 -\024\105\170\141\155\160\154\154\141\040\103\157\162\160\157\162 -\141\164\151\157\156\061\026\060\024\006\003\125\004\007\023\015 -\115\157\165\156\164\141\151\156\040\126\151\145\167\061\013\060 -\011\006\003\125\004\010\023\002\103\101\061\013\060\011\006\003 -\125\004\006\023\002\125\123 +\060\201\231\061\042\060\040\006\003\125\004\003\023\031\115\141 +\162\153\145\164\160\154\141\143\145\124\145\163\164\040\122\157 +\157\164\040\103\101\040\061\061\033\060\031\006\003\125\004\013 +\023\022\115\141\162\153\145\164\160\154\141\143\145\124\145\163 +\164\040\103\101\061\044\060\042\006\003\125\004\012\023\033\115 +\141\162\153\145\164\160\154\141\143\145\124\145\163\164\040\103 +\157\162\160\157\162\141\164\151\157\156\061\026\060\024\006\003 +\125\004\007\023\015\115\157\165\156\164\141\151\156\040\126\151 +\145\167\061\013\060\011\006\003\125\004\010\023\002\103\101\061 +\013\060\011\006\003\125\004\006\023\002\125\123 END CKA_SERIAL_NUMBER MULTILINE_OCTAL \002\001\001 END CKA_VALUE MULTILINE_OCTAL -\060\202\003\300\060\202\002\250\240\003\002\001\002\002\001\001 +\060\202\003\352\060\202\002\322\240\003\002\001\002\002\001\001 \060\015\006\011\052\206\110\206\367\015\001\001\005\005\000\060 -\201\204\061\033\060\031\006\003\125\004\003\023\022\105\170\141 -\155\160\154\154\141\040\122\157\157\164\040\103\101\040\061\061 -\024\060\022\006\003\125\004\013\023\013\105\170\141\155\160\154 -\154\141\040\103\101\061\035\060\033\006\003\125\004\012\023\024 -\105\170\141\155\160\154\154\141\040\103\157\162\160\157\162\141 -\164\151\157\156\061\026\060\024\006\003\125\004\007\023\015\115 -\157\165\156\164\141\151\156\040\126\151\145\167\061\013\060\011 -\006\003\125\004\010\023\002\103\101\061\013\060\011\006\003\125 -\004\006\023\002\125\123\060\036\027\015\061\062\061\061\062\061 -\062\063\060\060\060\063\132\027\015\062\062\061\061\061\071\062 -\063\060\060\060\063\132\060\201\204\061\033\060\031\006\003\125 -\004\003\023\022\105\170\141\155\160\154\154\141\040\122\157\157 -\164\040\103\101\040\061\061\024\060\022\006\003\125\004\013\023 -\013\105\170\141\155\160\154\154\141\040\103\101\061\035\060\033 -\006\003\125\004\012\023\024\105\170\141\155\160\154\154\141\040 -\103\157\162\160\157\162\141\164\151\157\156\061\026\060\024\006 -\003\125\004\007\023\015\115\157\165\156\164\141\151\156\040\126 -\151\145\167\061\013\060\011\006\003\125\004\010\023\002\103\101 -\061\013\060\011\006\003\125\004\006\023\002\125\123\060\202\001 -\042\060\015\006\011\052\206\110\206\367\015\001\001\001\005\000 -\003\202\001\017\000\060\202\001\012\002\202\001\001\000\332\255 -\200\271\353\277\343\215\020\027\261\053\357\061\075\375\164\371 -\224\036\227\017\253\373\233\061\207\106\273\172\037\376\227\235 -\110\121\303\065\154\340\335\037\375\010\321\256\073\267\176\335 -\322\363\251\051\077\315\135\143\321\335\266\250\120\322\302\327 -\361\033\256\304\267\126\325\330\245\267\125\020\314\366\244\360 -\331\032\174\242\105\075\220\177\133\317\332\353\274\257\322\123 -\341\122\031\065\242\175\070\042\123\073\205\351\057\330\305\174 -\004\073\324\153\123\021\255\111\012\114\310\374\357\375\001\007 -\034\374\235\111\112\161\036\323\223\224\262\336\340\237\035\111 -\202\307\122\255\053\257\065\037\370\235\014\073\207\317\110\376 -\205\112\335\337\126\343\234\003\225\033\356\072\371\261\175\343 -\153\262\257\031\230\116\271\120\201\273\025\374\105\346\127\326 -\314\334\335\106\336\114\154\066\360\072\312\245\003\237\377\302 -\153\271\337\167\277\057\103\145\325\205\235\374\016\120\277\171 -\031\373\362\103\001\175\115\141\017\310\122\343\127\131\232\244 -\077\056\263\351\044\273\075\104\226\224\247\321\266\317\002\003 -\001\000\001\243\073\060\071\060\017\006\003\125\035\023\001\001 -\377\004\005\060\003\001\001\377\060\016\006\003\125\035\017\001 -\001\377\004\004\003\002\002\004\060\026\006\003\125\035\045\001 -\001\377\004\014\060\012\006\010\053\006\001\005\005\007\003\003 -\060\015\006\011\052\206\110\206\367\015\001\001\005\005\000\003 -\202\001\001\000\227\120\113\310\374\002\002\163\167\074\162\233 -\024\157\215\261\001\075\201\165\056\113\103\327\222\142\076\145 -\222\041\227\066\023\175\323\144\016\372\277\163\362\102\176\256 -\003\107\075\330\255\306\304\223\266\271\146\152\140\017\166\056 -\034\021\052\133\010\117\117\131\214\134\365\032\155\335\074\120 -\036\002\361\020\235\366\203\145\262\353\267\277\063\377\210\355 -\361\172\077\220\252\003\375\172\260\105\311\317\023\337\231\053 -\327\212\052\073\241\371\145\114\255\052\302\031\150\001\164\260 -\173\124\206\234\355\225\056\224\156\200\066\000\143\325\111\341 -\157\175\324\305\126\071\053\325\163\372\057\335\207\140\041\306 -\030\360\233\211\373\331\252\360\067\306\274\047\357\164\316\244 -\157\122\247\030\326\300\352\031\037\261\176\333\342\336\221\207 -\014\214\142\016\072\305\370\046\140\133\074\137\210\120\126\301 -\202\350\333\347\342\253\325\330\276\160\074\066\266\261\021\056 -\064\152\370\352\226\311\100\376\303\225\273\146\307\275\066\310 -\211\226\344\146\126\041\237\037\213\001\325\112\113\054\250\110 -\042\057\035\220 +\201\231\061\042\060\040\006\003\125\004\003\023\031\115\141\162 +\153\145\164\160\154\141\143\145\124\145\163\164\040\122\157\157 +\164\040\103\101\040\061\061\033\060\031\006\003\125\004\013\023 +\022\115\141\162\153\145\164\160\154\141\143\145\124\145\163\164 +\040\103\101\061\044\060\042\006\003\125\004\012\023\033\115\141 +\162\153\145\164\160\154\141\143\145\124\145\163\164\040\103\157 +\162\160\157\162\141\164\151\157\156\061\026\060\024\006\003\125 +\004\007\023\015\115\157\165\156\164\141\151\156\040\126\151\145 +\167\061\013\060\011\006\003\125\004\010\023\002\103\101\061\013 +\060\011\006\003\125\004\006\023\002\125\123\060\036\027\015\061 +\062\061\062\061\063\062\060\061\064\061\070\132\027\015\062\062 +\061\062\061\061\062\060\061\064\061\070\132\060\201\231\061\042 +\060\040\006\003\125\004\003\023\031\115\141\162\153\145\164\160 +\154\141\143\145\124\145\163\164\040\122\157\157\164\040\103\101 +\040\061\061\033\060\031\006\003\125\004\013\023\022\115\141\162 +\153\145\164\160\154\141\143\145\124\145\163\164\040\103\101\061 +\044\060\042\006\003\125\004\012\023\033\115\141\162\153\145\164 +\160\154\141\143\145\124\145\163\164\040\103\157\162\160\157\162 +\141\164\151\157\156\061\026\060\024\006\003\125\004\007\023\015 +\115\157\165\156\164\141\151\156\040\126\151\145\167\061\013\060 +\011\006\003\125\004\010\023\002\103\101\061\013\060\011\006\003 +\125\004\006\023\002\125\123\060\202\001\042\060\015\006\011\052 +\206\110\206\367\015\001\001\001\005\000\003\202\001\017\000\060 +\202\001\012\002\202\001\001\000\274\203\257\274\062\142\054\152 +\063\120\342\237\046\350\213\024\052\144\011\127\322\132\151\033 +\346\154\213\124\062\111\265\217\032\077\207\305\147\365\256\372 +\041\212\170\064\145\372\245\010\226\224\355\200\170\341\172\213 +\237\240\324\261\263\230\040\044\173\201\146\126\062\335\124\334 +\170\013\101\150\057\225\047\154\254\127\047\100\154\121\262\216 +\071\346\055\363\125\263\222\321\127\003\334\347\102\352\053\317 +\176\366\343\114\355\001\241\321\374\152\344\144\075\244\324\317 +\200\064\321\034\000\167\036\251\316\330\317\073\370\262\170\157 +\217\106\067\300\200\100\022\053\265\076\373\104\163\107\313\215 +\223\262\325\024\120\050\111\352\201\174\315\051\222\320\367\224 +\363\233\217\301\324\353\050\077\314\217\262\327\163\142\345\065 +\100\063\144\000\107\213\240\220\203\037\257\054\245\040\213\225 +\313\321\156\174\342\236\332\300\301\016\377\355\233\216\207\066 +\023\256\062\275\250\035\250\143\365\041\271\025\277\156\273\330 +\330\151\257\105\122\272\220\234\015\216\375\335\302\354\042\132 +\076\204\122\004\222\141\022\367\002\003\001\000\001\243\073\060 +\071\060\017\006\003\125\035\023\001\001\377\004\005\060\003\001 +\001\377\060\016\006\003\125\035\017\001\001\377\004\004\003\002 +\002\004\060\026\006\003\125\035\045\001\001\377\004\014\060\012 +\006\010\053\006\001\005\005\007\003\003\060\015\006\011\052\206 +\110\206\367\015\001\001\005\005\000\003\202\001\001\000\164\037 +\012\101\256\130\023\311\005\143\361\352\336\021\173\017\251\137 +\304\134\323\311\031\260\214\364\346\161\364\162\363\236\106\347 +\146\301\371\352\373\167\174\323\065\106\141\306\131\200\024\152 +\116\114\267\040\036\047\244\007\066\205\022\250\172\177\250\103 +\120\325\214\013\131\342\052\117\364\057\344\071\371\003\337\204 +\207\065\032\261\206\245\323\050\222\061\063\026\035\217\124\360 +\054\234\045\357\356\107\011\165\071\253\327\040\174\341\353\137 +\206\352\044\315\373\173\322\121\041\112\215\305\205\003\300\012 +\102\326\257\322\351\232\243\370\053\304\063\173\203\173\174\255 +\376\251\161\362\233\261\361\343\327\005\357\011\161\060\332\107 +\004\222\324\267\334\341\155\226\104\104\173\050\333\262\305\021 +\327\053\146\213\335\204\312\275\177\344\045\236\147\176\367\301 +\004\061\107\346\220\347\054\156\333\071\210\010\275\336\133\160 +\051\173\225\027\307\260\103\371\354\322\075\232\242\335\372\041 +\375\250\267\052\203\015\226\151\315\100\257\353\235\351\214\165 +\306\351\144\072\025\076\343\163\320\131\344\331\332\203 END # Trust for "b2g-app-root-cert" -# Issuer: C=US,ST=CA,L=Mountain View,O=Examplla Corporation,OU=Examplla CA,CN=Examplla Root CA 1 +# Issuer: C=US,ST=CA,L=Mountain View,O=MarketplaceTest Corporation,OU=MarketplaceTest CA,CN=MarketplaceTest Root CA 1 # Serial Number: 1 (0x1) -# Subject: C=US,ST=CA,L=Mountain View,O=Examplla Corporation,OU=Examplla CA,CN=Examplla Root CA 1 -# Not Valid Before: Wed Nov 21 23:00:03 2012 -# Not Valid After : Sat Nov 19 23:00:03 2022 -# Fingerprint (MD5): 05:14:37:02:CC:6B:3B:0F:EB:40:2D:FA:C7:CF:D3:B6 -# Fingerprint (SHA1): 33:F8:4F:CB:0C:1F:CE:35:32:6A:8C:A1:C3:CB:C9:BE:1F:B8:ED:9E +# Subject: C=US,ST=CA,L=Mountain View,O=MarketplaceTest Corporation,OU=MarketplaceTest CA,CN=MarketplaceTest Root CA 1 +# Not Valid Before: Thu Dec 13 20:14:18 2012 +# Not Valid After : Sun Dec 11 20:14:18 2022 +# Fingerprint (MD5): 16:FA:62:5A:EB:A6:E0:35:72:EB:95:B0:7D:58:EE:79 +# Fingerprint (SHA1): 36:C7:33:40:5E:5C:53:8E:BD:31:B9:0F:4A:6C:30:86:64:F2:D2:E1 CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST CKA_TOKEN CK_BBOOL CK_TRUE CKA_PRIVATE CK_BBOOL CK_FALSE CKA_MODIFIABLE CK_BBOOL CK_FALSE CKA_LABEL UTF8 "b2g-app-root-cert" CKA_CERT_SHA1_HASH MULTILINE_OCTAL -\063\370\117\313\014\037\316\065\062\152\214\241\303\313\311\276 -\037\270\355\236 +\066\307\063\100\136\134\123\216\275\061\271\017\112\154\060\206 +\144\362\322\341 END CKA_CERT_MD5_HASH MULTILINE_OCTAL -\005\024\067\002\314\153\073\017\353\100\055\372\307\317\323\266 +\026\372\142\132\353\246\340\065\162\353\225\260\175\130\356\171 END CKA_ISSUER MULTILINE_OCTAL -\060\201\204\061\033\060\031\006\003\125\004\003\023\022\105\170 -\141\155\160\154\154\141\040\122\157\157\164\040\103\101\040\061 -\061\024\060\022\006\003\125\004\013\023\013\105\170\141\155\160 -\154\154\141\040\103\101\061\035\060\033\006\003\125\004\012\023 -\024\105\170\141\155\160\154\154\141\040\103\157\162\160\157\162 -\141\164\151\157\156\061\026\060\024\006\003\125\004\007\023\015 -\115\157\165\156\164\141\151\156\040\126\151\145\167\061\013\060 -\011\006\003\125\004\010\023\002\103\101\061\013\060\011\006\003 -\125\004\006\023\002\125\123 +\060\201\231\061\042\060\040\006\003\125\004\003\023\031\115\141 +\162\153\145\164\160\154\141\143\145\124\145\163\164\040\122\157 +\157\164\040\103\101\040\061\061\033\060\031\006\003\125\004\013 +\023\022\115\141\162\153\145\164\160\154\141\143\145\124\145\163 +\164\040\103\101\061\044\060\042\006\003\125\004\012\023\033\115 +\141\162\153\145\164\160\154\141\143\145\124\145\163\164\040\103 +\157\162\160\157\162\141\164\151\157\156\061\026\060\024\006\003 +\125\004\007\023\015\115\157\165\156\164\141\151\156\040\126\151 +\145\167\061\013\060\011\006\003\125\004\010\023\002\103\101\061 +\013\060\011\006\003\125\004\006\023\002\125\123 END CKA_SERIAL_NUMBER MULTILINE_OCTAL \002\001\001 diff --git a/security/manager/boot/src/nsStrictTransportSecurityService.cpp b/security/manager/boot/src/nsStrictTransportSecurityService.cpp index a874f79848e9..e27a2424ccf6 100644 --- a/security/manager/boot/src/nsStrictTransportSecurityService.cpp +++ b/security/manager/boot/src/nsStrictTransportSecurityService.cpp @@ -395,7 +395,7 @@ nsStrictTransportSecurityService::GetPreloadListEntry(const char *aHost) if (mUsePreloadList && currentTime < gPreloadListExpirationTime) { return (const nsSTSPreload *) bsearch(aHost, kSTSPreloadList, - PR_ARRAY_SIZE(kSTSPreloadList), + mozilla::ArrayLength(kSTSPreloadList), sizeof(nsSTSPreload), STSPreloadCompare); } diff --git a/security/manager/ssl/src/SharedSSLState.cpp b/security/manager/ssl/src/SharedSSLState.cpp index 3aa3d9b2ae8c..e31cf7e2a45a 100644 --- a/security/manager/ssl/src/SharedSSLState.cpp +++ b/security/manager/ssl/src/SharedSSLState.cpp @@ -25,8 +25,8 @@ using mozilla::unused; namespace { -static PRInt32 sCertOverrideSvcExists = 0; -static PRInt32 sCertDBExists = 0; +static int32_t sCertOverrideSvcExists = 0; +static int32_t sCertDBExists = 0; class MainThreadClearer : public SyncRunnableBase { diff --git a/security/manager/ssl/src/nsIdentityChecking.cpp b/security/manager/ssl/src/nsIdentityChecking.cpp index a32be397d3df..fafc127c76b9 100644 --- a/security/manager/ssl/src/nsIdentityChecking.cpp +++ b/security/manager/ssl/src/nsIdentityChecking.cpp @@ -1233,10 +1233,7 @@ nsNSSCertificate::hasValidEVOidTag(SECOidTag &resultOidTag, bool &validEV) CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST | CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE; - // We need a PRUint64 here instead of a nice int64_t (until bug 634793 is - // fixed) to match the type used in security/nss/lib/certdb/certt.h for - // cert_rev_flags_per_method. - PRUint64 methodFlags[2]; + uint64_t methodFlags[2]; methodFlags[cert_revocation_method_crl] = revMethodFlags; methodFlags[cert_revocation_method_ocsp] = revMethodFlags; diff --git a/security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zip b/security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zip index 0f828fb858b3..ec137ea14ad6 100644 Binary files a/security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zip and b/security/manager/ssl/tests/unit/test_signed_apps/privileged-app-test-1.0.zip differ diff --git a/services/sync/tests/unit/test_history_tracker.js b/services/sync/tests/unit/test_history_tracker.js index d6f6fc9baa1a..14c44eee0afe 100644 --- a/services/sync/tests/unit/test_history_tracker.js +++ b/services/sync/tests/unit/test_history_tracker.js @@ -2,6 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/PlacesUtils.jsm"); Cu.import("resource://services-sync/engines.js"); Cu.import("resource://services-sync/constants.js"); Cu.import("resource://services-sync/engines/history.js"); @@ -30,7 +31,27 @@ tracker.persistChangedIDs = false; let _counter = 0; function addVisit() { let uri = Utils.makeURI("http://getfirefox.com/" + _counter); - PlacesUtils.history.addVisit(uri, Date.now() * 1000, null, 1, false, 0); + let place = { + uri: uri, + visits: [ { + visitDate: Date.now() * 1000, + transitionType: PlacesUtils.history.TRANSITION_LINK + } ] + }; + let cb = Async.makeSpinningCallback(); + PlacesUtils.asyncHistory.updatePlaces(place, { + handleError: function Add_handleError() { + cb(new Error("Error adding history entry")); + }, + handleResult: function Add_handleResult() { + cb(); + }, + handleCompletion: function Add_handleCompletion() { + // Nothing to do + } + }); + // Spin the event loop to embed this async call in a sync API + cb.wait(); _counter++; return uri; } diff --git a/services/sync/tps/extensions/tps/modules/history.jsm b/services/sync/tps/extensions/tps/modules/history.jsm index 992281da278e..f3a274cc7024 100644 --- a/services/sync/tps/extensions/tps/modules/history.jsm +++ b/services/sync/tps/extensions/tps/modules/history.jsm @@ -108,16 +108,33 @@ var HistoryEntry = { "History entry in test file must have both 'visits' " + "and 'uri' properties"); let uri = Services.io.newURI(item.uri, null, null); + let place = { + uri: uri, + visits: [] + }; for each (visit in item.visits) { - let visitId = PlacesUtils.history.addVisit( - uri, - usSinceEpoch + (visit.date * 60 * 60 * 1000 * 1000), - null, visit.type, - visit.type == 5 || visit.type == 6, 0); - Logger.AssertTrue(visitId, "Error adding history entry"); - if ("title" in item) - PlacesUtils.history.setPageTitle(uri, item.title); + place.visits.push({ + visitDate: usSinceEpoch + (visit.date * 60 * 60 * 1000 * 1000), + transitionType: visit.type + }); } + if ("title" in item) { + place.title = item.title; + } + let cb = Async.makeSpinningCallback(); + PlacesUtils.asyncHistory.updatePlaces(place, { + handleError: function Add_handleError() { + cb(new Error("Error adding history entry")); + }, + handleResult: function Add_handleResult() { + cb(); + }, + handleCompletion: function Add_handleCompletion() { + // Nothing to do + } + }); + // Spin the event loop to embed this async call in a sync API + cb.wait(); }, /** diff --git a/testing/marionette/client/marionette/emulator.py b/testing/marionette/client/marionette/emulator.py index 811a83b55d8a..316b6dd2fd52 100644 --- a/testing/marionette/client/marionette/emulator.py +++ b/testing/marionette/client/marionette/emulator.py @@ -338,7 +338,10 @@ waitFor( # setup DNS fix for networking self._run_adb(['shell', 'setprop', 'net.dns1', '10.0.2.3']) - def setup(self, marionette, gecko_path=None, load_early=False): + def setup(self, marionette, gecko_path=None, load_early=False, busybox=None): + if busybox: + self.install_busybox(busybox) + if gecko_path: if load_early: # Inject prefs into the profile now, since we have to restart @@ -374,8 +377,6 @@ waitFor( # gecko in order to avoid an adb bug in which adb will sometimes # hang indefinitely while copying large files to the system # partition. - push_attempts = 10 - print 'installing gecko binaries...' # see bug 809437 for the path that lead to this madness @@ -384,18 +385,7 @@ waitFor( self._run_adb(['remount']) self.dm.removeDir('/data/local/b2g') self.dm.mkDir('/data/local/b2g') - for root, dirs, files in os.walk(gecko_path): - for filename in files: - rel_path = os.path.relpath(os.path.join(root, filename), gecko_path) - data_local_file = os.path.join('/data/local/b2g', rel_path) - for retry in range(1, push_attempts + 1): - print 'pushing', data_local_file, '(attempt %s of %s)' % (retry, push_attempts) - try: - self.dm.pushFile(os.path.join(root, filename), data_local_file) - break - except DMError: - if retry == push_attempts: - raise + self.dm.pushDir(gecko_path, '/data/local/b2g', retryLimit=10) self.dm.shellCheckOutput(['stop', 'b2g']) @@ -404,15 +394,11 @@ waitFor( rel_path = os.path.relpath(os.path.join(root, filename), gecko_path) data_local_file = os.path.join('/data/local/b2g', rel_path) system_b2g_file = os.path.join('/system/b2g', rel_path) - print 'copying', data_local_file, 'to', system_b2g_file - try: - self.dm.shellCheckOutput(['dd', - 'if=%s' % data_local_file, - 'of=%s' % system_b2g_file]) - except DMError: - if retry == push_attempts: - raise + print 'copying', data_local_file, 'to', system_b2g_file + self.dm.shellCheckOutput(['dd', + 'if=%s' % data_local_file, + 'of=%s' % system_b2g_file]) self.restart_b2g() except (DMError, MarionetteException): diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index 329ba083fb0d..f27b7365146c 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -150,9 +150,8 @@ class Marionette(object): if emulator: self.emulator.setup(self, gecko_path=gecko_path, - load_early=load_early) - if busybox: - self.emulator.install_busybox(busybox) + load_early=load_early, + busybox=busybox) def __del__(self): if self.emulator: diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py index 93f3ace07f16..319fd31cf6f7 100644 --- a/testing/mochitest/runtestsb2g.py +++ b/testing/mochitest/runtestsb2g.py @@ -102,6 +102,10 @@ class B2GOptions(MochitestOptions): type="string", dest="logcat_dir", help="directory to store logcat dump files") defaults["logcat_dir"] = None + self.add_option('--busybox', action='store', + type='string', dest='busybox', + help="Path to busybox binary to install on device") + defaults['busybox'] = None defaults["remoteTestRoot"] = "/data/local/tests" defaults["logFile"] = "mochitest.log" @@ -482,6 +486,8 @@ def main(): kwargs['gecko_path'] = options.geckoPath if options.logcat_dir: kwargs['logcat_dir'] = options.logcat_dir + if options.busybox: + kwargs['busybox'] = options.busybox # needless to say sdcard is only valid if using an emulator if options.sdcard: kwargs['sdcard'] = options.sdcard diff --git a/testing/mozbase/mozcrash/README.md b/testing/mozbase/mozcrash/README.md deleted file mode 100644 index ae6c8d54dec3..000000000000 --- a/testing/mozbase/mozcrash/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Mozcrash - -Package for getting a stack trace out of processes that have crashed and left behind a minidump file using the Google Breakpad library. - - -## Usage example - -TODO - - import mozcrash - - #... diff --git a/testing/mozbase/mozcrash/mozcrash/__init__.py b/testing/mozbase/mozcrash/mozcrash/__init__.py index 35e4dce462b9..469adc431178 100644 --- a/testing/mozbase/mozcrash/mozcrash/__init__.py +++ b/testing/mozbase/mozcrash/mozcrash/__init__.py @@ -1,5 +1,8 @@ # 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/. +""" +mozcrash is a library for getting a stack trace out of processes that have crashed and left behind a minidump file using the Google Breakpad library. +""" from mozcrash import * diff --git a/testing/mozbase/mozcrash/mozcrash/mozcrash.py b/testing/mozbase/mozcrash/mozcrash/mozcrash.py index f56d70e345f2..f22e06e85df2 100644 --- a/testing/mozbase/mozcrash/mozcrash/mozcrash.py +++ b/testing/mozbase/mozcrash/mozcrash/mozcrash.py @@ -2,10 +2,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. -from __future__ import with_statement __all__ = ['check_for_crashes'] -import os, sys, glob, urllib2, tempfile, subprocess, shutil, urlparse, zipfile +import os, sys, glob, urllib2, tempfile, re, subprocess, shutil, urlparse, zipfile import mozlog def is_url(thing): @@ -13,7 +12,11 @@ def is_url(thing): Return True if thing looks like a URL. """ # We want to download URLs like http://... but not Windows paths like c:\... - return len(urlparse.urlparse(thing).scheme) >= 2 + parsed = urlparse.urlparse(thing) + if 'scheme' in parsed: + return len(parsed.scheme) >= 2 + else: + return len(parsed[0]) >= 2 def extractall(zip, path = None): """ @@ -33,29 +36,38 @@ def extractall(zip, path = None): path = os.path.split(filename)[0] if not os.path.isdir(path): os.makedirs(path) - with open(filename, "wb") as dest: - dest.write(zip.read(name)) + + try: + f = open(filename, "wb") + f.write(zip.read(name)) + finally: + f.close() def check_for_crashes(dump_directory, symbols_path, stackwalk_binary=None, dump_save_path=None, test_name=None): """ - Print a stack trace for minidumps left behind by a crashing program. + Print a stack trace for minidump files left behind by a crashing program. - Arguments: - dump_directory: The directory in which to look for minidumps. - symbols_path: The path to symbols to use for dump processing. - This can either be a path to a directory - containing Breakpad-format symbols, or a URL - to a zip file containing a set of symbols. - stackwalk_binary: The path to the minidump_stackwalk binary. - If not set, the environment variable - MINIDUMP_STACKWALK will be checked. - dump_save_path: A directory in which to copy minidump files - for safekeeping. If not set, the environment - variable MINIDUMP_SAVE_PATH will be checked. - test_name: The test name to be used in log output. + `dump_directory` will be searched for minidump files. Any minidump files found will + have `stackwalk_binary` executed on them, with `symbols_path` passed as an extra + argument. + + `stackwalk_binary` should be a path to the minidump_stackwalk binary. + If `stackwalk_binary` is not set, the MINIDUMP_STACKWALK environment variable + will be checked and its value used if it is not empty. + + `symbols_path` should be a path to a directory containing symbols to use for + dump processing. This can either be a path to a directory containing Breakpad-format + symbols, or a URL to a zip file containing a set of symbols. + + If `dump_save_path` is set, it should be a path to a directory in which to copy minidump + files for safekeeping after a stack trace has been printed. If not set, the environment + variable MINIDUMP_SAVE_PATH will be checked and its value used if it is not empty. + + If `test_name` is set it will be used as the test name in log output. If not set the + filename of the calling function will be used. Returns True if any minidumps were found, False otherwise. """ @@ -75,10 +87,9 @@ def check_for_crashes(dump_directory, symbols_path, if len(dumps) == 0: return False - found_crash = False remove_symbols = False # If our symbols are at a remote URL, download them now - if is_url(symbols_path): + if symbols_path and is_url(symbols_path): log.info("Downloading symbols from: %s", symbols_path) remove_symbols = True # Get the symbols and write them to a temporary zipfile @@ -94,8 +105,9 @@ def check_for_crashes(dump_directory, symbols_path, try: for d in dumps: - log.info("PROCESS-CRASH | %s | application crashed (minidump found)", test_name) - log.info("Crash dump filename: %s", d) + stackwalk_output = [] + stackwalk_output.append("Crash dump filename: " + d) + top_frame = None if symbols_path and stackwalk_binary and os.path.exists(stackwalk_binary): # run minidump_stackwalk p = subprocess.Popen([stackwalk_binary, d, symbols_path], @@ -105,19 +117,36 @@ def check_for_crashes(dump_directory, symbols_path, if len(out) > 3: # minidump_stackwalk is chatty, # so ignore stderr when it succeeds. - print out + stackwalk_output.append(out) + # The top frame of the crash is always the line after "Thread N (crashed)" + # Examples: + # 0 libc.so + 0xa888 + # 0 libnss3.so!nssCertificate_Destroy [certificate.c : 102 + 0x0] + # 0 mozjs.dll!js::GlobalObject::getDebuggers() [GlobalObject.cpp:89df18f9b6da : 580 + 0x0] + # 0 libxul.so!void js::gc::MarkInternal(JSTracer*, JSObject**) [Marking.cpp : 92 + 0x28] + lines = out.splitlines() + for i, line in enumerate(lines): + if "(crashed)" in line: + match = re.search(r"^ 0 (?:.*!)?(?:void )?([^\[]+)", lines[i+1]) + if match: + top_frame = "@ %s" % match.group(1).strip() + break else: - print "stderr from minidump_stackwalk:" - print err + stackwalk_output.append("stderr from minidump_stackwalk:") + stackwalk_output.append(err) if p.returncode != 0: - log.error("minidump_stackwalk exited with return code %d", p.returncode) + stackwalk_output.append("minidump_stackwalk exited with return code %d" % p.returncode) else: if not symbols_path: - log.warn("No symbols path given, can't process dump.") + stackwalk_output.append("No symbols path given, can't process dump.") if not stackwalk_binary: - log.warn("MINIDUMP_STACKWALK not set, can't process dump.") + stackwalk_output.append("MINIDUMP_STACKWALK not set, can't process dump.") elif stackwalk_binary and not os.path.exists(stackwalk_binary): - log.warn("MINIDUMP_STACKWALK binary not found: %s", stackwalk_binary) + stackwalk_output.append("MINIDUMP_STACKWALK binary not found: %s" % stackwalk_binary) + if not top_frame: + top_frame = "Unknown top frame" + log.error("PROCESS-CRASH | %s | application crashed [%s]", test_name, top_frame) + print '\n'.join(stackwalk_output) if dump_save_path is None: dump_save_path = os.environ.get('MINIDUMP_SAVE_PATH', None) if dump_save_path: @@ -129,9 +158,8 @@ def check_for_crashes(dump_directory, symbols_path, extra = os.path.splitext(d)[0] + ".extra" if os.path.exists(extra): os.remove(extra) - found_crash = True finally: if remove_symbols: shutil.rmtree(symbols_path) - return found_crash + return True diff --git a/testing/mozbase/mozcrash/setup.py b/testing/mozbase/mozcrash/setup.py index 133d06bd0526..7d2be8a88823 100644 --- a/testing/mozbase/mozcrash/setup.py +++ b/testing/mozbase/mozcrash/setup.py @@ -2,26 +2,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/. - -import os from setuptools import setup -PACKAGE_VERSION = '0.1' - -# get documentation from the README -try: - here = os.path.dirname(os.path.abspath(__file__)) - description = file(os.path.join(here, 'README.md')).read() -except (OSError, IOError): - description = '' +PACKAGE_VERSION = '0.3' # dependencies -deps = [''] +deps = [] setup(name='mozcrash', version=PACKAGE_VERSION, - description="Package for printing stack traces from minidumps left behind by crashed processes.", - long_description=description, + description="Library for printing stack traces from minidumps left behind by crashed processes", + long_description="see http://mozbase.readthedocs.org/", classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers keywords='mozilla', author='Mozilla Automation and Tools team', diff --git a/toolkit/components/osfile/osfile_win_front.jsm b/toolkit/components/osfile/osfile_win_front.jsm index 5c1c75999033..4ad7da053ce2 100644 --- a/toolkit/components/osfile/osfile_win_front.jsm +++ b/toolkit/components/osfile/osfile_win_front.jsm @@ -314,7 +314,7 @@ }; /** - * Checks if a file exists + * Checks if a file or directory exists * * @param {string} path The path to the file. * @@ -322,7 +322,7 @@ */ File.exists = function Win_exists(path) { try { - let file = File.open(path); + let file = File.open(path, FILE_STAT_MODE, FILE_STAT_OPTIONS); file.close(); return true; } catch (x) { diff --git a/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js b/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js index f24498a6271b..3a7466b7cf48 100644 --- a/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js +++ b/toolkit/components/osfile/tests/mochi/worker_test_osfile_front.js @@ -787,5 +787,11 @@ function test_exists_file() info("test_exists_file: starting"); ok(OS.File.exists(file_name), "test_exists_file: file exists (OS.File.exists)"); ok(!OS.File.exists(file_name + ".tmp"), "test_exists_file: file does not exists (OS.File.exists)"); + + let dir_name = OS.Path.join("chrome", "toolkit", "components" ,"osfile", + "tests", "mochi"); + ok(OS.File.exists(dir_name), "test_exists_file: directory exists"); + ok(!OS.File.exists(dir_name) + ".tmp", "test_exists_file: directory does not exist"); + info("test_exists_file: complete"); } diff --git a/toolkit/components/places/nsNavHistory.cpp b/toolkit/components/places/nsNavHistory.cpp index 9df2bd042558..77604e7049ce 100644 --- a/toolkit/components/places/nsNavHistory.cpp +++ b/toolkit/components/places/nsNavHistory.cpp @@ -894,7 +894,6 @@ nsNavHistory::GetUpdateRequirements(const nsCOMArray& aQuerie bool nonTimeBasedItems = false; bool domainBasedItems = false; - bool queryContainsTransitions = false; for (i = 0; i < aQueries.Count(); i ++) { nsNavHistoryQuery* query = aQueries[i]; @@ -905,9 +904,6 @@ nsNavHistory::GetUpdateRequirements(const nsCOMArray& aQuerie return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS; } - if (query->Transitions().Length() > 0) - queryContainsTransitions = true; - // Note: we don't currently have any complex non-bookmarked items, but these // are expected to be added. Put detection of these items here. if (!query->SearchTerms().IsEmpty() || @@ -923,9 +919,6 @@ nsNavHistory::GetUpdateRequirements(const nsCOMArray& aQuerie nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY) return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS; - if (queryContainsTransitions) - return QUERYUPDATE_COMPLEX; - // Whenever there is a maximum number of results, // and we are not a bookmark query we must requery. This // is because we can't generally know if any given addition/change causes @@ -937,6 +930,7 @@ nsNavHistory::GetUpdateRequirements(const nsCOMArray& aQuerie return QUERYUPDATE_HOST; if (aQueries.Count() == 1 && !nonTimeBasedItems) return QUERYUPDATE_TIME; + return QUERYUPDATE_SIMPLE; } @@ -1061,6 +1055,14 @@ nsNavHistory::EvaluateQueryForNode(const nsCOMArray& aQueries } } + // Transitions matching. + const nsTArray& transitions = query->Transitions(); + if (aNode->mTransitionType > 0 && + transitions.Length() && + !transitions.Contains(aNode->mTransitionType)) { + continue; // transition doesn't match. + } + // If we ever make it to the bottom of this loop, that means it passed all // tests for the given query. Since queries are ORed together, that means // it passed everything and we are done. diff --git a/toolkit/components/places/nsNavHistoryResult.cpp b/toolkit/components/places/nsNavHistoryResult.cpp index 99e061315abd..e7ee2c73b9e4 100644 --- a/toolkit/components/places/nsNavHistoryResult.cpp +++ b/toolkit/components/places/nsNavHistoryResult.cpp @@ -106,7 +106,8 @@ nsNavHistoryResultNode::nsNavHistoryResultNode( mLastModified(0), mIndentLevel(-1), mFrecency(0), - mHidden(false) + mHidden(false), + mTransitionType(0) { mTags.SetIsVoid(true); } @@ -1952,7 +1953,8 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode( true, aOptions), mQueries(aQueries), mContentsValid(false), - mBatchChanges(0) + mBatchChanges(0), + mTransitions(mQueries[0]->Transitions()) { NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query"); @@ -1962,6 +1964,16 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode( mLiveUpdate = history->GetUpdateRequirements(mQueries, mOptions, &mHasSearchTerms); } + + // Collect transitions shared by all queries. + for (int32_t i = 1; i < mQueries.Count(); ++i) { + const nsTArray& queryTransitions = mQueries[i]->Transitions(); + for (uint32_t j = 0; j < mTransitions.Length() ; ++j) { + uint32_t transition = mTransitions.SafeElementAt(j, 0); + if (transition && !queryTransitions.Contains(transition)) + mTransitions.RemoveElement(transition); + } + } } nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode( @@ -1974,7 +1986,8 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode( true, aOptions), mQueries(aQueries), mContentsValid(false), - mBatchChanges(0) + mBatchChanges(0), + mTransitions(mQueries[0]->Transitions()) { NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query"); @@ -1984,6 +1997,16 @@ nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode( mLiveUpdate = history->GetUpdateRequirements(mQueries, mOptions, &mHasSearchTerms); } + + // Collect transitions shared by all queries. + for (int32_t i = 1; i < mQueries.Count(); ++i) { + const nsTArray& queryTransitions = mQueries[i]->Transitions(); + for (uint32_t j = 0; j < mTransitions.Length() ; ++j) { + uint32_t transition = mTransitions.SafeElementAt(j, 0); + if (transition && !queryTransitions.Contains(transition)) + mTransitions.RemoveElement(transition); + } + } } nsNavHistoryQueryResultNode::~nsNavHistoryQueryResultNode() { @@ -2603,12 +2626,19 @@ nsNavHistoryQueryResultNode::OnVisit(nsIURI* aURI, int64_t aVisitId, // QUERYUPDATE_SIMPLE case. } case QUERYUPDATE_SIMPLE: { + // If all of the queries are filtered by some transitions, skip the + // update if aTransitionType doesn't match any of them. + if (mTransitions.Length() > 0 && !mTransitions.Contains(aTransitionType)) + return NS_OK; + // The history service can tell us whether the new item should appear // in the result. We first have to construct a node for it to check. rv = history->VisitIdToResultNode(aVisitId, mOptions, getter_AddRefs(addition)); - if (NS_FAILED(rv) || !addition || - !history->EvaluateQueryForNode(mQueries, mOptions, addition)) + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_STATE(addition); + addition->mTransitionType = aTransitionType; + if (!history->EvaluateQueryForNode(mQueries, mOptions, addition)) return NS_OK; // don't need to include in our query break; } @@ -2873,7 +2903,7 @@ nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, // All visits for aTransitionType have been removed, if the query is // filtering on such transition type, this is equivalent to an onDeleteURI // notification. - if ((mQueries[0]->Transitions()).Contains(aTransitionType)) { + if (mTransitions.Length() > 0 && mTransitions.Contains(aTransitionType)) { nsresult rv = OnDeleteURI(aURI, aGUID, aReason); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/toolkit/components/places/nsNavHistoryResult.h b/toolkit/components/places/nsNavHistoryResult.h index 2fa1cb836d22..b2f216681c0b 100644 --- a/toolkit/components/places/nsNavHistoryResult.h +++ b/toolkit/components/places/nsNavHistoryResult.h @@ -382,6 +382,9 @@ public: // Hidden status of the page. Valid only for URI nodes. bool mHidden; + + // Transition type used when this node represents a single visit. + int32_t mTransitionType; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode, NS_NAVHISTORYRESULTNODE_IID) @@ -749,6 +752,9 @@ public: nsresult NotifyIfTagsChanged(nsIURI* aURI); uint32_t mBatchChanges; + + // Tracks transition type filters shared by all mQueries. + nsTArray mTransitions; }; diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp index 83915b5f6f06..3a8e7495c75d 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -314,19 +314,23 @@ nsAppStartup::Quit(uint32_t aMode) // If we're considering quitting, we will only do so if: if (ferocity == eConsiderQuit) { +#ifdef XP_MACOSX + nsCOMPtr appShell + (do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); + bool hasHiddenPrivateWindow = false; + if (appShell) { + appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow); + } + int32_t suspiciousCount = hasHiddenPrivateWindow ? 2 : 1; +#endif + if (mConsiderQuitStopper == 0) { // there are no windows... ferocity = eAttemptQuit; } #ifdef XP_MACOSX -#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING - else if (mConsiderQuitStopper == 2) { -#else - else if (mConsiderQuitStopper == 1) { -#endif + else if (mConsiderQuitStopper == suspiciousCount) { // ... or there is only a hiddenWindow left, and it's useless: - nsCOMPtr appShell - (do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); // Failure shouldn't be fatal, but will abort quit attempt: if (!appShell) @@ -337,11 +341,15 @@ nsAppStartup::Quit(uint32_t aMode) nsCOMPtr hiddenWindow; appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow)); #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING - nsCOMPtr hiddenPrivateWindow; - appShell->GetHiddenPrivateWindow(getter_AddRefs(hiddenPrivateWindow)); // If the remaining windows are useful, we won't quit: - if ((!hiddenWindow && !hiddenPrivateWindow) || usefulHiddenWindow) + nsCOMPtr hiddenPrivateWindow; + if (hasHiddenPrivateWindow) { + appShell->GetHiddenPrivateWindow(getter_AddRefs(hiddenPrivateWindow)); + if ((!hiddenWindow && !hiddenPrivateWindow) || usefulHiddenWindow) + return NS_OK; + } else if (!hiddenWindow || usefulHiddenWindow) { return NS_OK; + } #else // If the one window is useful, we won't quit: if (!hiddenWindow || usefulHiddenWindow) diff --git a/toolkit/components/telemetry/Makefile.in b/toolkit/components/telemetry/Makefile.in index 5ba4732cba94..8b164c0094f3 100644 --- a/toolkit/components/telemetry/Makefile.in +++ b/toolkit/components/telemetry/Makefile.in @@ -50,6 +50,8 @@ CPPSRCS = \ Telemetry.cpp \ $(NULL) +LOCAL_INCLUDES += -I$(topsrcdir)/xpcom/build + EXTRA_DSO_LDOPTS += \ $(MOZ_COMPONENT_LIBS) \ $(MOZ_JS_LIBS) \ diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 32252b514e22..9a57ebcc950e 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -5,6 +5,12 @@ #include +#ifdef XP_MACOS +#include +#endif + +#include + #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/Likely.h" @@ -13,7 +19,9 @@ #include "base/pickle.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" +#include "nsCOMArray.h" #include "nsCOMPtr.h" +#include "nsXPCOMPrivate.h" #include "mozilla/ModuleUtils.h" #include "nsIXPConnect.h" #include "mozilla/Services.h" @@ -303,6 +311,7 @@ private: static bool AddonReflector(AddonEntryType *entry, JSContext *cx, JSObject *obj); static bool CreateHistogramForAddon(const nsACString &name, AddonHistogramInfo &info); + void ReadLateWritesStacks(); AddonMapType mAddonMap; // This is used for speedy string->Telemetry::ID conversions @@ -321,9 +330,10 @@ private: Mutex mHangReportsMutex; nsIMemoryReporter *mMemoryReporter; + CombinedStacks mLateWritesStacks; // This is collected out of the main thread. bool mCachedTelemetryData; uint32_t mLastShutdownTime; - std::vector > mCallbacks; + nsCOMArray mCallbacks; friend class nsFetchTelemetryData; }; @@ -729,14 +739,15 @@ private: public: void MainThread() { mTelemetry->mCachedTelemetryData = true; - for (unsigned int i = 0, n = mTelemetry->mCallbacks.size(); i < n; ++i) { + for (unsigned int i = 0, n = mTelemetry->mCallbacks.Count(); i < n; ++i) { mTelemetry->mCallbacks[i]->Complete(); } - mTelemetry->mCallbacks.clear(); + mTelemetry->mCallbacks.Clear(); } NS_IMETHOD Run() { mTelemetry->mLastShutdownTime = ReadLastShutdownDuration(mFilename); + mTelemetry->ReadLateWritesStacks(); nsCOMPtr e = NS_NewRunnableMethod(this, &nsFetchTelemetryData::MainThread); NS_ENSURE_STATE(e); @@ -799,8 +810,8 @@ TelemetryImpl::AsyncFetchTelemetryData(nsIFetchTelemetryDataCallback *aCallback) } // We already have a read request running, just remember the callback. - if (!mCallbacks.empty()) { - mCallbacks.push_back(aCallback); + if (mCallbacks.Count() != 0) { + mCallbacks.AppendObject(aCallback); return NS_OK; } @@ -831,7 +842,7 @@ TelemetryImpl::AsyncFetchTelemetryData(nsIFetchTelemetryDataCallback *aCallback) return NS_OK; } - mCallbacks.push_back(aCallback); + mCallbacks.AppendObject(aCallback); nsCOMPtr event = new nsFetchTelemetryData(filename); targetThread->Dispatch(event, NS_DISPATCH_NORMAL); @@ -1532,6 +1543,150 @@ CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) { return ret; } +// Read a stack from the given file name. In case of any error, aStack is +// unchanged. +static void +ReadStack(const char *aFileName, Telemetry::ProcessedStack &aStack) +{ +#ifdef XP_MACOS + std::ifstream file(aFileName); + + size_t numModules; + file >> numModules; + if (file.fail()) { + return; + } + + char newline = file.get(); + if (file.fail() || newline != '\n') { + return; + } + + Telemetry::ProcessedStack stack; + for (size_t i = 0; i < numModules; ++i) { + std::string moduleName; + getline(file, moduleName); + if (file.fail()) { + return; + } + + Telemetry::ProcessedStack::Module module = { + moduleName, + 0, // mPdbAge + "", // mPdbSignature + "" // mPdbName + }; + stack.AddModule(module); + } + + size_t numFrames; + file >> numFrames; + if (file.fail()) { + return; + } + + newline = file.get(); + if (file.fail() || newline != '\n') { + return; + } + + for (size_t i = 0; i < numFrames; ++i) { + uint16_t index; + file >> index; + uintptr_t offset; + file >> std::hex >> offset >> std::dec; + if (file.fail()) { + return; + } + + Telemetry::ProcessedStack::Frame frame = { + offset, + index + }; + stack.AddFrame(frame); + } + + aStack = stack; +#endif +} + +void +TelemetryImpl::ReadLateWritesStacks() +{ + nsCOMPtr profileDir; + nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, + getter_AddRefs(profileDir)); + if (!profileDir || NS_FAILED(rv)) { + return; + } + + nsAutoCString nativePath; + rv = profileDir->GetNativePath(nativePath); + if (NS_FAILED(rv)) { + return; + } + + const char *name = nativePath.get(); + PRDir *dir = PR_OpenDir(name); + if (!dir) { + return; + } + + PRDirEntry *ent; + const char *prefix = "Telemetry.LateWriteFinal-"; + unsigned int prefixLen = strlen(prefix); + while ((ent = PR_ReadDir(dir, PR_SKIP_NONE))) { + if (strncmp(prefix, ent->name, prefixLen) != 0) { + continue; + } + + nsAutoCString stackNativePath = nativePath; + stackNativePath += XPCOM_FILE_PATH_SEPARATOR; + stackNativePath += nsDependentCString(ent->name); + + Telemetry::ProcessedStack stack; + ReadStack(stackNativePath.get(), stack); + if (stack.GetStackSize() != 0) { + mLateWritesStacks.AddStack(stack); + } + // Delete the file so that we don't report it again on the next run. + PR_Delete(stackNativePath.get()); + } + PR_CloseDir(dir); +} + +NS_IMETHODIMP +TelemetryImpl::GetLateWrites(JSContext *cx, jsval *ret) +{ + // The user must call AsyncReadTelemetryData first. We return an empty list + // instead of reporting a failure so that the rest of telemetry can uniformly + // handle the read not being available yet. + + // FIXME: we allocate the js object again and again in the getter. We should + // figure out a way to cache it. In order to do that we have to call + // JS_AddNamedObjectRoot. A natural place to do so is in the TelemetryImpl + // constructor, but it is not clear how to get a JSContext in there. + // Another option would be to call it in here when we first call + // CreateJSStackObject, but we would still need to figure out where to call + // JS_RemoveObjectRoot. Would it be ok to never call JS_RemoveObjectRoot + // and just set the pointer to nullptr is the telemetry destructor? + + JSObject *report; + if (!mCachedTelemetryData) { + CombinedStacks empty; + report = CreateJSStackObject(cx, empty); + } else { + report = CreateJSStackObject(cx, mLateWritesStacks); + } + + if (report == nullptr) { + return NS_ERROR_FAILURE; + } + + *ret = OBJECT_TO_JSVAL(report); + return NS_OK; +} + NS_IMETHODIMP TelemetryImpl::GetRegisteredHistograms(JSContext *cx, jsval *ret) { diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index b442af40fbda..a682ad8378b9 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -518,6 +518,7 @@ TelemetryPing.prototype = { histograms: this.getHistograms(Telemetry.histogramSnapshots), slowSQL: Telemetry.slowSQL, chromeHangs: Telemetry.chromeHangs, + lateWrites: Telemetry.lateWrites, addonHistograms: this.getAddonHistograms() }; diff --git a/toolkit/components/telemetry/nsITelemetry.idl b/toolkit/components/telemetry/nsITelemetry.idl index 69dc669a98d0..3cefb1f04249 100644 --- a/toolkit/components/telemetry/nsITelemetry.idl +++ b/toolkit/components/telemetry/nsITelemetry.idl @@ -87,6 +87,18 @@ interface nsITelemetry : nsISupports [implicit_jscontext] readonly attribute jsval chromeHangs; + /* + * An object with two fields: memoryMap and stacks. + * * memoryMap is a list of loaded libraries. + * * stacks is a list of stacks. Each stack is a list of pairs of the form + * [moduleIndex, offset]. The moduleIndex is an index into the memoryMap and + * offset is an offset in the library at memoryMap[moduleIndex]. + * This format is used to make it easier to send the stacks to the + * symbolication server. + */ + [implicit_jscontext] + readonly attribute jsval lateWrites; + /** * An object whose properties are the names of histograms defined in * TelemetryHistograms.h and whose corresponding values are the textual @@ -193,8 +205,9 @@ interface nsITelemetry : nsISupports readonly attribute jsval addonHistogramSnapshots; /** - * Read data from the previous run. After the callback is called, the data is - * available in lastShutdownDuration. + * Read data from the previous run. After the callback is called, the last + * shutdown time is available in lastShutdownDuration and any late + * writes in lateWrites. */ void asyncFetchTelemetryData(in nsIFetchTelemetryDataCallback aCallback); }; diff --git a/toolkit/components/url-classifier/Classifier.cpp b/toolkit/components/url-classifier/Classifier.cpp index 1df8598b57e4..90619b49debc 100644 --- a/toolkit/components/url-classifier/Classifier.cpp +++ b/toolkit/components/url-classifier/Classifier.cpp @@ -34,7 +34,6 @@ namespace safebrowsing { Classifier::Classifier() : mFreshTime(45 * 60) - , mPerClientRandomize(true) { } @@ -43,77 +42,6 @@ Classifier::~Classifier() Close(); } -/* - * Generate a unique 32-bit key for this user, which we will - * use to rehash all prefixes. This ensures that different users - * will get hash collisions on different prefixes, which in turn - * avoids that "unlucky" URLs get mysterious slowdowns, and that - * the servers get spammed if any such URL should get slashdotted. - * https://bugzilla.mozilla.org/show_bug.cgi?id=669407#c10 - */ -nsresult -Classifier::InitKey() -{ - nsCOMPtr storeFile; - nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = storeFile->AppendNative(NS_LITERAL_CSTRING("classifier.hashkey")); - NS_ENSURE_SUCCESS(rv, rv); - - bool exists; - rv = storeFile->Exists(&exists); - NS_ENSURE_SUCCESS(rv, rv); - - if (!exists) { - // generate and store key - nsCOMPtr rg = - do_GetService("@mozilla.org/security/random-generator;1"); - NS_ENSURE_STATE(rg); - - uint8_t *temp; - nsresult rv = rg->GenerateRandomBytes(sizeof(mHashKey), &temp); - NS_ENSURE_SUCCESS(rv, rv); - memcpy(&mHashKey, temp, sizeof(mHashKey)); - NS_Free(temp); - - nsCOMPtr out; - rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out), storeFile, - -1, -1, 0); - NS_ENSURE_SUCCESS(rv, rv); - - uint32_t written; - rv = out->Write(reinterpret_cast(&mHashKey), sizeof(uint32_t), &written); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr safeOut = do_QueryInterface(out); - rv = safeOut->Finish(); - NS_ENSURE_SUCCESS(rv, rv); - - LOG(("Initialized classifier, key = %X", mHashKey)); - } else { - // read key - nsCOMPtr inputStream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), storeFile, - -1, -1, 0); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr seekable = do_QueryInterface(inputStream); - nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); - NS_ENSURE_SUCCESS(rv, rv); - - void *buffer = &mHashKey; - rv = NS_ReadInputStreamToBuffer(inputStream, - &buffer, - sizeof(uint32_t)); - NS_ENSURE_SUCCESS(rv, rv); - - LOG(("Loaded classifier key = %X", mHashKey)); - } - - return NS_OK; -} - nsresult Classifier::SetupPathNames() { @@ -198,13 +126,6 @@ Classifier::Open(nsIFile& aCacheDirectory) mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); - rv = InitKey(); - if (NS_FAILED(rv)) { - // Without a usable key the database is useless - Reset(); - return NS_ERROR_FAILURE; - } - mTableFreshness.Init(); // Build the list of know urlclassifier lists @@ -321,9 +242,7 @@ Classifier::Check(const nsACString& aSpec, LookupResultArray& aResults) for (uint32_t i = 0; i < cacheArray.Length(); i++) { LookupCache *cache = cacheArray[i]; bool has, complete; - Prefix codedPrefix; - rv = cache->Has(lookupHash, hostKey, mHashKey, - &has, &complete, &codedPrefix); + rv = cache->Has(lookupHash, &has, &complete); NS_ENSURE_SUCCESS(rv, rv); if (has) { LookupResult *result = aResults.AppendElement(); @@ -345,7 +264,6 @@ Classifier::Check(const nsACString& aSpec, LookupResultArray& aResults) age)); result->hash.complete = lookupHash; - result->mCodedPrefix = codedPrefix; result->mComplete = complete; result->mFresh = (age < mFreshTime); result->mTableName.Assign(cache->TableName()); @@ -758,8 +676,7 @@ Classifier::GetLookupCache(const nsACString& aTable) } } - LookupCache *cache = new LookupCache(aTable, mStoreDirectory, - mPerClientRandomize); + LookupCache *cache = new LookupCache(aTable, mStoreDirectory); nsresult rv = cache->Init(); if (NS_FAILED(rv)) { return nullptr; diff --git a/toolkit/components/url-classifier/Classifier.h b/toolkit/components/url-classifier/Classifier.h index 53121bf76c33..0633fab851f6 100644 --- a/toolkit/components/url-classifier/Classifier.h +++ b/toolkit/components/url-classifier/Classifier.h @@ -60,7 +60,6 @@ public: nsresult CacheCompletions(const CacheResultArray& aResults); uint32_t GetHashKey(void) { return mHashKey; } void SetFreshTime(uint32_t aTime) { mFreshTime = aTime; } - void SetPerClientRandomize(bool aRandomize) { mPerClientRandomize = aRandomize; } /* * Get a bunch of extra prefixes to query for completion * and mask the real entry being requested @@ -84,7 +83,6 @@ private: const nsACString& aTable); LookupCache *GetLookupCache(const nsACString& aTable); - nsresult InitKey(); // Root dir of the Local profile. nsCOMPtr mCacheDirectory; @@ -101,7 +99,6 @@ private: // Stores the last time a given table was updated (seconds). nsDataHashtable mTableFreshness; uint32_t mFreshTime; - bool mPerClientRandomize; }; } diff --git a/toolkit/components/url-classifier/HashStore.cpp b/toolkit/components/url-classifier/HashStore.cpp index 41314f93ff3a..df317b76169e 100644 --- a/toolkit/components/url-classifier/HashStore.cpp +++ b/toolkit/components/url-classifier/HashStore.cpp @@ -994,13 +994,6 @@ HashStore::ProcessSubs() RemoveMatchingPrefixes(mSubPrefixes, &mAddCompletes); RemoveMatchingPrefixes(mSubPrefixes, &mSubCompletes); - // Clean up temporary subs (without per-client randomization), - // that we temporarily stored so we could knock out completes. - ChunkSet dummyChunks; - dummyChunks.Set(0); - ExpireEntries(&mSubPrefixes, dummyChunks); - mSubChunks.Remove(dummyChunks); - // Remove any remaining subbed prefixes from both addprefixes // and addcompletes. KnockoutSubs(&mSubPrefixes, &mAddPrefixes); diff --git a/toolkit/components/url-classifier/LookupCache.cpp b/toolkit/components/url-classifier/LookupCache.cpp index 9ed899da9b0f..2033d4252134 100644 --- a/toolkit/components/url-classifier/LookupCache.cpp +++ b/toolkit/components/url-classifier/LookupCache.cpp @@ -48,10 +48,8 @@ namespace safebrowsing { const uint32_t LOOKUPCACHE_MAGIC = 0x1231af3e; const uint32_t CURRENT_VERSION = 2; -LookupCache::LookupCache(const nsACString& aTableName, nsIFile* aStoreDir, - bool aPerClientRandomize) +LookupCache::LookupCache(const nsACString& aTableName, nsIFile* aStoreDir) : mPrimed(false) - , mPerClientRandomize(aPerClientRandomize) , mTableName(aTableName) , mStoreDirectory(aStoreDir) { @@ -191,25 +189,14 @@ LookupCache::Dump() nsresult LookupCache::Has(const Completion& aCompletion, - const Completion& aHostkey, - const uint32_t aHashKey, - bool* aHas, bool* aComplete, - Prefix* aOrigPrefix) + bool* aHas, bool* aComplete) { *aHas = *aComplete = false; uint32_t prefix = aCompletion.ToUint32(); - uint32_t hostkey = aHostkey.ToUint32(); - uint32_t codedkey; - nsresult rv = KeyedHash(prefix, hostkey, aHashKey, &codedkey, !mPerClientRandomize); - NS_ENSURE_SUCCESS(rv, rv); - - Prefix codedPrefix; - codedPrefix.FromUint32(codedkey); - *aOrigPrefix = codedPrefix; bool found; - rv = mPrefixSet->Contains(codedkey, &found); + nsresult rv = mPrefixSet->Contains(prefix, &found); NS_ENSURE_SUCCESS(rv, rv); LOG(("Probe in %s: %X, found %d", mTableName.get(), prefix, found)); @@ -594,63 +581,6 @@ LookupCache::GetHostKeys(const nsACString& aSpec, return NS_OK; } -/* We have both a prefix and a domain. Drop the domain, but - hash the domain, the prefix and a random value together, - ensuring any collisions happens at a different points for - different users. -*/ -/* static */ nsresult LookupCache::KeyedHash(uint32_t aPref, uint32_t aHostKey, - uint32_t aUserKey, uint32_t* aOut, - bool aPassthrough) -{ - /* Do not do any processing in passthrough mode. */ - if (aPassthrough) { - *aOut = aPref; - return NS_OK; - } - - /* This is a reimplementation of MurmurHash3 32-bit - based on the public domain C++ sources. - http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp - for nblocks = 2 - */ - uint32_t c1 = 0xCC9E2D51; - uint32_t c2 = 0x1B873593; - uint32_t c3 = 0xE6546B64; - uint32_t c4 = 0x85EBCA6B; - uint32_t c5 = 0xC2B2AE35; - uint32_t h1 = aPref; // seed - uint32_t k1; - uint32_t karr[2]; - - karr[0] = aHostKey; - karr[1] = aUserKey; - - for (uint32_t i = 0; i < 2; i++) { - k1 = karr[i]; - k1 *= c1; - k1 = (k1 << 15) | (k1 >> (32-15)); - k1 *= c2; - - h1 ^= k1; - h1 = (h1 << 13) | (h1 >> (32-13)); - h1 *= 5; - h1 += c3; - } - - h1 ^= 2; // len - // fmix - h1 ^= h1 >> 16; - h1 *= c4; - h1 ^= h1 >> 13; - h1 *= c5; - h1 ^= h1 >> 16; - - *aOut = h1; - - return NS_OK; -} - bool LookupCache::IsPrimed() { return mPrimed; diff --git a/toolkit/components/url-classifier/LookupCache.h b/toolkit/components/url-classifier/LookupCache.h index 6dc16893a1d9..de7546396735 100644 --- a/toolkit/components/url-classifier/LookupCache.h +++ b/toolkit/components/url-classifier/LookupCache.h @@ -45,9 +45,6 @@ public: // that is inserted to mask the true URL we are requesting bool mNoise; - // Value of actual key looked up in the prefixset (coded with client key) - Prefix mCodedPrefix; - // True if we've updated this table recently-enough. bool mFresh; @@ -89,18 +86,7 @@ public: static nsresult GetKey(const nsACString& aSpec, Completion* aHash, nsCOMPtr& aCryptoHash); - /* We have both a prefix and a domain. Drop the domain, but - hash the domain, the prefix and a random value together, - ensuring any collisions happens at a different points for - different users. If aPassthrough is set, we ignore the - random value and copy prefix directly into output. - */ - static nsresult KeyedHash(uint32_t aPref, uint32_t aHostKey, - uint32_t aUserKey, uint32_t* aOut, - bool aPassthrough); - - LookupCache(const nsACString& aTableName, nsIFile* aStoreFile, - bool aPerClientRandomize); + LookupCache(const nsACString& aTableName, nsIFile* aStoreFile); ~LookupCache(); const nsCString &TableName() const { return mTableName; } @@ -121,10 +107,7 @@ public: #endif nsresult WriteFile(); nsresult Has(const Completion& aCompletion, - const Completion& aHostkey, - uint32_t aHashKey, - bool* aHas, bool* aComplete, - Prefix* aOrigPrefix); + bool* aHas, bool* aComplete); bool IsPrimed(); private: @@ -147,7 +130,6 @@ private: Header mHeader; bool mPrimed; - bool mPerClientRandomize; nsCString mTableName; nsCOMPtr mStoreDirectory; CompletionArray mCompletions; diff --git a/toolkit/components/url-classifier/ProtocolParser.cpp b/toolkit/components/url-classifier/ProtocolParser.cpp index 0e3117c675ed..542c302ab735 100644 --- a/toolkit/components/url-classifier/ProtocolParser.cpp +++ b/toolkit/components/url-classifier/ProtocolParser.cpp @@ -65,9 +65,8 @@ ParseChunkRange(nsACString::const_iterator& aBegin, return false; } -ProtocolParser::ProtocolParser(uint32_t aHashKey) +ProtocolParser::ProtocolParser() : mState(PROTOCOL_STATE_CONTROL) - , mHashKey(aHashKey) , mUpdateStatus(NS_OK) , mUpdateWait(0) , mResetRequested(false) @@ -81,10 +80,9 @@ ProtocolParser::~ProtocolParser() } nsresult -ProtocolParser::Init(nsICryptoHash* aHasher, bool aPerClientRandomize) +ProtocolParser::Init(nsICryptoHash* aHasher) { mCryptoHash = aHasher; - mPerClientRandomize = aPerClientRandomize; return NS_OK; } @@ -426,7 +424,6 @@ ProtocolParser::ProcessPlaintextChunk(const nsACString& aChunk) return NS_ERROR_FAILURE; } - nsresult rv; nsTArray lines; ParseString(PromiseFlatCString(aChunk), '\n', lines); @@ -441,18 +438,9 @@ ProtocolParser::ProcessPlaintextChunk(const nsACString& aChunk) mTableUpdate->NewAddComplete(mChunkState.num, hash); } else { NS_ASSERTION(mChunkState.hashSize == 4, "Only 32- or 4-byte hashes can be used for add chunks."); - Completion hash; - Completion domHash; - Prefix newHash; - rv = LookupCache::GetKey(line, &domHash, mCryptoHash); - NS_ENSURE_SUCCESS(rv, rv); + Prefix hash; hash.FromPlaintext(line, mCryptoHash); - uint32_t codedHash; - rv = LookupCache::KeyedHash(hash.ToUint32(), domHash.ToUint32(), mHashKey, - &codedHash, !mPerClientRandomize); - NS_ENSURE_SUCCESS(rv, rv); - newHash.FromUint32(codedHash); - mTableUpdate->NewAddPrefix(mChunkState.num, newHash); + mTableUpdate->NewAddPrefix(mChunkState.num, hash); } } else { nsCString::const_iterator begin, iter, end; @@ -474,21 +462,8 @@ ProtocolParser::ProcessPlaintextChunk(const nsACString& aChunk) } else { NS_ASSERTION(mChunkState.hashSize == 4, "Only 32- or 4-byte hashes can be used for add chunks."); Prefix hash; - Completion domHash; - rv = LookupCache::GetKey(Substring(iter, end), &domHash, mCryptoHash); - NS_ENSURE_SUCCESS(rv, rv); hash.FromPlaintext(Substring(iter, end), mCryptoHash); - uint32_t codedHash; - rv = LookupCache::KeyedHash(hash.ToUint32(), domHash.ToUint32(), mHashKey, - &codedHash, !mPerClientRandomize); - NS_ENSURE_SUCCESS(rv, rv); - Prefix newHash; - newHash.FromUint32(codedHash); - mTableUpdate->NewSubPrefix(addChunk, newHash, mChunkState.num); - // Needed to knock out completes - // Fake chunk nr, will cause it to be removed next update - mTableUpdate->NewSubPrefix(addChunk, hash, 0); - mTableUpdate->NewSubChunk(0); + mTableUpdate->NewSubPrefix(addChunk, hash, mChunkState.num); } } } @@ -539,16 +514,8 @@ ProtocolParser::ProcessHostAdd(const Prefix& aDomain, uint8_t aNumEntries, NS_ASSERTION(mChunkState.hashSize == PREFIX_SIZE, "ProcessHostAdd should only be called for prefix hashes."); - uint32_t codedHash; - uint32_t domHash = aDomain.ToUint32(); - if (aNumEntries == 0) { - nsresult rv = LookupCache::KeyedHash(domHash, domHash, mHashKey, &codedHash, - !mPerClientRandomize); - NS_ENSURE_SUCCESS(rv, rv); - Prefix newHash; - newHash.FromUint32(codedHash); - mTableUpdate->NewAddPrefix(mChunkState.num, newHash); + mTableUpdate->NewAddPrefix(mChunkState.num, aDomain); return NS_OK; } @@ -560,12 +527,7 @@ ProtocolParser::ProcessHostAdd(const Prefix& aDomain, uint8_t aNumEntries, for (uint8_t i = 0; i < aNumEntries; i++) { Prefix hash; hash.Assign(Substring(aChunk, *aStart, PREFIX_SIZE)); - nsresult rv = LookupCache::KeyedHash(hash.ToUint32(), domHash, mHashKey, &codedHash, - !mPerClientRandomize); - NS_ENSURE_SUCCESS(rv, rv); - Prefix newHash; - newHash.FromUint32(codedHash); - mTableUpdate->NewAddPrefix(mChunkState.num, newHash); + mTableUpdate->NewAddPrefix(mChunkState.num, hash); *aStart += PREFIX_SIZE; } @@ -579,9 +541,6 @@ ProtocolParser::ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries, NS_ASSERTION(mChunkState.hashSize == PREFIX_SIZE, "ProcessHostSub should only be called for prefix hashes."); - uint32_t codedHash; - uint32_t domHash = aDomain.ToUint32(); - if (aNumEntries == 0) { if ((*aStart) + 4 > aChunk.Length()) { NS_WARNING("Received a zero-entry sub chunk without an associated add."); @@ -595,17 +554,7 @@ ProtocolParser::ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries, memcpy(&addChunk, addChunkStr.BeginReading(), 4); addChunk = PR_ntohl(addChunk); - nsresult rv = LookupCache::KeyedHash(domHash, domHash, mHashKey, &codedHash, - !mPerClientRandomize); - NS_ENSURE_SUCCESS(rv, rv); - Prefix newHash; - newHash.FromUint32(codedHash); - - mTableUpdate->NewSubPrefix(addChunk, newHash, mChunkState.num); - // Needed to knock out completes - // Fake chunk nr, will cause it to be removed next update - mTableUpdate->NewSubPrefix(addChunk, aDomain, 0); - mTableUpdate->NewSubChunk(0); + mTableUpdate->NewSubPrefix(addChunk, aDomain, mChunkState.num); return NS_OK; } @@ -626,17 +575,7 @@ ProtocolParser::ProcessHostSub(const Prefix& aDomain, uint8_t aNumEntries, prefix.Assign(Substring(aChunk, *aStart, PREFIX_SIZE)); *aStart += PREFIX_SIZE; - nsresult rv = LookupCache::KeyedHash(prefix.ToUint32(), domHash, mHashKey, - &codedHash, !mPerClientRandomize); - NS_ENSURE_SUCCESS(rv, rv); - Prefix newHash; - newHash.FromUint32(codedHash); - - mTableUpdate->NewSubPrefix(addChunk, newHash, mChunkState.num); - // Needed to knock out completes - // Fake chunk nr, will cause it to be removed next update - mTableUpdate->NewSubPrefix(addChunk, prefix, 0); - mTableUpdate->NewSubChunk(0); + mTableUpdate->NewSubPrefix(addChunk, prefix, mChunkState.num); } return NS_OK; diff --git a/toolkit/components/url-classifier/ProtocolParser.h b/toolkit/components/url-classifier/ProtocolParser.h index 7b5a92791f30..dd4d6f3b11e5 100644 --- a/toolkit/components/url-classifier/ProtocolParser.h +++ b/toolkit/components/url-classifier/ProtocolParser.h @@ -23,12 +23,12 @@ public: nsCString mac; }; - ProtocolParser(uint32_t aHashKey); + ProtocolParser(); ~ProtocolParser(); nsresult Status() const { return mUpdateStatus; } - nsresult Init(nsICryptoHash* aHasher, bool mPerClientRandomize); + nsresult Init(nsICryptoHash* aHasher); nsresult InitHMAC(const nsACString& aClientKey, const nsACString& aServerMAC); @@ -93,8 +93,6 @@ private: }; ChunkState mChunkState; - uint32_t mHashKey; - bool mPerClientRandomize; nsCOMPtr mCryptoHash; nsresult mUpdateStatus; diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 66422a450ffd..cbcda737d604 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -63,9 +63,6 @@ PRLogModuleInfo *gUrlClassifierDbServiceLog = nullptr; #define CHECK_PHISHING_PREF "browser.safebrowsing.enabled" #define CHECK_PHISHING_DEFAULT false -#define RANDOMIZE_CLIENT_PREF "urlclassifier.randomizeclient" -#define RANDOMIZE_CLIENT_DEFAULT false - #define GETHASH_NOISE_PREF "urlclassifier.gethashnoise" #define GETHASH_NOISE_DEFAULT 4 @@ -117,8 +114,7 @@ public: NS_DECL_NSIURLCLASSIFIERDBSERVICE NS_DECL_NSIURLCLASSIFIERDBSERVICEWORKER - nsresult Init(uint32_t aGethashNoise, nsCOMPtr aCacheDir, - bool aPerClientRandomize); + nsresult Init(uint32_t aGethashNoise, nsCOMPtr aCacheDir); // Queue a lookup for the worker to perform, called in the main thread. nsresult QueueLookup(const nsACString& lookupKey, @@ -181,15 +177,9 @@ private: // The client key with which the data from the server will be MAC'ed. nsCString mUpdateClientKey; - // The client-specific hash key to rehash - uint32_t mHashKey; - // The number of noise entries to add to the set of lookup results. uint32_t mGethashNoise; - // Randomize clients with a key or not. - bool mPerClientRandomize; - // Pending lookups are stored in a queue for processing. The queue // is protected by mPendingLookupLock. Mutex mPendingLookupLock; @@ -212,7 +202,6 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsUrlClassifierDBServiceWorker, nsUrlClassifierDBServiceWorker::nsUrlClassifierDBServiceWorker() : mInStream(false) , mGethashNoise(0) - , mPerClientRandomize(true) , mPendingLookupLock("nsUrlClassifierDBServerWorker.mPendingLookupLock") { } @@ -226,12 +215,10 @@ nsUrlClassifierDBServiceWorker::~nsUrlClassifierDBServiceWorker() nsresult nsUrlClassifierDBServiceWorker::Init(uint32_t aGethashNoise, - nsCOMPtr aCacheDir, - bool aPerClientRandomize) + nsCOMPtr aCacheDir) { mGethashNoise = aGethashNoise; mCacheDir = aCacheDir; - mPerClientRandomize = aPerClientRandomize; ResetUpdate(); @@ -323,7 +310,7 @@ nsUrlClassifierDBServiceWorker::DoLookup(const nsACString& spec, // We're going to be doing a gethash request, add some extra entries. // Note that we cannot pass the first two by reference, because we // add to completes, whicah can cause completes to reallocate and move. - AddNoise(completes->ElementAt(i).mCodedPrefix, + AddNoise(completes->ElementAt(i).hash.prefix, completes->ElementAt(i).mTableName, mGethashNoise, *completes); break; @@ -485,11 +472,11 @@ nsUrlClassifierDBServiceWorker::BeginStream(const nsACString &table, NS_ASSERTION(!mProtocolParser, "Should not have a protocol parser."); - mProtocolParser = new ProtocolParser(mHashKey); + mProtocolParser = new ProtocolParser(); if (!mProtocolParser) return NS_ERROR_OUT_OF_MEMORY; - mProtocolParser->Init(mCryptoHash, mPerClientRandomize); + mProtocolParser->Init(mCryptoHash); nsresult rv; @@ -709,7 +696,7 @@ nsUrlClassifierDBServiceWorker::CacheCompletions(CacheResultArray *results) // Ownership is transferred in to us nsAutoPtr resultsPtr(results); - nsAutoPtr pParse(new ProtocolParser(mHashKey)); + nsAutoPtr pParse(new ProtocolParser()); nsTArray updates; // Only cache results for tables that we have, don't take @@ -780,12 +767,10 @@ nsUrlClassifierDBServiceWorker::OpenDb() } classifier->SetFreshTime(gFreshnessGuarantee); - classifier->SetPerClientRandomize(mPerClientRandomize); rv = classifier->Open(*mCacheDir); NS_ENSURE_SUCCESS(rv, rv); - mHashKey = classifier->GetHashKey(); mClassifier = classifier; return NS_OK; @@ -1107,7 +1092,6 @@ nsUrlClassifierDBService::GetInstance(nsresult *result) nsUrlClassifierDBService::nsUrlClassifierDBService() : mCheckMalware(CHECK_MALWARE_DEFAULT) , mCheckPhishing(CHECK_PHISHING_DEFAULT) - , mPerClientRandomize(true) , mInUpdate(false) { } @@ -1159,15 +1143,6 @@ nsUrlClassifierDBService::Init() PR_ATOMIC_SET(&gFreshnessGuarantee, NS_SUCCEEDED(rv) ? tmpint : CONFIRM_AGE_DEFAULT_SEC); prefs->AddObserver(CONFIRM_AGE_PREF, this, false); - - rv = prefs->GetBoolPref(RANDOMIZE_CLIENT_PREF, &tmpbool); - mPerClientRandomize = NS_SUCCEEDED(rv) ? tmpbool : RANDOMIZE_CLIENT_DEFAULT; - - LOG(("Per client randomization is %s", - mPerClientRandomize ? "enabled" : "DISABLED")); - - /* We do not observe for runtime changes as changing this preference - in flight kills the database, so it's not really supported. */ } // Force PSM loading on main thread @@ -1192,7 +1167,7 @@ nsUrlClassifierDBService::Init() if (!mWorker) return NS_ERROR_OUT_OF_MEMORY; - rv = mWorker->Init(gethashNoise, cacheDir, mPerClientRandomize); + rv = mWorker->Init(gethashNoise, cacheDir); if (NS_FAILED(rv)) { mWorker = nullptr; return rv; diff --git a/toolkit/content/LightweightThemeConsumer.jsm b/toolkit/content/LightweightThemeConsumer.jsm index 91b5d87e65a8..4f22f9a89174 100644 --- a/toolkit/content/LightweightThemeConsumer.jsm +++ b/toolkit/content/LightweightThemeConsumer.jsm @@ -9,12 +9,19 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer", "resource://gre/modules/LightweightThemeImageOptimizer.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", + "resource://gre/modules/PrivateBrowsingUtils.jsm"); + this.LightweightThemeConsumer = function LightweightThemeConsumer(aDocument) { this._doc = aDocument; this._win = aDocument.defaultView; this._footerId = aDocument.documentElement.getAttribute("lightweightthemesfooter"); + if (PrivateBrowsingUtils.isWindowPrivate(this._win)) { + return; + } + let screen = this._win.screen; this._lastScreenWidth = screen.width; this._lastScreenHeight = screen.height; diff --git a/toolkit/content/PopupNotifications.jsm b/toolkit/content/PopupNotifications.jsm index 67eee03d40e3..60b5ddf9bedc 100644 --- a/toolkit/content/PopupNotifications.jsm +++ b/toolkit/content/PopupNotifications.jsm @@ -68,6 +68,10 @@ Notification.prototype = { iconBox; return anchorElement; + }, + + reshow: function() { + this.owner.reshow(this.anchorElement); } }; @@ -625,6 +629,10 @@ PopupNotifications.prototype = { while (anchor && anchor.parentNode != this.iconBox) anchor = anchor.parentNode; + this.reshow(anchor); + }, + + reshow: function PopupNotifications_reshow(anchor) { // Mark notifications anchored to this anchor as un-dismissed this._currentNotifications.forEach(function (n) { if (n.anchorElement == anchor) diff --git a/toolkit/content/aboutTelemetry.js b/toolkit/content/aboutTelemetry.js index 197e9e18be11..960521755eb6 100644 --- a/toolkit/content/aboutTelemetry.js +++ b/toolkit/content/aboutTelemetry.js @@ -734,7 +734,29 @@ function onLoad() { // Get the Telemetry Ping payload Telemetry.asyncFetchTelemetryData(displayPingData); -} +}; + +let LateWritesSingleton = { + renderLateWrites: function LateWritesSingleton_renderLateWrites(lateWrites) { + let writesDiv = document.getElementById("late-writes-data"); + clearDivData(writesDiv); + // FIXME: Add symbolication support. Refactor with the chrome hang one. + + let stacks = lateWrites.stacks; + if (stacks.length == 0) { + showEmptySectionMessage("late-writes-section"); + return; + } + + let memoryMap = lateWrites.memoryMap; + StackRenderer.renderMemoryMap(writesDiv, memoryMap); + + for (let i = 0; i < stacks.length; ++i) { + let stack = stacks[i]; + StackRenderer.renderStack(writesDiv, stack); + } + } +}; function displayPingData() { let ping = TelemetryPing.getPayload(); @@ -746,6 +768,8 @@ function displayPingData() { showEmptySectionMessage("simple-measurements-section"); } + LateWritesSingleton.renderLateWrites(ping.lateWrites); + // Show basic system info gathered if (Object.keys(ping.info).length) { KeyValueTable.render("system-info-table", ping.info); diff --git a/toolkit/content/aboutTelemetry.xhtml b/toolkit/content/aboutTelemetry.xhtml index 3a93494f79ac..c846e244abd5 100644 --- a/toolkit/content/aboutTelemetry.xhtml +++ b/toolkit/content/aboutTelemetry.xhtml @@ -81,6 +81,20 @@ +
+

&aboutTelemetry.lateWritesSection;

+ &aboutTelemetry.toggleOn; + + + +
+

&aboutTelemetry.systemInfoSection;

&aboutTelemetry.toggleOn; diff --git a/toolkit/content/widgets/button.xml b/toolkit/content/widgets/button.xml index 1829f8b52494..0d53def2334e 100644 --- a/toolkit/content/widgets/button.xml +++ b/toolkit/content/widgets/button.xml @@ -340,6 +340,17 @@ + + + + if (event.originalTarget == this) + this.open = true; + + + if (event.originalTarget == this) + this.open = true; + + + using namespace mozilla; namespace { @@ -424,15 +426,15 @@ GenerateDSAKeyPair(PK11SlotInfo * slot, 0x72,0xDF,0xFA,0x89,0x62,0x33,0x39,0x7A }; - MOZ_STATIC_ASSERT(PR_ARRAY_SIZE(P) == 1024 / PR_BITS_PER_BYTE, "bad DSA P"); - MOZ_STATIC_ASSERT(PR_ARRAY_SIZE(Q) == 160 / PR_BITS_PER_BYTE, "bad DSA Q"); - MOZ_STATIC_ASSERT(PR_ARRAY_SIZE(G) == 1024 / PR_BITS_PER_BYTE, "bad DSA G"); + MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(P) == 1024 / CHAR_BIT, "bad DSA P"); + MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(Q) == 160 / CHAR_BIT, "bad DSA Q"); + MOZ_STATIC_ASSERT(MOZ_ARRAY_LENGTH(G) == 1024 / CHAR_BIT, "bad DSA G"); PQGParams pqgParams = { NULL /*arena*/, - { siBuffer, P, PR_ARRAY_SIZE(P) }, - { siBuffer, Q, PR_ARRAY_SIZE(Q) }, - { siBuffer, G, PR_ARRAY_SIZE(G) } + { siBuffer, P, static_cast(mozilla::ArrayLength(P)) }, + { siBuffer, Q, static_cast(mozilla::ArrayLength(Q)) }, + { siBuffer, G, static_cast(mozilla::ArrayLength(G)) } }; return GenerateKeyPair(slot, privateKey, publicKey, CKM_DSA_KEY_PAIR_GEN, diff --git a/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd b/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd index 8233a499fb18..895f6f1a44ba 100644 --- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd +++ b/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd @@ -28,6 +28,10 @@ Simple Measurements "> + + diff --git a/toolkit/mozapps/downloads/nsHelperAppDlg.js b/toolkit/mozapps/downloads/nsHelperAppDlg.js index abb6c4825ac8..91f21e7b0e89 100644 --- a/toolkit/mozapps/downloads/nsHelperAppDlg.js +++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js @@ -109,7 +109,6 @@ function nsUnknownContentTypeDialog() { // Initialize data properties. this.mLauncher = null; this.mContext = null; - this.mSourcePath = null; this.chosenApp = null; this.givenDefaultApp = false; this.updateSelf = true; @@ -370,7 +369,10 @@ nsUnknownContentTypeDialog.prototype = { var suggestedFileName = this.mLauncher.suggestedFileName; // Some URIs do not implement nsIURL, so we can't just QI. - var url = this.mLauncher.source; + var url = this.mLauncher.source; + if (url instanceof Components.interfaces.nsINestedURI) + url = url.innermostURI; + var fname = ""; var iconPath = "goat"; this.mSourcePath = url.prePath; @@ -514,28 +516,17 @@ nsUnknownContentTypeDialog.prototype = { this.dialogElement( "location" ).setAttribute("realname", filename); this.dialogElement( "location" ).setAttribute("tooltiptext", displayname); - // if mSourcePath is a local file, then let's use the pretty path name instead of an ugly - // url... - var pathString = this.mSourcePath; - try - { - var fileURL = url.QueryInterface(Components.interfaces.nsIFileURL); - if (fileURL) - { - var fileObject = fileURL.file; - if (fileObject) - { - var parentObject = fileObject.parent; - if (parentObject) - { - pathString = parentObject.path; - } - } - } - } catch(ex) {} + // if mSourcePath is a local file, then let's use the pretty path name + // instead of an ugly url... + var pathString; + if (url instanceof Components.interfaces.nsIFileURL) { + try { + // Getting .file might throw, or .parent could be null + pathString = url.file.parent.path; + } catch (ex) {} + } - if (pathString == this.mSourcePath) - { + if (!pathString) { // wasn't a fileURL var tmpurl = url.clone(); // don't want to change the real url try { diff --git a/toolkit/mozapps/update/test/marionette/update_smoketest_ota_simple.js b/toolkit/mozapps/update/test/marionette/update_smoketest_ota_simple.js index c5f714da7859..fee892fa8a52 100644 --- a/toolkit/mozapps/update/test/marionette/update_smoketest_ota_simple.js +++ b/toolkit/mozapps/update/test/marionette/update_smoketest_ota_simple.js @@ -11,24 +11,34 @@ function testForceCheck() { } function testDownload() { - let gotDownloading = false; + let gotStarted = false, gotProgress = false, gotStopped = false; let progress = 0, total = 0; - addChromeEventListener("update-downloading", function(evt) { - gotDownloading = true; + addChromeEventListener("update-download-started", function(evt) { + gotStarted = true; return true; }); - addChromeEventListener("update-progress", function(evt) { + addChromeEventListener("update-download-progress", function(evt) { progress = evt.detail.progress; total = evt.detail.total; + gotProgress = true; if (total == progress) { - ok(gotDownloading); + ok(gotStarted); return true; } return false; }); + addChromeEventListener("update-download-stopped", function(evt) { + is(evt.detail.paused, false); + gotStopped = true; + ok(gotStarted); + ok(gotProgress); + return true; + }); addChromeEventListener("update-downloaded", function(evt) { - ok(gotDownloading); + ok(gotStarted); + ok(gotProgress); + ok(gotStopped); is(progress, total); return true; }); diff --git a/toolkit/mozapps/update/test/marionette/update_test_ota_simple.js b/toolkit/mozapps/update/test/marionette/update_test_ota_simple.js index e63e603de5c1..c79a6ef4bd3b 100644 --- a/toolkit/mozapps/update/test/marionette/update_test_ota_simple.js +++ b/toolkit/mozapps/update/test/marionette/update_test_ota_simple.js @@ -13,24 +13,34 @@ function testForceCheck() { } function testDownload() { - let gotDownloading = false; + let gotStarted = false, gotProgress = false, gotStopped = false; let progress = 0, total = 0; - addChromeEventListener("update-downloading", function(evt) { - gotDownloading = true; + addChromeEventListener("update-download-started", function(evt) { + gotStarted = true; return true; }); - addChromeEventListener("update-progress", function(evt) { + addChromeEventListener("update-download-progress", function(evt) { progress = evt.detail.progress; total = evt.detail.total; + gotProgress = true; if (total == progress) { - ok(gotDownloading); + ok(gotStarted); return true; } return false; }); + addChromeEventListener("update-download-stopped", function(evt) { + is(evt.detail.paused, false); + gotStopped = true; + ok(gotStarted); + ok(gotProgress); + return true; + }); addChromeEventListener("update-downloaded", function(evt) { - ok(gotDownloading); + ok(gotStarted); + ok(gotProgress); + ok(gotStopped); is(progress, total); return true; }); diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp index 9782ac541872..c03f6daf3fc8 100644 --- a/toolkit/profile/nsToolkitProfileService.cpp +++ b/toolkit/profile/nsToolkitProfileService.cpp @@ -859,7 +859,7 @@ nsToolkitProfileService::CreateTimesInternal(nsIFile* aProfileDir) NS_ENSURE_SUCCESS(rv, rv); // We don't care about microsecond resolution. - PRInt64 msec; + int64_t msec; LL_DIV(msec, PR_Now(), PR_USEC_PER_MSEC); // Write it out. diff --git a/toolkit/themes/gnomestripe/global/global.css b/toolkit/themes/gnomestripe/global/global.css index 602a2e7daab4..7166f479f0b6 100644 --- a/toolkit/themes/gnomestripe/global/global.css +++ b/toolkit/themes/gnomestripe/global/global.css @@ -268,10 +268,13 @@ label[disabled="true"] { .text-link { color: -moz-nativehyperlinktext; - text-decoration: underline; border: 1px solid transparent; cursor: pointer; } + +.text-link:hover { + text-decoration: underline; +} .text-link:focus { border: 1px dotted -moz-DialogText; diff --git a/toolkit/themes/pinstripe/global/console/console.css b/toolkit/themes/pinstripe/global/console/console.css index f3ab26d02896..f00009cc4868 100644 --- a/toolkit/themes/pinstripe/global/console/console.css +++ b/toolkit/themes/pinstripe/global/console/console.css @@ -50,14 +50,6 @@ padding-left: 6px; } -.text-link { - text-decoration: none; -} - -.text-link:hover { - text-decoration: underline; -} - /* ..... error rows ..... */ .console-row-code { diff --git a/toolkit/themes/pinstripe/global/global.css b/toolkit/themes/pinstripe/global/global.css index 0be212c96bda..013ca0f95cc9 100644 --- a/toolkit/themes/pinstripe/global/global.css +++ b/toolkit/themes/pinstripe/global/global.css @@ -239,10 +239,13 @@ description { .text-link { color: -moz-nativehyperlinktext; - text-decoration: underline; border: 1px solid transparent; cursor: pointer; } + +.text-link:hover { + text-decoration: underline; +} .text-link:-moz-focusring { border: 1px dotted -moz-DialogText; diff --git a/toolkit/themes/pinstripe/global/media/videocontrols.css b/toolkit/themes/pinstripe/global/media/videocontrols.css index 26b73a94534d..8e92e73f91c0 100644 --- a/toolkit/themes/pinstripe/global/media/videocontrols.css +++ b/toolkit/themes/pinstripe/global/media/videocontrols.css @@ -10,41 +10,13 @@ background-color: rgba(35,31,32,.74); } -.playButton { - background: url(chrome://global/skin/media/pauseButton.png) no-repeat center; - /* Remove the native button appearance and styling */ - -moz-appearance: none; - margin: 0; - padding: 0; - min-height: 28px; - min-width: 28px; - margin-right: -22px; /* 1/2 of scrubber thumb width, for overhang. */ - position: relative; /* Trick to work around negative margin interfering with clicking on the button. */ -} -.playButton[paused] { - background: url(chrome://global/skin/media/playButton.png) no-repeat center; -} - -.muteButton { - background: url(chrome://global/skin/media/muteButton.png) no-repeat center; - /* Remove the native button appearance and styling */ - -moz-appearance: none; - margin: 0; - padding: 0; - min-height: 28px; - min-width: 33px; -} -.muteButton[muted] { - background: url(chrome://global/skin/media/unmuteButton.png) no-repeat center; -} - -.muteButton[noAudio] { - background: url(chrome://global/skin/media/noAudio.png) no-repeat center; -} - +.playButton, +.muteButton, .fullscreenButton { - background: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0) no-repeat center; - -moz-appearance: none; + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + -moz-appearance: none; /* Remove the native button appearance and styling */ margin: 0; padding: 0; min-height: 28px; @@ -52,6 +24,32 @@ border: none; } +.playButton { + background-image: url(chrome://global/skin/media/pauseButton.png); + margin-right: -22px; /* 1/2 of scrubber thumb width, for overhang. */ + position: relative; /* Trick to work around negative margin interfering with clicking on the button. */ +} + +.playButton[paused] { + background-image: url(chrome://global/skin/media/playButton.png); +} + +.muteButton { + background-image: url(chrome://global/skin/media/muteButton.png); + min-width: 33px; +} +.muteButton[muted] { + background-image: url(chrome://global/skin/media/unmuteButton.png); +} + +.muteButton[noAudio] { + background-image: url(chrome://global/skin/media/noAudio.png); +} + +.fullscreenButton { + background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0); +} + .fullscreenButton[fullscreened] { background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16); } @@ -168,7 +166,7 @@ } .timeThumb[showhours="true"] { - background: url(chrome://global/skin/media/scrubberThumbWide.png) no-repeat center; + background-image: url(chrome://global/skin/media/scrubberThumbWide.png); } .timeLabel { diff --git a/toolkit/themes/winstripe/global/global.css b/toolkit/themes/winstripe/global/global.css index 9a8ae59c2451..141839f394b2 100644 --- a/toolkit/themes/winstripe/global/global.css +++ b/toolkit/themes/winstripe/global/global.css @@ -282,11 +282,14 @@ label[disabled="true"]:-moz-system-metric(windows-classic) { .text-link { color: -moz-nativehyperlinktext; - text-decoration: underline; border: 1px solid transparent; cursor: pointer; } +.text-link:hover { + text-decoration: underline; +} + .text-link:-moz-focusring { border: 1px dotted -moz-DialogText; } diff --git a/toolkit/themes/winstripe/global/media/videocontrols.css b/toolkit/themes/winstripe/global/media/videocontrols.css index 6a411588ec3a..271cc86b7c10 100644 --- a/toolkit/themes/winstripe/global/media/videocontrols.css +++ b/toolkit/themes/winstripe/global/media/videocontrols.css @@ -10,48 +10,44 @@ background-color: rgba(35,31,32,.74); } -.playButton { - background: url(chrome://global/skin/media/pauseButton.png) no-repeat center; - /* Remove the native button appearance and styling */ - -moz-appearance: none; +.playButton, +.muteButton, +.fullscreenButton { + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + -moz-appearance: none; /* Remove the native button appearance and styling */ margin: 0; padding: 0; min-height: 28px; min-width: 28px; border: none; +} + +.playButton { + background-image: url(chrome://global/skin/media/pauseButton.png); margin-right: -22px; /* 1/2 of scrubber thumb width, for overhang. */ position: relative; /* Trick to work around negative margin interfering with clicking on the button. */ } + .playButton[paused] { - background: url(chrome://global/skin/media/playButton.png) no-repeat center; + background-image: url(chrome://global/skin/media/playButton.png); } .muteButton { - background: url(chrome://global/skin/media/muteButton.png) no-repeat center; - /* Remove the native button appearance and styling */ - -moz-appearance: none; - margin: 0; - padding: 0; - min-height: 28px; + background-image: url(chrome://global/skin/media/muteButton.png); min-width: 33px; - border: none; } .muteButton[muted] { - background: url(chrome://global/skin/media/unmuteButton.png) no-repeat center; + background-image: url(chrome://global/skin/media/unmuteButton.png); } .muteButton[noAudio] { - background: url(chrome://global/skin/media/noAudio.png) no-repeat center; + background-image: url(chrome://global/skin/media/noAudio.png); } .fullscreenButton { - background: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0) no-repeat center; - -moz-appearance: none; - margin: 0; - padding: 0; - min-height: 28px; - min-width: 28px; - border: none; + background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0); } .fullscreenButton[fullscreened] { @@ -176,7 +172,7 @@ } .timeThumb[showhours="true"] { - background: url(chrome://global/skin/media/scrubberThumbWide.png) no-repeat center; + background-image: url(chrome://global/skin/media/scrubberThumbWide.png); } .timeLabel { diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index ac59e44a3755..9f18a16571e7 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -381,8 +381,8 @@ static nsDefaultMimeTypeEntry defaultMimeEntries [] = { IMAGE_PNG, "png" }, // -- end extensions used during startup { TEXT_CSS, "css" }, - { IMAGE_JPG, "jpeg" }, - { IMAGE_JPG, "jpg" }, + { IMAGE_JPEG, "jpeg" }, + { IMAGE_JPEG, "jpg" }, { TEXT_HTML, "html" }, { TEXT_HTML, "htm" }, { APPLICATION_XPINSTALL, "xpi" }, @@ -460,7 +460,7 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = { IMAGE_BMP, "bmp", "BMP Image" }, { IMAGE_GIF, "gif", "GIF Image" }, { IMAGE_ICO, "ico,cur", "ICO Image" }, - { IMAGE_JPG, "jpeg,jpg,jfif,pjpeg,pjp", "JPEG Image" }, + { IMAGE_JPEG, "jpeg,jpg,jfif,pjpeg,pjp", "JPEG Image" }, { IMAGE_PNG, "png", "PNG Image" }, { IMAGE_TIFF, "tiff,tif", "TIFF Image" }, { IMAGE_XBM, "xbm", "XBM Image" }, diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp index f13a8b208027..30bd32a25c40 100644 --- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -266,7 +266,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer, container->SortChildrenBy3DZOrder(children); //FIXME/bug 810334 - for (PRUint32 i = 0; i < children.Length(); i++) { + for (uint32_t i = 0; i < children.Length(); i++) { if (!PrepareLayerList(children[i], aClip)) { return false; } diff --git a/widget/windows/nsTextStore.cpp b/widget/windows/nsTextStore.cpp index f529600132f7..87dfd50035bb 100644 --- a/widget/windows/nsTextStore.cpp +++ b/widget/windows/nsTextStore.cpp @@ -13,6 +13,9 @@ #include "nscore.h" #include "nsTextStore.h" #include "nsWindow.h" +#ifdef MOZ_METRO +#include "winrt/MetroWidget.h" +#endif #include "nsPrintfCString.h" #include "WinUtils.h" #include "mozilla/Preferences.h" @@ -339,7 +342,6 @@ nsTextStore::nsTextStore() mRefCnt = 1; mEditCookie = 0; mSinkMask = 0; - mWindow = nullptr; mLock = 0; mLockQueued = 0; mTextChange.acpStart = INT32_MAX; @@ -351,8 +353,8 @@ nsTextStore::~nsTextStore() { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore instance is destroyed, " - "mWindow=0x%p, mDocumentMgr=0x%p, mContext=0x%p", - this, mWindow, mDocumentMgr.get(), mContext.get())); + "mWidget=0x%p, mDocumentMgr=0x%p, mContext=0x%p", + this, mWidget, mDocumentMgr, mContext)); if (mCompositionTimer) { mCompositionTimer->Cancel(); @@ -362,12 +364,12 @@ nsTextStore::~nsTextStore() } bool -nsTextStore::Create(nsWindow* aWindow, +nsTextStore::Create(nsWindowBase* aWidget, IMEState::Enabled aIMEEnabled) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::Create(aWindow=0x%p, aIMEEnabled=%s)", - this, aWindow, GetIMEEnabledName(aIMEEnabled))); + ("TSF: 0x%p nsTextStore::Create(aWidget=0x%p, aIMEEnabled=%s)", + this, aWidget, GetIMEEnabledName(aIMEEnabled))); if (mDocumentMgr) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, @@ -385,7 +387,8 @@ nsTextStore::Create(nsWindow* aWindow, "(0x%08X)", this, hr)); return false; } - mWindow = aWindow; + mWidget = aWidget; + // Create context and add it to document manager hr = mDocumentMgr->CreateContext(sTsfClientId, 0, static_cast(this), @@ -425,13 +428,13 @@ nsTextStore::Destroy(void) PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::Destroy()", this)); - if (mWindow) { + if (mWidget) { // When blurred, Tablet Input Panel posts "blur" messages // and try to insert text when the message is retrieved later. // But by that time the text store is already destroyed, // so try to get the message early MSG msg; - if (::PeekMessageW(&msg, mWindow->GetWindowHandle(), + if (::PeekMessageW(&msg, mWidget->GetWindowHandle(), sFlushTIPInputMessage, sFlushTIPInputMessage, PM_REMOVE)) { ::DispatchMessageW(&msg); @@ -443,7 +446,7 @@ nsTextStore::Destroy(void) mDocumentMgr = NULL; } mSink = NULL; - mWindow = NULL; + mWidget = nullptr; PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::Destroy() succeeded", this)); @@ -756,9 +759,9 @@ nsTextStore::GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP) "try to get normal selection...", this)); // Construct and initialize an event to get selection info - nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, mWindow); - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); + nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, mWidget); + mWidget->InitEvent(event); + mWidget->DispatchWindowEvent(&event); if (!event.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::GetSelectionInternal() FAILED to " @@ -1087,8 +1090,8 @@ nsTextStore::SendTextEventForCompositionString() } // Use NS_TEXT_TEXT to set composition string - nsTextEvent event(true, NS_TEXT_TEXT, mWindow); - mWindow->InitEvent(event); + nsTextEvent event(true, NS_TEXT_TEXT, mWidget); + mWidget->InitEvent(event); nsRefPtr composingRange; hr = mCompositionView->GetRange(getter_AddRefs(composingRange)); @@ -1218,18 +1221,18 @@ nsTextStore::SendTextEventForCompositionString() ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() " "dispatching compositionupdate event...", this)); nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, - mWindow); - mWindow->InitEvent(compositionUpdate); + mWidget); + mWidget->InitEvent(compositionUpdate); compositionUpdate.data = mCompositionString; mLastDispatchedCompositionString = mCompositionString; - mWindow->DispatchWindowEvent(&compositionUpdate); + mWidget->DispatchWindowEvent(&compositionUpdate); } - if (mWindow && !mWindow->Destroyed()) { + if (mWidget && !mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::SendTextEventForCompositionString() " "dispatching text event...", this)); - mWindow->DispatchWindowEvent(&event); + mWidget->DispatchWindowEvent(&event); } PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, @@ -1282,12 +1285,12 @@ nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection, } return S_OK; } else { - nsSelectionEvent event(true, NS_SELECTION_SET, mWindow); + nsSelectionEvent event(true, NS_SELECTION_SET, mWidget); event.mOffset = pSelection->acpStart; event.mLength = uint32_t(pSelection->acpEnd - pSelection->acpStart); event.mReversed = pSelection->style.ase == TS_AE_START; - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); + mWidget->InitEvent(event); + mWidget->DispatchWindowEvent(&event); if (!event.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::SetSelectionInternal() FAILED due to " @@ -1415,10 +1418,10 @@ nsTextStore::GetText(LONG acpStart, } } // Send NS_QUERY_TEXT_CONTENT to get text content - nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWindow); - mWindow->InitEvent(event); + nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWidget); + mWidget->InitEvent(event); event.InitForQueryTextContent(uint32_t(acpStart), length); - mWindow->DispatchWindowEvent(&event); + mWidget->DispatchWindowEvent(&event); if (!event.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::GetText() FAILED due to " @@ -1693,11 +1696,11 @@ nsTextStore::GetEndACP(LONG *pacp) } // Flattened text is retrieved and its length returned - nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWindow); - mWindow->InitEvent(event); + nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWidget); + mWidget->InitEvent(event); // Return entire text event.InitForQueryTextContent(0, INT32_MAX); - mWindow->DispatchWindowEvent(&event); + mWidget->DispatchWindowEvent(&event); if (!event.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::GetEndACP() FAILED due to " @@ -1801,10 +1804,10 @@ nsTextStore::GetTextExt(TsViewCookie vcView, } // use NS_QUERY_TEXT_RECT to get rect in system, screen coordinates - nsQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWindow); - mWindow->InitEvent(event); + nsQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWidget); + mWidget->InitEvent(event); event.InitForQueryTextRect(acpStart, acpEnd - acpStart); - mWindow->DispatchWindowEvent(&event); + mWidget->DispatchWindowEvent(&event); if (!event.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " @@ -1817,19 +1820,21 @@ nsTextStore::GetTextExt(TsViewCookie vcView, if (event.mReply.mRect.height <= 0) event.mReply.mRect.height = 1; - // convert to unclipped screen rect - nsWindow* refWindow = static_cast( - event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow); - // Result rect is in top level widget coordinates - refWindow = refWindow->GetTopLevelWindow(false); - if (!refWindow) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " - "no top level window", this)); - return E_FAIL; - } + if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) { + // convert to unclipped screen rect + nsWindow* refWindow = static_cast( + event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWidget); + // Result rect is in top level widget coordinates + refWindow = refWindow->GetTopLevelWindow(false); + if (!refWindow) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetTextExt() FAILED due to " + "no top level window", this)); + return E_FAIL; + } - event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset()); + event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset()); + } // get bounding screen rect to test for clipping if (!GetScreenExtInternal(*prc)) { @@ -1902,9 +1907,9 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt) ("TSF: 0x%p nsTextStore::GetScreenExtInternal()", this)); // use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates - nsQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWindow); - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); + nsQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWidget); + mWidget->InitEvent(event); + mWidget->DispatchWindowEvent(&event); if (!event.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " @@ -1912,35 +1917,50 @@ nsTextStore::GetScreenExtInternal(RECT &aScreenExt) return false; } - nsWindow* refWindow = static_cast( - event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow); - // Result rect is in top level widget coordinates - refWindow = refWindow->GetTopLevelWindow(false); - if (!refWindow) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " - "no top level window", this)); - return false; - } - - nsIntRect boundRect; - if (NS_FAILED(refWindow->GetClientBounds(boundRect))) { - PR_LOG(sTextStoreLog, PR_LOG_ERROR, - ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " - "failed to get the client bounds", this)); - return false; - } - - boundRect.MoveTo(0, 0); - - // Clip frame rect to window rect - boundRect.IntersectRect(event.mReply.mRect, boundRect); - if (!boundRect.IsEmpty()) { - boundRect.MoveBy(refWindow->WidgetToScreenOffset()); + if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { + nsIntRect boundRect; + if (NS_FAILED(mWidget->GetClientBounds(boundRect))) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + "failed to get the client bounds", this)); + return false; + } ::SetRect(&aScreenExt, boundRect.x, boundRect.y, boundRect.XMost(), boundRect.YMost()); } else { - ::SetRectEmpty(&aScreenExt); + NS_ASSERTION(XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop, + "environment isn't WindowsEnvironmentType_Desktop!"); + nsWindow* refWindow = static_cast( + event.mReply.mFocusedWidget ? + event.mReply.mFocusedWidget : mWidget); + // Result rect is in top level widget coordinates + refWindow = refWindow->GetTopLevelWindow(false); + if (!refWindow) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + "no top level window", this)); + return false; + } + + nsIntRect boundRect; + if (NS_FAILED(refWindow->GetClientBounds(boundRect))) { + PR_LOG(sTextStoreLog, PR_LOG_ERROR, + ("TSF: 0x%p nsTextStore::GetScreenExtInternal() FAILED due to " + "failed to get the client bounds", this)); + return false; + } + + boundRect.MoveTo(0, 0); + + // Clip frame rect to window rect + boundRect.IntersectRect(event.mReply.mRect, boundRect); + if (!boundRect.IsEmpty()) { + boundRect.MoveBy(refWindow->WidgetToScreenOffset()); + ::SetRect(&aScreenExt, boundRect.x, boundRect.y, + boundRect.XMost(), boundRect.YMost()); + } else { + ::SetRectEmpty(&aScreenExt); + } } PR_LOG(sTextStoreLog, PR_LOG_DEBUG, @@ -1956,8 +1976,9 @@ nsTextStore::GetWnd(TsViewCookie vcView, HWND *phwnd) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, - ("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), mWindow=0x%p", - this, vcView, phwnd, mWindow)); + ("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), " + "mWidget=0x%p", + this, vcView, phwnd, mWidget)); if (vcView != TEXTSTORE_DEFAULT_VIEW) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, @@ -1973,7 +1994,7 @@ nsTextStore::GetWnd(TsViewCookie vcView, return E_INVALIDARG; } - *phwnd = mWindow->GetWindowHandle(); + *phwnd = mWidget->GetWindowHandle(); PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::GetWnd() succeeded: *phwnd=0x%p", @@ -2135,10 +2156,11 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() " "dispatching a compositionstart event...", this)); - nsCompositionEvent compStartEvent(true, NS_COMPOSITION_START, mWindow); - mWindow->InitEvent(compStartEvent); - mWindow->DispatchWindowEvent(&compStartEvent); - if (!mWindow || mWindow->Destroyed()) { + nsCompositionEvent compStartEvent(true, NS_COMPOSITION_START, + mWidget); + mWidget->InitEvent(compStartEvent); + mWidget->DispatchWindowEvent(&compStartEvent); + if (!mWidget || mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED " "due to the widget destroyed by compositionstart event", this)); @@ -2149,10 +2171,11 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() " "dispatching a compositionupdate event...", this)); - nsCompositionEvent compUpdateEvent(true, NS_COMPOSITION_UPDATE, mWindow); + nsCompositionEvent compUpdateEvent(true, NS_COMPOSITION_UPDATE, + mWidget); compUpdateEvent.data = aInsertStr; - mWindow->DispatchWindowEvent(&compUpdateEvent); - if (!mWindow || mWindow->Destroyed()) { + mWidget->DispatchWindowEvent(&compUpdateEvent); + if (!mWidget || mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() " "FAILED due to the widget destroyed by compositionupdate event", @@ -2164,13 +2187,13 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() " "dispatching a text event...", this)); - nsTextEvent textEvent(true, NS_TEXT_TEXT, mWindow); - mWindow->InitEvent(textEvent); + nsTextEvent textEvent(true, NS_TEXT_TEXT, mWidget); + mWidget->InitEvent(textEvent); textEvent.theText = aInsertStr; textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING("\n")); - mWindow->DispatchWindowEvent(&textEvent); - if (!mWindow || mWindow->Destroyed()) { + mWidget->DispatchWindowEvent(&textEvent); + if (!mWidget || mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED " "due to the widget destroyed by text event", this)); @@ -2180,10 +2203,10 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() " "dispatching a compositionend event...", this)); - nsCompositionEvent compEndEvent(true, NS_COMPOSITION_END, mWindow); + nsCompositionEvent compEndEvent(true, NS_COMPOSITION_END, mWidget); compEndEvent.data = aInsertStr; - mWindow->DispatchWindowEvent(&compEndEvent); - if (!mWindow || mWindow->Destroyed()) { + mWidget->DispatchWindowEvent(&compEndEvent); + if (!mWidget || mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() FAILED " "due to the widget destroyed by compositionend event", this)); @@ -2209,9 +2232,9 @@ nsTextStore::InsertTextAtSelectionInternal(const nsAString &aInsertStr, PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::InsertTextAtSelectionInternal() succeeded: " - "mWindow=0x%p, mWindow->Destroyed()=%s, aTextChange={ acpStart=%ld, " + "mWidget=0x%p, mWidget->Destroyed()=%s, aTextChange={ acpStart=%ld, " "acpOldEnd=%ld, acpNewEnd=%ld }", - this, mWindow, GetBoolName(mWindow ? mWindow->Destroyed() : true), + this, mWidget, GetBoolName(mWidget ? mWidget->Destroyed() : true), aTextChange ? aTextChange->acpStart : 0, aTextChange ? aTextChange->acpOldEnd : 0, aTextChange ? aTextChange->acpNewEnd : 0)); @@ -2264,12 +2287,12 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition, "dispatching selectionset event...")); // Select composition range so the new composition replaces the range - nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWindow); - mWindow->InitEvent(selEvent); + nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWidget); + mWidget->InitEvent(selEvent); selEvent.mOffset = uint32_t(mCompositionStart); selEvent.mLength = uint32_t(mCompositionLength); selEvent.mReversed = false; - mWindow->DispatchWindowEvent(&selEvent); + mWidget->DispatchWindowEvent(&selEvent); if (!selEvent.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due " @@ -2278,9 +2301,9 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition, } // Set up composition - nsQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, mWindow); - mWindow->InitEvent(queryEvent); - mWindow->DispatchWindowEvent(&queryEvent); + nsQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, mWidget); + mWidget->InitEvent(queryEvent); + mWidget->DispatchWindowEvent(&queryEvent); if (!queryEvent.mSucceeded) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() FAILED due " @@ -2299,9 +2322,9 @@ nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition, mCompositionSelection.style.ase = TS_AE_END; mCompositionSelection.style.fInterimChar = FALSE; } - nsCompositionEvent event(true, NS_COMPOSITION_START, mWindow); - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); + nsCompositionEvent event(true, NS_COMPOSITION_START, mWidget); + mWidget->InitEvent(event); + mWidget->DispatchWindowEvent(&event); PR_LOG(sTextStoreLog, PR_LOG_DEBUG, ("TSF: 0x%p nsTextStore::OnStartCompositionInternal() succeeded: " @@ -2476,12 +2499,12 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) ("TSF: 0x%p nsTextStore::OnEndComposition(), " "dispatching compositionupdate event...", this)); nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE, - mWindow); - mWindow->InitEvent(compositionUpdate); + mWidget); + mWidget->InitEvent(compositionUpdate); compositionUpdate.data = mCompositionString; mLastDispatchedCompositionString = mCompositionString; - mWindow->DispatchWindowEvent(&compositionUpdate); - if (!mWindow || mWindow->Destroyed()) { + mWidget->DispatchWindowEvent(&compositionUpdate); + if (!mWidget || mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::OnEndComposition(), " "succeeded, but the widget has gone", this)); @@ -2494,14 +2517,14 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) "dispatching text event...", this)); // Use NS_TEXT_TEXT to commit composition string - nsTextEvent textEvent(true, NS_TEXT_TEXT, mWindow); - mWindow->InitEvent(textEvent); + nsTextEvent textEvent(true, NS_TEXT_TEXT, mWidget); + mWidget->InitEvent(textEvent); textEvent.theText = mCompositionString; textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING("\n")); - mWindow->DispatchWindowEvent(&textEvent); + mWidget->DispatchWindowEvent(&textEvent); - if (!mWindow || mWindow->Destroyed()) { + if (!mWidget || mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::OnEndComposition(), " "succeeded, but the widget has gone", this)); @@ -2512,12 +2535,12 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) ("TSF: 0x%p nsTextStore::OnEndComposition(), " "dispatching compositionend event...", this)); - nsCompositionEvent event(true, NS_COMPOSITION_END, mWindow); + nsCompositionEvent event(true, NS_COMPOSITION_END, mWidget); event.data = mLastDispatchedCompositionString; - mWindow->InitEvent(event); - mWindow->DispatchWindowEvent(&event); + mWidget->InitEvent(event); + mWidget->DispatchWindowEvent(&event); - if (!mWindow || mWindow->Destroyed()) { + if (!mWidget || mWidget->Destroyed()) { PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: 0x%p nsTextStore::OnEndComposition(), " "succeeded, but the widget has gone", this)); @@ -2538,22 +2561,24 @@ nsTextStore::OnEndComposition(ITfCompositionView* pComposition) // static nsresult -nsTextStore::OnFocusChange(bool aFocus, - nsWindow* aWindow, +nsTextStore::OnFocusChange(bool aGotFocus, + nsWindowBase* aFocusedWidget, IMEState::Enabled aIMEEnabled) { PR_LOG(sTextStoreLog, PR_LOG_DEBUG, - ("TSF: nsTextStore::OnFocusChange(aFocus=%s, aWindow=0x%p, " - "aIMEEnabled=%s), sTsfThreadMgr=0x%p, sTsfTextStore=0x%p", - GetBoolName(aFocus), aWindow, GetIMEEnabledName(aIMEEnabled), - sTsfThreadMgr, sTsfTextStore)); + ("TSF: nsTextStore::OnFocusChange(aGotFocus=%s, " + "aFocusedWidget=0x%p, aIMEEnabled=%s), sTsfThreadMgr=0x%p, " + "sTsfTextStore=0x%p", + GetBoolName(aGotFocus), aFocusedWidget, + GetIMEEnabledName(aIMEEnabled), sTsfThreadMgr, sTsfTextStore)); // no change notifications if TSF is disabled - if (!sTsfThreadMgr || !sTsfTextStore) + if (!sTsfThreadMgr || !sTsfTextStore) { return NS_ERROR_NOT_AVAILABLE; + } - if (aFocus) { - bool bRet = sTsfTextStore->Create(aWindow, aIMEEnabled); + if (aGotFocus) { + bool bRet = sTsfTextStore->Create(aFocusedWidget, aIMEEnabled); NS_ENSURE_TRUE(bRet, NS_ERROR_FAILURE); NS_ENSURE_TRUE(sTsfTextStore->mDocumentMgr, NS_ERROR_FAILURE); HRESULT hr = sTsfThreadMgr->SetFocus(sTsfTextStore->mDocumentMgr); @@ -2594,7 +2619,7 @@ nsTextStore::OnTextChangeInternal(uint32_t aStart, mTextChange.acpStart = NS_MIN(mTextChange.acpStart, LONG(aStart)); mTextChange.acpOldEnd = NS_MAX(mTextChange.acpOldEnd, LONG(aOldEnd)); mTextChange.acpNewEnd = NS_MAX(mTextChange.acpNewEnd, LONG(aNewEnd)); - ::PostMessageW(mWindow->GetWindowHandle(), + ::PostMessageW(mWidget->GetWindowHandle(), WM_USER_TSF_TEXTCHANGE, 0, 0); } return NS_OK; diff --git a/widget/windows/nsTextStore.h b/widget/windows/nsTextStore.h index 832b87ccc058..b04d819806c2 100644 --- a/widget/windows/nsTextStore.h +++ b/widget/windows/nsTextStore.h @@ -11,6 +11,7 @@ #include "nsCOMPtr.h" #include "nsITimer.h" #include "nsIWidget.h" +#include "nsWindowBase.h" #include "mozilla/Attributes.h" #include @@ -22,6 +23,9 @@ struct ITfDisplayAttributeMgr; struct ITfCategoryMgr; class nsWindow; class nsTextEvent; +#ifdef MOZ_METRO +class MetroWidget; +#endif // It doesn't work well when we notify TSF of text change // during a mutation observer call because things get broken. @@ -100,8 +104,9 @@ public: sTsfTextStore->SetInputContextInternal(aContext.mIMEState.mEnabled); } - static nsresult OnFocusChange(bool, nsWindow*, IMEState::Enabled); - + static nsresult OnFocusChange(bool aGotFocus, + nsWindowBase* aFocusedWidget, + IMEState::Enabled aIMEEnabled); static nsresult OnTextChange(uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd) @@ -154,7 +159,8 @@ protected: nsTextStore(); ~nsTextStore(); - bool Create(nsWindow*, IMEState::Enabled); + bool Create(nsWindowBase* aWidget, + IMEState::Enabled aIMEEnabled); bool Destroy(void); bool IsReadLock(DWORD aLock) const @@ -192,6 +198,8 @@ protected: HRESULT SaveTextEvent(const nsTextEvent* aEvent); nsresult OnCompositionTimer(); + // Holds the pointer to our current win32 or metro widget + nsRefPtr mWidget; // Document manager for the currently focused editor nsRefPtr mDocumentMgr; // Edit cookie associated with the current editing context @@ -202,8 +210,6 @@ protected: nsRefPtr mSink; // TS_AS_* mask of what events to notify DWORD mSinkMask; - // Window containing the focused editor - nsWindow* mWindow; // 0 if not locked, otherwise TS_LF_* indicating the current lock DWORD mLock; // 0 if no lock is queued, otherwise TS_LF_* indicating the queue lock diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index a88cbf3e027f..14ae0ec4b3a8 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -302,7 +302,7 @@ static const int32_t kResizableBorderMinSize = 3; * **************************************************************/ -nsWindow::nsWindow() : nsBaseWidget() +nsWindow::nsWindow() : nsWindowBase() { #ifdef PR_LOGGING if (!gWindowsLog) { @@ -5046,7 +5046,9 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, case WM_APPCOMMAND: { uint32_t appCommand = GET_APPCOMMAND_LPARAM(lParam); - + uint32_t contentCommandMessage = NS_EVENT_NULL; + // XXX After we implement KeyboardEvent.key, we should dispatch the + // key event if (GET_DEVICE_LPARAM(lParam) == FAPPCOMMAND_KEY) is. switch (appCommand) { case APPCOMMAND_BROWSER_BACKWARD: @@ -5075,6 +5077,31 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, result = true; } break; + + // Use content command for following commands: + case APPCOMMAND_COPY: + contentCommandMessage = NS_CONTENT_COMMAND_COPY; + break; + case APPCOMMAND_CUT: + contentCommandMessage = NS_CONTENT_COMMAND_CUT; + break; + case APPCOMMAND_PASTE: + contentCommandMessage = NS_CONTENT_COMMAND_PASTE; + break; + case APPCOMMAND_REDO: + contentCommandMessage = NS_CONTENT_COMMAND_REDO; + break; + case APPCOMMAND_UNDO: + contentCommandMessage = NS_CONTENT_COMMAND_UNDO; + break; + } + + if (contentCommandMessage) { + nsContentCommandEvent contentCommand(true, contentCommandMessage, this); + DispatchWindowEvent(&contentCommand); + // tell the driver that we handled the event + *aRetValue = 1; + result = true; } // default = false - tell the driver that the event was not handled } diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index 763a5badb024..5fca2e5af4c8 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -12,6 +12,7 @@ #include "nsAutoPtr.h" #include "nsBaseWidget.h" +#include "nsWindowBase.h" #include "nsdefs.h" #include "nsIdleService.h" #include "nsToolkit.h" @@ -64,7 +65,7 @@ class ModifierKeyState; * Native WIN32 window wrapper. */ -class nsWindow : public nsBaseWidget +class nsWindow : public nsWindowBase { typedef mozilla::TimeStamp TimeStamp; typedef mozilla::TimeDuration TimeDuration; @@ -79,9 +80,11 @@ public: friend class nsWindowGfx; - /** - * nsIWidget interface - */ + // nsWindowBase + virtual void InitEvent(nsGUIEvent& aEvent, nsIntPoint* aPoint = nullptr) MOZ_OVERRIDE; + virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) MOZ_OVERRIDE; + + // nsIWidget interface NS_IMETHOD Create(nsIWidget *aParent, nsNativeWidget aNativeParent, const nsIntRect &aRect, @@ -186,13 +189,11 @@ public: /** * Event helpers */ - void InitEvent(nsGUIEvent& event, nsIntPoint* aPoint = nullptr); virtual bool DispatchMouseEvent(uint32_t aEventType, WPARAM wParam, LPARAM lParam, bool aIsContextMenuKey = false, int16_t aButton = nsMouseEvent::eLeftButton, uint16_t aInputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE); - virtual bool DispatchWindowEvent(nsGUIEvent* event); virtual bool DispatchWindowEvent(nsGUIEvent*event, nsEventStatus &aStatus); void InitKeyEvent(nsKeyEvent& aKeyEvent, const NativeKey& aNativeKey, @@ -215,7 +216,6 @@ public: * Window utilities */ nsWindow* GetTopLevelWindow(bool aStopOnDialogOrPopup); - HWND GetWindowHandle() { return mWnd; } WNDPROC GetPrevWindowProc() { return mPrevWndProc; } WindowHook& GetWindowHook() { return mWindowHook; } nsWindow* GetParentWindow(bool aIncludeOwner); diff --git a/widget/windows/nsWindowBase.h b/widget/windows/nsWindowBase.h new file mode 100644 index 000000000000..38643b63e3a2 --- /dev/null +++ b/widget/windows/nsWindowBase.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; 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 nsWindowBase_h_ +#define nsWindowBase_h_ + +#include "nsBaseWidget.h" + +/* + * nsWindowBase - Base class of common methods other classes need to access + * in both win32 and winrt window classes. + */ + +class nsWindowBase : public nsBaseWidget +{ +public: + /* + * Return the HWND or null for this widget. + */ + virtual HWND GetWindowHandle() MOZ_FINAL { + return static_cast(GetNativeData(NS_NATIVE_WINDOW)); + } + + /* + * Init a standard gecko event for this widget. + */ + virtual void InitEvent(nsGUIEvent& aEvent, nsIntPoint* aPoint = nullptr) = 0; + + /* + * Dispatch a gecko event for this widget. + */ + virtual bool DispatchWindowEvent(nsGUIEvent* aEvent) = 0; +}; + +#endif // nsWindowBase_h_ diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 5e9bda0a6bbd..80e1290c55fd 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1070,7 +1070,7 @@ struct nsCycleCollector // Prepare for and cleanup after one or more collection(s). bool PrepareForCollection(nsCycleCollectorResults *aResults, nsTArray *aWhiteNodes); - void GCIfNeeded(bool aForceGC); + void FixGrayBits(bool aForceGC); void CleanupAfterCollection(); // Start and finish an individual collection. @@ -2699,10 +2699,10 @@ nsCycleCollector::LogPurpleRemoval(void* aObject) // and also when UnmarkGray has run out of stack. We also force GCs on shut // down to collect cycles involving both DOM and JS. void -nsCycleCollector::GCIfNeeded(bool aForceGC) +nsCycleCollector::FixGrayBits(bool aForceGC) { MOZ_ASSERT(NS_IsMainThread(), - "nsCycleCollector::GCIfNeeded() must be called on the main thread."); + "nsCycleCollector::FixGrayBits() must be called on the main thread."); if (mParams.mDoNothing) return; @@ -2711,6 +2711,8 @@ nsCycleCollector::GCIfNeeded(bool aForceGC) return; if (!aForceGC) { + mJSRuntime->FixWeakMappingGrayBits(); + bool needGC = mJSRuntime->NeedCollect(); // Only do a telemetry ping for non-shutdown CCs. Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_NEED_GC, needGC); @@ -2811,7 +2813,7 @@ nsCycleCollector::Collect(bool aMergeCompartments, uint32_t totalCollections = 0; while (aTryCollections > totalCollections) { // Synchronous cycle collection. Always force a JS GC beforehand. - GCIfNeeded(true); + FixGrayBits(true); if (aListener && NS_FAILED(aListener->Begin())) aListener = nullptr; if (!(BeginCollection(aMergeCompartments, aListener) && @@ -3272,7 +3274,7 @@ public: if (aListener) { aListener->GetWantAllTraces(&wantAllTraces); } - mCollector->GCIfNeeded(wantAllTraces); + mCollector->FixGrayBits(wantAllTraces); MutexAutoLock autoLock(mLock); diff --git a/xpcom/base/nsCycleCollector.h b/xpcom/base/nsCycleCollector.h index fbc6b51b2690..098f89f786be 100644 --- a/xpcom/base/nsCycleCollector.h +++ b/xpcom/base/nsCycleCollector.h @@ -67,6 +67,11 @@ struct nsCycleCollectionJSRuntime virtual void NotifyLeaveCycleCollectionThread() = 0; virtual void NotifyEnterMainThread() = 0; + /** + * Unmark gray any weak map values, as needed. + */ + virtual void FixWeakMappingGrayBits() = 0; + /** * Should we force a JavaScript GC before a CC? */ diff --git a/xpcom/glue/nsProxyRelease.cpp b/xpcom/glue/nsProxyRelease.cpp index 64b81e0899e8..4b8823e388f2 100644 --- a/xpcom/glue/nsProxyRelease.cpp +++ b/xpcom/glue/nsProxyRelease.cpp @@ -30,6 +30,11 @@ NS_ProxyRelease(nsIEventTarget *target, nsISupports *doomed, { nsresult rv; + if (!doomed) { + // nothing to do + return NS_OK; + } + if (!target) { NS_RELEASE(doomed); return NS_OK; diff --git a/xpcom/glue/nsProxyRelease.h b/xpcom/glue/nsProxyRelease.h index 51a330c04e8f..78d6868d49aa 100644 --- a/xpcom/glue/nsProxyRelease.h +++ b/xpcom/glue/nsProxyRelease.h @@ -117,7 +117,7 @@ public: ~nsMainThreadPtrHolder() { if (NS_IsMainThread()) { NS_IF_RELEASE(mRawPtr); - } else { + } else if (mRawPtr) { nsCOMPtr mainThread = do_GetMainThread(); if (!mainThread) { NS_WARNING("Couldn't get main thread! Leaking pointer."); @@ -165,6 +165,7 @@ class nsMainThreadPtrHandle nsMainThreadPtrHandle(const nsMainThreadPtrHandle& aOther) : mPtr(aOther.mPtr) {} nsMainThreadPtrHandle& operator=(const nsMainThreadPtrHandle& aOther) { mPtr = aOther.mPtr; + return *this; } operator nsMainThreadPtrHolder*() { return mPtr.get(); } diff --git a/xpcom/glue/nsThreadUtils.cpp b/xpcom/glue/nsThreadUtils.cpp index de50728d5047..437e45fec4c1 100644 --- a/xpcom/glue/nsThreadUtils.cpp +++ b/xpcom/glue/nsThreadUtils.cpp @@ -37,7 +37,8 @@ nsRunnable::Run() return NS_OK; } -NS_IMPL_THREADSAFE_ISUPPORTS1(nsCancelableRunnable, nsICancelableRunnable) +NS_IMPL_THREADSAFE_ISUPPORTS2(nsCancelableRunnable, nsICancelableRunnable, + nsIRunnable) NS_IMETHODIMP nsCancelableRunnable::Run() diff --git a/xpcom/idl-parser/xpidl.py b/xpcom/idl-parser/xpidl.py index 5e902d568b5b..551b778feb84 100644 --- a/xpcom/idl-parser/xpidl.py +++ b/xpcom/idl-parser/xpidl.py @@ -1009,7 +1009,8 @@ class IDLParser(object): 'raises': 'RAISES', 'readonly': 'READONLY', 'native': 'NATIVE', - 'typedef': 'TYPEDEF' + 'typedef': 'TYPEDEF', + 'Infinity': 'INFINITY' } tokens = [ @@ -1439,9 +1440,11 @@ class IDLParser(object): def p_optdefvalue(self, p): """optdefvalue : '=' STRING + | '=' INFINITY + | '=' '-' INFINITY | """ if len(p) > 1: - p[0] = p[2] + p[0] = "".join(p[2:]) else: p[0] = None diff --git a/xpcom/tests/Makefile.in b/xpcom/tests/Makefile.in index 52f19e7e7e19..58a035fac58e 100644 --- a/xpcom/tests/Makefile.in +++ b/xpcom/tests/Makefile.in @@ -73,6 +73,7 @@ CPP_UNIT_TESTS = \ TestObserverService.cpp \ TestPipe.cpp \ TestRefPtr.cpp \ + TestSettingsAPI.cpp \ TestTextFormatter.cpp \ TestTArray.cpp \ $(NULL) diff --git a/xpfe/appshell/public/nsIAppShellService.idl b/xpfe/appshell/public/nsIAppShellService.idl index 4c7d98affc49..f73bfd42b158 100644 --- a/xpfe/appshell/public/nsIAppShellService.idl +++ b/xpfe/appshell/public/nsIAppShellService.idl @@ -16,7 +16,7 @@ interface nsIAppShell; struct JSContext; %} -[scriptable, uuid(76e6364a-5453-47c7-ad83-8c30eff20a75)] +[scriptable, uuid(5c19ab54-67bf-46d0-ac5b-21abd9050c3b)] interface nsIAppShellService : nsISupports { /** @@ -117,4 +117,10 @@ interface nsIAppShellService : nsISupports * @param aWindow you see the pattern */ void unregisterTopLevelWindow(in nsIXULWindow aWindow); + + /** + * Whether the hidden private window has been lazily created. + */ + [noscript] + readonly attribute boolean hasHiddenPrivateWindow; }; diff --git a/xpfe/appshell/src/nsAppShellService.cpp b/xpfe/appshell/src/nsAppShellService.cpp index c66b192a8105..eb9ce06ab2ad 100644 --- a/xpfe/appshell/src/nsAppShellService.cpp +++ b/xpfe/appshell/src/nsAppShellService.cpp @@ -82,6 +82,22 @@ NS_IMPL_ISUPPORTS2(nsAppShellService, NS_IMETHODIMP nsAppShellService::CreateHiddenWindow() +{ + return CreateHiddenWindowHelper(false); +} + +void +nsAppShellService::EnsurePrivateHiddenWindow() +{ +#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING + if (!mHiddenPrivateWindow) { + CreateHiddenWindowHelper(true); + } +#endif +} + +nsresult +nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate) { nsresult rv; int32_t initialHeight = 100, initialWidth = 100; @@ -91,7 +107,11 @@ nsAppShellService::CreateHiddenWindow() nsAdoptingCString prefVal = Preferences::GetCString("browser.hiddenWindowChromeURL"); const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL; - mApplicationProvidedHiddenWindow = prefVal.get() ? true : false; + if (aIsPrivate) { + hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL; + } else { + mApplicationProvidedHiddenWindow = prefVal.get() ? true : false; + } #else static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL; uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL; @@ -102,23 +122,26 @@ nsAppShellService::CreateHiddenWindow() NS_ENSURE_SUCCESS(rv, rv); nsRefPtr newWindow; - rv = JustCreateTopWindow(nullptr, url, - chromeMask, initialWidth, initialHeight, - true, getter_AddRefs(newWindow)); - NS_ENSURE_SUCCESS(rv, rv); - - mHiddenWindow.swap(newWindow); + if (!aIsPrivate) { + rv = JustCreateTopWindow(nullptr, url, + chromeMask, initialWidth, initialHeight, + true, getter_AddRefs(newWindow)); + NS_ENSURE_SUCCESS(rv, rv); + mHiddenWindow.swap(newWindow); + } #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING - // Create the hidden private window - chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; + else { + // Create the hidden private window + chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW; - rv = JustCreateTopWindow(nullptr, url, - chromeMask, initialWidth, initialHeight, - true, getter_AddRefs(newWindow)); - NS_ENSURE_SUCCESS(rv, rv); + rv = JustCreateTopWindow(nullptr, url, + chromeMask, initialWidth, initialHeight, + true, getter_AddRefs(newWindow)); + NS_ENSURE_SUCCESS(rv, rv); - mHiddenPrivateWindow.swap(newWindow); + mHiddenPrivateWindow.swap(newWindow); + } #endif // RegisterTopLevelWindow(newWindow); -- Mac only @@ -446,6 +469,8 @@ nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow) #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING NS_ENSURE_ARG_POINTER(aWindow); + EnsurePrivateHiddenWindow(); + *aWindow = mHiddenPrivateWindow; NS_IF_ADDREF(*aWindow); return *aWindow ? NS_OK : NS_ERROR_FAILURE; @@ -458,6 +483,8 @@ NS_IMETHODIMP nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow) { #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING + EnsurePrivateHiddenWindow(); + nsresult rv; nsCOMPtr docShell; NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE); @@ -476,6 +503,19 @@ nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow) #endif } +NS_IMETHODIMP +nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow) +{ +#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING + NS_ENSURE_ARG_POINTER(aHasPrivateWindow); + + *aHasPrivateWindow = !!mHiddenPrivateWindow; + return NS_OK; +#else + return NS_ERROR_NOT_IMPLEMENTED; +#endif +} + NS_IMETHODIMP nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindow **aWindow, JSContext **aJSContext) diff --git a/xpfe/appshell/src/nsAppShellService.h b/xpfe/appshell/src/nsAppShellService.h index 0e6c2d6d8b83..e040678948ad 100644 --- a/xpfe/appshell/src/nsAppShellService.h +++ b/xpfe/appshell/src/nsAppShellService.h @@ -32,6 +32,9 @@ public: protected: ~nsAppShellService(); + nsresult CreateHiddenWindowHelper(bool aIsPrivate); + void EnsurePrivateHiddenWindow(); + nsresult JustCreateTopWindow(nsIXULWindow *aParent, nsIURI *aUrl, uint32_t aChromeMask,