This commit is contained in:
Ryan VanderMeulen 2014-06-17 15:42:06 -04:00
Родитель d962fbd62a 6f80c55849
Коммит b61dcafc3d
148 изменённых файлов: 2427 добавлений и 1157 удалений

Просмотреть файл

@ -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();
},
};
})();

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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);"

Просмотреть файл

@ -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>

Просмотреть файл

@ -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);
}
};

Просмотреть файл

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

Просмотреть файл

@ -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'

Просмотреть файл

@ -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')

Просмотреть файл

@ -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):

Просмотреть файл

@ -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")

Просмотреть файл

@ -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]

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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]

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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:

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

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

Просмотреть файл

@ -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);

Просмотреть файл

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

Просмотреть файл

@ -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);
};

Просмотреть файл

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

Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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);

Просмотреть файл

@ -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,

Просмотреть файл

@ -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]

Просмотреть файл

@ -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>

Просмотреть файл

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

Просмотреть файл

@ -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;

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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:

Просмотреть файл

@ -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]);
}
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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
});
});

Просмотреть файл

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

Просмотреть файл

@ -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]

Просмотреть файл

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

Просмотреть файл

@ -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"

Просмотреть файл

@ -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"

Просмотреть файл

@ -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.

Просмотреть файл

@ -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)
{

Просмотреть файл

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

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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

Просмотреть файл

@ -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).

Просмотреть файл

@ -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);
}
})();

Просмотреть файл

@ -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);
}

Просмотреть файл

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

Просмотреть файл

@ -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();

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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*/");

Просмотреть файл

@ -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");

Просмотреть файл

@ -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();

Просмотреть файл

@ -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,,");

Просмотреть файл

@ -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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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:

Просмотреть файл

@ -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:

Просмотреть файл

@ -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

Просмотреть файл

@ -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)

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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),

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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,

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);
}
};

Просмотреть файл

@ -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;
/*

Просмотреть файл

@ -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();

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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, \

Просмотреть файл

@ -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*

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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.

Просмотреть файл

@ -714,6 +714,7 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine,
if (aCreateLeft) {
DisplayListClipState::AutoSaveRestore clipState(mBuilder);
//XXX Needs vertical text love
nsRect markerRect = nsRect(aInsideMarkersArea.x - mLeft.mIntrinsicWidth,
aLine->BStart(),
mLeft.mIntrinsicWidth, aLine->BSize());
@ -722,7 +723,7 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine,
markerRect, clipState);
nsDisplayItem* marker = new (mBuilder)
nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
aLine->GetAscent(), mLeft.mStyle, 0);
aLine->GetLogicalAscent(), mLeft.mStyle, 0);
mMarkerList.AppendNewToTop(marker);
}
@ -737,7 +738,7 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine,
markerRect, clipState);
nsDisplayItem* marker = new (mBuilder)
nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
aLine->GetAscent(), mRight.mStyle, 1);
aLine->GetLogicalAscent(), mRight.mStyle, 1);
mMarkerList.AppendNewToTop(marker);
}
}

Просмотреть файл

@ -1257,6 +1257,19 @@ public:
}
}
nsPoint GetPhysicalPosition(WritingMode aWritingMode,
nscoord aContainerWidth) const
{
CHECK_WRITING_MODE(aWritingMode);
if (aWritingMode.IsVertical()) {
return nsPoint(aWritingMode.IsVerticalLR() ? BStart() : aContainerWidth - BEnd(),
IStart());
} else {
return nsPoint(aWritingMode.IsBidiLTR() ? IStart() : aContainerWidth - IEnd(),
BStart());
}
}
#if 0 // XXX this would require aContainerWidth as well
/**
* Return a LogicalRect representing this rect in a different writing mode

Просмотреть файл

@ -46,7 +46,7 @@ public:
virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
virtual nsIAtom* GetType() const MOZ_OVERRIDE;
virtual nscoord GetBaseline() const MOZ_OVERRIDE;
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const MOZ_OVERRIDE;
virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
{
@ -193,7 +193,7 @@ BRFrame::GetType() const
}
nscoord
BRFrame::GetBaseline() const
BRFrame::GetLogicalBaseline(mozilla::WritingMode aWritingMode) const
{
return mAscent;
}

Просмотреть файл

@ -16,7 +16,7 @@
#undef NOISY_FINAL_SIZE // enables debug output for desired width/height computation, once all children have been reflowed
#undef NOISY_REMOVE_FRAME
#undef NOISY_COMBINED_AREA // enables debug output for combined area computation
#undef NOISY_VERTICAL_MARGINS
#undef NOISY_BLOCK_DIR_MARGINS
#undef NOISY_REFLOW_REASON // gives a little info about why each reflow was requested
#undef REFLOW_STATUS_COVERAGE // I think this is most useful for printing, to see which frames return "incomplete"
#undef NOISY_FLOATMANAGER // enables debug output for float manager use, useful for analysing reflow of floats

Просмотреть файл

@ -488,12 +488,12 @@ nsBlockFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItem
}
nscoord
nsBlockFrame::GetBaseline() const
nsBlockFrame::GetLogicalBaseline(WritingMode aWritingMode) const
{
nscoord result;
if (nsLayoutUtils::GetLastLineBaseline(this, &result))
if (nsLayoutUtils::GetLastLineBaseline(aWritingMode, this, &result))
return result;
return nsFrame::GetBaseline();
return nsFrame::GetLogicalBaseline(aWritingMode);
}
nscoord
@ -1187,12 +1187,14 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
// XXX Use the entire line when we fix bug 25888.
nsLayoutUtils::LinePosition position;
WritingMode wm = aReflowState.GetWritingMode();
bool havePosition = nsLayoutUtils::GetFirstLinePosition(this, &position);
nscoord lineTop = havePosition ? position.mTop
: reflowState->ComputedPhysicalBorderPadding().top;
bool havePosition = nsLayoutUtils::GetFirstLinePosition(wm, this,
&position);
nscoord lineTop = havePosition ?
position.mBStart :
reflowState->ComputedLogicalBorderPadding().BStart(wm);
nsIFrame* bullet = GetOutsideBullet();
ReflowBullet(bullet, state, metrics, lineTop);
NS_ASSERTION(!BulletIsEmpty() || metrics.Height() == 0,
NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0,
"empty bullet took up space");
if (havePosition && !BulletIsEmpty()) {
@ -2461,7 +2463,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
if (metrics.BlockStartAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
nscoord ascent;
if (nsLayoutUtils::GetFirstLineBaseline(bullet, &ascent)) {
WritingMode wm = aState.mReflowState.GetWritingMode();
if (nsLayoutUtils::GetFirstLineBaseline(wm, bullet, &ascent)) {
metrics.SetBlockStartAscent(ascent);
} else {
metrics.SetBlockStartAscent(metrics.BSize(wm));
@ -3016,8 +3019,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// Now compute the collapsed margin-top value into aState.mPrevBottomMargin, assuming
// that all child margins collapse down to clearanceFrame.
nsBlockReflowContext::ComputeCollapsedTopMargin(reflowState,
&aState.mPrevBottomMargin, clearanceFrame, &mayNeedRetry);
nsBlockReflowContext::ComputeCollapsedBStartMargin(reflowState,
&aState.mPrevBottomMargin,
clearanceFrame,
&mayNeedRetry);
// XXX optimization; we could check the collapsing children to see if they are sure
// to require clearance, and so avoid retrying them
@ -3050,8 +3055,10 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// Compute the collapsed margin again, ignoring the incoming margin this time
mayNeedRetry = false;
nsBlockReflowContext::ComputeCollapsedTopMargin(reflowState,
&aState.mPrevBottomMargin, clearanceFrame, &mayNeedRetry);
nsBlockReflowContext::ComputeCollapsedBStartMargin(reflowState,
&aState.mPrevBottomMargin,
clearanceFrame,
&mayNeedRetry);
}
}
@ -3207,8 +3214,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
*aKeepReflowGoing = brc.PlaceBlock(blockHtmlRS, forceFit, aLine.get(),
collapsedBottomMargin,
overflowAreas,
frameReflowStatus,
aState.mContainerWidth);
frameReflowStatus);
if (!NS_FRAME_IS_FULLY_COMPLETE(frameReflowStatus) &&
ShouldAvoidBreakInside(aState.mReflowState)) {
*aKeepReflowGoing = false;
@ -3297,7 +3303,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// flow block. Since we just continued the child block frame,
// we know that line->mFirstChild is not the last flow block
// therefore zero out the running margin value.
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCK_DIR_MARGINS
ListTag(stdout);
printf(": reflow incomplete, frame=");
nsFrame::ListTag(stdout, frame);
@ -3325,7 +3331,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
aState.mOverflowTracker->Insert(nextFrame, frameReflowStatus);
NS_MergeReflowStatusInto(&aState.mReflowStatus, frameReflowStatus);
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCK_DIR_MARGINS
ListTag(stdout);
printf(": reflow complete but overflow incomplete for ");
nsFrame::ListTag(stdout, frame);
@ -3336,7 +3342,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
}
}
else { // frame is fully complete
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCK_DIR_MARGINS
ListTag(stdout);
printf(": reflow complete for ");
nsFrame::ListTag(stdout, frame);
@ -3345,12 +3351,12 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
#endif
aState.mPrevBottomMargin = collapsedBottomMargin;
}
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCK_DIR_MARGINS
ListTag(stdout);
printf(": frame=");
nsFrame::ListTag(stdout, frame);
printf(" carriedOutBottomMargin=%d collapsedBottomMargin=%d => %d\n",
brc.GetCarriedOutBottomMargin(), collapsedBottomMargin.get(),
printf(" carriedOutBEndMargin=%d collapsedBottomMargin=%d => %d\n",
brc.GetCarriedOutBEndMargin(), collapsedBottomMargin.get(),
aState.mPrevBottomMargin);
#endif
} else {
@ -4102,7 +4108,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
aLineLayout.AddBulletFrame(bullet, metrics);
addedBullet = true;
}
aLineLayout.BlockDirAlignLine();
aLineLayout.VerticalAlignLine();
// We want to compare to the available space that we would have had in
// the line's height *before* we placed any floats in the line itself.
@ -4164,7 +4170,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
(aLineLayout.GetLineEndsInBR() ||
IsLastLine(aState, aLine)));
aLineLayout.InlineDirAlignFrames(aLine, isLastLine);
aLineLayout.TextAlignLine(aLine, isLastLine);
// From here on, pfd->mBounds rectangles are incorrect because bidi
// might have moved frames around!
@ -5785,8 +5791,9 @@ nsBlockFrame::ReflowFloat(nsBlockReflowState& aState,
floatRS.mDiscoveredClearance = nullptr;
// Only first in flow gets a top margin.
if (!aFloat->GetPrevInFlow()) {
nsBlockReflowContext::ComputeCollapsedTopMargin(floatRS, &margin,
clearanceFrame, &mayNeedRetry);
nsBlockReflowContext::ComputeCollapsedBStartMargin(floatRS, &margin,
clearanceFrame,
&mayNeedRetry);
if (mayNeedRetry && !clearanceFrame) {
floatRS.mDiscoveredClearance = &clearanceFrame;

Просмотреть файл

@ -121,7 +121,7 @@ public:
nsIFrame* aOldFrame) MOZ_OVERRIDE;
virtual const nsFrameList& GetChildList(ChildListID aListID) const MOZ_OVERRIDE;
virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE;
virtual nscoord GetBaseline() const MOZ_OVERRIDE;
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const MOZ_OVERRIDE;
virtual nscoord GetCaretBaseline() const MOZ_OVERRIDE;
virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
virtual nsSplittableType GetSplittableType() const MOZ_OVERRIDE;

Просмотреть файл

@ -14,21 +14,24 @@
#include "nsLineBox.h"
#include "nsLayoutUtils.h"
using namespace mozilla;
#ifdef DEBUG
#undef NOISY_MAX_ELEMENT_SIZE
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
#undef NOISY_VERTICAL_MARGINS
#undef NOISY_BLOCK_DIR_MARGINS
#else
#undef NOISY_MAX_ELEMENT_SIZE
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
#undef NOISY_VERTICAL_MARGINS
#undef NOISY_BLOCK_DIR_MARGINS
#endif
nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext,
const nsHTMLReflowState& aParentRS)
: mPresContext(aPresContext),
mOuterReflowState(aParentRS),
mMetrics(aParentRS.GetWritingMode())
mSpace(aParentRS.GetWritingMode()),
mMetrics(aParentRS)
{
}
@ -41,39 +44,42 @@ static nsIFrame* DescendIntoBlockLevelFrame(nsIFrame* aFrame)
}
bool
nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame,
bool* aMayNeedRetry, bool* aBlockIsEmpty)
nsBlockReflowContext::ComputeCollapsedBStartMargin(const nsHTMLReflowState& aRS,
nsCollapsingMargin* aMargin,
nsIFrame* aClearanceFrame,
bool* aMayNeedRetry,
bool* aBlockIsEmpty)
{
// Include frame's top margin
aMargin->Include(aRS.ComputedPhysicalMargin().top);
WritingMode wm = aRS.GetWritingMode();
// Include frame's block-start margin
aMargin->Include(aRS.ComputedLogicalMargin().BStart(wm));
// The inclusion of the bottom margin when empty is done by the caller
// The inclusion of the block-end margin when empty is done by the caller
// since it doesn't need to be done by the top-level (non-recursive)
// caller.
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCKDIR_MARGINS
nsFrame::ListTag(stdout, aRS.frame);
printf(": %d => %d\n", aRS.ComputedPhysicalMargin().top, aMargin->get());
printf(": %d => %d\n", aRS.ComputedLogicalMargin().BStart(wm), aMargin->get());
#endif
bool dirtiedLine = false;
bool setBlockIsEmpty = false;
// Calculate the frame's generational top-margin from its child
// blocks. Note that if the frame has a non-zero top-border or
// top-padding then this step is skipped because it will be a margin
// Calculate the frame's generational block-start-margin from its child
// blocks. Note that if the frame has a non-zero block-start-border or
// block-start-padding then this step is skipped because it will be a margin
// root. It is also skipped if the frame is a margin root for other
// reasons.
nsIFrame* frame = DescendIntoBlockLevelFrame(aRS.frame);
nsPresContext* prescontext = frame->PresContext();
nsBlockFrame* block = nullptr;
if (0 == aRS.ComputedPhysicalBorderPadding().top) {
if (0 == aRS.ComputedLogicalBorderPadding().BStart(wm)) {
block = nsLayoutUtils::GetAsBlock(frame);
if (block) {
bool topMarginRoot, unused;
block->IsMarginRoot(&topMarginRoot, &unused);
if (topMarginRoot) {
bool bStartMarginRoot, unused;
block->IsMarginRoot(&bStartMarginRoot, &unused);
if (bStartMarginRoot) {
block = nullptr;
}
}
@ -112,7 +118,7 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
line->MarkDirty();
dirtiedLine = true;
}
bool isEmpty;
if (line->IsInline()) {
isEmpty = line->IsEmpty();
@ -129,7 +135,7 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
// child blocks margin and so in so that we can look into
// it. For its margins to be computed we need to have a reflow
// state for it.
// We may have to construct an extra reflow state here if
// we drilled down through a block wrapper. At the moment
// we can only drill down one level so we only have to support
@ -153,12 +159,18 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
if (kid->StyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE) {
*aMayNeedRetry = true;
}
if (ComputeCollapsedTopMargin(innerReflowState, aMargin, aClearanceFrame, aMayNeedRetry, &isEmpty)) {
if (ComputeCollapsedBStartMargin(innerReflowState, aMargin,
aClearanceFrame, aMayNeedRetry,
&isEmpty)) {
line->MarkDirty();
dirtiedLine = true;
}
if (isEmpty)
aMargin->Include(innerReflowState.ComputedPhysicalMargin().bottom);
if (isEmpty) {
WritingMode innerWM = innerReflowState.GetWritingMode();
LogicalMargin innerMargin =
innerReflowState.ComputedLogicalMargin().ConvertTo(wm, innerWM);
aMargin->Include(innerMargin.BEnd(wm));
}
}
if (outerReflowState != &aRS) {
delete const_cast<nsHTMLReflowState*>(outerReflowState);
@ -187,7 +199,7 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
*aBlockIsEmpty = aRS.frame->IsEmpty();
}
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCKDIR_MARGINS
nsFrame::ListTag(stdout, aRS.frame);
printf(": => %d\n", aMargin->get());
#endif
@ -197,55 +209,67 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
void
nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
bool aApplyTopMargin,
bool aApplyBStartMargin,
nsCollapsingMargin& aPrevMargin,
nscoord aClearance,
bool aIsAdjacentWithTop,
bool aIsAdjacentWithBStart,
nsLineBox* aLine,
nsHTMLReflowState& aFrameRS,
nsReflowStatus& aFrameReflowStatus,
nsBlockReflowState& aState)
{
mFrame = aFrameRS.frame;
mSpace = aSpace;
mWritingMode = aState.mReflowState.GetWritingMode();
mContainerWidth = aState.mContainerWidth;
mSpace = LogicalRect(mWritingMode, aSpace, mContainerWidth);
if (!aIsAdjacentWithTop) {
if (!aIsAdjacentWithBStart) {
aFrameRS.mFlags.mIsTopOfPage = false; // make sure this is cleared
}
if (aApplyTopMargin) {
mTopMargin = aPrevMargin;
if (aApplyBStartMargin) {
mBStartMargin = aPrevMargin;
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCKDIR_MARGINS
nsFrame::ListTag(stdout, mOuterReflowState.frame);
printf(": reflowing ");
nsFrame::ListTag(stdout, mFrame);
printf(" margin => %d, clearance => %d\n", mTopMargin.get(), aClearance);
printf(" margin => %d, clearance => %d\n", mBStartMargin.get(), aClearance);
#endif
// Adjust the available height if its constrained so that the
// Adjust the available block size if it's constrained so that the
// child frame doesn't think it can reflow into its margin area.
if (NS_UNCONSTRAINEDSIZE != aFrameRS.AvailableHeight()) {
aFrameRS.AvailableHeight() -= mTopMargin.get() + aClearance;
if (NS_UNCONSTRAINEDSIZE != aFrameRS.AvailableBSize()) {
aFrameRS.AvailableBSize() -= mBStartMargin.get() + aClearance;
}
}
nscoord tx = 0, ty = 0;
// The values of x and y do not matter for floats, so don't bother calculating
// them. Floats are guaranteed to have their own float manager, so tx and ty
// don't matter. mX and mY don't matter becacuse they are only used in
// PlaceBlock, which is not used for floats.
nscoord tI = 0, tB = 0;
// The values of x and y do not matter for floats, so don't bother
// calculating them. Floats are guaranteed to have their own float
// manager, so tI and tB don't matter. mICoord and mBCoord don't
// matter becacuse they are only used in PlaceBlock, which is not used
// for floats.
if (aLine) {
// Compute x/y coordinate where reflow will begin. Use the rules
// from 10.3.3 to determine what to apply. At this point in the
// reflow auto left/right margins will have a zero value.
// Compute inline/block coordinate where reflow will begin. Use the
// rules from 10.3.3 to determine what to apply. At this point in the
// reflow auto inline-start/end margins will have a zero value.
mX = tx = mSpace.x + aFrameRS.ComputedPhysicalMargin().left;
mY = ty = mSpace.y + mTopMargin.get() + aClearance;
WritingMode frameWM = aFrameRS.GetWritingMode();
mICoord = tI =
mSpace.IStart(mWritingMode) +
aFrameRS.ComputedLogicalMargin().ConvertTo(mWritingMode,
frameWM).IStart(mWritingMode);
mBCoord = tB = mSpace.BStart(mWritingMode) +
mBStartMargin.get() + aClearance;
//XXX temporary until nsFloatManager is logicalized
tI = aSpace.x + aFrameRS.ComputedPhysicalMargin().left;
tB = aSpace.y + mBStartMargin.get() + aClearance;
if ((mFrame->GetStateBits() & NS_BLOCK_FLOAT_MGR) == 0)
aFrameRS.mBlockDelta =
mOuterReflowState.mBlockDelta + ty - aLine->BStart();
mOuterReflowState.mBlockDelta + mBCoord - aLine->BStart();
}
// Let frame know that we are reflowing it
@ -256,9 +280,9 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
mMetrics.Height() = nscoord(0xdeadbeef);
#endif
mOuterReflowState.mFloatManager->Translate(tx, ty);
mOuterReflowState.mFloatManager->Translate(tI, tB);
mFrame->Reflow(mPresContext, mMetrics, aFrameRS, aFrameReflowStatus);
mOuterReflowState.mFloatManager->Translate(-tx, -ty);
mOuterReflowState.mFloatManager->Translate(-tI, -tB);
#ifdef DEBUG
if (!NS_INLINE_IS_BREAK_BEFORE(aFrameReflowStatus)) {
@ -303,92 +327,100 @@ nsBlockReflowContext::ReflowBlock(const nsRect& aSpace,
/**
* Attempt to place the block frame within the available space. If
* it fits, apply horizontal positioning (CSS 10.3.3), collapse
* margins (CSS2 8.3.1). Also apply relative positioning.
* it fits, apply inline-dir ("horizontal") positioning (CSS 10.3.3),
* collapse margins (CSS2 8.3.1). Also apply relative positioning.
*/
bool
nsBlockReflowContext::PlaceBlock(const nsHTMLReflowState& aReflowState,
bool aForceFit,
nsLineBox* aLine,
nsCollapsingMargin& aBottomMarginResult,
nsCollapsingMargin& aBEndMarginResult,
nsOverflowAreas& aOverflowAreas,
nsReflowStatus aReflowStatus,
nscoord aContainerWidth)
nsReflowStatus aReflowStatus)
{
// Compute collapsed bottom margin value.
// Compute collapsed block-end margin value.
WritingMode wm = aReflowState.GetWritingMode();
WritingMode parentWM = mMetrics.GetWritingMode();
if (NS_FRAME_IS_COMPLETE(aReflowStatus)) {
aBottomMarginResult = mMetrics.mCarriedOutBottomMargin;
aBottomMarginResult.Include(aReflowState.ComputedPhysicalMargin().bottom);
aBEndMarginResult = mMetrics.mCarriedOutBottomMargin;
aBEndMarginResult.Include(aReflowState.ComputedLogicalMargin().BEnd(wm));
} else {
// The used bottom-margin is set to zero above a break.
aBottomMarginResult.Zero();
aBEndMarginResult.Zero();
}
nsPoint position(mX, mY);
nscoord backupContainingBlockAdvance = 0;
// Check whether the block's bottom margin collapses with its top
// Check whether the block's block-end margin collapses with its block-start
// margin. See CSS 2.1 section 8.3.1; those rules seem to match
// nsBlockFrame::IsEmpty(). Any such block must have zero height so
// nsBlockFrame::IsEmpty(). Any such block must have zero block-size so
// check that first. Note that a block can have clearance and still
// have adjoining top/bottom margins, because the clearance goes
// above the top margin.
// have adjoining block-start/end margins, because the clearance goes
// above the block-start margin.
// Mark the frame as non-dirty; it has been reflowed (or we wouldn't
// be here), and we don't want to assert in CachedIsEmpty()
mFrame->RemoveStateBits(NS_FRAME_IS_DIRTY);
bool empty = 0 == mMetrics.Height() && aLine->CachedIsEmpty();
bool empty = 0 == mMetrics.BSize(parentWM) && aLine->CachedIsEmpty();
if (empty) {
// Collapse the bottom margin with the top margin that was already
// applied.
aBottomMarginResult.Include(mTopMargin);
// Collapse the block-end margin with the block-start margin that was
// already applied.
aBEndMarginResult.Include(mBStartMargin);
#ifdef NOISY_VERTICAL_MARGINS
#ifdef NOISY_BLOCKDIR_MARGINS
printf(" ");
nsFrame::ListTag(stdout, mOuterReflowState.frame);
printf(": ");
nsFrame::ListTag(stdout, mFrame);
printf(" -- collapsing top & bottom margin together; y=%d spaceY=%d\n",
position.y, mSpace.y);
printf(" -- collapsing block start & end margin together; BStart=%d spaceBStart=%d\n",
mBCoord, mSpace.BStart(mWritingMode));
#endif
// Section 8.3.1 of CSS 2.1 says that blocks with adjoining
// top/bottom margins whose top margin collapses with their
// parent's top margin should have their top border-edge at the
// "top/bottom" (i.e. block-start/end) margins whose top margin collapses
// with their parent's top margin should have their top border-edge at the
// top border-edge of their parent. We actually don't have to do
// anything special to make this happen. In that situation,
// nsBlockFrame::ShouldApplyTopMargin will have returned false,
// and mTopMargin and aClearance will have been zero in
// nsBlockFrame::ShouldApplyBStartMargin will have returned false,
// and mBStartMargin and aClearance will have been zero in
// ReflowBlock.
// If we did apply our top margin, but now we're collapsing it
// into the bottom margin, we need to back up the containing
// block's y-advance by our top margin so that it doesn't get
// If we did apply our block-start margin, but now we're collapsing it
// into the block-end margin, we need to back up the containing
// block's bCoord-advance by our block-start margin so that it doesn't get
// counted twice. Note that here we're allowing the line's bounds
// to become different from the block's position; we do this
// because the containing block will place the next line at the
// line's YMost, and it must place the next line at a different
// line's BEnd, and it must place the next line at a different
// point from where this empty block will be.
backupContainingBlockAdvance = mTopMargin.get();
backupContainingBlockAdvance = mBStartMargin.get();
}
// See if the frame fit. If it's the first frame or empty then it
// always fits. If the height is unconstrained then it always fits,
// even if there's some sort of integer overflow that makes y +
// mMetrics.Height() appear to go beyond the available height.
if (!empty && !aForceFit && mSpace.height != NS_UNCONSTRAINEDSIZE) {
nscoord yMost = position.y - backupContainingBlockAdvance + mMetrics.Height();
if (yMost > mSpace.YMost()) {
// always fits. If the block-size is unconstrained then it always fits,
// even if there's some sort of integer overflow that makes bCoord +
// mMetrics.BSize() appear to go beyond the available height.
if (!empty && !aForceFit &&
mSpace.BSize(mWritingMode) != NS_UNCONSTRAINEDSIZE) {
nscoord bEnd = mBCoord -
backupContainingBlockAdvance + mMetrics.BSize(mWritingMode);
if (bEnd > mSpace.BEnd(mWritingMode)) {
// didn't fit, we must acquit.
mFrame->DidReflow(mPresContext, &aReflowState, nsDidReflowStatus::FINISHED);
mFrame->DidReflow(mPresContext, &aReflowState,
nsDidReflowStatus::FINISHED);
return false;
}
}
aLine->SetBounds(aReflowState.GetWritingMode(),
nsRect(position.x,
position.y - backupContainingBlockAdvance,
mMetrics.Width(),
mMetrics.Height()),
aContainerWidth);
aLine->SetBounds(mWritingMode,
mICoord, mBCoord - backupContainingBlockAdvance,
mMetrics.ISize(mWritingMode), mMetrics.BSize(mWritingMode),
mContainerWidth);
// XXX temporary until other classes are logicalized
nsPoint position = LogicalRect(mWritingMode,
mICoord, mBCoord,
mMetrics.ISize(mWritingMode),
mMetrics.BSize(mWritingMode)).
GetPhysicalPosition(mWritingMode, mContainerWidth);
aReflowState.ApplyRelativePositioning(&position);

Просмотреть файл

@ -29,10 +29,10 @@ public:
~nsBlockReflowContext() { }
void ReflowBlock(const nsRect& aSpace,
bool aApplyTopMargin,
bool aApplyBStartMargin,
nsCollapsingMargin& aPrevMargin,
nscoord aClearance,
bool aIsAdjacentWithTop,
bool aIsAdjacentWithBStart,
nsLineBox* aLine,
nsHTMLReflowState& aReflowState,
nsReflowStatus& aReflowStatus,
@ -41,51 +41,52 @@ public:
bool PlaceBlock(const nsHTMLReflowState& aReflowState,
bool aForceFit,
nsLineBox* aLine,
nsCollapsingMargin& aBottomMarginResult /* out */,
nsCollapsingMargin& aBEndMarginResult /* out */,
nsOverflowAreas& aOverflowAreas,
nsReflowStatus aReflowStatus,
nscoord aContainerWidth);
nsReflowStatus aReflowStatus);
nsCollapsingMargin& GetCarriedOutBottomMargin() {
nsCollapsingMargin& GetCarriedOutBEndMargin() {
return mMetrics.mCarriedOutBottomMargin;
}
nscoord GetTopMargin() const {
return mTopMargin.get();
}
const nsHTMLReflowMetrics& GetMetrics() const {
return mMetrics;
}
/**
* Computes the collapsed top margin for a block whose reflow state is in aRS.
* Computes the collapsed block-start margin for a block whose reflow state
* is in aRS.
* The computed margin is added into aMargin.
* If aClearanceFrame is null then this is the first optimistic pass which shall assume
* that no frames have clearance, and we clear the HasClearance on all frames encountered.
* If non-null, this is the second pass and
* the caller has decided aClearanceFrame needs clearance (and we will
* therefore stop collapsing there); also, this function is responsible for marking
* it with SetHasClearance.
* If in the optimistic pass any frame is encountered that might possibly need
* clearance (i.e., if we really needed the optimism assumption) then we set aMayNeedRetry
* to true.
* We return true if we changed the clearance state of any line and marked it dirty.
* If aClearanceFrame is null then this is the first optimistic pass which
* shall assume that no frames have clearance, and we clear the HasClearance
* on all frames encountered.
* If non-null, this is the second pass and the caller has decided
* aClearanceFrame needs clearance (and we will therefore stop collapsing
* there); also, this function is responsible for marking it with
* SetHasClearance.
* If in the optimistic pass any frame is encountered that might possibly
* need clearance (i.e., if we really needed the optimism assumption) then
* we set aMayNeedRetry to true.
* We return true if we changed the clearance state of any line and marked it
* dirty.
*/
static bool ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
nsCollapsingMargin* aMargin, nsIFrame* aClearanceFrame,
bool* aMayNeedRetry, bool* aIsEmpty = nullptr);
static bool ComputeCollapsedBStartMargin(const nsHTMLReflowState& aRS,
nsCollapsingMargin* aMargin,
nsIFrame* aClearanceFrame,
bool* aMayNeedRetry,
bool* aIsEmpty = nullptr);
protected:
nsPresContext* mPresContext;
const nsHTMLReflowState& mOuterReflowState;
nsIFrame* mFrame;
nsRect mSpace;
mozilla::LogicalRect mSpace;
nscoord mX, mY;
nscoord mICoord, mBCoord, mContainerWidth;
mozilla::WritingMode mWritingMode;
nsHTMLReflowMetrics mMetrics;
nsCollapsingMargin mTopMargin;
nsCollapsingMargin mBStartMargin;
};
#endif /* nsBlockReflowContext_h___ */

Просмотреть файл

@ -781,11 +781,11 @@ nsBulletFrame::GetImage() const
}
nscoord
nsBulletFrame::GetBaseline() const
nsBulletFrame::GetLogicalBaseline(WritingMode aWritingMode) const
{
nscoord ascent = 0, bottomPadding;
if (GetStateBits() & BULLET_FRAME_IMAGE_LOADING) {
ascent = GetRect().height;
ascent = BSize(aWritingMode);
} else {
nsRefPtr<nsFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm),
@ -820,7 +820,8 @@ nsBulletFrame::GetBaseline() const
break;
}
}
return ascent + GetUsedBorderAndPadding().top;
return ascent +
GetLogicalUsedMargin(aWritingMode).BStart(aWritingMode);
}
void

Просмотреть файл

@ -86,7 +86,7 @@ public:
virtual bool IsEmpty() MOZ_OVERRIDE;
virtual bool IsSelfEmpty() MOZ_OVERRIDE;
virtual nscoord GetBaseline() const MOZ_OVERRIDE;
virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const MOZ_OVERRIDE;
float GetFontSizeInflation() const;
bool HasFontSizeInflation() const {

Просмотреть файл

@ -464,7 +464,7 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
}
}
int columnCount = 0;
int contentBottom = 0;
int contentBEnd = 0;
bool reflowNext = false;
while (child) {
@ -494,7 +494,8 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
bool skipResizeHeightShrink = shrinkingHeightOnly
&& child->GetScrollableOverflowRect().YMost() <= aConfig.mColMaxHeight;
nscoord childContentBottom = 0;
nscoord childContentBEnd = 0;
WritingMode wm = child->GetWritingMode();
if (!reflowNext && (skipIncremental || skipResizeHeightShrink)) {
// This child does not need to be reflowed, but we may need to move it
MoveChildTo(this, child, childOrigin);
@ -508,7 +509,7 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
} else {
aStatus = mLastFrameStatus;
}
childContentBottom = nsLayoutUtils::CalculateContentBottom(child);
childContentBEnd = nsLayoutUtils::CalculateContentBEnd(wm, child);
#ifdef DEBUG_roc
printf("*** Skipping child #%d %p (incremental %d, resize height shrink %d): status = %d\n",
columnCount, (void*)child, skipIncremental, skipResizeHeightShrink, aStatus);
@ -547,8 +548,7 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
kidReflowState.mFlags.mNextInFlowUntouched = true;
}
nsHTMLReflowMetrics kidDesiredSize(aReflowState.GetWritingMode(),
aDesiredSize.mFlags);
nsHTMLReflowMetrics kidDesiredSize(wm, aDesiredSize.mFlags);
// XXX it would be cool to consult the float manager for the
// previous block to figure out the region of floats from the
@ -578,12 +578,12 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
FinishReflowChild(child, PresContext(), kidDesiredSize,
&kidReflowState, childOrigin.x, childOrigin.y, 0);
childContentBottom = nsLayoutUtils::CalculateContentBottom(child);
if (childContentBottom > aConfig.mColMaxHeight) {
childContentBEnd = nsLayoutUtils::CalculateContentBEnd(wm, child);
if (childContentBEnd > aConfig.mColMaxHeight) {
allFit = false;
}
if (childContentBottom > availSize.height) {
aColData.mMaxOverflowingHeight = std::max(childContentBottom,
if (childContentBEnd > availSize.height) {
aColData.mMaxOverflowingHeight = std::max(childContentBEnd,
aColData.mMaxOverflowingHeight);
}
}
@ -591,9 +591,9 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
contentRect.UnionRect(contentRect, child->GetRect());
ConsiderChildOverflow(overflowRects, child);
contentBottom = std::max(contentBottom, childContentBottom);
aColData.mLastHeight = childContentBottom;
aColData.mSumHeight += childContentBottom;
contentBEnd = std::max(contentBEnd, childContentBEnd);
aColData.mLastHeight = childContentBEnd;
aColData.mSumHeight += childContentBEnd;
// Build a continuation column if necessary
nsIFrame* kidNextInFlow = child->GetNextInFlow();
@ -637,8 +637,8 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
kidNextInFlow->RemoveStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
}
if ((contentBottom > aReflowState.ComputedMaxHeight() ||
contentBottom > aReflowState.ComputedHeight()) &&
if ((contentBEnd > aReflowState.ComputedMaxBSize() ||
contentBEnd > aReflowState.ComputedBSize()) &&
aConfig.mBalanceColCount < INT32_MAX) {
// We overflowed vertically, but have not exceeded the number of
// columns. We're going to go into overflow columns now, so balancing
@ -702,8 +702,8 @@ nsColumnSetFrame::ReflowChildren(nsHTMLReflowMetrics& aDesiredSize,
}
}
aColData.mMaxHeight = contentBottom;
contentRect.height = std::max(contentRect.height, contentBottom);
aColData.mMaxHeight = contentBEnd;
contentRect.height = std::max(contentRect.height, contentBEnd);
mLastFrameStatus = aStatus;
// contentRect included the borderPadding.left,borderPadding.top of the child rects

Просмотреть файл

@ -373,7 +373,7 @@ nsFirstLetterFrame::DrainOverflowFrames(nsPresContext* aPresContext)
}
nscoord
nsFirstLetterFrame::GetBaseline() const
nsFirstLetterFrame::GetLogicalBaseline(WritingMode aWritingMode) const
{
return mBaseline;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше