Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-06-17 15:41:18 -04:00
commit 66a404b11c
165 changed files with 2778 additions and 1826 deletions

View File

@ -7,6 +7,7 @@ let LoopUI;
XPCOMUtils.defineLazyModuleGetter(this, "injectLoopAPI", "resource:///modules/loop/MozLoopAPI.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/loop/MozLoopService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/PanelFrame.jsm");
(function() {
@ -19,41 +20,24 @@ XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/l
* the panel to the button which triggers it.
*/
openCallPanel: function(event) {
let panel = document.getElementById("loop-panel");
let anchor = event.target;
let iframe = document.getElementById("loop-panel-frame");
let callback = iframe => {
iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() {
iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
injectLoopAPI(iframe.contentWindow);
if (!iframe) {
// XXX This should be using SharedFrame (bug 1011392 may do this).
iframe = document.createElement("iframe");
iframe.setAttribute("id", "loop-panel-frame");
iframe.setAttribute("type", "content");
iframe.setAttribute("class", "loop-frame social-panel-frame");
iframe.setAttribute("flex", "1");
panel.appendChild(iframe);
}
// We use loopPanelInitialized so that we know we've finished localising before
// sizing the panel.
iframe.contentWindow.addEventListener("loopPanelInitialized",
function documentLoaded() {
iframe.contentWindow.removeEventListener("loopPanelInitialized",
documentLoaded, true);
}, true);
// We inject in DOMContentLoaded as that is before any scripts have tun.
iframe.addEventListener("DOMContentLoaded", function documentDOMLoaded() {
iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
injectLoopAPI(iframe.contentWindow);
}, true);
};
// We use loopPanelInitialized so that we know we've finished localising before
// sizing the panel.
iframe.contentWindow.addEventListener("loopPanelInitialized",
function documentLoaded() {
iframe.contentWindow.removeEventListener("loopPanelInitialized",
documentLoaded, true);
// XXX We end up with the wrong size here, so this
// needs further investigation (bug 1011394).
sizeSocialPanelToContent(panel, iframe);
}, true);
}, true);
iframe.setAttribute("src", "about:looppanel");
panel.hidden = false;
panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
PanelFrame.showPopup(window, PanelUI, event.target, "loop", null,
"about:looppanel", null, callback);
},
/**
@ -63,6 +47,5 @@ XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService", "resource:///modules/l
initialize: function() {
MozLoopService.initialize();
},
};
})();

View File

@ -12,13 +12,12 @@ let SocialUI,
(function() {
// The minimum sizes for the auto-resize panel code.
const PANEL_MIN_HEIGHT = 100;
const PANEL_MIN_WIDTH = 330;
XPCOMUtils.defineLazyModuleGetter(this, "SharedFrame",
"resource:///modules/SharedFrame.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame",
"resource:///modules/PanelFrame.jsm");
XPCOMUtils.defineLazyGetter(this, "OpenGraphBuilder", function() {
let tmp = {};
Cu.import("resource:///modules/Social.jsm", tmp);
@ -1145,66 +1144,6 @@ SocialStatus = {
return this._toolbarHelper;
},
get _dynamicResizer() {
delete this._dynamicResizer;
this._dynamicResizer = new DynamicResizeWatcher();
return this._dynamicResizer;
},
// status panels are one-per button per-process, we swap the docshells between
// windows when necessary
_attachNotificatonPanel: function(aParent, aButton, provider) {
aParent.hidden = !SocialUI.enabled;
let notificationFrameId = "social-status-" + provider.origin;
let frame = document.getElementById(notificationFrameId);
// If the button was customized to a new location, we we'll destroy the
// iframe and start fresh.
if (frame && frame.parentNode != aParent) {
SharedFrame.forgetGroup(frame.id);
frame.parentNode.removeChild(frame);
frame = null;
}
if (!frame) {
let size = provider.getPageSize("status");
let {width, height} = size ? size : {width: PANEL_MIN_WIDTH, height: PANEL_MIN_HEIGHT};
frame = SharedFrame.createFrame(
notificationFrameId, /* frame name */
aParent, /* parent */
{
"type": "content",
"mozbrowser": "true",
"class": "social-panel-frame",
"id": notificationFrameId,
"tooltip": "aHTMLTooltip",
"context": "contentAreaContextMenu",
"flex": "1",
// work around bug 793057 - by making the panel roughly the final size
// we are more likely to have the anchor in the correct position.
"style": "width: " + width + "px; height: " + height + "px;",
"dynamicresizer": !size,
"origin": provider.origin,
"src": provider.statusURL
}
);
if (frame.socialErrorListener)
frame.socialErrorListener.remove();
if (frame.docShell) {
frame.docShell.isActive = false;
Social.setErrorListener(frame, this.setPanelErrorMessage.bind(this));
}
} else {
frame.setAttribute("origin", provider.origin);
SharedFrame.updateURL(notificationFrameId, provider.statusURL);
}
aButton.setAttribute("notificationFrameId", notificationFrameId);
},
updateButton: function(origin) {
let id = this._toolbarHelper.idFromOrigin(origin);
let widget = CustomizableUI.getWidget(id);
@ -1249,96 +1188,8 @@ SocialStatus = {
let origin = aToolbarButton.getAttribute("origin");
let provider = Social._getProviderFromOrigin(origin);
// if we're a slice in the hamburger, use that panel instead
let widgetGroup = CustomizableUI.getWidget(aToolbarButton.getAttribute("id"));
let widget = widgetGroup.forWindow(window);
let panel, showingEvent, hidingEvent;
let inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
if (inMenuPanel) {
panel = document.getElementById("PanelUI-socialapi");
this._attachNotificatonPanel(panel, aToolbarButton, provider);
widget.node.setAttribute("closemenu", "none");
showingEvent = "ViewShowing";
hidingEvent = "ViewHiding";
} else {
panel = document.getElementById("social-notification-panel");
this._attachNotificatonPanel(panel, aToolbarButton, provider);
showingEvent = "popupshown";
hidingEvent = "popuphidden";
}
let notificationFrameId = aToolbarButton.getAttribute("notificationFrameId");
let notificationFrame = document.getElementById(notificationFrameId);
let wasAlive = SharedFrame.isGroupAlive(notificationFrameId);
SharedFrame.setOwner(notificationFrameId, notificationFrame);
// Clear dimensions on all browsers so the panel size will
// only use the selected browser.
let frameIter = panel.firstElementChild;
while (frameIter) {
frameIter.collapsed = (frameIter != notificationFrame);
frameIter = frameIter.nextElementSibling;
}
function dispatchPanelEvent(name) {
let evt = notificationFrame.contentDocument.createEvent("CustomEvent");
evt.initCustomEvent(name, true, true, {});
notificationFrame.contentDocument.documentElement.dispatchEvent(evt);
}
// we only use a dynamic resizer when we're located the toolbar.
let dynamicResizer;
if (!inMenuPanel && notificationFrame.getAttribute("dynamicresizer") == "true") {
dynamicResizer = this._dynamicResizer;
}
panel.addEventListener(hidingEvent, function onpopuphiding() {
panel.removeEventListener(hidingEvent, onpopuphiding);
aToolbarButton.removeAttribute("open");
if (dynamicResizer)
dynamicResizer.stop();
notificationFrame.docShell.isActive = false;
dispatchPanelEvent("socialFrameHide");
});
panel.addEventListener(showingEvent, function onpopupshown() {
panel.removeEventListener(showingEvent, onpopupshown);
// 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.
let initFrameShow = () => {
notificationFrame.docShell.isActive = true;
notificationFrame.docShell.isAppTab = true;
if (dynamicResizer)
dynamicResizer.start(panel, notificationFrame);
dispatchPanelEvent("socialFrameShow");
};
if (!inMenuPanel)
aToolbarButton.setAttribute("open", "true");
if (notificationFrame.contentDocument &&
notificationFrame.contentDocument.readyState == "complete" && wasAlive) {
initFrameShow();
} else {
// first time load, wait for load and dispatch after load
notificationFrame.addEventListener("load", function panelBrowserOnload(e) {
notificationFrame.removeEventListener("load", panelBrowserOnload, true);
initFrameShow();
}, true);
}
});
if (inMenuPanel) {
PanelUI.showSubView("PanelUI-socialapi", widget.node,
CustomizableUI.AREA_PANEL);
} else {
let anchor = document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container");
// Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup
// handling from preventing it being opened in some cases.
setTimeout(function() {
panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
}, 0);
}
PanelFrame.showPopup(window, PanelUI, aToolbarButton, "social", origin,
provider.statusURL, provider.getPageSize("status"));
},
setPanelErrorMessage: function(aNotificationFrame) {

View File

@ -268,6 +268,12 @@
position="topcenter topright"/>
#ifdef MOZ_LOOP
<panel id="loop-notification-panel"
class="loop-panel social-panel"
type="arrow"
hidden="true"
noautofocus="true"/>
<panel id="loop-panel"
class="loop-panel social-panel"
type="arrow"
@ -782,9 +788,13 @@
#ifdef MOZ_LOOP
<!-- XXX Bug 1013989 will provide a label for the button -->
<!-- This uses badged to be compatible with the social api code it shares.
We may also want it to be badged in the future, for notification
purposes. -->
<toolbarbutton id="loop-call-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
persist="class"
type="badged"
removable="true"
tooltiptext="&loopCallButton.tooltip;"
oncommand="LoopUI.openCallPanel(event);"

View File

@ -141,6 +141,10 @@
<panelview id="PanelUI-socialapi" flex="1"/>
#ifdef MOZ_LOOP
<panelview id="PanelUI-loopapi" flex="1"/>
#endif
<panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);">
<label value="&feedsMenu.label;" class="panel-subview-header"/>
</panelview>

View File

@ -2,61 +2,30 @@
* 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/. */
function test() {
let inspector, doc, toolbox;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let {require} = devtools;
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
"use strict";
waitForExplicitFinish();
// Test that hovering over nodes in the markup-view shows the highlighter over
// those nodes
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
doc = content.document;
waitForFocus(setupTest, content);
}, true);
waitForExplicitFinish();
content.location = "data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>";
let test = asyncTest(function*() {
info("Loading the test document and opening the inspector");
yield addTab("data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
let {toolbox, inspector} = yield openInspector();
function setupTest() {
openInspector((aInspector, aToolbox) => {
toolbox = aToolbox;
inspector = aInspector;
inspector.selection.setNode(doc.querySelector("span"), "test");
inspector.toolbox.once("highlighter-ready", runTests);
});
}
info("Selecting the test node");
yield selectNode("span", inspector);
function runTests() {
Task.spawn(function() {
yield hoverH1InMarkupView();
yield assertH1Highlighted();
let container = getContainerForRawNode(inspector.markup, getNode("h1"));
finishUp();
}).then(null, Cu.reportError);
}
let onHighlighterReady = toolbox.once("highlighter-ready");
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousemove"},
inspector.markup.doc.defaultView);
yield onHighlighterReady;
function hoverH1InMarkupView() {
let deferred = promise.defer();
let container = getContainerForRawNode(inspector.markup, doc.querySelector("h1"));
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
is(getHighlitNode(), getNode("h1"), "The highlighter highlights the right node");
inspector.toolbox.once("highlighter-ready", deferred.resolve);
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousemove"},
inspector.markup.doc.defaultView);
return deferred.promise;
}
function assertH1Highlighted() {
ok(isHighlighting(), "The highlighter is shown on a markup container hover");
is(getHighlitNode(), doc.querySelector("h1"), "The highlighter highlights the right node");
}
function finishUp() {
inspector = doc = toolbox = null;
gBrowser.removeCurrentTab();
finish();
}
}
gBrowser.removeCurrentTab();
});

View File

@ -4,90 +4,88 @@
* 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/. */
let doc;
let div;
let rotated;
let inspector;
let contentViewer;
"use strict";
function createDocument() {
div = doc.createElement("div");
// Test that the highlighter is correctly displayed over a variety of elements
waitForExplicitFinish();
let test = asyncTest(function*() {
info("Adding the test tab and creating the document");
yield addTab("data:text/html;charset=utf-8,browser_inspector_highlighter.js");
createDocument(content.document);
info("Opening the inspector");
let {toolbox, inspector} = yield openInspector();
info("Selecting the simple, non-transformed DIV");
let div = getNode(".simple-div");
yield selectNode(div, inspector, "highlight");
testSimpleDivHighlighted(div);
yield zoomTo(2);
testZoomedSimpleDivHighlighted(div);
yield zoomTo(1);
info("Selecting the rotated DIV");
let rotated = getNode(".rotated-div");
let onBoxModelUpdate = waitForBoxModelUpdate();
yield selectNode(rotated, inspector, "highlight");
yield onBoxModelUpdate;
testMouseOverRotatedHighlights(rotated);
gBrowser.removeCurrentTab();
});
function createDocument(doc) {
info("Creating the test document");
let div = doc.createElement("div");
div.className = "simple-div";
div.setAttribute("style",
"padding:5px; border:7px solid red; margin: 9px; " +
"position:absolute; top:30px; left:150px;");
let textNode = doc.createTextNode("Gort! Klaatu barada nikto!");
rotated = doc.createElement("div");
rotated.setAttribute("style",
div.appendChild(doc.createTextNode("Gort! Klaatu barada nikto!"));
doc.body.appendChild(div);
let rotatedDiv = doc.createElement("div");
rotatedDiv.className = "rotated-div";
rotatedDiv.setAttribute("style",
"padding:5px; border:7px solid red; margin: 9px; " +
"transform:rotate(45deg); " +
"position:absolute; top:30px; left:80px;");
div.appendChild(textNode);
doc.body.appendChild(div);
doc.body.appendChild(rotated);
openInspector(aInspector => {
inspector = aInspector;
inspector.selection.setNode(div, null);
inspector.once("inspector-updated", testMouseOverDivHighlights);
});
doc.body.appendChild(rotatedDiv);
}
function testMouseOverDivHighlights() {
ok(isHighlighting(), "Highlighter is shown");
is(getHighlitNode(), div, "Highlighter's outline correspond to the non-rotated div");
testNonTransformedBoxModelDimensionsNoZoom();
}
function testSimpleDivHighlighted(div) {
ok(isHighlighting(), "The highlighter is shown");
is(getHighlitNode(), div, "The highlighter's outline corresponds to the simple div");
function testNonTransformedBoxModelDimensionsNoZoom() {
info("Highlighted the non-rotated div");
info("Checking that the simple div is correctly highlighted");
isNodeCorrectlyHighlighted(div, "non-zoomed");
waitForBoxModelUpdate().then(testNonTransformedBoxModelDimensionsZoomed);
contentViewer = gBrowser.selectedBrowser.docShell.contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
contentViewer.fullZoom = 2;
}
function testNonTransformedBoxModelDimensionsZoomed() {
info("Highlighted the zoomed, non-rotated div");
function testZoomedSimpleDivHighlighted(div) {
info("Checking that the simple div is correctly highlighted, " +
"even when the page is zoomed");
isNodeCorrectlyHighlighted(div, "zoomed");
waitForBoxModelUpdate().then(testMouseOverRotatedHighlights);
contentViewer.fullZoom = 1;
}
function testMouseOverRotatedHighlights() {
let onBoxModelUpdate = waitForBoxModelUpdate();
inspector.selection.setNode(rotated);
inspector.once("inspector-updated", () => {
onBoxModelUpdate.then(() => {
ok(isHighlighting(), "Highlighter is shown");
info("Highlighted the rotated div");
isNodeCorrectlyHighlighted(rotated, "rotated");
function zoomTo(level) {
info("Zooming page to " + level);
let def = promise.defer();
executeSoon(finishUp);
});
});
waitForBoxModelUpdate().then(def.resolve);
let contentViewer = gBrowser.selectedBrowser.docShell.contentViewer
.QueryInterface(Ci.nsIMarkupDocumentViewer);
contentViewer.fullZoom = level;
return def.promise;
}
function finishUp() {
inspector.toolbox.highlighterUtils.stopPicker().then(() => {
doc = div = rotated = inspector = contentViewer = null;
let target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.closeToolbox(target);
gBrowser.removeCurrentTab();
finish();
});
}
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html;charset=utf-8,browser_inspector_highlighter.js";
function testMouseOverRotatedHighlights(rotated) {
ok(isHighlighting(), "The highlighter is shown");
info("Checking that the rotated div is correctly highlighted");
isNodeCorrectlyHighlighted(rotated, "rotated");
}

View File

@ -44,6 +44,34 @@ SimpleTest.registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
});
/**
* Define an async test based on a generator function
*/
function asyncTest(generator) {
return () => Task.spawn(generator).then(null, ok.bind(null, false)).then(finish);
}
/**
* Add a new test tab in the browser and load the given url.
* @param {String} url The url to be loaded in the new tab
* @return a promise that resolves to the tab object when the url is loaded
*/
function addTab(url) {
let def = promise.defer();
let tab = gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
info("URL " + url + " loading complete into new test tab");
waitForFocus(() => {
def.resolve(tab);
}, content);
}, true);
content.location = url;
return def.promise;
}
/**
* Simple DOM node accesor function that takes either a node or a string css
* selector as argument and returns the corresponding node

View File

@ -293,7 +293,7 @@ MarkupView.prototype = {
*/
_shouldNewSelectionBeHighlighted: function() {
let reason = this._inspector.selection.reason;
let unwantedReasons = ["inspector-open", "navigateaway", "test"];
let unwantedReasons = ["inspector-open", "navigateaway", "nodeselected", "test"];
let isHighlitNode = this._hoveredNode === this._inspector.selection.nodeFront;
return !isHighlitNode && reason && unwantedReasons.indexOf(reason) === -1;
},

View File

@ -0,0 +1,209 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// A module for working with panels with iframes shared across windows.
this.EXPORTED_SYMBOLS = ["PanelFrame"];
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SharedFrame", "resource:///modules/SharedFrame.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DynamicResizeWatcher", "resource:///modules/Social.jsm");
// The minimum sizes for the auto-resize panel code.
const PANEL_MIN_HEIGHT = 100;
const PANEL_MIN_WIDTH = 330;
let PanelFrameInternal = {
/**
* Helper function to get and hold a single instance of a DynamicResizeWatcher.
*/
get _dynamicResizer() {
delete this._dynamicResizer;
this._dynamicResizer = new DynamicResizeWatcher();
return this._dynamicResizer;
},
/**
* Status panels are one-per button per-process, we swap the docshells between
* windows when necessary.
*
* @param {DOMWindow} aWindow The window in which to show the popup.
* @param {PanelUI} aPanelUI The panel UI object that represents the application menu.
* @param {DOMElement} aButton The button element that is pressed to show the popup.
* @param {String} aType The type of panel this is, e.g. "social" or "loop".
* @param {String} aOrigin Optional, the origin to use for the iframe.
* @param {String} aSrc The url to load into the iframe.
* @param {String} aSize The initial size of the panel (width and height are the same
* if specified).
*/
_attachNotificatonPanel: function(aWindow, aParent, aButton, aType, aOrigin, aSrc, aSize) {
aParent.hidden = false;
let notificationFrameId = aOrigin ? aType + "-status-" + aOrigin : aType;
let frame = aWindow.document.getElementById(notificationFrameId);
// If the button was customized to a new location, we we'll destroy the
// iframe and start fresh.
if (frame && frame.parentNode != aParent) {
SharedFrame.forgetGroup(frame.id);
frame.parentNode.removeChild(frame);
frame = null;
}
if (!frame) {
let {width, height} = aSize ? aSize : {width: PANEL_MIN_WIDTH, height: PANEL_MIN_HEIGHT};
frame = SharedFrame.createFrame(
notificationFrameId, /* frame name */
aParent, /* parent */
{
"type": "content",
"mozbrowser": "true",
// All frames use social-panel-frame as the class.
"class": "social-panel-frame",
"id": notificationFrameId,
"tooltip": "aHTMLTooltip",
"context": "contentAreaContextMenu",
"flex": "1",
// work around bug 793057 - by making the panel roughly the final size
// we are more likely to have the anchor in the correct position.
"style": "width: " + width + "px; height: " + height + "px;",
"dynamicresizer": !aSize,
"origin": aOrigin,
"src": aSrc
}
);
} else {
frame.setAttribute("origin", aOrigin);
SharedFrame.updateURL(notificationFrameId, aSrc);
}
aButton.setAttribute("notificationFrameId", notificationFrameId);
}
};
/**
* The exported PanelFrame object
*/
let PanelFrame = {
/**
* Shows a popup in a pop-up panel, or in a sliding panel view in the application menu.
* It will move the iframe to different DOM locations depending on where it needs to be
* shown, enabling one iframe to be used for the entire session.
*
* @param {DOMWindow} aWindow The window in which to show the popup.
* @param {PanelUI} aPanelUI The panel UI object that represents the application menu.
* @param {DOMElement} aToolbarButton The button element that is pressed to show the popup.
* @param {String} aType The type of panel this is, e.g. "social" or "loop".
* @param {String} aOrigin Optional, the origin to use for the iframe.
* @param {String} aSrc The url to load into the iframe.
* @param {String} aSize The initial size of the panel (width and height are the same
* if specified).
* @param {Function} aCallback Optional, callback to be called with the iframe when it is
* set up.
*/
showPopup: function(aWindow, aPanelUI, aToolbarButton, aType, aOrigin, aSrc, aSize, aCallback) {
// if we're a slice in the hamburger, use that panel instead
let widgetGroup = CustomizableUI.getWidget(aToolbarButton.getAttribute("id"));
let widget = widgetGroup.forWindow(aWindow);
let panel, showingEvent, hidingEvent;
let inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
if (inMenuPanel) {
panel = aWindow.document.getElementById("PanelUI-" + aType + "api");
PanelFrameInternal._attachNotificatonPanel(aWindow, panel, aToolbarButton, aType, aOrigin, aSrc, aSize);
widget.node.setAttribute("closemenu", "none");
showingEvent = "ViewShowing";
hidingEvent = "ViewHiding";
} else {
panel = aWindow.document.getElementById(aType + "-notification-panel");
PanelFrameInternal._attachNotificatonPanel(aWindow, panel, aToolbarButton, aType, aOrigin, aSrc, aSize);
showingEvent = "popupshown";
hidingEvent = "popuphidden";
}
let notificationFrameId = aToolbarButton.getAttribute("notificationFrameId");
let notificationFrame = aWindow.document.getElementById(notificationFrameId);
let wasAlive = SharedFrame.isGroupAlive(notificationFrameId);
SharedFrame.setOwner(notificationFrameId, notificationFrame);
// Clear dimensions on all browsers so the panel size will
// only use the selected browser.
let frameIter = panel.firstElementChild;
while (frameIter) {
frameIter.collapsed = (frameIter != notificationFrame);
frameIter = frameIter.nextElementSibling;
}
function dispatchPanelEvent(name) {
let evt = notificationFrame.contentDocument.createEvent("CustomEvent");
evt.initCustomEvent(name, true, true, {});
notificationFrame.contentDocument.documentElement.dispatchEvent(evt);
}
// we only use a dynamic resizer when we're located the toolbar.
let dynamicResizer;
if (!inMenuPanel && notificationFrame.getAttribute("dynamicresizer") == "true") {
dynamicResizer = PanelFrameInternal._dynamicResizer;
}
panel.addEventListener(hidingEvent, function onpopuphiding() {
panel.removeEventListener(hidingEvent, onpopuphiding);
aToolbarButton.removeAttribute("open");
if (dynamicResizer)
dynamicResizer.stop();
notificationFrame.docShell.isActive = false;
dispatchPanelEvent(aType + "FrameHide");
});
panel.addEventListener(showingEvent, function onpopupshown() {
panel.removeEventListener(showingEvent, onpopupshown);
// 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.
let initFrameShow = () => {
notificationFrame.docShell.isActive = true;
notificationFrame.docShell.isAppTab = true;
if (dynamicResizer)
dynamicResizer.start(panel, notificationFrame);
dispatchPanelEvent(aType + "FrameShow");
};
if (!inMenuPanel)
aToolbarButton.setAttribute("open", "true");
if (notificationFrame.contentDocument &&
notificationFrame.contentDocument.readyState == "complete" && wasAlive) {
initFrameShow();
} else {
// first time load, wait for load and dispatch after load
notificationFrame.addEventListener("load", function panelBrowserOnload(e) {
notificationFrame.removeEventListener("load", panelBrowserOnload, true);
initFrameShow();
}, true);
}
});
if (inMenuPanel) {
aPanelUI.showSubView("PanelUI-" + aType + "api", widget.node,
CustomizableUI.AREA_PANEL);
} else {
let anchor = aWindow.document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container");
// Bug 849216 - open the popup asynchronously so we avoid the auto-rollup
// handling from preventing it being opened in some cases.
Services.tm.mainThread.dispatch(function() {
panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
}, Ci.nsIThread.DISPATCH_NORMAL);
}
if (aCallback)
aCallback(notificationFrame);
}
};

View File

@ -17,6 +17,7 @@ EXTRA_JS_MODULES += [
'Feeds.jsm',
'NetworkPrioritizer.jsm',
'offlineAppCache.jsm',
'PanelFrame.jsm',
'RemotePrompt.jsm',
'SharedFrame.jsm',
'SitePermissions.jsm',

View File

@ -106,8 +106,9 @@ browser.jar:
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
* skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
skin/classic/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel.png)

View File

@ -2,185 +2,18 @@
* 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/. */
:root {
-moz-appearance: none;
font-size: 75%;
background-color: transparent;
}
%include ../../shared/newtab/newTab.inc.css
/* SCROLLBOX */
#newtab-scrollbox:not([page-disabled]),
#newtab-scrollbox:not([page-disabled]) #newtab-margin-bottom {
color: rgb(0,0,0);
background-color: hsl(0,0%,95%);
}
/* UNDO */
#newtab-undo-container {
padding: 4px 3px;
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
background-color: rgba(255,255,255,.4);
color: #525e69;
}
#newtab-undo-label {
margin-top: 0;
margin-bottom: 0;
}
.newtab-undo-button {
-moz-appearance: none;
color: rgb(221,72,20);
cursor: pointer;
padding: 0;
margin: 0 4px;
border: 0;
background: transparent;
text-decoration: none;
min-width: 0;
}
.newtab-undo-button:hover {
text-decoration: underline;
}
.newtab-undo-button:-moz-focusring {
outline: 1px dotted;
}
#newtab-undo-close-button {
-moz-appearance: none;
padding: 0;
border: none;
height: 16px;
width: 16px;
}
#newtab-undo-close-button:-moz-focusring {
outline: 1px dotted;
}
/* TOGGLE */
#newtab-toggle {
width: 16px;
height: 16px;
padding: 0;
border: none;
background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
}
#newtab-toggle[page-disabled] {
background-position: -232px 0;
}
/* CELLS */
.newtab-cell {
background-color: rgba(255,255,255,.2);
border: 1px solid #dee0e1;
transition: border-color 100ms ease-out;
}
.newtab-cell:empty {
border: 1px dashed;
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
}
.newtab-cell:hover:not(:empty):not([dragged]):not([ignorehover]) {
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
}
/* SITES */
.newtab-site {
text-decoration: none;
transition-property: top, left, opacity, box-shadow, background-color;
}
.newtab-cell:not([ignorehover]) > .newtab-site:hover,
.newtab-site[dragged] {
box-shadow: 0 0 10px rgba(8,22,37,.3);
}
.newtab-site[dragged] {
transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);
}
/* THUMBNAILS */
.newtab-thumbnail {
background-origin: padding-box;
background-clip: padding-box;
background-repeat: no-repeat;
background-size: cover;
}
.newtab-site[type=affiliate] .newtab-thumbnail,
.newtab-site[type=organic] .newtab-thumbnail,
.newtab-site[type=sponsored] .newtab-thumbnail {
background-position: center center;
background-size: auto;
}
/* TITLES */
.newtab-title {
color: #525c66;
font-family: sans-serif;
font-size: 13px;
}
.newtab-site[type=sponsored] .newtab-title {
-moz-padding-end: 24px;
}
/* CONTROLS */
.newtab-control {
width: 24px;
height: 24px;
padding: 1px 2px 3px;
border: none;
background: transparent url(chrome://browser/skin/newtab/controls.png);
}
.newtab-control-pin:hover {
background-position: -24px 0;
}
.newtab-control-pin:active {
background-position: -48px 0;
}
.newtab-control-pin[pinned] {
background-position: -72px 0;
}
.newtab-control-pin[pinned]:hover {
background-position: -96px 0;
}
.newtab-control-pin[pinned]:active {
background-position: -120px 0;
}
.newtab-control-block {
background-position: -144px 0;
}
.newtab-control-block:hover {
background-position: -168px 0;
}
.newtab-control-block:active {
background-position: -192px 0;
}
.newtab-control-sponsored {
background-position: -249px -1px;
}
.newtab-control-sponsored:hover {
background-position: -265px -1px;
}
.newtab-control-sponsored[panelShown] {
background-position: -281px -1px;
}

View File

@ -170,9 +170,9 @@ browser.jar:
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
* skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (newtab/controls@2x.png)
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
skin/classic/browser/setDesktopBackground.css
skin/classic/browser/monitor.png
skin/classic/browser/monitor_16-10.png

View File

@ -2,196 +2,13 @@
* 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/. */
:root {
-moz-appearance: none;
font-size: 75%;
background-color: transparent;
}
%include ../../shared/newtab/newTab.inc.css
/* SCROLLBOX */
#newtab-scrollbox:not([page-disabled]),
#newtab-scrollbox:not([page-disabled]) #newtab-margin-bottom {
color: rgb(0,0,0);
background-color: hsl(0,0%,95%);
}
/* UNDO */
#newtab-undo-container {
padding: 4px 3px;
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
background-color: rgba(255,255,255,.4);
color: #525e69;
}
#newtab-undo-label {
margin-top: 0;
margin-bottom: 0;
}
.newtab-undo-button {
-moz-appearance: none;
color: rgb(20,79,174);
cursor: pointer;
padding: 0;
margin: 0 4px;
border: 0;
background: transparent;
text-decoration: none;
min-width: 0;
}
.newtab-undo-button:hover {
text-decoration: underline;
}
.newtab-undo-button:-moz-focusring {
outline: 1px dotted;
}
#newtab-undo-close-button {
padding: 0;
border: none;
}
#newtab-undo-close-button:-moz-focusring {
outline: 1px dotted;
}
/* TOGGLE */
#newtab-toggle {
width: 16px;
height: 16px;
padding: 0;
border: none;
background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
}
#newtab-toggle[page-disabled] {
background-position: -232px 0;
}
@media (min-resolution: 2dppx) {
#newtab-toggle {
background-image: url(chrome://browser/skin/newtab/controls@2x.png);
background-size: 296px;
}
}
/* CELLS */
.newtab-cell {
background-color: rgba(255,255,255,.2);
border: 1px solid #dee0e1;
transition: border-color 100ms ease-out;
}
.newtab-cell:empty {
border: 1px dashed;
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
}
.newtab-cell:hover:not(:empty):not([dragged]):not([ignorehover]) {
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
}
/* SITES */
.newtab-site {
text-decoration: none;
transition-property: top, left, opacity, box-shadow, background-color;
}
.newtab-cell:not([ignorehover]) > .newtab-site:hover,
.newtab-site[dragged] {
box-shadow: 0 0 10px rgba(8,22,37,.3);
}
.newtab-site[dragged] {
transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);
}
/* THUMBNAILS */
.newtab-thumbnail {
background-origin: padding-box;
background-clip: padding-box;
background-repeat: no-repeat;
background-size: cover;
}
.newtab-site[type=affiliate] .newtab-thumbnail,
.newtab-site[type=organic] .newtab-thumbnail,
.newtab-site[type=sponsored] .newtab-thumbnail {
background-position: center center;
background-size: auto;
}
/* TITLES */
.newtab-title {
color: #525c66;
font-family: Lucida Grande;
font-size: 13px;
}
.newtab-site[type=sponsored] .newtab-title {
-moz-padding-end: 24px;
}
/* CONTROLS */
.newtab-control {
width: 24px;
height: 24px;
padding: 1px 2px 3px;
border: none;
background: transparent url(chrome://browser/skin/newtab/controls.png);
}
@media (min-resolution: 2dppx) {
.newtab-control {
background-image: url(chrome://browser/skin/newtab/controls@2x.png);
background-size: 296px;
}
}
.newtab-control-pin:hover {
background-position: -24px 0;
}
.newtab-control-pin:active {
background-position: -48px 0;
}
.newtab-control-pin[pinned] {
background-position: -72px 0;
}
.newtab-control-pin[pinned]:hover {
background-position: -96px 0;
}
.newtab-control-pin[pinned]:active {
background-position: -120px 0;
}
.newtab-control-block {
background-position: -144px 0;
}
.newtab-control-block:hover {
background-position: -168px 0;
}
.newtab-control-block:active {
background-position: -192px 0;
}
.newtab-control-sponsored {
background-position: -249px -1px;
}
.newtab-control-sponsored:hover {
background-position: -265px -1px;
}
.newtab-control-sponsored[panelShown] {
background-position: -281px -1px;
}

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,196 @@
/* 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/. */
:root {
-moz-appearance: none;
font-size: 75%;
background-color: transparent;
}
/* SCROLLBOX */
#newtab-scrollbox:not([page-disabled]),
#newtab-scrollbox:not([page-disabled]) #newtab-margin-bottom {
color: rgb(0,0,0);
background-color: hsl(0,0%,95%);
}
/* UNDO */
#newtab-undo-container {
padding: 4px 3px;
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
background-color: rgba(255,255,255,.4);
color: #525e69;
}
#newtab-undo-label {
margin-top: 0;
margin-bottom: 0;
}
.newtab-undo-button {
-moz-appearance: none;
cursor: pointer;
padding: 0;
margin: 0 4px;
border: 0;
background: transparent;
text-decoration: none;
min-width: 0;
}
.newtab-undo-button:hover {
text-decoration: underline;
}
.newtab-undo-button:-moz-focusring {
outline: 1px dotted;
}
#newtab-undo-close-button {
-moz-appearance: none;
padding: 0;
border: none;
}
#newtab-undo-close-button:-moz-focusring {
outline: 1px dotted;
}
/* TOGGLE */
#newtab-toggle {
width: 16px;
height: 16px;
padding: 0;
border: none;
background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
}
#newtab-toggle[page-disabled] {
background-position: -232px 0;
}
@media (min-resolution: 2dppx) {
#newtab-toggle {
background-image: url(chrome://browser/skin/newtab/controls@2x.png);
background-size: 296px;
}
}
/* CELLS */
.newtab-cell {
background-color: rgba(255,255,255,.2);
border: 1px solid #dee0e1;
transition: border-color 100ms ease-out;
}
.newtab-cell:empty {
border: 1px dashed;
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
}
.newtab-cell:hover:not(:empty):not([dragged]):not([ignorehover]) {
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
}
/* SITES */
.newtab-site {
text-decoration: none;
transition-property: top, left, opacity, box-shadow, background-color;
}
.newtab-cell:not([ignorehover]) > .newtab-site:hover,
.newtab-site[dragged] {
box-shadow: 0 0 10px rgba(8,22,37,.3);
}
.newtab-site[dragged] {
transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);
}
/* THUMBNAILS */
.newtab-thumbnail {
background-origin: padding-box;
background-clip: padding-box;
background-repeat: no-repeat;
background-size: cover;
}
.newtab-site[type=affiliate] .newtab-thumbnail,
.newtab-site[type=organic] .newtab-thumbnail,
.newtab-site[type=sponsored] .newtab-thumbnail {
background-position: center center;
background-size: auto;
}
/* TITLES */
.newtab-title {
color: #525c66;
font-size: 13px;
}
.newtab-site[type=sponsored] .newtab-title {
-moz-padding-end: 24px;
}
/* CONTROLS */
.newtab-control {
width: 24px;
height: 24px;
padding: 1px 2px 3px;
border: none;
background: transparent url(chrome://browser/skin/newtab/controls.png);
}
@media (min-resolution: 2dppx) {
.newtab-control {
background-image: url(chrome://browser/skin/newtab/controls@2x.png);
background-size: 296px;
}
}
.newtab-control-pin:hover {
background-position: -24px 0;
}
.newtab-control-pin:active {
background-position: -48px 0;
}
.newtab-control-pin[pinned] {
background-position: -72px 0;
}
.newtab-control-pin[pinned]:hover {
background-position: -96px 0;
}
.newtab-control-pin[pinned]:active {
background-position: -120px 0;
}
.newtab-control-block {
background-position: -144px 0;
}
.newtab-control-block:hover {
background-position: -168px 0;
}
.newtab-control-block:active {
background-position: -192px 0;
}
.newtab-control-sponsored {
background-position: -249px -1px;
}
.newtab-control-sponsored:hover {
background-position: -265px -1px;
}
.newtab-control-sponsored[panelShown] {
background-position: -281px -1px;
}

View File

@ -127,8 +127,9 @@ browser.jar:
skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png)
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
* skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
skin/classic/browser/places/places.css (places/places.css)
* skin/classic/browser/places/organizer.css (places/organizer.css)
skin/classic/browser/places/bookmark.png (places/bookmark.png)
@ -532,8 +533,9 @@ browser.jar:
skin/classic/aero/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16-aero.png)
skin/classic/aero/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/aero/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
skin/classic/aero/browser/newtab/newTab.css (newtab/newTab.css)
* skin/classic/aero/browser/newtab/newTab.css (newtab/newTab.css)
skin/classic/aero/browser/newtab/controls.png (../shared/newtab/controls.png)
skin/classic/aero/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
* skin/classic/aero/browser/places/places.css (places/places-aero.css)
* skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css)
skin/classic/aero/browser/places/bookmark.png (places/bookmark-aero.png)

View File

@ -2,188 +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/. */
:root {
-moz-appearance: none;
font-size: 75%;
background-color: transparent;
}
%include ../../shared/newtab/newTab.inc.css
/* SCROLLBOX */
#newtab-scrollbox:not([page-disabled]),
#newtab-scrollbox:not([page-disabled]) #newtab-margin-bottom {
color: rgb(0,0,0);
background-color: hsl(0,0%,95%);
}
/* UNDO */
#newtab-undo-container {
padding: 4px 3px;
border: 1px solid;
border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
background-color: rgba(255,255,255,.4);
color: #525e69;
}
#newtab-undo-label {
margin-top: 0;
margin-bottom: 0;
}
.newtab-undo-button {
-moz-appearance: none;
color: -moz-nativehyperlinktext;
color: rgb(0,102,204);
cursor: pointer;
padding: 0;
margin: 0 4px;
border: 0;
background: transparent;
text-decoration: none;
min-width: 0;
}
.newtab-undo-button:hover {
text-decoration: underline;
}
.newtab-undo-button:-moz-focusring {
outline: 1px dotted;
}
.newtab-undo-button > .button-box {
padding: 0;
}
#newtab-undo-close-button {
-moz-appearance: none;
padding: 0;
border: none;
}
#newtab-undo-close-button:-moz-focusring {
outline: 1px dotted;
}
/* TOGGLE */
#newtab-toggle {
width: 16px;
height: 16px;
padding: 0;
border: none;
background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
}
#newtab-toggle[page-disabled] {
background-position: -232px 0;
}
/* CELLS */
.newtab-cell {
background-color: rgba(255,255,255,.2);
border: 1px solid #dee0e1;
transition: border-color 100ms ease-out;
}
.newtab-cell:empty {
border: 1px dashed;
border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
}
.newtab-cell:hover:not(:empty):not([dragged]):not([ignorehover]) {
border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
}
/* SITES */
.newtab-site {
text-decoration: none;
transition-property: top, left, opacity, box-shadow, background-color;
}
.newtab-cell:not([ignorehover]) > .newtab-site:hover,
.newtab-site[dragged] {
box-shadow: 0 0 10px rgba(8,22,37,.3);
}
.newtab-site[dragged] {
transition-property: box-shadow, background-color;
background-color: rgb(242,242,242);
}
/* THUMBNAILS */
.newtab-thumbnail {
background-origin: padding-box;
background-clip: padding-box;
background-repeat: no-repeat;
background-size: cover;
}
.newtab-site[type=affiliate] .newtab-thumbnail,
.newtab-site[type=organic] .newtab-thumbnail,
.newtab-site[type=sponsored] .newtab-thumbnail {
background-position: center center;
background-size: auto;
}
/* TITLES */
.newtab-title {
color: #525c66;
font-family: Segoe UI;
font-size: 13px;
}
.newtab-site[type=sponsored] .newtab-title {
-moz-padding-end: 24px;
}
/* CONTROLS */
.newtab-control {
width: 24px;
height: 24px;
padding: 1px 2px 3px;
border: none;
background: transparent url(chrome://browser/skin/newtab/controls.png);
}
.newtab-control-pin:hover {
background-position: -24px 0;
}
.newtab-control-pin:active {
background-position: -48px 0;
}
.newtab-control-pin[pinned] {
background-position: -72px 0;
}
.newtab-control-pin[pinned]:hover {
background-position: -96px 0;
}
.newtab-control-pin[pinned]:active {
background-position: -120px 0;
}
.newtab-control-block {
background-position: -144px 0;
}
.newtab-control-block:hover {
background-position: -168px 0;
}
.newtab-control-block:active {
background-position: -192px 0;
}
.newtab-control-sponsored {
background-position: -249px -1px;
}
.newtab-control-sponsored:hover {
background-position: -265px -1px;
}
.newtab-control-sponsored[panelShown] {
background-position: -281px -1px;
}

View File

@ -510,6 +510,9 @@ class Automation(object):
else:
env['MOZ_CRASHREPORTER_DISABLE'] = '1'
# Crash on non-local network connections.
env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1'
env['GNOME_DISABLE_CRASH_DIALOG'] = '1'
env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1'

View File

@ -494,6 +494,9 @@ def environment(xrePath, env=None, crashreporter=True, debugger=False, dmdPath=N
else:
env['MOZ_CRASHREPORTER_DISABLE'] = '1'
# Crash on non-local network connections.
env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1'
# Set WebRTC logging in case it is not set yet
env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5')
env.setdefault('R_LOG_LEVEL', '6')

View File

@ -70,6 +70,9 @@ class RemoteAutomation(Automation):
else:
env['MOZ_CRASHREPORTER_DISABLE'] = '1'
# Crash on non-local network connections.
env['MOZ_DISABLE_NONLOCAL_CONNECTIONS'] = '1'
return env
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath):

View File

@ -2068,6 +2068,7 @@ GK_ATOM(overlay_scrollbars, "overlay-scrollbars")
GK_ATOM(windows_default_theme, "windows-default-theme")
GK_ATOM(mac_graphite_theme, "mac-graphite-theme")
GK_ATOM(mac_lion_theme, "mac-lion-theme")
GK_ATOM(mac_yosemite_theme, "mac-yosemite-theme")
GK_ATOM(windows_compositor, "windows-compositor")
GK_ATOM(windows_glass, "windows-glass")
GK_ATOM(touch_enabled, "touch-enabled")
@ -2099,6 +2100,7 @@ GK_ATOM(_moz_overlay_scrollbars, "-moz-overlay-scrollbars")
GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme")
GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme")
GK_ATOM(_moz_mac_lion_theme, "-moz-mac-lion-theme")
GK_ATOM(_moz_mac_yosemite_theme, "-moz-mac-yosemite-theme")
GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
GK_ATOM(_moz_windows_glass, "-moz-windows-glass")

View File

@ -360,7 +360,6 @@ skip-if = buildapp == 'b2g' # b2g(bug 901343, specialpowers.wrap issue [nsIChann
[test_bug422403-2.xhtml]
skip-if = buildapp == 'b2g'
[test_bug422537.html]
skip-if = buildapp == 'b2g' || e10s # b2g(xmlhttprequest causes crash, bug 902271) b2g-debug(xmlhttprequest causes crash, bug 902271) b2g-desktop(xmlhttprequest causes crash, bug 902271)
[test_bug424212.html]
[test_bug424359-1.html]
skip-if = buildapp == 'b2g'
@ -375,7 +374,6 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop spec
[test_bug429157.html]
[test_bug431082.html]
[test_bug431701.html]
skip-if = buildapp == 'b2g' || e10s # b2g(xmlhttprequest causes crash, bug 902271) b2g-debug(xmlhttprequest causes crash, bug 902271) b2g-desktop(xmlhttprequest causes crash, bug 902271)
[test_bug431833.html]
[test_bug433533.html]
[test_bug433662.html]

View File

@ -0,0 +1,42 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://testing-common/httpd.js");
Cu.import("resource://gre/modules/NetUtil.jsm");
var server = new HttpServer();
server.start(-1);
var docbody = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body></body></html>';
function handler(metadata, response) {
let body = NetUtil.readInputStreamToString(metadata.bodyInputStream,
metadata.bodyInputStream.available());
response.setStatusLine(metadata.httpVersion, 200, "OK");
response.write(body, body.length);
}
function run_test() {
do_test_pending();
server.registerPathHandler("/foo", handler);
var parser = Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
parser.init();
let doc = parser.parseFromString(docbody, "text/html");
let xhr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
xhr.onload = function() {
do_check_eq(xhr.responseText, docbody);
server.stop(do_test_finished);
};
xhr.onerror = function() {
do_check_false(false);
server.stop(do_test_finished);
};
xhr.open("POST", "http://localhost:" + server.identity.primaryPort + "/foo", true);
xhr.send(doc);
}

View File

@ -30,6 +30,7 @@ run-sequentially = Hardcoded 4444 port.
# Bug 1018414: hardcoded localhost doesn't work properly on some OS X installs
skip-if = os == 'mac'
[test_thirdpartyutil.js]
[test_xhr_document.js]
[test_xhr_standalone.js]
[test_xmlserializer.js]
[test_csp_ignores_path.js]

View File

@ -0,0 +1,3 @@
function run_test() {
run_test_in_child("../unit/test_xhr_document.js");
}

View File

@ -3,3 +3,4 @@ head =
tail =
[test_bug553888_wrap.js]
[test_xhr_document_ipc.js]

View File

@ -4358,7 +4358,7 @@ CanvasPath::CanvasPath(nsISupports* aParent)
mPathBuilder = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()->CreatePathBuilder();
}
CanvasPath::CanvasPath(nsISupports* aParent, RefPtr<PathBuilder> aPathBuilder)
CanvasPath::CanvasPath(nsISupports* aParent, TemporaryRef<PathBuilder> aPathBuilder)
: mParent(aParent), mPathBuilder(aPathBuilder)
{
SetIsDOMBinding();
@ -4555,8 +4555,8 @@ CanvasPath::BezierTo(const gfx::Point& aCP1,
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
}
RefPtr<gfx::Path>
CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const
TemporaryRef<gfx::Path>
CanvasPath::GetPath(const CanvasWindingRule& winding, const DrawTarget* aTarget) const
{
FillRule fillRule = FillRule::FILL_WINDING;
if (winding == CanvasWindingRule::Evenodd) {
@ -4564,7 +4564,7 @@ CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtr<mozi
}
if (mPath &&
(mPath->GetBackendType() == mTarget->GetType()) &&
(mPath->GetBackendType() == aTarget->GetType()) &&
(mPath->GetFillRule() == fillRule)) {
return mPath;
}
@ -4580,8 +4580,8 @@ CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtr<mozi
}
// retarget our backend if we're used with a different backend
if (mPath->GetBackendType() != mTarget->GetType()) {
RefPtr<PathBuilder> tmpPathBuilder = mTarget->CreatePathBuilder(fillRule);
if (mPath->GetBackendType() != aTarget->GetType()) {
RefPtr<PathBuilder> tmpPathBuilder = aTarget->CreatePathBuilder(fillRule);
mPath->StreamToSink(tmpPathBuilder);
mPath = tmpPathBuilder->Finish();
} else if (mPath->GetFillRule() != fillRule) {

View File

@ -85,11 +85,14 @@ public:
const gfx::Point& aCP2,
const gfx::Point& aCP3);
mozilla::RefPtr<mozilla::gfx::Path> GetPath(const CanvasWindingRule& winding,
const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const;
TemporaryRef<gfx::Path> GetPath(const CanvasWindingRule& aWinding,
const gfx::DrawTarget* aTarget) const;
explicit CanvasPath(nsISupports* aParent);
CanvasPath(nsISupports* aParent, RefPtr<gfx::PathBuilder> mPathBuilder);
// TemporaryRef arg because the return value from Path::CopyToBuilder() is
// passed directly and we can't drop the only ref to have a raw pointer.
CanvasPath(nsISupports* aParent,
TemporaryRef<gfx::PathBuilder> aPathBuilder);
virtual ~CanvasPath() {}
private:

View File

@ -21,7 +21,7 @@ namespace dom {
class HTMLFormElement;
class HTMLImageElement;
class OwningNodeListOrElement;
template<typename> class Nullable;
template<typename> struct Nullable;
class HTMLFormControlsCollection : public nsIHTMLCollection
, public nsWrapperCache

View File

@ -27,7 +27,7 @@ class ErrorResult;
namespace dom {
class OwningNodeOrHTMLCollection;
template<typename> class Nullable;
template<typename> struct Nullable;
class HTMLAllCollection MOZ_FINAL : public nsISupports
, public nsWrapperCache

View File

@ -15,7 +15,7 @@
#include "nsIThread.h"
class nsIFile;
template <class> class already_AddRefed;
template <class> struct already_AddRefed;
namespace mozilla {
namespace gmp {

View File

@ -58,8 +58,13 @@ function log(msg) {
function finish(v) {
log("finish: " + v.name);
v.parentNode.removeChild(v);
clearInterval(v.checkStateInterval);
for (var i=0; i<gEventTypes.length; i++) {
v.removeEventListener(gEventTypes[i], listener, false);
}
removeNodeAndSource(v);
manager.finished(v.token);
v = null;
}
@ -86,6 +91,7 @@ function createMedia(type, src, token) {
for (var i=0; i<gEventTypes.length; i++) {
v.addEventListener(gEventTypes[i], listener, false);
}
v.preload = "metadata";
v.src = src;
v.name = src;
document.body.appendChild(v);

View File

@ -588,7 +588,7 @@ SVGContentUtils::CoordToFloat(nsPresContext *aPresContext,
}
}
RefPtr<gfx::Path>
TemporaryRef<gfx::Path>
SVGContentUtils::GetPath(const nsAString& aPathString)
{
SVGPathData pathData;

View File

@ -249,7 +249,7 @@ public:
* Returns a path
* string formatted as an SVG path
*/
static mozilla::RefPtr<mozilla::gfx::Path>
static mozilla::TemporaryRef<mozilla::gfx::Path>
GetPath(const nsAString& aPathString);
};

View File

@ -14,7 +14,7 @@
class nsIStackFrame;
template <class T>
class already_AddRefed;
struct already_AddRefed;
namespace mozilla {
namespace dom {

View File

@ -25,6 +25,7 @@
class DeviceStorageFile;
class nsIInputStream;
class nsIOutputStream;
namespace mozilla {
class EventListenerManager;
@ -92,6 +93,9 @@ public:
nsresult Remove();
nsresult Write(nsIInputStream* aInputStream);
nsresult Write(InfallibleTArray<uint8_t>& bits);
nsresult Append(nsIInputStream* aInputStream);
nsresult Append(nsIInputStream* aInputStream,
nsIOutputStream* aOutputStream);
void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> >& aFiles,
PRTime aSince = 0);
void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> >& aFiles,
@ -218,6 +222,13 @@ public:
already_AddRefed<DOMRequest>
AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
already_AddRefed<DOMRequest>
AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath, ErrorResult& aRv);
already_AddRefed<DOMRequest>
AddOrAppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
const int32_t aRequestType, ErrorResult& aRv);
already_AddRefed<DOMRequest>
Get(const nsAString& aPath, ErrorResult& aRv)
{

View File

@ -49,7 +49,31 @@ DeviceStorageRequestParent::Dispatch()
nsCOMPtr<nsIInputStream> stream;
blob->GetInternalStream(getter_AddRefs(stream));
nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream);
nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
DEVICE_STORAGE_REQUEST_CREATE);
nsCOMPtr<nsIEventTarget> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
target->Dispatch(r, NS_DISPATCH_NORMAL);
break;
}
case DeviceStorageParams::TDeviceStorageAppendParams:
{
DeviceStorageAppendParams p = mParams;
nsRefPtr<DeviceStorageFile> dsf =
new DeviceStorageFile(p.type(), p.storageName(), p.relpath());
BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
nsCOMPtr<nsIInputStream> stream;
blob->GetInternalStream(getter_AddRefs(stream));
nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream,
DEVICE_STORAGE_REQUEST_APPEND);
nsCOMPtr<nsIEventTarget> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
@ -244,6 +268,14 @@ DeviceStorageRequestParent::EnsureRequiredPermissions(
break;
}
case DeviceStorageParams::TDeviceStorageAppendParams:
{
DeviceStorageAppendParams p = mParams;
type = p.type();
requestType = DEVICE_STORAGE_REQUEST_APPEND;
break;
}
case DeviceStorageParams::TDeviceStorageCreateFdParams:
{
DeviceStorageCreateFdParams p = mParams;
@ -576,10 +608,12 @@ DeviceStorageRequestParent::CreateFdEvent::CancelableRun()
DeviceStorageRequestParent::WriteFileEvent::
WriteFileEvent(DeviceStorageRequestParent* aParent,
DeviceStorageFile* aFile,
nsIInputStream* aInputStream)
nsIInputStream* aInputStream,
int32_t aRequestType)
: CancelableRunnable(aParent)
, mFile(aFile)
, mInputStream(aInputStream)
, mRequestType(aRequestType)
{
}
@ -600,14 +634,26 @@ DeviceStorageRequestParent::WriteFileEvent::CancelableRun()
}
bool check = false;
nsresult rv;
mFile->mFile->Exists(&check);
if (check) {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS);
if (mRequestType == DEVICE_STORAGE_REQUEST_CREATE) {
if (check) {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_EXISTS);
return NS_DispatchToMainThread(r);
}
rv = mFile->Write(mInputStream);
} else if (mRequestType == DEVICE_STORAGE_REQUEST_APPEND) {
if (!check) {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
return NS_DispatchToMainThread(r);
}
rv = mFile->Append(mInputStream);
} else {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
return NS_DispatchToMainThread(r);
}
nsresult rv = mFile->Write(mInputStream);
if (NS_FAILED(rv)) {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
}

View File

@ -132,12 +132,14 @@ private:
class WriteFileEvent : public CancelableRunnable
{
public:
WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, nsIInputStream* aInputStream);
WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile,
nsIInputStream* aInputStream, int32_t aRequestType);
virtual ~WriteFileEvent();
virtual nsresult CancelableRun();
private:
nsRefPtr<DeviceStorageFile> mFile;
nsCOMPtr<nsIInputStream> mInputStream;
int32_t mRequestType;
};
class DeleteFileEvent : public CancelableRunnable

View File

@ -408,6 +408,7 @@ DeviceStorageTypeChecker::GetAccessForRequest(
aAccessResult.AssignLiteral("read");
break;
case DEVICE_STORAGE_REQUEST_WRITE:
case DEVICE_STORAGE_REQUEST_APPEND:
case DEVICE_STORAGE_REQUEST_DELETE:
case DEVICE_STORAGE_REQUEST_FORMAT:
case DEVICE_STORAGE_REQUEST_MOUNT:
@ -1063,9 +1064,6 @@ DeviceStorageFile::Write(nsIInputStream* aInputStream)
return rv;
}
uint64_t bufSize = 0;
aInputStream->Available(&bufSize);
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile);
@ -1073,36 +1071,7 @@ DeviceStorageFile::Write(nsIInputStream* aInputStream)
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
outputStream,
4096*4);
NS_ENSURE_SUCCESS(rv, rv);
while (bufSize) {
uint32_t wrote;
rv = bufferedOutputStream->WriteFrom(
aInputStream,
static_cast<uint32_t>(std::min<uint64_t>(bufSize, UINT32_MAX)),
&wrote);
if (NS_FAILED(rv)) {
break;
}
bufSize -= wrote;
}
iocomplete = new IOEventComplete(this, "modified");
rv = NS_DispatchToMainThread(iocomplete);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
bufferedOutputStream->Close();
outputStream->Close();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
return Append(aInputStream, outputStream);
}
nsresult
@ -1146,6 +1115,62 @@ DeviceStorageFile::Write(InfallibleTArray<uint8_t>& aBits)
return NS_OK;
}
nsresult
DeviceStorageFile::Append(nsIInputStream* aInputStream)
{
if (!aInputStream || !mFile) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile, PR_WRONLY | PR_CREATE_FILE | PR_APPEND, -1, 0);
if (!outputStream) {
return NS_ERROR_FAILURE;
}
return Append(aInputStream, outputStream);
}
nsresult
DeviceStorageFile::Append(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
{
uint64_t bufSize = 0;
aInputStream->Available(&bufSize);
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
nsresult rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
aOutputStream,
4096*4);
NS_ENSURE_SUCCESS(rv, rv);
while (bufSize) {
uint32_t wrote;
rv = bufferedOutputStream->WriteFrom(
aInputStream,
static_cast<uint32_t>(std::min<uint64_t>(bufSize, UINT32_MAX)),
&wrote);
if (NS_FAILED(rv)) {
break;
}
bufSize -= wrote;
}
nsCOMPtr<nsIRunnable> iocomplete = new IOEventComplete(this, "modified");
rv = NS_DispatchToMainThread(iocomplete);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
bufferedOutputStream->Close();
aOutputStream->Close();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
DeviceStorageFile::Remove()
{
@ -2373,13 +2398,16 @@ class WriteFileEvent : public nsRunnable
public:
WriteFileEvent(nsIDOMBlob* aBlob,
DeviceStorageFile *aFile,
already_AddRefed<DOMRequest> aRequest)
already_AddRefed<DOMRequest> aRequest,
int32_t aRequestType)
: mBlob(aBlob)
, mFile(aFile)
, mRequest(aRequest)
, mRequestType(aRequestType)
{
MOZ_ASSERT(mFile);
MOZ_ASSERT(mRequest);
MOZ_ASSERT(mRequestType);
}
~WriteFileEvent() {}
@ -2393,17 +2421,33 @@ public:
bool check = false;
mFile->mFile->Exists(&check);
if (check) {
nsresult rv;
if (mRequestType == DEVICE_STORAGE_REQUEST_APPEND) {
if (!check) {
nsCOMPtr<nsIRunnable> event =
new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
return NS_DispatchToMainThread(event);
}
rv = mFile->Append(stream);
}
else if (mRequestType == DEVICE_STORAGE_REQUEST_CREATE) {
if (check) {
nsCOMPtr<nsIRunnable> event =
new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS);
return NS_DispatchToMainThread(event);
}
rv = mFile->Write(stream);
if (NS_FAILED(rv)) {
mFile->mFile->Remove(false);
}
} else {
nsCOMPtr<nsIRunnable> event =
new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_FILE_EXISTS);
new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN);
return NS_DispatchToMainThread(event);
}
nsresult rv = mFile->Write(stream);
if (NS_FAILED(rv)) {
mFile->mFile->Remove(false);
nsCOMPtr<nsIRunnable> event =
new PostErrorEvent(mRequest.forget(), POST_ERROR_EVENT_UNKNOWN);
return NS_DispatchToMainThread(event);
@ -2420,8 +2464,10 @@ private:
nsCOMPtr<nsIDOMBlob> mBlob;
nsRefPtr<DeviceStorageFile> mFile;
nsRefPtr<DOMRequest> mRequest;
int32_t mRequestType;
};
class ReadFileEvent : public nsRunnable
{
public:
@ -2841,7 +2887,49 @@ public:
->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
r = new WriteFileEvent(mBlob, mFile, mRequest.forget());
r = new WriteFileEvent(mBlob, mFile, mRequest.forget(), mRequestType);
break;
}
case DEVICE_STORAGE_REQUEST_APPEND:
{
if (!mBlob || !mFile->mFile) {
return NS_ERROR_FAILURE;
}
DeviceStorageTypeChecker* typeChecker
= DeviceStorageTypeChecker::CreateOrGet();
if (!typeChecker) {
return NS_OK;
}
if (!typeChecker->Check(mFile->mStorageType, mFile->mFile) ||
!typeChecker->Check(mFile->mStorageType, mBlob)) {
r = new PostErrorEvent(mRequest.forget(),
POST_ERROR_EVENT_ILLEGAL_TYPE);
return NS_DispatchToCurrentThread(r);
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
BlobChild* actor
= ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
if (!actor) {
return NS_ERROR_FAILURE;
}
DeviceStorageAppendParams params;
params.blobChild() = actor;
params.type() = mFile->mStorageType;
params.storageName() = mFile->mStorageName;
params.relpath() = mFile->mPath;
PDeviceStorageRequestChild* child
= new DeviceStorageRequestChild(mRequest, mFile);
ContentChild::GetSingleton()
->SendPDeviceStorageRequestConstructor(child, params);
return NS_OK;
}
r = new WriteFileEvent(mBlob, mFile, mRequest.forget(), mRequestType);
break;
}
@ -3457,6 +3545,23 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob *aBlob,
already_AddRefed<DOMRequest>
nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
ErrorResult& aRv)
{
return AddOrAppendNamed(aBlob, aPath,
DEVICE_STORAGE_REQUEST_CREATE, aRv);
}
already_AddRefed<DOMRequest>
nsDOMDeviceStorage::AppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
ErrorResult& aRv)
{
return AddOrAppendNamed(aBlob, aPath,
DEVICE_STORAGE_REQUEST_APPEND, aRv);
}
already_AddRefed<DOMRequest>
nsDOMDeviceStorage::AddOrAppendNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
const int32_t aRequestType, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
@ -3493,7 +3598,9 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
}
return request.forget();
}
return ds->AddNamed(aBlob, storagePath, aRv);
return ds->AddOrAppendNamed(aBlob, storagePath,
aRequestType, aRv);
}
nsRefPtr<DOMRequest> request = new DOMRequest(win);
@ -3506,9 +3613,13 @@ nsDOMDeviceStorage::AddNamed(nsIDOMBlob* aBlob, const nsAString& aPath,
} else if (!typeChecker->Check(mStorageType, dsf->mFile) ||
!typeChecker->Check(mStorageType, aBlob)) {
r = new PostErrorEvent(request, POST_ERROR_EVENT_ILLEGAL_TYPE);
} else {
r = new DeviceStorageRequest(DEVICE_STORAGE_REQUEST_CREATE,
} else if (aRequestType == DEVICE_STORAGE_REQUEST_APPEND ||
aRequestType == DEVICE_STORAGE_REQUEST_CREATE) {
r = new DeviceStorageRequest(DeviceStorageRequestType(aRequestType),
win, mPrincipal, dsf, request, aBlob);
} else {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
rv = NS_DispatchToCurrentThread(r);

View File

@ -45,6 +45,7 @@ class ErrorResult;
enum DeviceStorageRequestType {
DEVICE_STORAGE_REQUEST_READ,
DEVICE_STORAGE_REQUEST_WRITE,
DEVICE_STORAGE_REQUEST_APPEND,
DEVICE_STORAGE_REQUEST_CREATE,
DEVICE_STORAGE_REQUEST_DELETE,
DEVICE_STORAGE_REQUEST_WATCH,

View File

@ -30,3 +30,4 @@ support-files = devicestorage_common.js
[test_fs_get.html]
[test_fs_remove.html]
[test_fs_createFile.html]
[test_fs_appendFile.html]

View File

@ -0,0 +1,90 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=855952
-->
<head>
<title>Test for basic sanity of the device storage API </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=855952">Mozilla Bug 855952</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var file = new Blob(["This is a text file."], {type: "text/plain"});
var appendFile = new Blob([" Another text file."], {type: "text/plain"});
devicestorage_setup();
function deleteSuccess(e) {
devicestorage_cleanup();
}
function deleteError(e) {
ok(false, "deleteError was called : " + e.target.error.name);
devicestorage_cleanup();
}
function appendSuccess(e) {
ok(true, "appendSuccess was called.");
request = gStorage.delete(e.target.result)
request.onsuccess = deleteSuccess;
request.onerror = deleteError;
}
function appendError(e) {
ok(false, "appendError was called.");
devicestorage_cleanup();
}
function addSuccess(e) {
ok(true, "addSuccess was called");
request = gStorage.appendNamed(appendFile, e.target.result);
ok(request, "Should have a non-null request");
request.onsuccess = appendSuccess;
request.onerror = appendError;
}
function addError(e) {
// test file is already exists. clean it up and try again..
request = gStorage.delete(e.target.result)
request.onsuccess = addFile;
}
function addFile() {
// Add a file first
request = gStorage.addNamed(file, "devicestorage/append.asc");
ok(request, "Should have a non-null request");
request.onsuccess = addSuccess;
request.onerror = addError;
}
function runtest() {
addFile();
}
var gStorage = navigator.getDeviceStorage("sdcard");
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(gStorage, "Should get storage from sdcard");
runtest();
</script>
</pre>
</body>
</html>

View File

@ -10,7 +10,7 @@
#include "nsIOutputStream.h"
#include "nsString.h"
template <class> class already_AddRefed;
template <class> struct already_AddRefed;
namespace mozilla {
namespace dom {

View File

@ -118,6 +118,14 @@ struct DeviceStorageAddParams
PBlob blob;
};
struct DeviceStorageAppendParams
{
nsString type;
nsString storageName;
nsString relpath;
PBlob blob;
};
struct DeviceStorageCreateFdParams
{
nsString type;
@ -151,6 +159,7 @@ struct DeviceStorageEnumerationParams
union DeviceStorageParams
{
DeviceStorageAddParams;
DeviceStorageAppendParams;
DeviceStorageCreateFdParams;
DeviceStorageGetParams;
DeviceStorageDeleteParams;

View File

@ -82,9 +82,9 @@ let NotificationDB = {
var promise = OS.File.read(NOTIFICATION_STORE_PATH, { encoding: "utf-8"});
return promise.then(
function onSuccess(data) {
// JSON parsing failure will get handled by a later catch in the promise
// chain
this.notifications = JSON.parse(data);
if (data.length > 0) {
this.notifications = JSON.parse(data);
}
// populate the list of notifications by tag
if (this.notifications) {
for (var origin in this.notifications) {

View File

@ -150,9 +150,12 @@ NotificationStorage.prototype = {
} catch (e) {
debug("Error calling callback done: " + e);
}
case kMessageNotificationSaveOk:
case kMessageNotificationDeleteOk:
debug("Error received when treating: '" + message.name + "': " + message.data.errorMsg);
case kMessageNotificationSaveKo:
case kMessageNotificationDeleteKo:
if (DEBUG) {
debug("Error received when treating: '" + message.name +
"': " + message.data.errorMsg);
}
break;
default:

View File

@ -0,0 +1,63 @@
"use strict";
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
let systemNotification = {
origin: "app://system.gaiamobile.org/manifest.webapp",
id: "{2bc883bf-2809-4432-b0f4-f54e10372764}",
title: "SystemNotification:" + Date.now(),
dir: "auto",
lang: "",
body: "System notification body",
tag: "",
icon: "icon.png"
};
let calendarNotification = {
origin: "app://calendar.gaiamobile.org/manifest.webapp",
id: "{d8d11299-a58e-429b-9a9a-57c562982fbf}",
title: "CalendarNotification:" + Date.now(),
dir: "auto",
lang: "",
body: "Calendar notification body",
tag: "",
icon: "icon.png"
};
// Helper to start the NotificationDB
function startNotificationDB() {
Cu.import("resource://gre/modules/NotificationDB.jsm");
}
// Helper function to add a listener, send message and treat the reply
function addAndSend(msg, reply, callback, payload, runNext = true) {
let handler = {
receiveMessage: function(message) {
if (message.name === reply) {
cpmm.removeMessageListener(reply, handler);
callback(message);
if (runNext) {
run_next_test();
}
}
}
};
cpmm.addMessageListener(reply, handler);
cpmm.sendAsyncMessage(msg, payload);
}
// helper fonction, comparing two notifications
function compareNotification(notif1, notif2) {
// retrieved notification should be the second one sent
for (let prop in notif1) {
// compare each property
do_check_eq(notif1[prop], notif2[prop]);
}
}

View File

@ -1,66 +1,11 @@
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
let systemNotification = {
origin: "app://system.gaiamobile.org/manifest.webapp",
id: "{2bc883bf-2809-4432-b0f4-f54e10372764}",
title: "SystemNotification:" + Date.now(),
dir: "auto",
lang: "",
body: "System notification body",
tag: "",
icon: "icon.png"
};
let calendarNotification = {
origin: "app://calendar.gaiamobile.org/manifest.webapp",
id: "{d8d11299-a58e-429b-9a9a-57c562982fbf}",
title: "CalendarNotification:" + Date.now(),
dir: "auto",
lang: "",
body: "Calendar notification body",
tag: "",
icon: "icon.png"
};
"use strict";
function run_test() {
do_get_profile();
Cu.import("resource://gre/modules/NotificationDB.jsm");
startNotificationDB();
run_next_test();
}
// Helper function to add a listener, send message and treat the reply
function addAndSend(msg, reply, callback, payload, runNext = true) {
let handler = {
receiveMessage: function(message) {
if (message.name === reply) {
cpmm.removeMessageListener(reply, handler);
callback(message);
if (runNext) {
run_next_test();
}
}
}
};
cpmm.addMessageListener(reply, handler);
cpmm.sendAsyncMessage(msg, payload);
}
// helper fonction, comparing two notifications
function compareNotification(notif1, notif2) {
// retrieved notification should be the second one sent
for (let prop in notif1) {
// compare each property
do_check_eq(notif1[prop], notif2[prop]);
}
}
// Get one notification, none exists
add_test(function test_get_none() {
let requestID = 0;

View File

@ -0,0 +1,56 @@
"use strict";
function run_test() {
do_get_profile();
run_next_test();
}
/// For bug 1024090: test edge case of notificationstore.json
add_test(function test_bug1024090_purge() {
Cu.import("resource://gre/modules/osfile.jsm");
const NOTIFICATION_STORE_PATH =
OS.Path.join(OS.Constants.Path.profileDir, "notificationstore.json");
let cleanup = OS.File.writeAtomic(NOTIFICATION_STORE_PATH, "");
cleanup.then(
function onSuccess() {
ok(true, "Notification database cleaned.");
},
function onError(reason) {
ok(false, "Notification database error when cleaning: " + reason);
}
).then(function next() {
do_print("Cleanup steps completed: " + NOTIFICATION_STORE_PATH);
startNotificationDB();
run_next_test();
});
});
// Store one notification
add_test(function test_bug1024090_send_one() {
let requestID = 1;
let msgReply = "Notification:Save:Return:OK";
let msgHandler = function(message) {
equal(requestID, message.data.requestID, "Checking requestID");
};
addAndSend("Notification:Save", msgReply, msgHandler, {
origin: systemNotification.origin,
notification: systemNotification,
requestID: requestID
});
});
// Get one notification, one exists
add_test(function test_bug1024090_get_one() {
let requestID = 2;
let msgReply = "Notification:GetAll:Return:OK";
let msgHandler = function(message) {
equal(requestID, message.data.requestID, "Checking requestID");
equal(1, message.data.notifications.length, "One notification stored");
};
addAndSend("Notification:GetAll", msgReply, msgHandler, {
origin: systemNotification.origin,
requestID: requestID
});
});

View File

@ -1,5 +1,6 @@
[DEFAULT]
head =
head = common_test_notificationdb.js
tail =
[test_notificationdb.js]
[test_notificationdb_bug1024090.js]

View File

@ -15,6 +15,20 @@ interface DeviceStorage : EventTarget {
[Throws]
DOMRequest? addNamed(Blob? aBlob, DOMString aName);
/**
* Append data to a given file.
* If the file doesn't exist, a "NotFoundError" event will be dispatched.
* In the same time, it is a request.onerror case.
* If the file exists, it will be opened with the following permission:
* "PR_WRONLY|PR_CREATE_FILE|PR_APPEND".
* The function will return null when blob file is null and other unexpected situations.
* @parameter aBlob: A Blob object representing the data to append
* @parameter aName: A string representing the full name (path + file name) of the file
* to append data to.
*/
[Throws]
DOMRequest? appendNamed(Blob? aBlob, DOMString aName);
[Throws]
DOMRequest get(DOMString aName);
[Throws]

View File

@ -28,6 +28,7 @@ EXPORTS.mozilla.gfx += [
'Rect.h',
'Scale.h',
'ScaleFactor.h',
'SourceSurfaceCairo.h',
'Tools.h',
'Types.h',
'UserData.h',

View File

@ -6,6 +6,7 @@
#include "GLTextureImage.h"
#include "GLContext.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
#include "gfxPlatform.h"
#include "gfxUtils.h"
#include "gfx2DGlue.h"

View File

@ -14,6 +14,7 @@
#include "LayerSorter.h" // for SortLayersBy3DZOrder
#include "LayersLogging.h" // for AppendToString
#include "ReadbackLayer.h" // for ReadbackLayer
#include "gfxImageSurface.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxUtils.h" // for gfxUtils, etc
#include "gfx2DGlue.h"

View File

@ -127,6 +127,7 @@ static int gCMSIntent = QCMS_INTENT_DEFAULT;
static void ShutdownCMS();
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/SourceSurfaceCairo.h"
using namespace mozilla::gfx;
/* Class to listen for pref changes so that chrome code can dynamically
@ -629,56 +630,12 @@ void SourceSurfaceDestroyed(void *aData)
delete static_cast<DependentSourceSurfaceUserData*>(aData);
}
#if MOZ_TREE_CAIRO
void SourceSnapshotDetached(cairo_surface_t *nullSurf)
{
gfxImageSurface* origSurf =
static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
origSurf->SetData(&kSourceSurface, nullptr, nullptr);
}
#else
void SourceSnapshotDetached(void *nullSurf)
{
gfxImageSurface* origSurf = static_cast<gfxImageSurface*>(nullSurf);
origSurf->SetData(&kSourceSurface, nullptr, nullptr);
}
#endif
void
gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface *aSurface)
{
aSurface->SetData(&kSourceSurface, nullptr, nullptr);
}
static TemporaryRef<DataSourceSurface>
CopySurface(gfxASurface* aSurface)
{
const nsIntSize size = aSurface->GetSize();
gfxImageFormat format = gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType());
RefPtr<DataSourceSurface> data =
Factory::CreateDataSourceSurface(ToIntSize(size),
ImageFormatToSurfaceFormat(format));
if (!data) {
return nullptr;
}
DataSourceSurface::MappedSurface map;
DebugOnly<bool> result = data->Map(DataSourceSurface::WRITE, &map);
MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
nsRefPtr<gfxImageSurface> image = new gfxImageSurface(map.mData, size, map.mStride, format);
nsRefPtr<gfxContext> ctx = new gfxContext(image);
ctx->SetSource(aSurface);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint();
data->Unmap();
return data;
}
/* static */ TemporaryRef<SourceSurface>
gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
{
@ -687,9 +644,8 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
}
if (!aTarget) {
if (gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()) {
aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
} else {
aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
if (!aTarget) {
return nullptr;
}
}
@ -715,6 +671,33 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
format = SurfaceFormat::B8G8R8A8;
}
if (aTarget->GetType() == BackendType::CAIRO) {
// If we're going to be used with a CAIRO DrawTarget, then just create a
// SourceSurfaceCairo since we don't know the underlying type of the CAIRO
// DrawTarget and can't pick a better surface type. Doing this also avoids
// readback of aSurface's surface into memory if, for example, aSurface
// wraps an xlib cairo surface (which can be important to avoid a major
// slowdown).
NativeSurface surf;
surf.mFormat = format;
surf.mType = NativeSurfaceType::CAIRO_SURFACE;
surf.mSurface = aSurface->CairoSurface();
surf.mSize = ToIntSize(aSurface->GetSize());
// We return here regardless of whether CreateSourceSurfaceFromNativeSurface
// succeeds or not since we don't expect to be able to do any better below
// if it fails.
//
// Note that the returned SourceSurfaceCairo holds a strong reference to
// the cairo_surface_t* that it wraps, which essencially means it holds a
// strong reference to aSurface since aSurface shares its
// cairo_surface_t*'s reference count variable. As a result we can't cache
// srcBuffer on aSurface (see below) since aSurface would then hold a
// strong reference back to srcBuffer, creating a reference loop and a
// memory leak. Not caching is fine since wrapping is cheap enough (no
// copying) so we can just wrap again next time we're called.
return aTarget->CreateSourceSurfaceFromNativeSurface(surf);
}
RefPtr<SourceSurface> srcBuffer;
#ifdef XP_WIN
@ -730,48 +713,69 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
dt->Flush();
}
srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
} else
}
#endif
if (aSurface->CairoSurface() && aTarget->GetType() == BackendType::CAIRO) {
// If this is an xlib cairo surface we don't want to fetch it into memory
// because this is a major slow down.
// Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
if (!srcBuffer) {
// If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
// the same data, then optimize it for aTarget:
RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
if (surf) {
srcBuffer = aTarget->OptimizeSourceSurface(surf);
if (srcBuffer == surf) {
// GetWrappedDataSourceSurface returns a SourceSurface that holds a
// strong reference to aSurface since it wraps aSurface's data and
// needs it to stay alive. As a result we can't cache srcBuffer on
// aSurface (below) since aSurface would then hold a strong reference
// back to srcBuffer, creating a reference loop and a memory leak. Not
// caching is fine since wrapping is cheap enough (no copying) so we
// can just wrap again next time we're called.
//
// Note that the check below doesn't catch this since srcBuffer will be a
// SourceSurfaceRawData object (even if aSurface is not a gfxImageSurface
// object), which is why we need this separate check.
return srcBuffer.forget();
}
}
}
if (!srcBuffer) {
MOZ_ASSERT(aTarget->GetType() != BackendType::CAIRO,
"We already tried CreateSourceSurfaceFromNativeSurface with a "
"DrawTargetCairo above");
// We've run out of performant options. We now try creating a SourceSurface
// using a temporary DrawTargetCairo and then optimizing it to aTarget's
// actual type. The CreateSourceSurfaceFromNativeSurface() call will
// likely create a DataSourceSurface (possibly involving copying and/or
// readback), and the OptimizeSourceSurface may well copy again and upload
// to the GPU. So, while this code path is rarely hit, hitting it may be
// very slow.
NativeSurface surf;
surf.mFormat = format;
surf.mType = NativeSurfaceType::CAIRO_SURFACE;
surf.mSurface = aSurface->CairoSurface();
surf.mSize = ToIntSize(aSurface->GetSize());
srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
RefPtr<DrawTarget> drawTarget =
Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(1, 1), format);
srcBuffer = drawTarget->CreateSourceSurfaceFromNativeSurface(surf);
if (srcBuffer) {
// It's cheap enough to make a new one so we won't keep it around and
// keeping it creates a cycle.
return srcBuffer.forget();
srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
}
}
if (!srcBuffer) {
nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
return nullptr;
}
RefPtr<DataSourceSurface> dataSurf;
if (imgSurface) {
dataSurf = GetWrappedDataSourceSurface(aSurface);
} else {
dataSurf = CopySurface(aSurface);
}
if (!dataSurf) {
return nullptr;
}
srcBuffer = aTarget->OptimizeSourceSurface(dataSurf);
if (imgSurface && srcBuffer == dataSurf) {
// Our wrapping surface will hold a reference to its image surface. We cause
// a reference cycle if we add it to the cache. And caching it is pretty
// pointless since we'll just wrap it again next use.
return srcBuffer.forget();
}
if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
aSurface->CairoSurface()) ||
(srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
aSurface->CairoSurface())) {
// See the "Note that the returned SourceSurfaceCairo..." comment above.
return srcBuffer.forget();
}
// Add user data to aSurface so we can cache lookups in the future.

View File

@ -3411,6 +3411,22 @@ RasterImage::DecodePool::DecodeJob::Run()
return NS_OK;
}
RasterImage::DecodePool::DecodeJob::~DecodeJob()
{
if (gMultithreadedDecoding) {
// Dispatch mImage to main thread to prevent mImage from being destructed by decode thread.
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
if (mainThread) {
// Handle ambiguous nsISupports inheritance
RasterImage* rawImg = nullptr;
mImage.swap(rawImg);
DebugOnly<nsresult> rv = NS_ProxyRelease(mainThread, NS_ISUPPORTS_CAST(ImageResource*, rawImg));
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to proxy release to main thread");
}
}
}
nsresult
RasterImage::DecodePool::DecodeUntilSizeAvailable(RasterImage* aImg)
{

View File

@ -487,6 +487,9 @@ private:
NS_IMETHOD Run();
protected:
virtual ~DecodeJob();
private:
nsRefPtr<DecodeRequest> mRequest;
nsRefPtr<RasterImage> mImage;

View File

@ -9,7 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/ipc/Transport.h"
template <class> class already_AddRefed;
template <class> struct already_AddRefed;
namespace mozilla {
namespace dom {

View File

@ -177,8 +177,9 @@ class ConstTwoByteChars : public mozilla::RangedPtr<const jschar>
extern Latin1CharsZ
LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx, TwoByteChars tbchars);
template <typename CharT>
extern UTF8CharsZ
TwoByteCharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, TwoByteChars tbchars);
CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const CharT> chars);
uint32_t
Utf8ToOneUcs4Char(const uint8_t *utf8Buffer, int utf8Length);

View File

@ -22,6 +22,9 @@ using namespace js;
using mozilla::AddToHash;
using mozilla::HashString;
using mozilla::Range;
using mozilla::RangedPtr;
using JS::AutoCheckCannotGC;
// We should be able to assert this for *any* fp->scopeChain().
static void
@ -49,10 +52,11 @@ IsEvalCacheCandidate(JSScript *script)
/* static */ HashNumber
EvalCacheHashPolicy::hash(const EvalCacheLookup &l)
{
return AddToHash(HashString(l.str->chars(), l.str->length()),
l.callerScript.get(),
l.version,
l.pc);
AutoCheckCannotGC nogc;
uint32_t hash = l.str->hasLatin1Chars()
? HashString(l.str->latin1Chars(nogc), l.str->length())
: HashString(l.str->twoByteChars(nogc), l.str->length());
return AddToHash(hash, l.callerScript.get(), l.version, l.pc);
}
/* static */ bool
@ -145,23 +149,18 @@ enum EvalJSONResult {
EvalJSON_NotJSON
};
static EvalJSONResult
TryEvalJSON(JSContext *cx, JSScript *callerScript,
ConstTwoByteChars chars, size_t length, MutableHandleValue rval)
template <typename CharT>
static bool
EvalStringMightBeJSON(const Range<const CharT> chars)
{
// If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON.
// Try the JSON parser first because it's much faster. If the eval string
// isn't JSON, JSON parsing will probably fail quickly, so little time
// will be lost.
//
// Don't use the JSON parser if the caller is strict mode code, because in
// strict mode object literals must not have repeated properties, and the
// JSON parser cheerfully (and correctly) accepts them. If you're parsing
// JSON with eval and using strict mode, you deserve to be slow.
size_t length = chars.length();
if (length > 2 &&
((chars[0] == '[' && chars[length - 1] == ']') ||
(chars[0] == '(' && chars[length - 1] == ')')) &&
(!callerScript || !callerScript->strict()))
(chars[0] == '(' && chars[length - 1] == ')')))
{
// Remarkably, JavaScript syntax is not a superset of JSON syntax:
// strings in JavaScript cannot contain the Unicode line and paragraph
@ -169,27 +168,68 @@ TryEvalJSON(JSContext *cx, JSScript *callerScript,
// Rather than force the JSON parser to handle this quirk when used by
// eval, we simply don't use the JSON parser when either character
// appears in the provided string. See bug 657367.
for (const jschar *cp = &chars[1], *end = &chars[length - 2]; ; cp++) {
if (*cp == 0x2028 || *cp == 0x2029)
break;
if (cp == end) {
bool isArray = (chars[0] == '[');
auto jsonChars = isArray
? Range<const jschar>(chars.get(), length)
: Range<const jschar>(chars.get() + 1U, length - 2);
JSONParser<jschar> parser(cx, jsonChars, JSONParserBase::NoError);
RootedValue tmp(cx);
if (!parser.parse(&tmp))
return EvalJSON_Failure;
if (tmp.isUndefined())
return EvalJSON_NotJSON;
rval.set(tmp);
return EvalJSON_Success;
if (sizeof(CharT) > 1) {
for (RangedPtr<const CharT> cp = chars.start() + 1, end = chars.end() - 1;
cp < end;
cp++)
{
jschar c = *cp;
if (c == 0x2028 || c == 0x2029)
return false;
}
}
return true;
}
return EvalJSON_NotJSON;
return false;
}
template <typename CharT>
static EvalJSONResult
ParseEvalStringAsJSON(JSContext *cx, const Range<const CharT> chars, MutableHandleValue rval)
{
size_t len = chars.length();
MOZ_ASSERT((chars[0] == '(' && chars[len - 1] == ')') ||
(chars[0] == '[' && chars[len - 1] == ']'));
auto jsonChars = (chars[0] == '[')
? chars
: Range<const CharT>(chars.start().get() + 1U, len - 2);
JSONParser<CharT> parser(cx, jsonChars, JSONParserBase::NoError);
if (!parser.parse(rval))
return EvalJSON_Failure;
return rval.isUndefined() ? EvalJSON_NotJSON : EvalJSON_Success;
}
static EvalJSONResult
TryEvalJSON(JSContext *cx, JSScript *callerScript, JSFlatString *str, MutableHandleValue rval)
{
// Don't use the JSON parser if the caller is strict mode code, because in
// strict mode object literals must not have repeated properties, and the
// JSON parser cheerfully (and correctly) accepts them. If you're parsing
// JSON with eval and using strict mode, you deserve to be slow.
if (callerScript && callerScript->strict())
return EvalJSON_NotJSON;
if (str->hasLatin1Chars()) {
AutoCheckCannotGC nogc;
if (!EvalStringMightBeJSON(str->latin1Range(nogc)))
return EvalJSON_NotJSON;
} else {
AutoCheckCannotGC nogc;
if (!EvalStringMightBeJSON(str->twoByteRange(nogc)))
return EvalJSON_NotJSON;
}
AutoStableStringChars flatChars(cx, str);
if (!flatChars.init())
return EvalJSON_Failure;
return flatChars.isLatin1()
? ParseEvalStringAsJSON(cx, flatChars.latin1Range(), rval)
: ParseEvalStringAsJSON(cx, flatChars.twoByteRange(), rval);
}
// Define subset of ExecuteType so that casting performs the injection.
@ -261,11 +301,8 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
if (!flatStr)
return false;
size_t length = flatStr->length();
ConstTwoByteChars chars(flatStr->chars(), length);
RootedScript callerScript(cx, caller ? caller.script() : nullptr);
EvalJSONResult ejr = TryEvalJSON(cx, callerScript, chars, length, args.rval());
EvalJSONResult ejr = TryEvalJSON(cx, callerScript, flatStr, args.rval());
if (ejr != EvalJSON_NotJSON)
return ejr == EvalJSON_Success;
@ -297,7 +334,16 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
.setNoScriptRval(false)
.setOriginPrincipals(originPrincipals)
.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
SourceBufferHolder srcBuf(chars.get(), length, SourceBufferHolder::NoOwnership);
AutoStableStringChars flatChars(cx, flatStr);
if (!flatChars.initTwoByte(cx))
return false;
const jschar *chars = flatChars.twoByteRange().start().get();
SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, flatStr->length(), ownership);
JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, callerScript, options,
srcBuf, flatStr, staticLevel);
@ -333,10 +379,7 @@ js::DirectEvalStringFromIon(JSContext *cx,
if (!flatStr)
return false;
size_t length = flatStr->length();
ConstTwoByteChars chars(flatStr->chars(), length);
EvalJSONResult ejr = TryEvalJSON(cx, callerScript, chars, length, vp);
EvalJSONResult ejr = TryEvalJSON(cx, callerScript, flatStr, vp);
if (ejr != EvalJSON_NotJSON)
return ejr == EvalJSON_Success;
@ -364,7 +407,16 @@ js::DirectEvalStringFromIon(JSContext *cx,
.setNoScriptRval(false)
.setOriginPrincipals(originPrincipals)
.setIntroductionInfo(introducerFilename, "eval", lineno, maybeScript, pcOffset);
SourceBufferHolder srcBuf(chars.get(), length, SourceBufferHolder::NoOwnership);
AutoStableStringChars flatChars(cx, flatStr);
if (!flatChars.initTwoByte(cx))
return false;
const jschar *chars = flatChars.twoByteRange().start().get();
SourceBufferHolder::Ownership ownership = flatChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
: SourceBufferHolder::NoOwnership;
SourceBufferHolder srcBuf(chars, flatStr->length(), ownership);
JSScript *compiled = frontend::CompileScript(cx, &cx->tempLifoAlloc(),
scopeobj, callerScript, options,
srcBuf, flatStr, staticLevel);

View File

@ -7198,7 +7198,7 @@ Parser<ParseHandler>::objectLiteral()
if (!abortIfSyntaxParser())
return null();
tokenStream.ungetToken();
if (!tokenStream.checkForKeyword(atom->charsZ(), atom->length(), nullptr))
if (!tokenStream.checkForKeyword(atom, nullptr))
return null();
PropertyName *name = handler.isName(propname);
JS_ASSERT(atom);

View File

@ -50,8 +50,9 @@ static const KeywordInfo keywords[] = {
// Returns a KeywordInfo for the specified characters, or nullptr if the string
// is not a keyword.
template <typename CharT>
static const KeywordInfo *
FindKeyword(const jschar *s, size_t length)
FindKeyword(const CharT *s, size_t length)
{
JS_ASSERT(length != 0);
@ -87,30 +88,47 @@ FindKeyword(const jschar *s, size_t length)
return nullptr;
}
static const KeywordInfo *
FindKeyword(JSLinearString *str)
{
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? FindKeyword(str->latin1Chars(nogc), str->length())
: FindKeyword(str->twoByteChars(nogc), str->length());
}
template <typename CharT>
static bool
IsIdentifier(const CharT *chars, size_t length)
{
if (length == 0)
return false;
if (!IsIdentifierStart(*chars))
return false;
const CharT *end = chars + length;
while (++chars != end) {
if (!IsIdentifierPart(*chars))
return false;
}
return true;
}
bool
frontend::IsIdentifier(JSLinearString *str)
{
const jschar *chars = str->chars();
size_t length = str->length();
if (length == 0)
return false;
jschar c = *chars;
if (!IsIdentifierStart(c))
return false;
const jschar *end = chars + length;
while (++chars != end) {
c = *chars;
if (!IsIdentifierPart(c))
return false;
}
return true;
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? ::IsIdentifier(str->latin1Chars(nogc), str->length())
: ::IsIdentifier(str->twoByteChars(nogc), str->length());
}
bool
frontend::IsKeyword(JSLinearString *str)
{
return FindKeyword(str->chars(), str->length()) != nullptr;
return FindKeyword(str) != nullptr;
}
TokenStream::SourceCoords::SourceCoords(ExclusiveContext *cx, uint32_t ln)
@ -962,12 +980,8 @@ TokenStream::putIdentInTokenbuf(const jschar *identStart)
}
bool
TokenStream::checkForKeyword(const jschar *s, size_t length, TokenKind *ttp)
TokenStream::checkForKeyword(const KeywordInfo *kw, TokenKind *ttp)
{
const KeywordInfo *kw = FindKeyword(s, length);
if (!kw)
return true;
if (kw->tokentype == TOK_RESERVED)
return reportError(JSMSG_RESERVED_ID, kw->chars);
@ -992,6 +1006,26 @@ TokenStream::checkForKeyword(const jschar *s, size_t length, TokenKind *ttp)
return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars);
}
bool
TokenStream::checkForKeyword(const jschar *s, size_t length, TokenKind *ttp)
{
const KeywordInfo *kw = FindKeyword(s, length);
if (!kw)
return true;
return checkForKeyword(kw, ttp);
}
bool
TokenStream::checkForKeyword(JSAtom *atom, TokenKind *ttp)
{
const KeywordInfo *kw = FindKeyword(atom);
if (!kw)
return true;
return checkForKeyword(kw, ttp);
}
enum FirstCharKind {
// A jschar has the 'OneChar' kind if it, by itself, constitutes a valid
// token that cannot also be a prefix of a longer token. E.g. ';' has the

View File

@ -22,6 +22,8 @@
#include "js/Vector.h"
#include "vm/RegExpObject.h"
struct KeywordInfo;
namespace js {
namespace frontend {
@ -655,7 +657,9 @@ class MOZ_STACK_CLASS TokenStream
// null, report a SyntaxError ("if is a reserved identifier") and return
// false. If ttp is non-null, return true with the keyword's TokenKind in
// *ttp.
bool checkForKeyword(const KeywordInfo *kw, TokenKind *ttp);
bool checkForKeyword(const jschar *s, size_t length, TokenKind *ttp);
bool checkForKeyword(JSAtom *atom, TokenKind *ttp);
// This class maps a userbuf offset (which is 0-indexed) to a line number
// (which is 1-indexed) and a column index (which is 0-indexed).

View File

@ -366,3 +366,35 @@ if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
}
})();
/* Implicit "use strict" context in functions with dynamic linking failure */
(function () {
var funcCode = 'function g(x) {\n\
x=x|0;\n\
return x + 1 | 0;}';
var moduleCode = 'function (glob) {\n\
"use asm";\n\
var fround = glob.Math.fround;\n\
' + funcCode + '\n\
return g;\n\
}',
useStrict = '"use strict";';
var f6 = eval(useStrict + ";\n(" + moduleCode + "({Math:{}}))");
var expectedToString = funcCode.replace('{', '{\n' + useStrict + '\n')
var expectedToSource = expectedToString
assertEq(f6.toString(), expectedToString);
assertEq(f6.toSource(), expectedToSource);
if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
var mf6 = eval("\"use strict\";\n(" + moduleCode + ")");
assertEq(isAsmJSModuleLoadedFromCache(mf6), true);
var f6 = mf6({Math:{}});
assertEq(f6.toString(), expectedToString);
assertEq(f6.toSource(), expectedToSource);
}
})();

View File

@ -0,0 +1,7 @@
function f(x) {
x = eval("a = arguments.callee.arguments; 10");
}
for (var i=0; i<5; i++) {
f(5);
assertEq(a[0], 10);
}

View File

@ -0,0 +1,10 @@
gczeal(8, 2)
try {
[new String, y]
} catch (e) {}
r = /()/
try {
"".replace(r, () => {
[]()
});
} catch(e) {}

View File

@ -0,0 +1,20 @@
function test() {
var arr = [
toLatin1("abc"),
toLatin1("abcd"),
toLatin1("123\u00ff")
];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr.length; j++) {
var s1 = arr[i];
var s2 = arr[j];
var s1tb = "\u1200" + s1;
var s2tb = "\u1200" + s2;
assertEq(s1 < s2, s1tb < s2tb);
assertEq(s1 > s2, s1tb > s2tb);
assertEq(s1 <= s2, s1tb <= s2tb);
assertEq(s1 >= s2, s1tb >= s2tb);
}
}
}
test();

View File

@ -0,0 +1,22 @@
var s = toLatin1("someName");
// Latin1
function f(someName) {
someName();
}
try {
f(3);
} catch(e) {
assertEq(e.message.contains("someName"), true);
}
// TwoByte
function g(someName\u1200) {
someName\u1200();
}
try {
g(3);
} catch(e) {
// Note: string is deflated; don't check for the \u1200.
assertEq(e.message.contains("someName"), true);
}

View File

@ -0,0 +1,10 @@
function f(s) {
var x = 3, y = 5;
var z = eval(s);
assertEq(z, 8);
}
var s = toLatin1("x + y");
f(s); // Latin1
f(s);
f("x + y;/*\u1200*/"); // TwoByte
f("x + y;/*\u1200*/");

View File

@ -0,0 +1,14 @@
var arrLatin1 = [toLatin1("abc1"), toLatin1("abc\u00A0")];
assertEq(arrLatin1.join(toLatin1("sep\u00ff")), "abc1sep\xFFabc\xA0");
var arrTwoByte = [toLatin1("abc2"), "def\u1200"];
assertEq(arrTwoByte.join(toLatin1("sep\u00fe")), "abc2sep\xFEdef\u1200");
assertEq(arrLatin1.join(toLatin1("-")), "abc1-abc\xA0");
assertEq(arrTwoByte.join(toLatin1("7")), "abc27def\u1200");
assertEq(arrLatin1.join("\u1200"), "abc1\u1200abc\xA0");
assertEq(arrTwoByte.join("\u1200"), "abc2\u1200def\u1200");
assertEq(arrLatin1.join("---\u1200"), "abc1---\u1200abc\xA0");
assertEq(arrTwoByte.join("---\u1200"), "abc2---\u1200def\u1200");

View File

@ -32,3 +32,33 @@ function testErrorPos() {
}
}
testErrorPos();
function testEvalHack() {
// Latin1
var arr = eval(toLatin1("[1, 2, 3, \"abc\"]"));
assertEq(JSON.stringify(arr), '[1,2,3,"abc"]');
// TwoByte
arr = eval("[1, 2, 3, \"abc\u1200\"]");
assertEq(JSON.stringify(arr), '[1,2,3,"abc\u1200"]');
}
testEvalHack();
function testEvalHackNotJSON() {
// Latin1
var arr = eval(toLatin1("[]; var q; [1, 2, 3, \"abc\"]"));
assertEq(JSON.stringify(arr), '[1,2,3,"abc"]');
// TwoByte
arr = eval("[]; var z; [1, 2, 3, \"abc\u1200\"]");
assertEq(JSON.stringify(arr), '[1,2,3,"abc\u1200"]');
try {
eval("[1, 2, 3, \"abc\u2028\"]");
throw new Error("U+2028 shouldn't eval");
} catch (e) {
assertEq(e instanceof SyntaxError, true,
"should have thrown a SyntaxError, instead got " + e);
}
}
testEvalHackNotJSON();

View File

@ -0,0 +1,24 @@
// Latin1
var s = toLatin1("abcdef,g,,");
var res = s.split(toLatin1(","));
assertEq(res[0], "abcdef");
assertEq(res[1], "g");
assertEq(res[2], "");
assertEq(res[3], "");
s = toLatin1("abcdef,gh,,");
res = s.split("\u1200");
assertEq(res[0], "abcdef,gh,,");
// TwoByte
s = "abcdef\u1200\u1200,g,,";
res = s.split(",");
assertEq(res[0], "abcdef\u1200\u1200");
assertEq(res[1], "g");
assertEq(res[2], "");
assertEq(res[3], "");
res = s.split("\u1200");
assertEq(res[0], "abcdef");
assertEq(res[1], "");
assertEq(res[2], ",g,,");

View File

@ -607,6 +607,11 @@ HandleDynamicLinkFailure(JSContext *cx, CallArgs args, AsmJSModule &module, Hand
.setCompileAndGo(false)
.setNoScriptRval(false);
// The exported function inherits an implicit strict context if the module
// also inherited it somehow.
if (module.strict())
options.strictOption = true;
SourceBufferHolder srcBuf(src->chars(), end - begin, SourceBufferHolder::NoOwnership);
if (!frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf))
return false;

View File

@ -2960,10 +2960,11 @@ EqualStringsHelper(JSString *str1, JSString *str2)
JS_ASSERT(!str2->isAtom());
JS_ASSERT(str1->length() == str2->length());
const jschar *chars = str2->getChars(nullptr);
if (!chars)
JSLinearString *str2Linear = str2->ensureLinear(nullptr);
if (!str2Linear)
return false;
return mozilla::PodEqual(str1->asAtom().chars(), chars, str1->length());
return EqualChars(&str1->asLinear(), str2Linear);
}
bool

View File

@ -685,19 +685,20 @@ GetDynamicName(JSContext *cx, JSObject *scopeChain, JSString *str, Value *vp)
bool
FilterArgumentsOrEval(JSContext *cx, JSString *str)
{
// getChars() is fallible, but cannot GC: it can only allocate a character
// for the flattened string. If this call fails then the calling Ion code
// will bailout, resume in the interpreter and likely fail again when
// trying to flatten the string and unwind the stack.
const jschar *chars = str->getChars(cx);
if (!chars)
// ensureLinear() is fallible, but cannot GC: it can only allocate a
// character buffer for the flattened string. If this call fails then the
// calling Ion code will bailout, resume in Baseline and likely fail again
// when trying to flatten the string and unwind the stack.
JS::AutoCheckCannotGC nogc;
JSLinearString *linear = str->ensureLinear(cx);
if (!linear)
return false;
static const jschar arguments[] = {'a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's'};
static const jschar eval[] = {'e', 'v', 'a', 'l'};
return !StringHasPattern(chars, str->length(), arguments, mozilla::ArrayLength(arguments)) &&
!StringHasPattern(chars, str->length(), eval, mozilla::ArrayLength(eval));
return !StringHasPattern(linear, arguments, mozilla::ArrayLength(arguments)) &&
!StringHasPattern(linear, eval, mozilla::ArrayLength(eval));
}
#ifdef JSGC_GENERATIONAL

View File

@ -1675,11 +1675,11 @@ Assembler::as_dtm(LoadStore ls, Register rn, uint32_t mask,
}
BufferOffset
Assembler::as_Imm32Pool(Register dest, uint32_t value, ARMBuffer::PoolEntry *pe, Condition c)
Assembler::as_Imm32Pool(Register dest, uint32_t value, Condition c)
{
PoolHintPun php;
php.phd.init(0, c, PoolHintData::poolDTR, dest);
return m_buffer.insertEntry(4, (uint8_t*)&php.raw, int32Pool, (uint8_t*)&value, pe);
return m_buffer.insertEntry(4, (uint8_t*)&php.raw, int32Pool, (uint8_t*)&value);
}
void
@ -1716,12 +1716,12 @@ Assembler::as_BranchPool(uint32_t value, RepatchLabel *label, ARMBuffer::PoolEnt
}
BufferOffset
Assembler::as_FImm64Pool(VFPRegister dest, double value, ARMBuffer::PoolEntry *pe, Condition c)
Assembler::as_FImm64Pool(VFPRegister dest, double value, Condition c)
{
JS_ASSERT(dest.isDouble());
PoolHintPun php;
php.phd.init(0, c, PoolHintData::poolVDTR, dest);
return m_buffer.insertEntry(4, (uint8_t*)&php.raw, doublePool, (uint8_t*)&value, pe);
return m_buffer.insertEntry(4, (uint8_t*)&php.raw, doublePool, (uint8_t*)&value);
}
struct PaddedFloat32
@ -1732,7 +1732,7 @@ struct PaddedFloat32
JS_STATIC_ASSERT(sizeof(PaddedFloat32) == sizeof(double));
BufferOffset
Assembler::as_FImm32Pool(VFPRegister dest, float value, ARMBuffer::PoolEntry *pe, Condition c)
Assembler::as_FImm32Pool(VFPRegister dest, float value, Condition c)
{
/*
* Insert floats into the double pool as they have the same limitations on
@ -1743,7 +1743,7 @@ Assembler::as_FImm32Pool(VFPRegister dest, float value, ARMBuffer::PoolEntry *pe
PoolHintPun php;
php.phd.init(0, c, PoolHintData::poolVDTR, dest);
PaddedFloat32 pf = { value, 0 };
return m_buffer.insertEntry(4, (uint8_t*)&php.raw, doublePool, (uint8_t*)&pf, pe);
return m_buffer.insertEntry(4, (uint8_t*)&php.raw, doublePool, (uint8_t*)&pf);
}
// Pool callbacks stuff:

View File

@ -1482,14 +1482,14 @@ class Assembler : public AssemblerShared
//overwrite a pool entry with new data.
void as_WritePoolEntry(Instruction *addr, Condition c, uint32_t data);
// load a 32 bit immediate from a pool into a register
BufferOffset as_Imm32Pool(Register dest, uint32_t value, ARMBuffer::PoolEntry *pe = nullptr, Condition c = Always);
BufferOffset as_Imm32Pool(Register dest, uint32_t value, Condition c = Always);
// make a patchable jump that can target the entire 32 bit address space.
BufferOffset as_BranchPool(uint32_t value, RepatchLabel *label, ARMBuffer::PoolEntry *pe = nullptr, Condition c = Always);
// load a 64 bit floating point immediate from a pool into a register
BufferOffset as_FImm64Pool(VFPRegister dest, double value, ARMBuffer::PoolEntry *pe = nullptr, Condition c = Always);
BufferOffset as_FImm64Pool(VFPRegister dest, double value, Condition c = Always);
// load a 32 bit floating point immediate from a pool into a register
BufferOffset as_FImm32Pool(VFPRegister dest, float value, ARMBuffer::PoolEntry *pe = nullptr, Condition c = Always);
BufferOffset as_FImm32Pool(VFPRegister dest, float value, Condition c = Always);
// Control flow stuff:

View File

@ -380,11 +380,11 @@ MacroAssemblerARM::ma_alu(Register src1, Imm32 imm, Register dest,
// Going to have to use a load. If the operation is a move, then just move it into the
// destination register
if (op == op_mov) {
as_Imm32Pool(dest, imm.value, nullptr, c);
as_Imm32Pool(dest, imm.value, c);
return;
} else {
// If this isn't just going into a register, then stick it in a temp, and then proceed.
as_Imm32Pool(ScratchRegister, imm.value, nullptr, c);
as_Imm32Pool(ScratchRegister, imm.value, c);
}
}
as_alu(dest, src1, O2Reg(ScratchRegister), op, sc, c);
@ -442,7 +442,7 @@ MacroAssemblerARM::ma_movPatchable(Imm32 imm_, Register dest, Assembler::Conditi
break;
case L_LDR:
if(i == nullptr)
as_Imm32Pool(dest, imm, nullptr, c);
as_Imm32Pool(dest, imm, c);
else
as_WritePoolEntry(i, c, imm);
break;
@ -1332,11 +1332,11 @@ MacroAssemblerARM::ma_b(void *target, Relocation::Kind reloc, Assembler::Conditi
as_bx(ScratchRegister, c);
break;
case Assembler::B_LDR_BX:
as_Imm32Pool(ScratchRegister, trg, nullptr, c);
as_Imm32Pool(ScratchRegister, trg, c);
as_bx(ScratchRegister, c);
break;
case Assembler::B_LDR:
as_Imm32Pool(pc, trg, nullptr, c);
as_Imm32Pool(pc, trg, c);
if (c == Always)
m_buffer.markGuard();
break;
@ -1493,7 +1493,7 @@ MacroAssemblerARM::ma_vimm(double value, FloatRegister dest, Condition cc)
}
}
// Fall back to putting the value in a pool.
as_FImm64Pool(dest, value, nullptr, cc);
as_FImm64Pool(dest, value, cc);
}
static inline uint32_t
@ -1530,7 +1530,7 @@ MacroAssemblerARM::ma_vimm_f32(float value, FloatRegister dest, Condition cc)
}
}
// Fall back to putting the value in a pool.
as_FImm32Pool(vd, value, nullptr, cc);
as_FImm32Pool(vd, value, cc);
}
void

View File

@ -5525,7 +5525,10 @@ JS_EncodeStringToUTF8(JSContext *cx, HandleString str)
if (!linear)
return nullptr;
return TwoByteCharsToNewUTF8CharsZ(cx, linear->range()).c_str();
JS::AutoCheckCannotGC nogc;
return linear->hasLatin1Chars()
? JS::CharsToNewUTF8CharsZ(cx, linear->latin1Range(nogc)).c_str()
: JS::CharsToNewUTF8CharsZ(cx, linear->twoByteRange(nogc)).c_str();
}
JS_PUBLIC_API(size_t)

View File

@ -943,23 +943,22 @@ struct EmptySeparatorOp
bool operator()(JSContext *, StringBuffer &sb) { return true; }
};
template <typename CharT>
struct CharSeparatorOp
{
jschar sep;
explicit CharSeparatorOp(jschar sep) : sep(sep) {};
const CharT sep;
explicit CharSeparatorOp(CharT sep) : sep(sep) {};
bool operator()(JSContext *, StringBuffer &sb) { return sb.append(sep); }
};
struct StringSeparatorOp
{
const jschar *sepchars;
size_t seplen;
HandleLinearString sep;
StringSeparatorOp(const jschar *sepchars, size_t seplen)
: sepchars(sepchars), seplen(seplen) {};
explicit StringSeparatorOp(HandleLinearString sep) : sep(sep) {}
bool operator()(JSContext *cx, StringBuffer &sb) {
return sb.append(sepchars, seplen);
return sb.append(sep);
}
};
@ -1064,22 +1063,16 @@ ArrayJoin(JSContext *cx, CallArgs &args)
return false;
// Steps 4 and 5
RootedString sepstr(cx, nullptr);
const jschar *sepchars;
size_t seplen;
RootedLinearString sepstr(cx);
if (!Locale && args.hasDefined(0)) {
sepstr = ToString<CanGC>(cx, args[0]);
JSString *s = ToString<CanGC>(cx, args[0]);
if (!s)
return false;
sepstr = s->ensureLinear(cx);
if (!sepstr)
return false;
sepchars = sepstr->getChars(cx);
if (!sepchars)
return false;
seplen = sepstr->length();
} else {
HandlePropertyName comma = cx->names().comma;
sepstr = comma;
sepchars = comma->chars();
seplen = comma->length();
sepstr = cx->names().comma;
}
JS::Anchor<JSString*> anchor(sepstr);
@ -1100,9 +1093,12 @@ ArrayJoin(JSContext *cx, CallArgs &args)
}
StringBuffer sb(cx);
if (sepstr->hasTwoByteChars() && !sb.ensureTwoByteChars())
return false;
// The separator will be added |length - 1| times, reserve space for that
// so that we don't have to unnecessarily grow the buffer.
size_t seplen = sepstr->length();
if (length > 0 && !sb.reserve(seplen * (length - 1)))
return false;
@ -1112,11 +1108,18 @@ ArrayJoin(JSContext *cx, CallArgs &args)
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
} else if (seplen == 1) {
CharSeparatorOp op(sepchars[0]);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
jschar c = sepstr->latin1OrTwoByteChar(0);
if (c <= JSString::MAX_LATIN1_CHAR) {
CharSeparatorOp<Latin1Char> op(c);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
} else {
CharSeparatorOp<jschar> op(c);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
}
} else {
StringSeparatorOp op(sepchars, seplen);
StringSeparatorOp op(sepstr);
if (!ArrayJoinKernel<Locale>(cx, op, obj, length, sb))
return false;
}

View File

@ -1051,6 +1051,10 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
systemZone(nullptr),
systemAvailableChunkListHead(nullptr),
userAvailableChunkListHead(nullptr),
#ifdef JSGC_GENERATIONAL
nursery(rt),
storeBuffer(rt, nursery),
#endif
bytes(0),
maxBytes(0),
maxMallocBytes(0),
@ -1108,10 +1112,6 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
objectsMarkedInDeadZones(0),
poked(false),
heapState(Idle),
#ifdef JSGC_GENERATIONAL
nursery(rt),
storeBuffer(rt, nursery),
#endif
#ifdef JS_GC_ZEAL
zealMode(0),
zealFrequency(0),

View File

@ -1198,21 +1198,24 @@ Sprinter::putString(JSString *s)
InvariantChecker ic(this);
size_t length = s->length();
const jschar *chars = s->getChars(context);
if (!chars)
return -1;
size_t size = length;
if (size == (size_t) -1)
return -1;
ptrdiff_t oldOffset = offset;
char *buffer = reserve(size);
if (!buffer)
return -1;
DeflateStringToBuffer(nullptr, chars, length, buffer, &size);
buffer[size] = 0;
JSLinearString *linear = s->ensureLinear(context);
if (!linear)
return -1;
AutoCheckCannotGC nogc;
if (linear->hasLatin1Chars())
mozilla::PodCopy(reinterpret_cast<Latin1Char*>(buffer), linear->latin1Chars(nogc), length);
else
DeflateStringToBuffer(nullptr, linear->twoByteChars(nogc), length, buffer, &size);
buffer[size] = 0;
return oldOffset;
}

View File

@ -1317,10 +1317,12 @@ StringMatch(JSLinearString *text, JSLinearString *pat, uint32_t start = 0)
static const size_t sRopeMatchThresholdRatioLog2 = 5;
bool
js::StringHasPattern(const jschar *text, uint32_t textLen,
const jschar *pat, uint32_t patLen)
js::StringHasPattern(JSLinearString *text, const jschar *pat, uint32_t patLen)
{
return StringMatch(text, textLen, pat, patLen) != -1;
AutoCheckCannotGC nogc;
return text->hasLatin1Chars()
? StringMatch(text->latin1Chars(nogc), text->length(), pat, patLen) != -1
: StringMatch(text->twoByteChars(nogc), text->length(), pat, patLen) != -1;
}
int
@ -3704,13 +3706,11 @@ class SplitStringMatcher
bool operator()(JSContext *cx, JSLinearString *str, size_t index, SplitMatchResult *res) const
{
JS_ASSERT(index == 0 || index < str->length());
const jschar *chars = str->chars();
int match = StringMatch(chars + index, str->length() - index,
sep->chars(), sep->length());
int match = StringMatch(str, sep, index);
if (match == -1)
res->setFailure();
else
res->setResult(sep->length(), index + match + sep->length());
res->setResult(sep->length(), match + sep->length());
return true;
}
};
@ -4464,8 +4464,8 @@ js::StringToSource(JSContext *cx, JSString *str)
return js_QuoteString(cx, str, '"');
}
static bool
EqualChars(JSLinearString *str1, JSLinearString *str2)
bool
js::EqualChars(JSLinearString *str1, JSLinearString *str2)
{
MOZ_ASSERT(str1->length() == str2->length());
@ -4523,8 +4523,28 @@ js::EqualStrings(JSLinearString *str1, JSLinearString *str2)
return EqualChars(str1, str2);
}
static bool
CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
static int32_t
CompareStringsImpl(JSLinearString *str1, JSLinearString *str2)
{
size_t len1 = str1->length();
size_t len2 = str2->length();
AutoCheckCannotGC nogc;
if (str1->hasLatin1Chars()) {
const Latin1Char *chars1 = str1->latin1Chars(nogc);
return str2->hasLatin1Chars()
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
}
const jschar *chars1 = str1->twoByteChars(nogc);
return str2->hasLatin1Chars()
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
}
bool
js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
{
JS_ASSERT(str1);
JS_ASSERT(str2);
@ -4534,28 +4554,22 @@ CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32_t *resul
return true;
}
const jschar *s1 = str1->getChars(cx);
if (!s1)
JSLinearString *linear1 = str1->ensureLinear(cx);
if (!linear1)
return false;
const jschar *s2 = str2->getChars(cx);
if (!s2)
JSLinearString *linear2 = str2->ensureLinear(cx);
if (!linear2)
return false;
*result = CompareChars(s1, str1->length(), s2, str2->length());
*result = CompareStringsImpl(linear1, linear2);
return true;
}
bool
js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
{
return CompareStringsImpl(cx, str1, str2, result);
}
int32_t
js::CompareAtoms(JSAtom *atom1, JSAtom *atom2)
{
return CompareChars(atom1->chars(), atom1->length(), atom2->chars(), atom2->length());
return CompareStringsImpl(atom1, atom2);
}
bool
@ -4568,12 +4582,13 @@ js::StringEqualsAscii(JSLinearString *str, const char *asciiBytes)
#endif
if (length != str->length())
return false;
const jschar *chars = str->chars();
for (size_t i = 0; i != length; ++i) {
if (unsigned(asciiBytes[i]) != unsigned(chars[i]))
return false;
}
return true;
const Latin1Char *latin1 = reinterpret_cast<const Latin1Char *>(asciiBytes);
AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? PodEqual(latin1, str->latin1Chars(nogc), length)
: EqualCharsLatin1TwoByte(latin1, str->twoByteChars(nogc), length);
}
size_t

View File

@ -48,16 +48,17 @@ SkipSpace(const CharT *s, const CharT *end)
// Return less than, equal to, or greater than zero depending on whether
// s1 is less than, equal to, or greater than s2.
template <typename Char1, typename Char2>
inline int32_t
CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2)
CompareChars(const Char1 *s1, size_t len1, const Char2 *s2, size_t len2)
{
size_t n = Min(l1, l2);
size_t n = Min(len1, len2);
for (size_t i = 0; i < n; i++) {
if (int32_t cmp = s1[i] - s2[i])
return cmp;
}
return (int32_t)(l1 - l2);
return int32_t(len1 - len2);
}
} /* namespace js */
@ -183,6 +184,9 @@ EqualStrings(JSContext *cx, JSLinearString *str1, JSLinearString *str2, bool *re
extern bool
EqualStrings(JSLinearString *str1, JSLinearString *str2);
extern bool
EqualChars(JSLinearString *str1, JSLinearString *str2);
/*
* Return less than, equal to, or greater than zero depending on whether
* str1 is less than, equal to, or greater than str2.
@ -201,8 +205,7 @@ StringEqualsAscii(JSLinearString *str, const char *asciiBytes);
/* Return true if the string contains a pattern anywhere inside it. */
extern bool
StringHasPattern(const jschar *text, uint32_t textlen,
const jschar *pat, uint32_t patlen);
StringHasPattern(JSLinearString *text, const jschar *pat, uint32_t patlen);
extern int
StringFindPattern(const jschar *text, uint32_t textlen,

View File

@ -320,16 +320,6 @@ GetLine(FILE *file, const char * prompt)
return nullptr;
}
static char *
JSStringToUTF8(JSContext *cx, JSString *str)
{
JSLinearString *linear = str->ensureLinear(cx);
if (!linear)
return nullptr;
return TwoByteCharsToNewUTF8CharsZ(cx, linear->range()).c_str();
}
/* State to store as JSContext private. */
struct JSShellContextData {
/* Creation timestamp, used by the elapsed() shell builtin. */
@ -492,7 +482,7 @@ EvalAndPrint(JSContext *cx, Handle<JSObject*> global, const char *bytes, size_t
if (!str)
return false;
char *utf8chars = JSStringToUTF8(cx, str);
char *utf8chars = JS_EncodeStringToUTF8(cx, str);
if (!utf8chars)
return false;
fprintf(out, "%s\n", utf8chars);
@ -1446,14 +1436,17 @@ Run(JSContext *cx, unsigned argc, jsval *vp)
if (!filename)
return false;
const jschar *ucbuf = nullptr;
size_t buflen;
str = FileAsString(cx, filename.ptr());
if (str)
ucbuf = JS_GetStringCharsAndLength(cx, str, &buflen);
if (!ucbuf)
if (!str)
return false;
AutoStableStringChars chars(cx, &str->asLinear());
if (!chars.initTwoByte(cx))
return false;
const jschar *ucbuf = chars.twoByteRange().start().get();
size_t buflen = str->length();
JS::Anchor<JSString *> a_str(str);
RootedScript script(cx);
@ -1564,10 +1557,10 @@ PutStr(JSContext *cx, unsigned argc, jsval *vp)
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 0) {
JSString *str = JS::ToString(cx, args[0]);
RootedString str(cx, JS::ToString(cx, args[0]));
if (!str)
return false;
char *bytes = JSStringToUTF8(cx, str);
char *bytes = JS_EncodeStringToUTF8(cx, str);
if (!bytes)
return false;
fputs(bytes, gOutFile);
@ -1592,10 +1585,10 @@ static bool
PrintInternal(JSContext *cx, const CallArgs &args, FILE *file)
{
for (unsigned i = 0; i < args.length(); i++) {
JSString *str = JS::ToString(cx, args[i]);
RootedString str(cx, JS::ToString(cx, args[i]));
if (!str)
return false;
char *bytes = JSStringToUTF8(cx, str);
char *bytes = JS_EncodeStringToUTF8(cx, str);
if (!bytes)
return false;
fprintf(file, "%s%s", i ? " " : "", bytes);

View File

@ -156,7 +156,7 @@ struct CopyScriptFrameIterArgs
* invalid.
*/
void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) {
if (!iter_.isJit())
if (!iter_.isIon())
ArgumentsObject::MaybeForwardToCallObject(iter_.abstractFramePtr(), obj, data);
}
};

View File

@ -25,16 +25,13 @@ JS::LossyTwoByteCharsToNewLatin1CharsZ(js::ThreadSafeContext *cx, TwoByteChars t
return Latin1CharsZ(latin1, len);
}
template <typename CharT>
static size_t
GetDeflatedUTF8StringLength(const jschar *chars, size_t nchars)
GetDeflatedUTF8StringLength(const CharT *chars, size_t nchars)
{
size_t nbytes;
const jschar *end;
unsigned c, c2;
nbytes = nchars;
for (end = chars + nchars; chars != end; chars++) {
c = *chars;
size_t nbytes = nchars;
for (const CharT *end = chars + nchars; chars < end; chars++) {
jschar c = *chars;
if (c < 0x80)
continue;
if (0xD800 <= c && c <= 0xDFFF) {
@ -43,7 +40,7 @@ GetDeflatedUTF8StringLength(const jschar *chars, size_t nchars)
nbytes += 2; /* Bad Surrogate */
continue;
}
c2 = chars[1];
jschar c2 = chars[1];
if (c2 < 0xDC00 || c2 > 0xDFFF) {
nbytes += 2; /* Bad Surrogate */
continue;
@ -77,8 +74,9 @@ PutUTF8ReplacementCharacter(char **dst, size_t *dstlenp) {
* Write up to |*dstlenp| bytes into |dst|. Writes the number of bytes used
* into |*dstlenp| on success. Returns false on failure.
*/
template <typename CharT>
static bool
DeflateStringToUTF8Buffer(js::ThreadSafeContext *cx, const jschar *src, size_t srclen,
DeflateStringToUTF8Buffer(js::ThreadSafeContext *cx, const CharT *src, size_t srclen,
char *dst, size_t *dstlenp)
{
size_t dstlen = *dstlenp;
@ -140,28 +138,34 @@ bufferTooSmall:
return false;
}
template <typename CharT>
UTF8CharsZ
JS::TwoByteCharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, TwoByteChars tbchars)
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, const mozilla::Range<const CharT> chars)
{
JS_ASSERT(cx);
/* Get required buffer size. */
jschar *str = tbchars.start().get();
size_t len = GetDeflatedUTF8StringLength(str, tbchars.length());
const CharT *str = chars.start().get();
size_t len = GetDeflatedUTF8StringLength(str, chars.length());
/* Allocate buffer. */
unsigned char *utf8 = cx->pod_malloc<unsigned char>(len + 1);
char *utf8 = cx->pod_malloc<char>(len + 1);
if (!utf8)
return UTF8CharsZ();
/* Encode to UTF8. */
DeflateStringToUTF8Buffer(cx, str, tbchars.length(), (char *)utf8, &len);
DeflateStringToUTF8Buffer(cx, str, chars.length(), utf8, &len);
utf8[len] = '\0';
return UTF8CharsZ(utf8, len);
}
template UTF8CharsZ
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, mozilla::Range<const Latin1Char> chars);
template UTF8CharsZ
JS::CharsToNewUTF8CharsZ(js::ThreadSafeContext *cx, mozilla::Range<const jschar> chars);
static const uint32_t INVALID_UTF8 = UINT32_MAX;
/*

View File

@ -292,7 +292,7 @@ intrinsic_ParallelSpew(ThreadSafeContext *cx, unsigned argc, Value *vp)
if (!inspector.ensureChars(cx, nogc))
return false;
ScopedJSFreePtr<char> bytes(TwoByteCharsToNewUTF8CharsZ(cx, inspector.twoByteRange()).c_str());
ScopedJSFreePtr<char> bytes(JS::CharsToNewUTF8CharsZ(cx, inspector.twoByteRange()).c_str());
parallel::Spew(parallel::SpewOps, bytes);
args.rval().setUndefined();

View File

@ -320,7 +320,7 @@ JSRope::flattenInternal(ExclusiveContext *maybecx)
}
JSString *child = str->d.s.u2.left;
JS_ASSERT(child->isRope());
str->d.s.u2.nonInlineCharsTwoByte = left.nonInlineChars();
str->setNonInlineChars(left.nonInlineChars<CharT>(nogc));
child->d.u1.flattenData = uintptr_t(str) | Tag_VisitRightChild;
str = child;
}

View File

@ -258,6 +258,8 @@ class JSString : public js::gc::BarrieredCell<JSString>
static const uint32_t MAX_LENGTH = JS_BIT(28) - 1;
static const JS::Latin1Char MAX_LATIN1_CHAR = 0xff;
/*
* Helper function to validate that a string of a given length is
* representable by a JSString. An allocation overflow is reported if false
@ -655,14 +657,14 @@ class JSLinearString : public JSString
return JS::TwoByteChars(chars(), length());
}
JS::Latin1Chars latin1Range(const JS::AutoCheckCannotGC &nogc) const {
mozilla::Range<const JS::Latin1Char> latin1Range(const JS::AutoCheckCannotGC &nogc) const {
JS_ASSERT(JSString::isLinear());
return JS::Latin1Chars(latin1Chars(nogc), length());
return mozilla::Range<const JS::Latin1Char>(latin1Chars(nogc), length());
}
JS::TwoByteChars twoByteRange(const JS::AutoCheckCannotGC &nogc) const {
mozilla::Range<const jschar> twoByteRange(const JS::AutoCheckCannotGC &nogc) const {
JS_ASSERT(JSString::isLinear());
return JS::TwoByteChars(twoByteChars(nogc), length());
return mozilla::Range<const jschar>(twoByteChars(nogc), length());
}
MOZ_ALWAYS_INLINE
@ -1046,9 +1048,13 @@ class ScopedThreadSafeStringInspector
return latin1Chars_;
}
JS::TwoByteChars twoByteRange() const {
mozilla::Range<const Latin1Char> latin1Range() const {
MOZ_ASSERT(state_ == Latin1);
return mozilla::Range<const Latin1Char>(latin1Chars_, str_->length());
}
mozilla::Range<const jschar> twoByteRange() const {
MOZ_ASSERT(state_ == TwoByte);
return JS::TwoByteChars(twoByteChars_, str_->length());
return mozilla::Range<const jschar>(twoByteChars_, str_->length());
}
};
@ -1064,7 +1070,7 @@ class ScopedThreadSafeStringInspector
class MOZ_STACK_CLASS AutoStableStringChars
{
/* Ensure the string is kept alive while we're using its chars. */
Rooted<JSLinearString*> s_;
RootedLinearString s_;
union {
const jschar *twoByteChars_;
const JS::Latin1Char *latin1Chars_;
@ -1097,6 +1103,16 @@ class MOZ_STACK_CLASS AutoStableStringChars
return mozilla::Range<const jschar>(twoByteChars_, s_->length());
}
/* If we own the chars, transfer ownership to the caller. */
bool maybeGiveOwnershipToCaller() {
MOZ_ASSERT(state_ != Uninitialized);
if (!ownsChars_)
return false;
state_ = Uninitialized;
ownsChars_ = false;
return true;
}
private:
AutoStableStringChars(const AutoStableStringChars &other) MOZ_DELETE;
void operator=(const AutoStableStringChars &other) MOZ_DELETE;

View File

@ -67,8 +67,6 @@ class StringBuffer
return cb.ref<TwoByteCharBuffer>();
}
static const Latin1Char MaxLatin1Char = 0xff;
bool inflateChars();
public:
@ -107,7 +105,7 @@ class StringBuffer
inline bool append(const jschar c) {
if (isLatin1()) {
if (c <= MaxLatin1Char)
if (c <= JSString::MAX_LATIN1_CHAR)
return latin1Chars().append(Latin1Char(c));
if (!inflateChars())
return false;
@ -224,7 +222,7 @@ StringBuffer::append(const jschar *begin, const jschar *end)
while (true) {
if (begin >= end)
return true;
if (*begin > MaxLatin1Char)
if (*begin > JSString::MAX_LATIN1_CHAR)
break;
if (!latin1Chars().append(*begin))
return false;
@ -246,7 +244,9 @@ StringBuffer::append(JSLinearString *str)
if (!inflateChars())
return false;
}
return twoByteChars().append(str->twoByteChars(nogc), str->length());
return str->hasLatin1Chars()
? twoByteChars().append(str->latin1Chars(nogc), str->length())
: twoByteChars().append(str->twoByteChars(nogc), str->length());
}
inline bool
@ -261,7 +261,9 @@ StringBuffer::appendSubstring(JSLinearString *base, size_t off, size_t len)
if (!inflateChars())
return false;
}
return twoByteChars().append(base->twoByteChars(nogc) + off, len);
return base->hasLatin1Chars()
? twoByteChars().append(base->latin1Chars(nogc) + off, len)
: twoByteChars().append(base->twoByteChars(nogc) + off, len);
}
inline bool

View File

@ -15,7 +15,7 @@
#include "nsStringFwd.h"
class nsPresState;
template<typename> class already_AddRefed;
template<typename> struct already_AddRefed;
#define NS_ILAYOUTHISTORYSTATE_IID \
{ 0x5208993e, 0xd812, 0x431e, \

View File

@ -4595,17 +4595,19 @@ nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
/* static */ bool
nsLayoutUtils::GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
nsLayoutUtils::GetFirstLineBaseline(WritingMode aWritingMode,
const nsIFrame* aFrame, nscoord* aResult)
{
LinePosition position;
if (!GetFirstLinePosition(aFrame, &position))
if (!GetFirstLinePosition(aWritingMode, aFrame, &position))
return false;
*aResult = position.mBaseline;
return true;
}
/* static */ bool
nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
nsLayoutUtils::GetFirstLinePosition(WritingMode aWM,
const nsIFrame* aFrame,
LinePosition* aResult)
{
const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
@ -4614,11 +4616,11 @@ nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
// so, use the baseline of its first row.
nsIAtom* fType = aFrame->GetType();
if (fType == nsGkAtoms::tableOuterFrame) {
aResult->mTop = 0;
aResult->mBaseline = aFrame->GetBaseline();
aResult->mBStart = 0;
aResult->mBaseline = aFrame->GetLogicalBaseline(aWM);
// This is what we want for the list bullet caller; not sure if
// other future callers will want the same.
aResult->mBottom = aFrame->GetSize().height;
aResult->mBEnd = aFrame->BSize(aWM);
return true;
}
@ -4629,11 +4631,13 @@ nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
NS_NOTREACHED("not scroll frame");
}
LinePosition kidPosition;
if (GetFirstLinePosition(sFrame->GetScrolledFrame(), &kidPosition)) {
if (GetFirstLinePosition(aWM,
sFrame->GetScrolledFrame(), &kidPosition)) {
// Consider only the border and padding that contributes to the
// kid's position, not the scrolling, so we get the initial
// position.
*aResult = kidPosition + aFrame->GetUsedBorderAndPadding().top;
*aResult = kidPosition +
aFrame->GetLogicalUsedBorderAndPadding(aWM).BStart(aWM);
return true;
}
return false;
@ -4643,8 +4647,9 @@ nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
LinePosition kidPosition;
nsIFrame* kid = aFrame->GetFirstPrincipalChild();
// kid might be a legend frame here, but that's ok.
if (GetFirstLinePosition(kid, &kidPosition)) {
*aResult = kidPosition + kid->GetNormalPosition().y;
if (GetFirstLinePosition(aWM, kid, &kidPosition)) {
*aResult = kidPosition +
kid->GetLogicalNormalPosition(aWM, aFrame->GetSize().width).B(aWM);
return true;
}
return false;
@ -4660,18 +4665,23 @@ nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
if (line->IsBlock()) {
nsIFrame *kid = line->mFirstChild;
LinePosition kidPosition;
if (GetFirstLinePosition(kid, &kidPosition)) {
*aResult = kidPosition + kid->GetNormalPosition().y;
if (GetFirstLinePosition(aWM, kid, &kidPosition)) {
//XXX Not sure if this is the correct value to use for container
// width here. It will only be used in vertical-rl layout,
// which we don't have full support and testing for yet.
nscoord containerWidth = line->mContainerWidth;
*aResult = kidPosition +
kid->GetLogicalNormalPosition(aWM, containerWidth).B(aWM);
return true;
}
} else {
// XXX Is this the right test? We have some bogus empty lines
// floating around, but IsEmpty is perhaps too weak.
if (line->BSize() != 0 || !line->IsEmpty()) {
nscoord top = line->BStart();
aResult->mTop = top;
aResult->mBaseline = top + line->GetAscent();
aResult->mBottom = top + line->BSize();
nscoord bStart = line->BStart();
aResult->mBStart = bStart;
aResult->mBaseline = bStart + line->GetLogicalAscent();
aResult->mBEnd = bStart + line->BSize();
return true;
}
}
@ -4680,7 +4690,8 @@ nsLayoutUtils::GetFirstLinePosition(const nsIFrame* aFrame,
}
/* static */ bool
nsLayoutUtils::GetLastLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
nsLayoutUtils::GetLastLineBaseline(WritingMode aWM,
const nsIFrame* aFrame, nscoord* aResult)
{
const nsBlockFrame* block = nsLayoutUtils::GetAsBlock(const_cast<nsIFrame*>(aFrame));
if (!block)
@ -4693,21 +4704,24 @@ nsLayoutUtils::GetLastLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
if (line->IsBlock()) {
nsIFrame *kid = line->mFirstChild;
nscoord kidBaseline;
if (GetLastLineBaseline(kid, &kidBaseline)) {
nscoord containerWidth = line->mContainerWidth;
if (GetLastLineBaseline(aWM, kid, &kidBaseline)) {
// Ignore relative positioning for baseline calculations
*aResult = kidBaseline + kid->GetNormalPosition().y;
*aResult = kidBaseline +
kid->GetLogicalNormalPosition(aWM, containerWidth).B(aWM);
return true;
} else if (kid->GetType() == nsGkAtoms::scrollFrame) {
// Use the bottom of the scroll frame.
// XXX CSS2.1 really doesn't say what to do here.
*aResult = kid->GetNormalPosition().y + kid->GetRect().height;
*aResult = kid->GetLogicalNormalPosition(aWM, containerWidth).B(aWM) +
kid->BSize(aWM);
return true;
}
} else {
// XXX Is this the right test? We have some bogus empty lines
// floating around, but IsEmpty is perhaps too weak.
if (line->BSize() != 0 || !line->IsEmpty()) {
*aResult = line->BStart() + line->GetAscent();
*aResult = line->BStart() + line->GetLogicalAscent();
return true;
}
}
@ -4716,45 +4730,49 @@ nsLayoutUtils::GetLastLineBaseline(const nsIFrame* aFrame, nscoord* aResult)
}
static nscoord
CalculateBlockContentBottom(nsBlockFrame* aFrame)
CalculateBlockContentBEnd(WritingMode aWM, nsBlockFrame* aFrame)
{
NS_PRECONDITION(aFrame, "null ptr");
nscoord contentBottom = 0;
nscoord contentBEnd = 0;
for (nsBlockFrame::line_iterator line = aFrame->begin_lines(),
line_end = aFrame->end_lines();
line != line_end; ++line) {
if (line->IsBlock()) {
nsIFrame* child = line->mFirstChild;
nscoord offset = child->GetNormalPosition().y;
contentBottom = std::max(contentBottom,
nsLayoutUtils::CalculateContentBottom(child) + offset);
nscoord containerWidth = line->mContainerWidth;
nscoord offset =
child->GetLogicalNormalPosition(aWM, containerWidth).B(aWM);
contentBEnd =
std::max(contentBEnd,
nsLayoutUtils::CalculateContentBEnd(aWM, child) + offset);
}
else {
contentBottom = std::max(contentBottom, line->BEnd());
contentBEnd = std::max(contentBEnd, line->BEnd());
}
}
return contentBottom;
return contentBEnd;
}
/* static */ nscoord
nsLayoutUtils::CalculateContentBottom(nsIFrame* aFrame)
nsLayoutUtils::CalculateContentBEnd(WritingMode aWM, nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame, "null ptr");
nscoord contentBottom = aFrame->GetRect().height;
nscoord contentBEnd = aFrame->BSize(aWM);
// We want scrollable overflow rather than visual because this
// calculation is intended to affect layout.
if (aFrame->GetScrollableOverflowRect().height > contentBottom) {
LogicalSize overflowSize(aWM, aFrame->GetScrollableOverflowRect().Size());
if (overflowSize.BSize(aWM) > contentBEnd) {
nsIFrame::ChildListIDs skip(nsIFrame::kOverflowList |
nsIFrame::kExcessOverflowContainersList |
nsIFrame::kOverflowOutOfFlowList);
nsBlockFrame* blockFrame = GetAsBlock(aFrame);
if (blockFrame) {
contentBottom =
std::max(contentBottom, CalculateBlockContentBottom(blockFrame));
contentBEnd =
std::max(contentBEnd, CalculateBlockContentBEnd(aWM, blockFrame));
skip |= nsIFrame::kPrincipalList;
}
nsIFrame::ChildListIterator lists(aFrame);
@ -4763,14 +4781,16 @@ nsLayoutUtils::CalculateContentBottom(nsIFrame* aFrame)
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
nsIFrame* child = childFrames.get();
nscoord offset = child->GetNormalPosition().y;
contentBottom = std::max(contentBottom,
CalculateContentBottom(child) + offset);
nscoord offset =
child->GetLogicalNormalPosition(aWM,
aFrame->GetSize().width).B(aWM);
contentBEnd = std::max(contentBEnd,
CalculateContentBEnd(aWM, child) + offset);
}
}
}
}
return contentBottom;
return contentBEnd;
}
/* static */ nsIFrame*

View File

@ -65,6 +65,7 @@ namespace mozilla {
class SVGImageContext;
struct IntrinsicSize;
struct ContainerLayerParameters;
class WritingMode;
namespace dom {
class DOMRectList;
class Element;
@ -1360,7 +1361,8 @@ public:
* Returns true if a baseline was found (and fills in aResult).
* Otherwise returns false.
*/
static bool GetFirstLineBaseline(const nsIFrame* aFrame, nscoord* aResult);
static bool GetFirstLineBaseline(mozilla::WritingMode aWritingMode,
const nsIFrame* aFrame, nscoord* aResult);
/**
* Just like GetFirstLineBaseline, except also returns the top and
@ -1370,17 +1372,18 @@ public:
* Otherwise returns false.
*/
struct LinePosition {
nscoord mTop, mBaseline, mBottom;
nscoord mBStart, mBaseline, mBEnd;
LinePosition operator+(nscoord aOffset) const {
LinePosition result;
result.mTop = mTop + aOffset;
result.mBStart = mBStart + aOffset;
result.mBaseline = mBaseline + aOffset;
result.mBottom = mBottom + aOffset;
result.mBEnd = mBEnd + aOffset;
return result;
}
};
static bool GetFirstLinePosition(const nsIFrame* aFrame,
static bool GetFirstLinePosition(mozilla::WritingMode aWritingMode,
const nsIFrame* aFrame,
LinePosition* aResult);
@ -1392,17 +1395,20 @@ public:
* Returns true if a baseline was found (and fills in aResult).
* Otherwise returns false.
*/
static bool GetLastLineBaseline(const nsIFrame* aFrame, nscoord* aResult);
static bool GetLastLineBaseline(mozilla::WritingMode aWritingMode,
const nsIFrame* aFrame, nscoord* aResult);
/**
* Returns a y coordinate relative to this frame's origin that represents
* the logical bottom of the frame or its visible content, whichever is lower.
* Returns a block-dir coordinate relative to this frame's origin that
* represents the logical block-end of the frame or its visible content,
* whichever is further from the origin.
* Relative positioning is ignored and margins and glyph bounds are not
* considered.
* This value will be >= mRect.height() and <= overflowRect.YMost() unless
* This value will be >= mRect.BSize() and <= overflowRect.BEnd() unless
* relative positioning is applied.
*/
static nscoord CalculateContentBottom(nsIFrame* aFrame);
static nscoord CalculateContentBEnd(mozilla::WritingMode aWritingMode,
nsIFrame* aFrame);
/**
* Gets the closest frame (the frame passed in or one of its parents) that

View File

@ -585,8 +585,9 @@ nsFieldSetFrame::AccessibleType()
#endif
nscoord
nsFieldSetFrame::GetBaseline() const
nsFieldSetFrame::GetLogicalBaseline(WritingMode aWritingMode) const
{
nsIFrame* inner = GetInner();
return inner->GetPosition().y + inner->GetBaseline();
return inner->BStart(aWritingMode, GetParent()->GetSize().width) +
inner->GetLogicalBaseline(aWritingMode);
}

View File

@ -25,7 +25,7 @@ public:
nsSize aCBSize, nscoord aAvailableWidth,
nsSize aMargin, nsSize aBorder, nsSize aPadding,
uint32_t aFlags) MOZ_OVERRIDE;
virtual nscoord GetBaseline() const MOZ_OVERRIDE;
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const MOZ_OVERRIDE;
/**
* The area to paint box-shadows around. It's the border rect except

View File

@ -63,14 +63,15 @@ nsFormControlFrame::GetIntrinsicHeight()
}
nscoord
nsFormControlFrame::GetBaseline() const
nsFormControlFrame::GetLogicalBaseline(WritingMode aWritingMode) const
{
NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
"frame must not be dirty");
// Treat radio buttons and checkboxes as having an intrinsic baseline
// at the bottom of the control (use the bottom content edge rather
// than the bottom margin edge).
return mRect.height - GetUsedBorderAndPadding().bottom;
return BSize(aWritingMode) -
GetLogicalUsedBorderAndPadding(aWritingMode).BEnd(aWritingMode);
}
void

View File

@ -45,7 +45,8 @@ public:
mozilla::WidgetGUIEvent* aEvent,
nsEventStatus* aEventStatus) MOZ_OVERRIDE;
virtual nscoord GetBaseline() const MOZ_OVERRIDE;
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode)
const MOZ_OVERRIDE;
/**
* Respond to the request to resize and/or reflow

View File

@ -333,7 +333,8 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
// Make sure we have a useful 'ascent' value for the child
if (contentsDesiredSize.BlockStartAscent() ==
nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
contentsDesiredSize.SetBlockStartAscent(aFirstKid->GetBaseline());
WritingMode wm = aButtonReflowState.GetWritingMode();
contentsDesiredSize.SetBlockStartAscent(aFirstKid->GetLogicalBaseline(wm));
}
// OK, we're done with the child frame.

Some files were not shown because too many files have changed in this diff Show More