merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-09-16 12:56:33 +02:00
Родитель d130bd9cf1 6beabc555f
Коммит 8689785991
47 изменённых файлов: 976 добавлений и 265 удалений

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

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

Двоичные данные
media/libstagefright/gtest/test_case_1301065-harder.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065-i64max.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065-i64min.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065-max-ez.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065-max-ok.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065-overfl.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065-u32max.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065-u64max.mp4 Normal file

Двоичный файл не отображается.

Двоичные данные
media/libstagefright/gtest/test_case_1301065.mp4 Normal file

Двоичный файл не отображается.

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

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