зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
8689785991
|
@ -837,6 +837,16 @@ AccessibleWrap::accSelect(
|
|||
return CO_E_OBJNOTCONNECTED;
|
||||
|
||||
if (flagsSelect & SELFLAG_TAKEFOCUS) {
|
||||
if (XRE_IsContentProcess()) {
|
||||
// In this case we might have been invoked while the IPC MessageChannel is
|
||||
// waiting on a sync reply. We cannot dispatch additional IPC while that
|
||||
// is happening, so we dispatch TakeFocus from the main thread to
|
||||
// guarantee that we are outside any IPC.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
mozilla::NewRunnableMethod(xpAccessible, &Accessible::TakeFocus);
|
||||
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
|
||||
return S_OK;
|
||||
}
|
||||
xpAccessible->TakeFocus();
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -342,11 +342,20 @@ xpcAccessible::GetValue(nsAString& aValue)
|
|||
NS_IMETHODIMP
|
||||
xpcAccessible::GetHelp(nsAString& aHelp)
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoString help;
|
||||
Intl()->Help(help);
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->Help(help);
|
||||
#endif
|
||||
} else {
|
||||
Intl()->Help(help);
|
||||
}
|
||||
|
||||
aHelp.Assign(help);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -357,10 +366,19 @@ xpcAccessible::GetAccessKey(nsAString& aAccessKey)
|
|||
{
|
||||
aAccessKey.Truncate();
|
||||
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->AccessKey().ToString(aAccessKey);
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->AccessKey().ToString(aAccessKey);
|
||||
#endif
|
||||
} else {
|
||||
Intl()->AccessKey().ToString(aAccessKey);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -368,10 +386,18 @@ NS_IMETHODIMP
|
|||
xpcAccessible::GetKeyboardShortcut(nsAString& aKeyBinding)
|
||||
{
|
||||
aKeyBinding.Truncate();
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->KeyboardShortcut().ToString(aKeyBinding);
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->KeyboardShortcut().ToString(aKeyBinding);
|
||||
#endif
|
||||
} else {
|
||||
Intl()->KeyboardShortcut().ToString(aKeyBinding);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -500,7 +526,7 @@ xpcAccessible::GetRelations(nsIArray** aRelations)
|
|||
NS_ENSURE_ARG_POINTER(aRelations);
|
||||
*aRelations = nullptr;
|
||||
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIMutableArray> relations = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||
|
@ -551,10 +577,19 @@ xpcAccessible::GetFocusedChild(nsIAccessible** aChild)
|
|||
NS_ENSURE_ARG_POINTER(aChild);
|
||||
*aChild = nullptr;
|
||||
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_IF_ADDREF(*aChild = ToXPC(Intl()->FocusedChild()));
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
NS_IF_ADDREF(*aChild = ToXPC(proxy->FocusedChild()));
|
||||
#endif
|
||||
} else {
|
||||
NS_IF_ADDREF(*aChild = ToXPC(Intl()->FocusedChild()));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -565,11 +600,21 @@ xpcAccessible::GetChildAtPoint(int32_t aX, int32_t aY,
|
|||
NS_ENSURE_ARG_POINTER(aAccessible);
|
||||
*aAccessible = nullptr;
|
||||
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_IF_ADDREF(*aAccessible =
|
||||
ToXPC(Intl()->ChildAtPoint(aX, aY, Accessible::eDirectChild)));
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
NS_IF_ADDREF(*aAccessible =
|
||||
ToXPC(proxy->ChildAtPoint(aX, aY, Accessible::eDirectChild)));
|
||||
#endif
|
||||
} else {
|
||||
NS_IF_ADDREF(*aAccessible =
|
||||
ToXPC(Intl()->ChildAtPoint(aX, aY, Accessible::eDirectChild)));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -580,41 +625,78 @@ xpcAccessible::GetDeepestChildAtPoint(int32_t aX, int32_t aY,
|
|||
NS_ENSURE_ARG_POINTER(aAccessible);
|
||||
*aAccessible = nullptr;
|
||||
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_IF_ADDREF(*aAccessible =
|
||||
ToXPC(Intl()->ChildAtPoint(aX, aY, Accessible::eDeepestChild)));
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
NS_IF_ADDREF(*aAccessible =
|
||||
ToXPC(proxy->ChildAtPoint(aX, aY, Accessible::eDeepestChild)));
|
||||
#endif
|
||||
} else {
|
||||
NS_IF_ADDREF(*aAccessible =
|
||||
ToXPC(Intl()->ChildAtPoint(aX, aY, Accessible::eDeepestChild)));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::SetSelected(bool aSelect)
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->SetSelected(aSelect);
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->SetSelected(aSelect);
|
||||
#endif
|
||||
} else {
|
||||
Intl()->SetSelected(aSelect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::TakeSelection()
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->TakeSelection();
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->TakeSelection();
|
||||
#endif
|
||||
} else {
|
||||
Intl()->TakeSelection();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::TakeFocus()
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->TakeFocus();
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->TakeFocus();
|
||||
#endif
|
||||
} else {
|
||||
Intl()->TakeFocus();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -623,65 +705,122 @@ xpcAccessible::GetActionCount(uint8_t* aActionCount)
|
|||
{
|
||||
NS_ENSURE_ARG_POINTER(aActionCount);
|
||||
*aActionCount = 0;
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aActionCount = Intl()->ActionCount();
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
*aActionCount = proxy->ActionCount();
|
||||
#endif
|
||||
} else {
|
||||
*aActionCount = Intl()->ActionCount();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::GetActionName(uint8_t aIndex, nsAString& aName)
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (aIndex >= Intl()->ActionCount())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
nsString name;
|
||||
proxy->ActionNameAt(aIndex, name);
|
||||
aName.Assign(name);
|
||||
#endif
|
||||
} else {
|
||||
if (aIndex >= Intl()->ActionCount())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
Intl()->ActionNameAt(aIndex, aName);
|
||||
}
|
||||
|
||||
Intl()->ActionNameAt(aIndex, aName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::GetActionDescription(uint8_t aIndex, nsAString& aDescription)
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (aIndex >= Intl()->ActionCount())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
nsString description;
|
||||
proxy->ActionDescriptionAt(aIndex, description);
|
||||
aDescription.Assign(description);
|
||||
#endif
|
||||
} else {
|
||||
if (aIndex >= Intl()->ActionCount())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
Intl()->ActionDescriptionAt(aIndex, aDescription);
|
||||
}
|
||||
|
||||
Intl()->ActionDescriptionAt(aIndex, aDescription);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::DoAction(uint8_t aIndex)
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return Intl()->DoAction(aIndex) ?
|
||||
NS_OK : NS_ERROR_INVALID_ARG;
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
return proxy->DoAction(aIndex) ? NS_OK : NS_ERROR_INVALID_ARG;
|
||||
#endif
|
||||
} else {
|
||||
return Intl()->DoAction(aIndex) ?
|
||||
NS_OK : NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::ScrollTo(uint32_t aHow)
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->ScrollTo(aHow);
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->ScrollTo(aHow);
|
||||
#endif
|
||||
} else {
|
||||
Intl()->ScrollTo(aHow);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::ScrollToPoint(uint32_t aCoordinateType, int32_t aX, int32_t aY)
|
||||
{
|
||||
if (!Intl())
|
||||
if (IntlGeneric().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->ScrollToPoint(aCoordinateType, aX, aY);
|
||||
if (ProxyAccessible* proxy = IntlGeneric().AsProxy()) {
|
||||
#if defined(XP_WIN)
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#else
|
||||
proxy->ScrollToPoint(aCoordinateType, aX, aY);
|
||||
#endif
|
||||
} else {
|
||||
Intl()->ScrollToPoint(aCoordinateType, aX, aY);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ module.metadata = {
|
|||
};
|
||||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const { Services } = require("resource://gre/modules/Services.jsm");
|
||||
const { setTimeout } = require("../timers");
|
||||
const { platform } = require("../system");
|
||||
const { getMostRecentBrowserWindow, getOwnerBrowserWindow,
|
||||
|
@ -186,6 +187,13 @@ function display(panel, options, anchor) {
|
|||
panel.setAttribute("flip", "both");
|
||||
}
|
||||
|
||||
panel.viewFrame = document.importNode(panel.backgroundFrame, false);
|
||||
panel.appendChild(panel.viewFrame);
|
||||
|
||||
let {privateBrowsingId} = getDocShell(panel.viewFrame).getOriginAttributes();
|
||||
let principal = Services.scriptSecurityManager.createNullPrincipal({privateBrowsingId});
|
||||
getDocShell(panel.viewFrame).createAboutBlankContentViewer(principal);
|
||||
|
||||
// Resize the iframe instead of using panel.sizeTo
|
||||
// because sizeTo doesn't work with arrow panels
|
||||
panel.firstChild.style.width = width + "px";
|
||||
|
@ -252,12 +260,10 @@ function make(document, options) {
|
|||
document = document || getMostRecentBrowserWindow().document;
|
||||
let panel = document.createElementNS(XUL_NS, "panel");
|
||||
panel.setAttribute("type", "arrow");
|
||||
panel.setAttribute("sdkscriptenabled", "" + options.allowJavascript);
|
||||
panel.setAttribute("sdkscriptenabled", options.allowJavascript);
|
||||
|
||||
// Note that panel is a parent of `viewFrame` who's `docShell` will be
|
||||
// configured at creation time. If `panel` and there for `viewFrame` won't
|
||||
// have an owner document attempt to access `docShell` will throw. There
|
||||
// for we attach panel to a document.
|
||||
// The panel needs to be attached to a browser window in order for us
|
||||
// to copy browser styles to the content document when it loads.
|
||||
attach(panel, document);
|
||||
|
||||
let frameOptions = {
|
||||
|
@ -269,34 +275,29 @@ function make(document, options) {
|
|||
// history and in consequence do not dispatch "inner-window-destroyed"
|
||||
// notifications.
|
||||
browser: false,
|
||||
// Note that use of this URL let's use swap frame loaders earlier
|
||||
// than if we used default "about:blank".
|
||||
uri: "data:text/plain;charset=utf-8,"
|
||||
};
|
||||
|
||||
let backgroundFrame = createFrame(addonWindow, frameOptions);
|
||||
setupPanelFrame(backgroundFrame);
|
||||
|
||||
let viewFrame = createFrame(panel, frameOptions);
|
||||
setupPanelFrame(viewFrame);
|
||||
getDocShell(backgroundFrame).inheritPrivateBrowsingId = false;
|
||||
|
||||
function onDisplayChange({type, target}) {
|
||||
// Events from child element like <select /> may propagate (dropdowns are
|
||||
// popups too), in which case frame loader shouldn't be swapped.
|
||||
// See Bug 886329
|
||||
if (target !== this) return;
|
||||
function onPopupShowing({type, target}) {
|
||||
if (target === this) {
|
||||
let attrs = getDocShell(backgroundFrame).getOriginAttributes();
|
||||
getDocShell(panel.viewFrame).setOriginAttributes(attrs);
|
||||
|
||||
try {
|
||||
swapFrameLoaders(backgroundFrame, viewFrame);
|
||||
// We need to re-set this because... swapFrameLoaders. Or something.
|
||||
let shouldEnableScript = panel.getAttribute("sdkscriptenabled") == "true";
|
||||
getDocShell(backgroundFrame).allowJavascript = shouldEnableScript;
|
||||
getDocShell(viewFrame).allowJavascript = shouldEnableScript;
|
||||
swapFrameLoaders(backgroundFrame, panel.viewFrame);
|
||||
}
|
||||
catch(error) {
|
||||
console.exception(error);
|
||||
}
|
||||
|
||||
function onPopupHiding({type, target}) {
|
||||
if (target === this) {
|
||||
swapFrameLoaders(backgroundFrame, panel.viewFrame);
|
||||
|
||||
panel.viewFrame.remove();
|
||||
panel.viewFrame = null;
|
||||
}
|
||||
events.emit(type, { subject: panel });
|
||||
}
|
||||
|
||||
function onContentReady({target, type}) {
|
||||
|
@ -316,14 +317,15 @@ function make(document, options) {
|
|||
events.emit(type, { subject: panel });
|
||||
}
|
||||
|
||||
function onPanelStateChange({type}) {
|
||||
events.emit(type, { subject: panel })
|
||||
function onPanelStateChange({target, type}) {
|
||||
if (target === this)
|
||||
events.emit(type, { subject: panel })
|
||||
}
|
||||
|
||||
panel.addEventListener("popupshowing", onDisplayChange, false);
|
||||
panel.addEventListener("popuphiding", onDisplayChange, false);
|
||||
panel.addEventListener("popupshown", onPanelStateChange, false);
|
||||
panel.addEventListener("popuphidden", onPanelStateChange, false);
|
||||
panel.addEventListener("popupshowing", onPopupShowing);
|
||||
panel.addEventListener("popuphiding", onPopupHiding);
|
||||
for (let event of ["popupshowing", "popuphiding", "popupshown", "popuphidden"])
|
||||
panel.addEventListener(event, onPanelStateChange);
|
||||
|
||||
panel.addEventListener("click", onPanelClick, false);
|
||||
|
||||
|
@ -339,9 +341,8 @@ function make(document, options) {
|
|||
|
||||
events.on("document-element-inserted", onContentChange);
|
||||
|
||||
|
||||
panel.backgroundFrame = backgroundFrame;
|
||||
panel.viewFrame = viewFrame;
|
||||
panel.viewFrame = null;
|
||||
|
||||
// Store event listener on the panel instance so that it won't be GC-ed
|
||||
// while panel is alive.
|
||||
|
@ -368,9 +369,7 @@ exports.detach = detach;
|
|||
|
||||
function dispose(panel) {
|
||||
panel.backgroundFrame.remove();
|
||||
panel.viewFrame.remove();
|
||||
panel.backgroundFrame = null;
|
||||
panel.viewFrame = null;
|
||||
events.off("document-element-inserted", panel.onContentChange);
|
||||
panel.onContentChange = null;
|
||||
detach(panel);
|
||||
|
@ -392,11 +391,7 @@ function style(panel) {
|
|||
let contentDocument = getContentDocument(panel);
|
||||
let window = document.defaultView;
|
||||
let node = document.getAnonymousElementByAttribute(panel, "class",
|
||||
"panel-arrowcontent") ||
|
||||
// Before bug 764755, anonymous content was different:
|
||||
// TODO: Remove this when targeting FF16+
|
||||
document.getAnonymousElementByAttribute(panel, "class",
|
||||
"panel-inner-arrowcontent");
|
||||
"panel-arrowcontent");
|
||||
|
||||
let { color, fontFamily, fontSize, fontWeight } = window.getComputedStyle(node);
|
||||
|
||||
|
@ -424,10 +419,7 @@ function style(panel) {
|
|||
}
|
||||
exports.style = style;
|
||||
|
||||
var getContentFrame = panel =>
|
||||
(isOpen(panel) || isOpening(panel)) ?
|
||||
panel.firstChild :
|
||||
panel.backgroundFrame
|
||||
var getContentFrame = panel => panel.viewFrame || panel.backgroundFrame;
|
||||
exports.getContentFrame = getContentFrame;
|
||||
|
||||
function getContentDocument(panel) {
|
||||
|
@ -436,7 +428,10 @@ function getContentDocument(panel) {
|
|||
exports.getContentDocument = getContentDocument;
|
||||
|
||||
function setURL(panel, url) {
|
||||
getContentFrame(panel).setAttribute("src", url ? data.url(url) : url);
|
||||
let frame = getContentFrame(panel);
|
||||
let webNav = getDocShell(frame).QueryInterface(Ci.nsIWebNavigation);
|
||||
|
||||
webNav.loadURI(url ? data.url(url) : "about:blank", 0, null, null, null);
|
||||
}
|
||||
|
||||
exports.setURL = setURL;
|
||||
|
|
|
@ -7,6 +7,8 @@ const { open, focus, close } = require('sdk/window/helpers');
|
|||
const { isPrivate } = require('sdk/private-browsing');
|
||||
const { defer } = require('sdk/core/promise');
|
||||
const { browserWindows: windows } = require('sdk/windows');
|
||||
const { getInnerId, getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { getActiveView } = require('sdk/view/core');
|
||||
|
||||
const BROWSER = 'chrome://browser/content/browser.xul';
|
||||
|
||||
|
@ -17,7 +19,7 @@ exports.testRequirePanel = function(assert) {
|
|||
|
||||
exports.testShowPanelInPrivateWindow = function(assert, done) {
|
||||
let panel = require('sdk/panel').Panel({
|
||||
contentURL: "data:text/html;charset=utf-8,"
|
||||
contentURL: "data:text/html;charset=utf-8,I'm a leaf on the wind"
|
||||
});
|
||||
|
||||
assert.ok(windows.length > 0, 'there is at least one open window');
|
||||
|
@ -25,7 +27,50 @@ exports.testShowPanelInPrivateWindow = function(assert, done) {
|
|||
assert.equal(isPrivate(window), false, 'open window is private');
|
||||
}
|
||||
|
||||
testShowPanel(assert, panel).
|
||||
let panelView = getActiveView(panel);
|
||||
let expectedWindowId = getInnerId(panelView.backgroundFrame.contentWindow);
|
||||
|
||||
function checkPanelFrame() {
|
||||
let iframe = panelView.firstChild;
|
||||
|
||||
assert.equal(panelView.viewFrame, iframe, 'panel has the correct viewFrame value');
|
||||
|
||||
let windowId = getInnerId(iframe.contentWindow);
|
||||
|
||||
assert.equal(windowId, expectedWindowId, 'panel has the correct window visible');
|
||||
|
||||
assert.equal(iframe.contentDocument.body.textContent,
|
||||
"I'm a leaf on the wind",
|
||||
'the panel has the expected content');
|
||||
}
|
||||
|
||||
function testPanel(window) {
|
||||
let { promise, resolve } = defer();
|
||||
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [1]');
|
||||
|
||||
panel.once('show', function() {
|
||||
assert.ok(panel.isShowing, 'the panel is showing');
|
||||
|
||||
checkPanelFrame();
|
||||
|
||||
panel.once('hide', function() {
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [2]');
|
||||
|
||||
resolve(window);
|
||||
});
|
||||
|
||||
panel.hide();
|
||||
});
|
||||
|
||||
panel.show();
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
let initialWindow = getMostRecentBrowserWindow();
|
||||
|
||||
testPanel(initialWindow).
|
||||
then(makeEmptyPrivateBrowserWindow).
|
||||
then(focus).
|
||||
then(function(window) {
|
||||
|
@ -33,28 +78,10 @@ exports.testShowPanelInPrivateWindow = function(assert, done) {
|
|||
assert.pass('private window was focused');
|
||||
return window;
|
||||
}).
|
||||
then(function(window) {
|
||||
let { promise, resolve } = defer();
|
||||
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [1]');
|
||||
|
||||
panel.once('show', function() {
|
||||
assert.ok(panel.isShowing, 'the panel is showing');
|
||||
|
||||
panel.once('hide', function() {
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [2]');
|
||||
|
||||
resolve(window);
|
||||
});
|
||||
|
||||
panel.hide();
|
||||
});
|
||||
|
||||
panel.show();
|
||||
|
||||
return promise;
|
||||
}).
|
||||
then(testPanel).
|
||||
then(close).
|
||||
then(() => focus(initialWindow)).
|
||||
then(testPanel).
|
||||
then(done).
|
||||
then(null, assert.fail);
|
||||
};
|
||||
|
@ -70,32 +97,3 @@ function makeEmptyPrivateBrowserWindow(options) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testShowPanel(assert, panel) {
|
||||
let { promise, resolve } = defer();
|
||||
let shown = false;
|
||||
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [1]');
|
||||
|
||||
panel.once('hide', function() {
|
||||
assert.ok(!panel.isShowing, 'the panel is not showing [2]');
|
||||
assert.ok(shown, 'the panel was shown')
|
||||
|
||||
resolve(null);
|
||||
});
|
||||
|
||||
panel.once('show', function() {
|
||||
shown = true;
|
||||
|
||||
assert.ok(panel.isShowing, 'the panel is showing');
|
||||
|
||||
panel.hide();
|
||||
});
|
||||
|
||||
panel.show();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
//Test disabled because of bug 911071
|
||||
module.exports = {}
|
||||
|
|
|
@ -174,6 +174,7 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
|
|||
background-size: 1px auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item:-moz-locale-dir(rtl) {
|
||||
|
@ -200,6 +201,7 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
|
|||
.searchbar-engine-one-off-item[selected] {
|
||||
background-color: Highlight;
|
||||
background-image: none;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item > .button-box {
|
||||
|
@ -304,10 +306,8 @@ menuitem[cmd="cmd_clearhistory"][disabled] {
|
|||
background-color: var(--arrowpanel-dimmed-further);
|
||||
}
|
||||
|
||||
.search-setting-button-compact {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear");
|
||||
}
|
||||
|
||||
.search-setting-button-compact[selected] {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
|
||||
.search-setting-button-compact > .button-box > .button-icon {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg");
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@
|
|||
background-size: 1px auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item:-moz-locale-dir(rtl) {
|
||||
|
@ -189,6 +190,7 @@
|
|||
.searchbar-engine-one-off-item[selected] {
|
||||
background-color: Highlight;
|
||||
background-image: none;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item > .button-box > .button-text {
|
||||
|
@ -286,10 +288,8 @@
|
|||
background-color: var(--arrowpanel-dimmed-further);
|
||||
}
|
||||
|
||||
.search-setting-button-compact {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear");
|
||||
}
|
||||
|
||||
.search-setting-button-compact[selected] {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
|
||||
.search-setting-button-compact > .button-box > .button-icon {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg");
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
}
|
||||
|
|
|
@ -2,21 +2,6 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 32 32">
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
use {
|
||||
fill: GrayText;
|
||||
}
|
||||
use[id$="-inverted"] {
|
||||
fill: highlighttext;
|
||||
}
|
||||
</style>
|
||||
<defs>
|
||||
<path id="glyphShape-gear" d="M28,16c0-1.7,0.9-3.1,2-3.3c-0.4-1.5-0.9-2.9-1.7-4.2c-0.9,0.7-2.6,0.3-3.8-0.9c-1.2-1.2-1.6-2.8-0.9-3.8 c-1.3-0.8-2.7-1.4-4.2-1.7c-0.2,1.1-1.6,2-3.3,2S13,3.1,12.8,2c-1.5,0.4-2.9,0.9-4.2,1.7c0.7,0.9,0.3,2.6-0.9,3.8 c-1.4,1.1-3,1.5-4,0.9C2.9,9.7,2.4,11.2,2,12.7c1.1,0.2,2,1.6,2,3.3s-0.9,3.1-2,3.3c0.4,1.5,0.9,2.9,1.7,4.2 c0.9-0.7,2.6-0.3,3.8,0.9c1.2,1.2,1.6,2.8,0.9,3.8c1.3,0.8,2.7,1.4,4.2,1.7c0.2-1.1,1.6-2,3.3-2s3.1,0.9,3.3,2 c1.5-0.4,2.9-0.9,4.2-1.7c-0.7-0.9-0.3-2.6,0.9-3.8c1.3-1.2,2.8-1.6,3.8-0.9c0.8-1.3,1.4-2.7,1.7-4.2C28.9,19.1,28,17.7,28,16z M16,24c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S20.4,24,16,24z"/>
|
||||
</defs>
|
||||
<use id="gear" xlink:href="#glyphShape-gear"/>
|
||||
<use id="gear-inverted" xlink:href="#glyphShape-gear"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 32 32">
|
||||
<path id="glyphShape-gear" d="M28,16c0-1.7,0.9-3.1,2-3.3c-0.4-1.5-0.9-2.9-1.7-4.2c-0.9,0.7-2.6,0.3-3.8-0.9c-1.2-1.2-1.6-2.8-0.9-3.8 c-1.3-0.8-2.7-1.4-4.2-1.7c-0.2,1.1-1.6,2-3.3,2S13,3.1,12.8,2c-1.5,0.4-2.9,0.9-4.2,1.7c0.7,0.9,0.3,2.6-0.9,3.8 c-1.4,1.1-3,1.5-4,0.9C2.9,9.7,2.4,11.2,2,12.7c1.1,0.2,2,1.6,2,3.3s-0.9,3.1-2,3.3c0.4,1.5,0.9,2.9,1.7,4.2 c0.9-0.7,2.6-0.3,3.8,0.9c1.2,1.2,1.6,2.8,0.9,3.8c1.3,0.8,2.7,1.4,4.2,1.7c0.2-1.1,1.6-2,3.3-2s3.1,0.9,3.3,2 c1.5-0.4,2.9-0.9,4.2-1.7c-0.7-0.9-0.3-2.6,0.9-3.8c1.3-1.2,2.8-1.6,3.8-0.9c0.8-1.3,1.4-2.7,1.7-4.2C28.9,19.1,28,17.7,28,16z M16,24c-4.4,0-8-3.6-8-8s3.6-8,8-8s8,3.6,8,8S20.4,24,16,24z"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 1.3 KiB После Ширина: | Высота: | Размер: 983 B |
|
@ -171,6 +171,7 @@
|
|||
background-size: 1px auto;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item:-moz-locale-dir(rtl) {
|
||||
|
@ -197,6 +198,7 @@
|
|||
.searchbar-engine-one-off-item[selected] {
|
||||
background-color: Highlight;
|
||||
background-image: none;
|
||||
color: HighlightText;
|
||||
}
|
||||
|
||||
.searchbar-engine-one-off-item > .button-box {
|
||||
|
@ -296,10 +298,8 @@
|
|||
background-color: var(--arrowpanel-dimmed-further);
|
||||
}
|
||||
|
||||
.search-setting-button-compact {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear");
|
||||
}
|
||||
|
||||
.search-setting-button-compact[selected] {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg#gear-inverted");
|
||||
.search-setting-button-compact > .button-box > .button-icon {
|
||||
list-style-image: url("chrome://browser/skin/gear.svg");
|
||||
filter: url(chrome://browser/skin/filters.svg#fill);
|
||||
fill: currentColor;
|
||||
}
|
||||
|
|
|
@ -794,6 +794,7 @@ nsDocShell::nsDocShell()
|
|||
, mDeviceSizeIsPageSize(false)
|
||||
, mWindowDraggingAllowed(false)
|
||||
, mInFrameSwap(false)
|
||||
, mInheritPrivateBrowsingId(true)
|
||||
, mCanExecuteScripts(false)
|
||||
, mFiredUnloadEvent(false)
|
||||
, mEODForCurrentDocument(false)
|
||||
|
@ -2487,6 +2488,20 @@ nsDocShell::SetAllowContentRetargetingOnChildren(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetInheritPrivateBrowsingId(bool* aInheritPrivateBrowsingId)
|
||||
{
|
||||
*aInheritPrivateBrowsingId = mPrivateBrowsingId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId)
|
||||
{
|
||||
mInheritPrivateBrowsingId = aInheritPrivateBrowsingId;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
|
||||
{
|
||||
|
@ -3319,6 +3334,9 @@ nsresult
|
|||
nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
|
||||
{
|
||||
bool wasFrame = IsFrame();
|
||||
#ifdef DEBUG
|
||||
bool wasPrivate = UsePrivateBrowsing();
|
||||
#endif
|
||||
|
||||
nsresult rv = nsDocLoader::SetDocLoaderParent(aParent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -3373,8 +3391,10 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
|
|||
value = false;
|
||||
}
|
||||
SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
|
||||
value = parentAsDocShell->GetAffectPrivateSessionLifetime();
|
||||
SetAffectPrivateSessionLifetime(value);
|
||||
if (mInheritPrivateBrowsingId) {
|
||||
value = parentAsDocShell->GetAffectPrivateSessionLifetime();
|
||||
SetAffectPrivateSessionLifetime(value);
|
||||
}
|
||||
uint32_t flags;
|
||||
if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) {
|
||||
SetDefaultLoadFlags(flags);
|
||||
|
@ -3386,7 +3406,7 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
|
|||
}
|
||||
|
||||
nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
|
||||
if (parentAsLoadContext &&
|
||||
if (parentAsLoadContext && mInheritPrivateBrowsingId &&
|
||||
NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) {
|
||||
SetPrivateBrowsing(value);
|
||||
}
|
||||
|
@ -3399,6 +3419,9 @@ nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
|
|||
// Our parent has changed. Recompute scriptability.
|
||||
RecomputeCanExecuteScripts();
|
||||
|
||||
NS_ASSERTION(mInheritPrivateBrowsingId || wasPrivate == UsePrivateBrowsing(),
|
||||
"Private browsing state changed while inheritance was disabled");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -951,6 +951,7 @@ protected:
|
|||
bool mDeviceSizeIsPageSize : 1;
|
||||
bool mWindowDraggingAllowed : 1;
|
||||
bool mInFrameSwap : 1;
|
||||
bool mInheritPrivateBrowsingId : 1;
|
||||
|
||||
// Because scriptability depends on the mAllowJavascript values of our
|
||||
// ancestors, we cache the effective scriptability and recompute it when
|
||||
|
|
|
@ -300,6 +300,15 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
*/
|
||||
[infallible] attribute boolean allowContentRetargetingOnChildren;
|
||||
|
||||
/**
|
||||
* True if this docShell should inherit the private browsing ID from
|
||||
* its parent when reparented.
|
||||
*
|
||||
* NOTE: This should *not* be set false in new code, or for docShells
|
||||
* inserted anywhere other than as children of panels.
|
||||
*/
|
||||
[infallible] attribute boolean inheritPrivateBrowsingId;
|
||||
|
||||
/**
|
||||
* Get an enumerator over this docShell and its children.
|
||||
*
|
||||
|
|
|
@ -362,9 +362,7 @@ function finish() {
|
|||
ww.registerNotification(function(subject, topic, data) {
|
||||
if (topic == "domwindowclosed") {
|
||||
ww.unregisterNotification(arguments.callee);
|
||||
SimpleTest.waitForFocus(function() {
|
||||
SimpleTest.finish();
|
||||
}, opener);
|
||||
SimpleTest.waitForFocus(SimpleTest.finish, opener);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -7181,12 +7181,13 @@ class CGPerSignatureCall(CGThing):
|
|||
""" % deprecated[0])))
|
||||
|
||||
lenientFloatCode = None
|
||||
if idlNode.getExtendedAttribute('LenientFloat') is not None:
|
||||
if setter:
|
||||
lenientFloatCode = "return true;\n"
|
||||
elif idlNode.isMethod():
|
||||
lenientFloatCode = ("args.rval().setUndefined();\n"
|
||||
"return true;\n")
|
||||
if (idlNode.getExtendedAttribute('LenientFloat') is not None and
|
||||
(setter or idlNode.isMethod())):
|
||||
cgThings.append(CGGeneric(dedent(
|
||||
"""
|
||||
bool foundNonFiniteFloat = false;
|
||||
""")))
|
||||
lenientFloatCode = "foundNonFiniteFloat = true;\n"
|
||||
|
||||
argsPre = []
|
||||
if idlNode.isStatic():
|
||||
|
@ -7330,6 +7331,25 @@ class CGPerSignatureCall(CGThing):
|
|||
idlNode, invalidEnumValueFatal=not setter,
|
||||
lenientFloatCode=lenientFloatCode))
|
||||
|
||||
# Now that argument processing is done, enforce the LenientFloat stuff
|
||||
if lenientFloatCode:
|
||||
if setter:
|
||||
foundNonFiniteFloatBehavior = "return true;\n"
|
||||
else:
|
||||
assert idlNode.isMethod()
|
||||
foundNonFiniteFloatBehavior = dedent(
|
||||
"""
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
""")
|
||||
cgThings.append(CGGeneric(fill(
|
||||
"""
|
||||
if (foundNonFiniteFloat) {
|
||||
$*{returnSteps}
|
||||
}
|
||||
""",
|
||||
returnSteps=foundNonFiniteFloatBehavior)))
|
||||
|
||||
if needsUnwrap:
|
||||
# Something depends on having the unwrapped object, so unwrap it now.
|
||||
xraySteps = []
|
||||
|
|
|
@ -2991,10 +2991,13 @@ CanvasRenderingContext2D::FillRect(double aX, double aY, double aW,
|
|||
bounds = mTarget->GetTransform().TransformBounds(fillRect);
|
||||
}
|
||||
|
||||
AntialiasMode antialiasMode = CurrentState().imageSmoothingEnabled ?
|
||||
AntialiasMode::DEFAULT : AntialiasMode::NONE;
|
||||
|
||||
AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)->
|
||||
FillRect(gfx::Rect(aX, aY, aW, aH),
|
||||
CanvasGeneralPattern().ForStyle(this, Style::FILL, mTarget),
|
||||
DrawOptions(state.globalAlpha, op));
|
||||
DrawOptions(state.globalAlpha, op, antialiasMode));
|
||||
|
||||
RedrawUser(gfxRect(aX, aY, aW, aH));
|
||||
}
|
||||
|
@ -4888,6 +4891,9 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||
|
||||
if (!res.mSourceSurface) {
|
||||
res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget);
|
||||
if (res.mSourceSurface) {
|
||||
gfxUtils::WriteAsPNG(res.mSourceSurface, "/Volumes/firefoxos/Dev/mozilla-git/temp.png");
|
||||
}
|
||||
}
|
||||
|
||||
if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) {
|
||||
|
@ -4953,11 +4959,15 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||
}
|
||||
|
||||
SamplingFilter samplingFilter;
|
||||
AntialiasMode antialiasMode;
|
||||
|
||||
if (CurrentState().imageSmoothingEnabled)
|
||||
if (CurrentState().imageSmoothingEnabled) {
|
||||
samplingFilter = gfx::SamplingFilter::LINEAR;
|
||||
else
|
||||
antialiasMode = AntialiasMode::DEFAULT;
|
||||
} else {
|
||||
samplingFilter = gfx::SamplingFilter::POINT;
|
||||
antialiasMode = AntialiasMode::NONE;
|
||||
}
|
||||
|
||||
gfx::Rect bounds;
|
||||
|
||||
|
@ -4980,8 +4990,8 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
|
|||
DrawSurface(srcSurf,
|
||||
gfx::Rect(aDx, aDy, aDw, aDh),
|
||||
sourceRect,
|
||||
DrawSurfaceOptions(samplingFilter),
|
||||
DrawOptions(CurrentState().globalAlpha, UsedOperation()));
|
||||
DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED),
|
||||
DrawOptions(CurrentState().globalAlpha, UsedOperation(), antialiasMode));
|
||||
} else {
|
||||
DrawDirectlyToCanvas(drawInfo, &bounds,
|
||||
gfx::Rect(aDx, aDy, aDw, aDh),
|
||||
|
|
|
@ -322,7 +322,6 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
|||
const dom::AudioChannel aAudioChannel)
|
||||
{
|
||||
auto startTime = TimeStamp::Now();
|
||||
auto isFirst = CubebUtils::GetFirstStream();
|
||||
|
||||
LOG("%s channels: %d, rate: %d", __FUNCTION__, aNumChannels, aRate);
|
||||
mChannels = aNumChannels;
|
||||
|
@ -348,23 +347,26 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
|
|||
params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
|
||||
mAudioClock.Init(aRate);
|
||||
|
||||
return OpenCubeb(params, startTime, isFirst);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioStream::OpenCubeb(cubeb_stream_params& aParams,
|
||||
TimeStamp aStartTime, bool aIsFirst)
|
||||
{
|
||||
cubeb* cubebContext = CubebUtils::GetCubebContext();
|
||||
if (!cubebContext) {
|
||||
NS_WARNING("Can't get cubeb context!");
|
||||
CubebUtils::ReportCubebStreamInitFailure(true);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return OpenCubeb(cubebContext, params, startTime, CubebUtils::GetFirstStream());
|
||||
}
|
||||
|
||||
nsresult
|
||||
AudioStream::OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams,
|
||||
TimeStamp aStartTime, bool aIsFirst)
|
||||
{
|
||||
MOZ_ASSERT(aContext);
|
||||
|
||||
cubeb_stream* stream = nullptr;
|
||||
/* Convert from milliseconds to frames. */
|
||||
uint32_t latency_frames = CubebUtils::GetCubebLatency() * aParams.rate / 1000;
|
||||
if (cubeb_stream_init(cubebContext, &stream, "AudioStream",
|
||||
if (cubeb_stream_init(aContext, &stream, "AudioStream",
|
||||
nullptr, nullptr, nullptr, &aParams,
|
||||
latency_frames,
|
||||
DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
|
||||
|
|
|
@ -245,7 +245,7 @@ protected:
|
|||
int64_t GetPositionInFramesUnlocked();
|
||||
|
||||
private:
|
||||
nsresult OpenCubeb(cubeb_stream_params& aParams,
|
||||
nsresult OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams,
|
||||
TimeStamp aStartTime, bool aIsFirst);
|
||||
|
||||
static long DataCallback_S(cubeb_stream*, void* aThis,
|
||||
|
|
|
@ -591,6 +591,9 @@ AudioCallbackDriver::Init()
|
|||
cubeb* cubebContext = CubebUtils::GetCubebContext();
|
||||
if (!cubebContext) {
|
||||
NS_WARNING("Could not get cubeb context.");
|
||||
if (!mFromFallback) {
|
||||
CubebUtils::ReportCubebStreamInitFailure(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -581,7 +581,10 @@ XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText,
|
|||
return;
|
||||
}
|
||||
|
||||
snapshot.GetAsString(aResponseText);
|
||||
if (!snapshot.GetAsString(aResponseText)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -645,7 +648,9 @@ XMLHttpRequestMainThread::CreateResponseParsedJSON(JSContext* aCx)
|
|||
}
|
||||
|
||||
nsAutoString string;
|
||||
mResponseText.GetAsString(string);
|
||||
if (!mResponseText.GetAsString(string)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// The Unicode converter has already zapped the BOM if there was one
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
|
|
|
@ -47,11 +47,11 @@ public:
|
|||
mData.Append(aString);
|
||||
}
|
||||
|
||||
void
|
||||
MOZ_MUST_USE bool
|
||||
GetAsString(nsAString& aString)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
aString = mData;
|
||||
return aString.Assign(mData, mozilla::fallible);
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -60,12 +60,12 @@ public:
|
|||
return mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
}
|
||||
|
||||
void
|
||||
MOZ_MUST_USE bool
|
||||
GetAsString(nsAString& aString, uint32_t aLength)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(aLength <= mData.Length());
|
||||
aString.Assign(mData.BeginReading(), aLength);
|
||||
return aString.Assign(mData.BeginReading(), aLength, mozilla::fallible);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -120,7 +120,7 @@ XMLHttpRequestString::Append(const nsAString& aString)
|
|||
mBuffer->Append(aString);
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
XMLHttpRequestString::GetAsString(nsAString& aString) const
|
||||
{
|
||||
return mBuffer->GetAsString(aString);
|
||||
|
@ -186,13 +186,12 @@ XMLHttpRequestStringSnapshot::Set(XMLHttpRequestStringBuffer* aBuffer,
|
|||
mVoid = false;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
XMLHttpRequestStringSnapshot::GetAsString(nsAString& aString) const
|
||||
{
|
||||
if (mBuffer) {
|
||||
MOZ_ASSERT(!mVoid);
|
||||
mBuffer->GetAsString(aString, mLength);
|
||||
return;
|
||||
return mBuffer->GetAsString(aString, mLength);
|
||||
}
|
||||
|
||||
aString.Truncate();
|
||||
|
@ -200,6 +199,8 @@ XMLHttpRequestStringSnapshot::GetAsString(nsAString& aString) const
|
|||
if (mVoid) {
|
||||
aString.SetIsVoid(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
// This method should be called only when the string is really needed because
|
||||
// it can cause the duplication of the strings in case the loading of the XHR
|
||||
// is not completed yet.
|
||||
void GetAsString(nsAString& aString) const;
|
||||
MOZ_MUST_USE bool GetAsString(nsAString& aString) const;
|
||||
|
||||
size_t SizeOfThis(MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
|
@ -118,7 +118,7 @@ public:
|
|||
return !mLength;
|
||||
}
|
||||
|
||||
void GetAsString(nsAString& aString) const;
|
||||
MOZ_MUST_USE bool GetAsString(nsAString& aString) const;
|
||||
|
||||
private:
|
||||
XMLHttpRequestStringSnapshot(const XMLHttpRequestStringSnapshot&) = delete;
|
||||
|
|
|
@ -2425,9 +2425,10 @@ XMLHttpRequestWorker::GetResponseText(nsAString& aResponseText, ErrorResult& aRv
|
|||
return;
|
||||
}
|
||||
|
||||
nsAutoString foo;
|
||||
mStateData.mResponseText.GetAsString(foo);
|
||||
aResponseText.Assign(foo.BeginReading(), foo.Length());
|
||||
if (!mStateData.mResponseText.GetAsString(aResponseText)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -82,6 +82,16 @@ static mozilla::LazyLogModule sRefreshDriverLog("nsRefreshDriver");
|
|||
// after 10 minutes, stop firing off inactive timers
|
||||
#define DEFAULT_INACTIVE_TIMER_DISABLE_SECONDS 600
|
||||
|
||||
// The number of seconds spent skipping frames because we are waiting for the compositor
|
||||
// before logging.
|
||||
#ifdef MOZ_VALGRIND
|
||||
#define REFRESH_WAIT_WARNING 10
|
||||
#elif defined(DEBUG) || defined(MOZ_ASAN)
|
||||
#define REFRESH_WAIT_WARNING 5
|
||||
#else
|
||||
#define REFRESH_WAIT_WARNING 1
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
// `true` if we are currently in jank-critical mode.
|
||||
//
|
||||
|
@ -1010,7 +1020,7 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
|
|||
mWaitingForTransaction(false),
|
||||
mSkippedPaints(false),
|
||||
mResizeSuppressed(false),
|
||||
mWarningThreshold(1)
|
||||
mWarningThreshold(REFRESH_WAIT_WARNING)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mPresContext,
|
||||
|
@ -1061,7 +1071,7 @@ nsRefreshDriver::AdvanceTimeAndRefresh(int64_t aMilliseconds)
|
|||
// Disable any refresh driver throttling when entering test mode
|
||||
mWaitingForTransaction = false;
|
||||
mSkippedPaints = false;
|
||||
mWarningThreshold = 1;
|
||||
mWarningThreshold = REFRESH_WAIT_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2062,14 +2072,14 @@ nsRefreshDriver::IsWaitingForPaint(mozilla::TimeStamp aTime)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (aTime > (mMostRecentTick + TimeDuration::FromMilliseconds(mWarningThreshold * 1000))) {
|
||||
gfxCriticalNote << "Refresh driver waiting for the compositor for "
|
||||
<< (aTime - mMostRecentTick).ToSeconds()
|
||||
<< " seconds.";
|
||||
mWarningThreshold *= 2;
|
||||
}
|
||||
|
||||
if (mWaitingForTransaction) {
|
||||
if (mSkippedPaints && aTime > (mMostRecentTick + TimeDuration::FromMilliseconds(mWarningThreshold * 1000))) {
|
||||
gfxCriticalNote << "Refresh driver waiting for the compositor for "
|
||||
<< (aTime - mMostRecentTick).ToSeconds()
|
||||
<< " seconds.";
|
||||
mWarningThreshold *= 2;
|
||||
}
|
||||
|
||||
mSkippedPaints = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>Reference for bug 1271714: .fixed should have a yellow background</title>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
.fixed {
|
||||
border: 1px solid black;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="fixed"></div>
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>Bug 1271714: Hit testing should be able to find the .fixed element</title>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
.positionedClip {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
position: fixed;
|
||||
border: 1px solid black;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="positionedClip">
|
||||
<div class="relative">
|
||||
<div class="fixed"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
document.elementFromPoint(100, 30).style.backgroundColor = "yellow";
|
||||
|
||||
</script>
|
|
@ -1954,6 +1954,7 @@ fuzzy(100,2000) == 1239564.html 1239564-ref.html
|
|||
== 1242781.html 1242781-ref.html
|
||||
== 1263845.html 1263845-ref.html
|
||||
== 1260543-1.html 1260543-1-ref.html
|
||||
== 1271714-1.html 1271714-1-ref.html
|
||||
== 1272997-1.html 1272997-1-ref.html
|
||||
random-if(!winWidget) == 1273154-1.html 1273154-1-ref.html # depends on Windows font
|
||||
random-if(!winWidget) == 1273154-2.html 1273154-2-ref.html # depends on Windows font
|
||||
|
|
|
@ -154,7 +154,8 @@ MP4Metadata::MP4Metadata(Stream* aSource)
|
|||
#ifdef MOZ_RUST_MP4PARSE
|
||||
, mRust(MakeUnique<MP4MetadataRust>(aSource))
|
||||
, mPreferRust(false)
|
||||
, mReportedTelemetry(false)
|
||||
, mReportedAudioTrackTelemetry(false)
|
||||
, mReportedVideoTrackTelemetry(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
@ -204,18 +205,16 @@ MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
|
|||
MOZ_LOG(sLog, LogLevel::Info, ("%s tracks found: stagefright=%u rust=%u",
|
||||
TrackTypeToString(aType), numTracks, numTracksRust));
|
||||
|
||||
if (!mReportedTelemetry) {
|
||||
bool numTracksMatch = numTracks == numTracksRust;
|
||||
bool numTracksMatch = numTracks == numTracksRust;
|
||||
|
||||
if (aType == mozilla::TrackInfo::kAudioTrack) {
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO,
|
||||
if (aType == mozilla::TrackInfo::kAudioTrack && !mReportedAudioTrackTelemetry) {
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO,
|
||||
numTracksMatch);
|
||||
mReportedAudioTrackTelemetry = true;
|
||||
} else if (aType == mozilla::TrackInfo::kVideoTrack && !mReportedVideoTrackTelemetry) {
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO,
|
||||
numTracksMatch);
|
||||
} else if (aType == mozilla::TrackInfo::kVideoTrack) {
|
||||
Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO,
|
||||
numTracksMatch);
|
||||
}
|
||||
|
||||
mReportedTelemetry = true;
|
||||
mReportedVideoTrackTelemetry = true;
|
||||
}
|
||||
|
||||
if (mPreferRust || ShouldPreferRust()) {
|
||||
|
|
|
@ -40,7 +40,8 @@ private:
|
|||
#ifdef MOZ_RUST_MP4PARSE
|
||||
UniquePtr<MP4MetadataRust> mRust;
|
||||
mutable bool mPreferRust;
|
||||
mutable bool mReportedTelemetry;
|
||||
mutable bool mReportedAudioTrackTelemetry;
|
||||
mutable bool mReportedVideoTrackTelemetry;
|
||||
bool ShouldPreferRust() const;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -25,9 +25,11 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include <media/stagefright/foundation/ABitReader.h>
|
||||
#include <media/stagefright/foundation/ABuffer.h>
|
||||
|
@ -43,6 +45,31 @@ static const uint32_t kMAX_ALLOCATION =
|
|||
|
||||
namespace stagefright {
|
||||
|
||||
static const int64_t OVERFLOW_ERROR = -INT64_MAX;
|
||||
|
||||
// Calculate units*1,000,000/hz, trying to avoid overflow.
|
||||
// Return OVERFLOW_ERROR in case of unavoidable overflow.
|
||||
int64_t unitsToUs(int64_t units, int64_t hz) {
|
||||
const int64_t MAX_S = INT64_MAX / 1000000;
|
||||
if (std::abs(units) <= MAX_S) {
|
||||
return units * 1000000 / hz;
|
||||
}
|
||||
// Hard case, avoid overflow-inducing 'units*1M' by calculating:
|
||||
// (units / hz) * 1M + ((units % hz) * 1M) / hz.
|
||||
// ^-- ^-- ^-- overflows still possible
|
||||
int64_t units_div_hz = units / hz;
|
||||
int64_t units_rem_hz = units % hz;
|
||||
if (std::abs(units_div_hz) > MAX_S || std::abs(units_rem_hz) > MAX_S) {
|
||||
return OVERFLOW_ERROR;
|
||||
}
|
||||
int64_t quot_us = units_div_hz * 1000000;
|
||||
int64_t rem_us = (units_rem_hz * 1000000) / hz;
|
||||
if (std::abs(quot_us) > INT64_MAX - std::abs(rem_us)) {
|
||||
return OVERFLOW_ERROR;
|
||||
}
|
||||
return quot_us + rem_us;
|
||||
}
|
||||
|
||||
class MPEG4Source : public MediaSource {
|
||||
public:
|
||||
MPEG4Source(const sp<MetaData> &format,
|
||||
|
@ -1063,6 +1090,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
|
|||
return ERROR_MALFORMED;
|
||||
}
|
||||
mLastTrack->timescale = ntohl(timescale);
|
||||
if (!mLastTrack->timescale) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
|
||||
// Now that we've parsed the media timescale, we can interpret
|
||||
// the edit list data.
|
||||
|
@ -1088,11 +1118,14 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
|
|||
duration = ntohl(duration32);
|
||||
}
|
||||
}
|
||||
if (!mLastTrack->timescale) {
|
||||
if (duration < 0) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
mLastTrack->meta->setInt64(
|
||||
kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
|
||||
int64_t duration_us = unitsToUs(duration, mLastTrack->timescale);
|
||||
if (duration_us == OVERFLOW_ERROR) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
mLastTrack->meta->setInt64(kKeyDuration, duration_us);
|
||||
|
||||
uint8_t lang[2];
|
||||
off64_t lang_offset;
|
||||
|
@ -1798,9 +1831,15 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
|
|||
}
|
||||
duration = ntohl(duration32);
|
||||
}
|
||||
if (duration < 0) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
int64_t duration_us = unitsToUs(duration, mHeaderTimescale);
|
||||
if (duration_us == OVERFLOW_ERROR) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
if (duration && mHeaderTimescale) {
|
||||
mFileMetaData->setInt64(
|
||||
kKeyMovieDuration, (duration * 1000000) / mHeaderTimescale);
|
||||
mFileMetaData->setInt64(kKeyMovieDuration, duration_us);
|
||||
}
|
||||
|
||||
*offset += chunk_size;
|
||||
|
@ -1965,11 +2004,21 @@ void MPEG4Extractor::storeEditList()
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t segment_duration = (mLastTrack->segment_duration * 1000000) / mHeaderTimescale;
|
||||
if (mLastTrack->segment_duration > uint64_t(INT64_MAX) ||
|
||||
mLastTrack->empty_duration > uint64_t(INT64_MAX)) {
|
||||
return;
|
||||
}
|
||||
uint64_t segment_duration =
|
||||
uint64_t(unitsToUs(mLastTrack->segment_duration, mHeaderTimescale));
|
||||
// media_time is measured in media time scale units.
|
||||
int64_t media_time = (mLastTrack->media_time * 1000000) / mLastTrack->timescale;
|
||||
int64_t media_time = unitsToUs(mLastTrack->media_time, mLastTrack->timescale);
|
||||
// empty_duration is in the Movie Header Box's timescale.
|
||||
int64_t empty_duration = (mLastTrack->empty_duration * 1000000) / mHeaderTimescale;
|
||||
int64_t empty_duration = unitsToUs(mLastTrack->empty_duration, mHeaderTimescale);
|
||||
if (segment_duration == OVERFLOW_ERROR ||
|
||||
media_time == OVERFLOW_ERROR ||
|
||||
empty_duration == OVERFLOW_ERROR) {
|
||||
return;
|
||||
}
|
||||
media_time -= empty_duration;
|
||||
mLastTrack->meta->setInt64(kKeyMediaTime, media_time);
|
||||
|
||||
|
@ -2070,7 +2119,7 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint64_t total_duration = 0;
|
||||
int64_t total_duration = 0;
|
||||
for (unsigned int i = 0; i < referenceCount; i++) {
|
||||
uint32_t d1, d2, d3;
|
||||
|
||||
|
@ -2093,11 +2142,18 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
|
|||
ALOGV(" item %d, %08x %08x %08x", i, d1, d2, d3);
|
||||
SidxEntry se;
|
||||
se.mSize = d1 & 0x7fffffff;
|
||||
se.mDurationUs = 1000000LL * d2 / timeScale;
|
||||
int64_t durationUs = unitsToUs(d2, timeScale);
|
||||
if (durationUs == OVERFLOW_ERROR || durationUs > int64_t(UINT32_MAX)) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
se.mDurationUs = uint32_t(durationUs);
|
||||
mSidxEntries.AppendElement(se);
|
||||
}
|
||||
|
||||
mSidxDuration = total_duration * 1000000 / timeScale;
|
||||
mSidxDuration = unitsToUs(total_duration, timeScale);
|
||||
if (mSidxDuration == OVERFLOW_ERROR) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
ALOGV("duration: %lld", mSidxDuration);
|
||||
|
||||
if (!mLastTrack) {
|
||||
|
|
|
@ -157,29 +157,50 @@ struct TestFileData
|
|||
{
|
||||
const char* mFilename;
|
||||
uint32_t mNumberVideoTracks;
|
||||
int64_t mVideoDuration; // For first video track, -1 if N/A.
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
uint32_t mNumberAudioTracks;
|
||||
int64_t mAudioDuration; // For first audio track, -1 if N/A.
|
||||
bool mHasCrypto;
|
||||
uint64_t mMoofReachedOffset; // or 0 for the end.
|
||||
bool mValidMoof;
|
||||
bool mHeader;
|
||||
};
|
||||
static const TestFileData testFiles[] = {
|
||||
// filename #V w h #A crypt off moof headr
|
||||
{ "test_case_1156505.mp4", 0, 0, 0, 0, false, 152, false, false },
|
||||
{ "test_case_1181213.mp4", 0, 0, 0, 0, false, 0, false, false },
|
||||
{ "test_case_1181215.mp4", 0, 0, 0, 0, false, 0, false, false },
|
||||
{ "test_case_1181220.mp4", 0, 0, 0, 0, false, 0, false, false },
|
||||
{ "test_case_1181223.mp4", 0, 0, 0, 0, false, 0, false, false },
|
||||
{ "test_case_1181719.mp4", 0, 0, 0, 0, false, 0, false, false },
|
||||
{ "test_case_1185230.mp4", 1, 320, 240, 1, false, 0, false, false },
|
||||
{ "test_case_1187067.mp4", 1, 160, 90, 0, false, 0, false, false },
|
||||
{ "test_case_1200326.mp4", 0, 0, 0, 0, false, 0, false, false },
|
||||
{ "test_case_1204580.mp4", 1, 320, 180, 0, false, 0, false, false },
|
||||
{ "test_case_1216748.mp4", 0, 0, 0, 0, false, 152, false, false },
|
||||
{ "test_case_1296473.mp4", 0, 0, 0, 0, false, 0, false, false },
|
||||
{ "test_case_1296532.mp4", 1, 560, 320, 1, true, 0, true, true }
|
||||
// filename #V dur w h #A dur crypt off moof headr
|
||||
{ "test_case_1156505.mp4", 0, -1, 0, 0, 0, -1, false, 152, false, false },
|
||||
{ "test_case_1181213.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1181215.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1181220.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1181223.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1181719.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1185230.mp4", 1, 416666,
|
||||
320, 240, 1, 5, false, 0, false, false },
|
||||
{ "test_case_1187067.mp4", 1, 80000,
|
||||
160, 90, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1200326.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1204580.mp4", 1, 502500,
|
||||
320, 180, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1216748.mp4", 0, -1, 0, 0, 0, -1, false, 152, false, false },
|
||||
{ "test_case_1296473.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1296532.mp4", 1, 5589333,
|
||||
560, 320, 1, 5589333,
|
||||
true, 0, true, true },
|
||||
{ "test_case_1301065.mp4", 0, -1, 0, 0, 1, 100079991719000000,
|
||||
false, 0, false, false },
|
||||
{ "test_case_1301065-u32max.mp4", 0, -1, 0, 0, 1, 97391548639,
|
||||
false, 0, false, false },
|
||||
{ "test_case_1301065-max-ez.mp4", 0, -1, 0, 0, 1, 209146758205306,
|
||||
false, 0, false, false },
|
||||
{ "test_case_1301065-harder.mp4", 0, -1, 0, 0, 1, 209146758205328,
|
||||
false, 0, false, false },
|
||||
{ "test_case_1301065-max-ok.mp4", 0, -1, 0, 0, 1, 9223372036854775804,
|
||||
false, 0, false, false },
|
||||
{ "test_case_1301065-overfl.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1301065-i64max.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1301065-i64min.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
{ "test_case_1301065-u64max.mp4", 0, -1, 0, 0, 0, -1, false, 0, false, false },
|
||||
};
|
||||
|
||||
TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
||||
|
@ -211,6 +232,7 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
|||
ASSERT_TRUE(!!videoInfo);
|
||||
EXPECT_TRUE(videoInfo->IsValid());
|
||||
EXPECT_TRUE(videoInfo->IsVideo());
|
||||
EXPECT_EQ(testFiles[test].mVideoDuration, videoInfo->mDuration);
|
||||
EXPECT_EQ(testFiles[test].mWidth, videoInfo->mDisplay.width);
|
||||
EXPECT_EQ(testFiles[test].mHeight, videoInfo->mDisplay.height);
|
||||
FallibleTArray<mp4_demuxer::Index::Indice> indices;
|
||||
|
@ -229,6 +251,7 @@ TEST(stagefright_MPEG4Metadata, test_case_mp4)
|
|||
ASSERT_TRUE(!!audioInfo);
|
||||
EXPECT_TRUE(audioInfo->IsValid());
|
||||
EXPECT_TRUE(audioInfo->IsAudio());
|
||||
EXPECT_EQ(testFiles[test].mAudioDuration, audioInfo->mDuration);
|
||||
FallibleTArray<mp4_demuxer::Index::Indice> indices;
|
||||
EXPECT_TRUE(metadata.ReadTrackIndex(indices, audioInfo->mTrackId));
|
||||
for (const mp4_demuxer::Index::Indice& indice : indices) {
|
||||
|
|
|
@ -25,6 +25,15 @@ TEST_HARNESS_FILES.gtest += [
|
|||
'test_case_1216748.mp4',
|
||||
'test_case_1296473.mp4',
|
||||
'test_case_1296532.mp4',
|
||||
'test_case_1301065-harder.mp4',
|
||||
'test_case_1301065-i64max.mp4',
|
||||
'test_case_1301065-i64min.mp4',
|
||||
'test_case_1301065-max-ez.mp4',
|
||||
'test_case_1301065-max-ok.mp4',
|
||||
'test_case_1301065-overfl.mp4',
|
||||
'test_case_1301065-u32max.mp4',
|
||||
'test_case_1301065-u64max.mp4',
|
||||
'test_case_1301065.mp4',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_RUST']:
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -37367,6 +37367,12 @@
|
|||
]
|
||||
},
|
||||
"testharness": {
|
||||
"2dcontext/path-objects/2d.path.lineTo.nonfinite.details.html": [
|
||||
{
|
||||
"path": "2dcontext/path-objects/2d.path.lineTo.nonfinite.details.html",
|
||||
"url": "/2dcontext/path-objects/2d.path.lineTo.nonfinite.details.html"
|
||||
}
|
||||
],
|
||||
"IndexedDB/idbcursor-continuePrimaryKey-exception-order.htm": [
|
||||
{
|
||||
"path": "IndexedDB/idbcursor-continuePrimaryKey-exception-order.htm",
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
|
||||
<title>Canvas test: 2d.path.lineTo.nonfinite.details</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/common/canvas-tests.js"></script>
|
||||
<link rel="stylesheet" href="/common/canvas-tests.css">
|
||||
<body class="show_output">
|
||||
|
||||
<h1>2d.path.lineTo.nonfinite.details</h1>
|
||||
<p class="desc">lineTo() with Infinity/NaN for first arg still converts the second arg</p>
|
||||
|
||||
|
||||
<p class="output">Actual output:</p>
|
||||
<canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
|
||||
<p class="output expectedtext">Expected output:<p><img src="/images/clear-100x50.png" class="output expected" id="expected" alt="">
|
||||
<ul id="d"></ul>
|
||||
<script>
|
||||
var t = async_test("lineTo() with Infinity/NaN for first arg still converts the second arg");
|
||||
_addTest(function(canvas, ctx) {
|
||||
|
||||
for (var arg1 of [Infinity, -Infinity, NaN]) {
|
||||
var converted = false;
|
||||
ctx.lineTo(arg1, { valueOf: function() { converted = true; return 0; } });
|
||||
_assert(converted, "converted");
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
|
@ -6197,6 +6197,18 @@
|
|||
@assert pixel 90,45 == 0,255,0,255;
|
||||
expected: green
|
||||
|
||||
- name: 2d.path.lineTo.nonfinite.details
|
||||
desc: lineTo() with Infinity/NaN for first arg still converts the second arg
|
||||
testing:
|
||||
- 2d.nonfinite
|
||||
code: |
|
||||
for (var arg1 of [Infinity, -Infinity, NaN]) {
|
||||
var converted = false;
|
||||
ctx.lineTo(arg1, { valueOf: function() { converted = true; return 0; } });
|
||||
@assert converted;
|
||||
}
|
||||
expected: clear
|
||||
|
||||
- name: 2d.path.quadraticCurveTo.ensuresubpath.1
|
||||
desc: If there is no subpath, the first control point is added (and nothing is drawn up to it)
|
||||
testing:
|
||||
|
|
|
@ -51,9 +51,11 @@ UNIFIED_SOURCES += [
|
|||
]
|
||||
|
||||
# Are we targeting x86 or x86-64? If so, compile the SSE2 functions for
|
||||
# nsUTF8Utils.cpp.
|
||||
# nsUTF8Utils.cpp and nsReadableUtils.cpp.
|
||||
if CONFIG['INTEL_ARCHITECTURE']:
|
||||
SOURCES += ['nsUTF8UtilsSSE2.cpp']
|
||||
SOURCES['nsUTF8UtilsSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES += ['nsReadableUtilsSSE2.cpp']
|
||||
SOURCES['nsReadableUtilsSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -5,14 +5,79 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsReadableUtilsImpl.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsUTF8Utils.h"
|
||||
|
||||
using mozilla::IsASCII;
|
||||
|
||||
/**
|
||||
* Fallback implementation for finding the first non-ASCII character in a
|
||||
* UTF-16 string.
|
||||
*/
|
||||
static inline int32_t
|
||||
FirstNonASCIIUnvectorized(const char16_t* aBegin, const char16_t* aEnd)
|
||||
{
|
||||
typedef mozilla::NonASCIIParameters<sizeof(size_t)> p;
|
||||
const size_t kMask = p::mask();
|
||||
const uintptr_t kAlignMask = p::alignMask();
|
||||
const size_t kNumUnicharsPerWord = p::numUnicharsPerWord();
|
||||
|
||||
const char16_t* idx = aBegin;
|
||||
|
||||
// Align ourselves to a word boundary.
|
||||
for (; idx != aEnd && ((uintptr_t(idx) & kAlignMask) != 0); idx++) {
|
||||
if (!IsASCII(*idx)) {
|
||||
return idx - aBegin;
|
||||
}
|
||||
}
|
||||
|
||||
// Check one word at a time.
|
||||
const char16_t* wordWalkEnd = mozilla::aligned(aEnd, kAlignMask);
|
||||
for (; idx != wordWalkEnd; idx += kNumUnicharsPerWord) {
|
||||
const size_t word = *reinterpret_cast<const size_t*>(idx);
|
||||
if (word & kMask) {
|
||||
return idx - aBegin;
|
||||
}
|
||||
}
|
||||
|
||||
// Take care of the remainder one character at a time.
|
||||
for (; idx != aEnd; idx++) {
|
||||
if (!IsASCII(*idx)) {
|
||||
return idx - aBegin;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns -1 if all characters in str are ASCII characters.
|
||||
* Otherwise, it returns a value less than or equal to the index of the first
|
||||
* ASCII character in str. For example, if first non-ASCII character is at
|
||||
* position 25, it may return 25, 24, or 16. But it guarantees
|
||||
* there are only ASCII characters before returned value.
|
||||
*/
|
||||
static inline int32_t
|
||||
FirstNonASCII(const char16_t* aBegin, const char16_t* aEnd)
|
||||
{
|
||||
#ifdef MOZILLA_MAY_SUPPORT_SSE2
|
||||
if (mozilla::supports_sse2()) {
|
||||
return mozilla::SSE2::FirstNonASCII(aBegin, aEnd);
|
||||
}
|
||||
#endif
|
||||
|
||||
return FirstNonASCIIUnvectorized(aBegin, aEnd);
|
||||
}
|
||||
|
||||
void
|
||||
LossyCopyUTF16toASCII(const nsAString& aSource, nsACString& aDest)
|
||||
{
|
||||
|
@ -180,16 +245,46 @@ bool
|
|||
AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
|
||||
const mozilla::fallible_t& aFallible)
|
||||
{
|
||||
// At 16 characters analysis showed better performance of both the all ASCII
|
||||
// and non-ASCII cases, so we limit calling |FirstNonASCII| to strings of
|
||||
// that length.
|
||||
const nsAString::size_type kFastPathMinLength = 16;
|
||||
|
||||
int32_t firstNonASCII = 0;
|
||||
if (aSource.Length() >= kFastPathMinLength) {
|
||||
firstNonASCII = FirstNonASCII(aSource.BeginReading(), aSource.EndReading());
|
||||
}
|
||||
|
||||
if (firstNonASCII == -1) {
|
||||
// This is all ASCII, we can use the more efficient lossy append.
|
||||
mozilla::CheckedInt<nsACString::size_type> new_length(aSource.Length());
|
||||
new_length += aDest.Length();
|
||||
|
||||
if (!new_length.isValid() ||
|
||||
!aDest.SetCapacity(new_length.value(), aFallible)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LossyAppendUTF16toASCII(aSource, aDest);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAString::const_iterator source_start, source_end;
|
||||
CalculateUTF8Size calculator;
|
||||
copy_string(aSource.BeginReading(source_start),
|
||||
aSource.EndReading(source_end), calculator);
|
||||
aSource.BeginReading(source_start);
|
||||
aSource.EndReading(source_end);
|
||||
|
||||
size_t count = calculator.Size();
|
||||
// Skip the characters that we know are single byte.
|
||||
source_start.advance(firstNonASCII);
|
||||
|
||||
copy_string(source_start,
|
||||
source_end, calculator);
|
||||
|
||||
// Include the ASCII characters that were skipped in the count.
|
||||
size_t count = calculator.Size() + firstNonASCII;
|
||||
|
||||
if (count) {
|
||||
auto old_dest_length = aDest.Length();
|
||||
|
||||
// Grow the buffer if we need to.
|
||||
mozilla::CheckedInt<nsACString::size_type> new_length(count);
|
||||
new_length += old_dest_length;
|
||||
|
@ -201,11 +296,30 @@ AppendUTF16toUTF8(const nsAString& aSource, nsACString& aDest,
|
|||
|
||||
// All ready? Time to convert
|
||||
|
||||
ConvertUTF16toUTF8 converter(aDest.BeginWriting() + old_dest_length);
|
||||
copy_string(aSource.BeginReading(source_start),
|
||||
nsAString::const_iterator ascii_end;
|
||||
aSource.BeginReading(ascii_end);
|
||||
|
||||
if (firstNonASCII >= static_cast<int32_t>(kFastPathMinLength)) {
|
||||
// Use the more efficient lossy converter for the ASCII portion.
|
||||
LossyConvertEncoding16to8 lossy_converter(
|
||||
aDest.BeginWriting() + old_dest_length);
|
||||
nsAString::const_iterator ascii_start;
|
||||
aSource.BeginReading(ascii_start);
|
||||
ascii_end.advance(firstNonASCII);
|
||||
|
||||
copy_string(ascii_start, ascii_end, lossy_converter);
|
||||
} else {
|
||||
// Not using the lossy shortcut, we need to include the leading ASCII
|
||||
// chars.
|
||||
firstNonASCII = 0;
|
||||
}
|
||||
|
||||
ConvertUTF16toUTF8 converter(
|
||||
aDest.BeginWriting() + old_dest_length + firstNonASCII);
|
||||
copy_string(ascii_end,
|
||||
aSource.EndReading(source_end), converter);
|
||||
|
||||
NS_ASSERTION(converter.Size() == count,
|
||||
NS_ASSERTION(converter.Size() == count - firstNonASCII,
|
||||
"Unexpected disparity between CalculateUTF8Size and "
|
||||
"ConvertUTF16toUTF8");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
inline bool IsASCII(char16_t aChar) {
|
||||
return (aChar & 0xFF80) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a pointer before or equal to |aPtr| that is is suitably aligned.
|
||||
*/
|
||||
inline const char16_t* aligned(const char16_t* aPtr, const uintptr_t aMask)
|
||||
{
|
||||
return reinterpret_cast<const char16_t*>(
|
||||
reinterpret_cast<const uintptr_t>(aPtr) & ~aMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Structures for word-sized vectorization of ASCII checking for UTF-16
|
||||
* strings.
|
||||
*/
|
||||
template<size_t size> struct NonASCIIParameters;
|
||||
template<> struct NonASCIIParameters<4> {
|
||||
static inline size_t mask() { return 0xff80ff80; }
|
||||
static inline uintptr_t alignMask() { return 0x3; }
|
||||
static inline size_t numUnicharsPerWord() { return 2; }
|
||||
};
|
||||
|
||||
template<> struct NonASCIIParameters<8> {
|
||||
static inline size_t mask() {
|
||||
static const uint64_t maskAsUint64 = UINT64_C(0xff80ff80ff80ff80);
|
||||
// We have to explicitly cast this 64-bit value to a size_t, or else
|
||||
// compilers for 32-bit platforms will warn about it being too large to fit
|
||||
// in the size_t return type. (Fortunately, this code isn't actually
|
||||
// invoked on 32-bit platforms -- they'll use the <4> specialization above.
|
||||
// So it is, in fact, OK that this value is too large for a 32-bit size_t.)
|
||||
return (size_t)maskAsUint64;
|
||||
}
|
||||
static inline uintptr_t alignMask() { return 0x7; }
|
||||
static inline size_t numUnicharsPerWord() { return 4; }
|
||||
};
|
||||
|
||||
namespace SSE2 {
|
||||
|
||||
int32_t FirstNonASCII(const char16_t* aBegin, const char16_t* aEnd);
|
||||
|
||||
} // namespace SSE2
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
#include "nsReadableUtilsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace SSE2 {
|
||||
|
||||
static inline bool
|
||||
is_zero (__m128i x)
|
||||
{
|
||||
return
|
||||
_mm_movemask_epi8(_mm_cmpeq_epi8(x, _mm_setzero_si128())) == 0xffff;
|
||||
}
|
||||
|
||||
int32_t
|
||||
FirstNonASCII(const char16_t* aBegin, const char16_t* aEnd)
|
||||
{
|
||||
const size_t kNumUnicharsPerVector = sizeof(__m128i) / sizeof(char16_t);
|
||||
typedef NonASCIIParameters<sizeof(size_t)> p;
|
||||
const size_t kMask = p::mask();
|
||||
const uintptr_t kXmmAlignMask = 0xf;
|
||||
const uint16_t kShortMask = 0xff80;
|
||||
const size_t kNumUnicharsPerWord = p::numUnicharsPerWord();
|
||||
|
||||
const char16_t* idx = aBegin;
|
||||
|
||||
// Align ourselves to a 16-byte boundary as required by _mm_load_si128
|
||||
for (; idx != aEnd && ((uintptr_t(idx) & kXmmAlignMask) != 0); idx++) {
|
||||
if (!IsASCII(*idx)) {
|
||||
return idx - aBegin;
|
||||
}
|
||||
}
|
||||
|
||||
// Check one XMM register (16 bytes) at a time.
|
||||
const char16_t* vectWalkEnd = aligned(aEnd, kXmmAlignMask);
|
||||
__m128i vectmask = _mm_set1_epi16(static_cast<int16_t>(kShortMask));
|
||||
for (; idx != vectWalkEnd; idx += kNumUnicharsPerVector) {
|
||||
const __m128i vect = *reinterpret_cast<const __m128i*>(idx);
|
||||
if (!is_zero(_mm_and_si128(vect, vectmask))) {
|
||||
return idx - aBegin;
|
||||
}
|
||||
}
|
||||
|
||||
// Check one word at a time.
|
||||
const char16_t* wordWalkEnd = aligned(aEnd, p::alignMask());
|
||||
for(; idx != wordWalkEnd; idx += kNumUnicharsPerWord) {
|
||||
const size_t word = *reinterpret_cast<const size_t*>(idx);
|
||||
if (word & kMask) {
|
||||
return idx - aBegin;
|
||||
}
|
||||
}
|
||||
|
||||
// Take care of the remainder one character at a time.
|
||||
for (; idx != aEnd; idx++) {
|
||||
if (!IsASCII(*idx)) {
|
||||
return idx - aBegin;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace SSE2
|
||||
} // namespace mozilla
|
|
@ -122,4 +122,70 @@ TEST(UTF, Hash16)
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests the handling of a non-ascii character at various locations in a
|
||||
* UTF-16 string that is being converted to UTF-8.
|
||||
*/
|
||||
void NonASCII16_helper(const size_t aStrSize)
|
||||
{
|
||||
const size_t kTestSize = aStrSize;
|
||||
const size_t kMaxASCII = 0x80;
|
||||
const char16_t kUTF16Char = 0xC9;
|
||||
const char kUTF8Surrogates[] = { char(0xC3), char(0x89) };
|
||||
|
||||
// Generate a string containing only ASCII characters.
|
||||
nsString asciiString;
|
||||
asciiString.SetLength(kTestSize);
|
||||
nsCString asciiCString;
|
||||
asciiCString.SetLength(kTestSize);
|
||||
|
||||
auto str_buff = asciiString.BeginWriting();
|
||||
auto cstr_buff = asciiCString.BeginWriting();
|
||||
for (size_t i = 0; i < kTestSize; i++) {
|
||||
str_buff[i] = i % kMaxASCII;
|
||||
cstr_buff[i] = i % kMaxASCII;
|
||||
}
|
||||
|
||||
// Now go through and test conversion when exactly one character will
|
||||
// result in a multibyte sequence.
|
||||
for (size_t i = 0; i < kTestSize; i++) {
|
||||
// Setup the UTF-16 string.
|
||||
nsString unicodeString(asciiString);
|
||||
auto buff = unicodeString.BeginWriting();
|
||||
buff[i] = kUTF16Char;
|
||||
|
||||
// Do the conversion, make sure the length increased by 1.
|
||||
nsCString dest;
|
||||
AppendUTF16toUTF8(unicodeString, dest);
|
||||
EXPECT_EQ(dest.Length(), unicodeString.Length() + 1);
|
||||
|
||||
// Build up the expected UTF-8 string.
|
||||
nsCString expected;
|
||||
|
||||
// First add the leading ASCII chars.
|
||||
expected.Append(asciiCString.BeginReading(), i);
|
||||
|
||||
// Now append the UTF-8 surrogate pair we expect the UTF-16 unicode char to
|
||||
// be converted to.
|
||||
for (auto& c : kUTF8Surrogates) {
|
||||
expected.Append(c);
|
||||
}
|
||||
|
||||
// And finish with the trailing ASCII chars.
|
||||
expected.Append(asciiCString.BeginReading() + i + 1, kTestSize - i - 1);
|
||||
|
||||
EXPECT_STREQ(dest.BeginReading(), expected.BeginReading());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UTF, NonASCII16)
|
||||
{
|
||||
// Test with various string sizes to catch any special casing.
|
||||
NonASCII16_helper(1);
|
||||
NonASCII16_helper(8);
|
||||
NonASCII16_helper(16);
|
||||
NonASCII16_helper(32);
|
||||
NonASCII16_helper(512);
|
||||
}
|
||||
|
||||
} // namespace TestUTF
|
||||
|
|
Загрузка…
Ссылка в новой задаче