The great layout servo rust update

This commit is contained in:
Fedor 2023-10-06 19:14:40 +03:00
parent f6d16ef724
commit 7b3dbae42d
5742 changed files with 772369 additions and 303036 deletions

View File

@ -295,14 +295,11 @@ module.exports = {
],
"rules": {
"consistent-return": "off",
"dot-notation": "off",
"mozilla/avoid-removeChild": "off",
"mozilla/consistent-if-bracing": "off",
"mozilla/no-arbitrary-setTimeout": "off",
"mozilla/no-compare-against-boolean-literals": "off",
"mozilla/no-define-cc-etc": "off",
"mozilla/no-useless-parameters": "off",
"mozilla/no-useless-run-test": "off",
"mozilla/reject-importGlobalProperties": "off",
"mozilla/use-cc-etc": "off",
"mozilla/use-chromeutils-generateqi": "off",
@ -318,7 +315,6 @@ module.exports = {
"no-else-return": "off",
"no-empty": "off",
"no-eval": "off",
"no-extra-boolean-cast": "off",
"no-func-assign": "off",
"no-global-assign": "off",
"no-implied-eval": "off",
@ -338,7 +334,6 @@ module.exports = {
"no-shadow-restricted-names": "off",
"no-sparse-arrays": "off",
"no-throw-literal": "off",
"no-unneeded-ternary": "off",
"no-unreachable": "off",
"no-unsanitized/method": "off",
"no-unsanitized/property": "off",

517
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -605,8 +605,8 @@ TextAttrsMgr::TextDecorValue::TextDecorValue(nsIFrame* aFrame) {
mStyle = textReset->mTextDecorationStyle;
mColor = textReset->mTextDecorationColor.CalcColor(aFrame);
mLine =
textReset->mTextDecorationLine & (StyleTextDecorationLine_UNDERLINE |
StyleTextDecorationLine_LINE_THROUGH);
textReset->mTextDecorationLine & (StyleTextDecorationLine::UNDERLINE |
StyleTextDecorationLine::LINE_THROUGH);
}
TextAttrsMgr::TextDecorTextAttr::TextDecorTextAttr(nsIFrame* aRootFrame,

View File

@ -357,7 +357,7 @@ class TextAttrsMgr {
public:
TextDecorValue()
: mColor{0},
mLine{StyleTextDecorationLine_NONE},
mLine{StyleTextDecorationLine::NONE},
mStyle{NS_STYLE_TEXT_DECORATION_STYLE_NONE} {}
explicit TextDecorValue(nsIFrame* aFrame);
@ -366,10 +366,10 @@ class TextAttrsMgr {
bool IsDefined() const { return IsUnderline() || IsLineThrough(); }
bool IsUnderline() const {
return bool(mLine & mozilla::StyleTextDecorationLine_UNDERLINE);
return bool(mLine & mozilla::StyleTextDecorationLine::UNDERLINE);
}
bool IsLineThrough() const {
return bool(mLine & mozilla::StyleTextDecorationLine_LINE_THROUGH);
return bool(mLine & mozilla::StyleTextDecorationLine::LINE_THROUGH);
}
bool operator==(const TextDecorValue& aValue) {

View File

@ -72,6 +72,7 @@
#include "mozilla/PresShell.h"
#include "mozilla/Unused.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_ui.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLCanvasElement.h"
@ -240,7 +241,7 @@ KeyBinding Accessible::AccessKey() const {
if (!key) return KeyBinding();
// Get modifier mask. Use ui.key.generalAccessKey (unless it is -1).
switch (Preferences::GetInt("ui.key.generalAccessKey", -1)) {
switch (StaticPrefs::ui_key_generalAccessKey()) {
case -1:
break;
case dom::KeyboardEvent_Binding::DOM_VK_SHIFT:
@ -266,10 +267,12 @@ KeyBinding Accessible::AccessKey() const {
int32_t modifierMask = 0;
switch (treeItem->ItemType()) {
case nsIDocShellTreeItem::typeChrome:
rv = Preferences::GetInt("ui.key.chromeAccess", &modifierMask);
modifierMask = StaticPrefs::ui_key_chromeAccess();
rv = NS_OK;
break;
case nsIDocShellTreeItem::typeContent:
rv = Preferences::GetInt("ui.key.contentAccess", &modifierMask);
modifierMask = StaticPrefs::ui_key_contentAccess();
rv = NS_OK;
break;
}

View File

@ -1187,11 +1187,19 @@ Accessible* DocAccessible::GetAccessibleOrDescendant(nsINode* aNode) const {
Accessible* acc = GetAccessible(aNode);
if (acc) return acc;
if (aNode == mContent || aNode == mDocumentNode->GetRootElement()) {
// If the node is the doc's body or root element, return the doc accessible.
return const_cast<DocAccessible*>(this);
}
acc = GetContainerAccessible(aNode);
if (acc) {
uint32_t childCnt = acc->ChildCount();
// We access the `mChildren` array directly so that we don't access
// lazily created children in places like `XULTreeAccessible` and
// `XULTreeGridAccessible`.
uint32_t childCnt = acc->mChildren.Length();
for (uint32_t idx = 0; idx < childCnt; idx++) {
Accessible* child = acc->GetChildAt(idx);
Accessible* child = acc->mChildren.ElementAt(idx);
for (nsIContent* elm = child->GetContent();
elm && elm != acc->GetContent();
elm = elm->GetFlattenedTreeParent()) {

View File

@ -35,6 +35,7 @@
#include "mozilla/TextEditor.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLBRElement.h"
#include "mozilla/dom/HTMLHeadingElement.h"
#include "mozilla/dom/Selection.h"
#include "gfxSkipChars.h"
#include <algorithm>
@ -882,13 +883,9 @@ HyperTextAccessible::DefaultTextAttributes() {
}
int32_t HyperTextAccessible::GetLevelInternal() {
if (mContent->IsHTMLElement(nsGkAtoms::h1)) return 1;
if (mContent->IsHTMLElement(nsGkAtoms::h2)) return 2;
if (mContent->IsHTMLElement(nsGkAtoms::h3)) return 3;
if (mContent->IsHTMLElement(nsGkAtoms::h4)) return 4;
if (mContent->IsHTMLElement(nsGkAtoms::h5)) return 5;
if (mContent->IsHTMLElement(nsGkAtoms::h6)) return 6;
if (auto* heading = dom::HTMLHeadingElement::FromNode(mContent)) {
return heading->AccessibilityLevel();
}
return AccessibleWrap::GetLevelInternal();
}

View File

@ -569,47 +569,23 @@
// ////////////////////////////////////////////////////////////////////////
// HTML:h1, HTML:h2, HTML:h3, HTML:h4, HTML:h5, HTML:h6
obj = {
role: ROLE_HEADING,
attributes: { "level": "1" },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
};
testElm("h1", obj);
function headingWithLevel(i) {
return {
role: ROLE_HEADING,
attributes: { "level": i.toString() },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
};
}
obj = {
role: ROLE_HEADING,
attributes: { "level": "2" },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
};
testElm("h2", obj);
obj = {
role: ROLE_HEADING,
attributes: { "level": "3" },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
};
testElm("h3", obj);
obj = {
role: ROLE_HEADING,
attributes: { "level": "4" },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
};
testElm("h4", obj);
obj = {
role: ROLE_HEADING,
attributes: { "level": "5" },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
};
testElm("h5", obj);
obj = {
role: ROLE_HEADING,
attributes: { "level": "6" },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ],
};
testElm("h6", obj);
const headingChangesEnabled = SpecialPowers.getBoolPref("accessibility.heading-element-level-changes.enabled");
for (let level = 1; level <= 6; ++level) {
testElm("h" + level, headingWithLevel(level));
let expectedLevelWithAncestors = headingChangesEnabled ? level + 1 : level;
for (const ancestor of ["section", "article", "aside", "nav"]) {
testElm("h" + level + "_in_" + ancestor, headingWithLevel(level == 1 ? expectedLevelWithAncestors : level));
testElm("h" + level + "_in_" + ancestor + "_in_hgroup", headingWithLevel(expectedLevelWithAncestors));
}
}
// ////////////////////////////////////////////////////////////////////////
// HTML:header
@ -1596,15 +1572,71 @@
<header id="header">A logo</header>
<article>
<header id="header_in_article">Not logo</header>
<h1 id="h1_in_article">heading1</h1>
<h2 id="h2_in_article">heading2</h2>
<h3 id="h3_in_article">heading3</h3>
<h4 id="h4_in_article">heading4</h4>
<h5 id="h5_in_article">heading5</h5>
<h6 id="h6_in_article">heading6</h6>
<hgroup>
<h1 id="h1_in_article_in_hgroup">heading1</h1>
<h2 id="h2_in_article_in_hgroup">heading2</h2>
<h3 id="h3_in_article_in_hgroup">heading3</h3>
<h4 id="h4_in_article_in_hgroup">heading4</h4>
<h5 id="h5_in_article_in_hgroup">heading5</h5>
<h6 id="h6_in_article_in_hgroup">heading6</h6>
</hgroup>
</article>
<aside>
<header id="header_in_aside">Not logo</header>
<h1 id="h1_in_aside">heading1</h1>
<h2 id="h2_in_aside">heading2</h2>
<h3 id="h3_in_aside">heading3</h3>
<h4 id="h4_in_aside">heading4</h4>
<h5 id="h5_in_aside">heading5</h5>
<h6 id="h6_in_aside">heading6</h6>
<hgroup>
<h1 id="h1_in_aside_in_hgroup">heading1</h1>
<h2 id="h2_in_aside_in_hgroup">heading2</h2>
<h3 id="h3_in_aside_in_hgroup">heading3</h3>
<h4 id="h4_in_aside_in_hgroup">heading4</h4>
<h5 id="h5_in_aside_in_hgroup">heading5</h5>
<h6 id="h6_in_aside_in_hgroup">heading6</h6>
</hgroup>
</aside>
<nav>
<header id="header_in_nav">Not logo</header>
<h1 id="h1_in_nav">heading1</h1>
<h2 id="h2_in_nav">heading2</h2>
<h3 id="h3_in_nav">heading3</h3>
<h4 id="h4_in_nav">heading4</h4>
<h5 id="h5_in_nav">heading5</h5>
<h6 id="h6_in_nav">heading6</h6>
<hgroup>
<h1 id="h1_in_nav_in_hgroup">heading1</h1>
<h2 id="h2_in_nav_in_hgroup">heading2</h2>
<h3 id="h3_in_nav_in_hgroup">heading3</h3>
<h4 id="h4_in_nav_in_hgroup">heading4</h4>
<h5 id="h5_in_nav_in_hgroup">heading5</h5>
<h6 id="h6_in_nav_in_hgroup">heading6</h6>
</hgroup>
</nav>
<section>
<header id="header_in_section">Not logo</header>
<h1 id="h1_in_section">heading1</h1>
<h2 id="h2_in_section">heading2</h2>
<h3 id="h3_in_section">heading3</h3>
<h4 id="h4_in_section">heading4</h4>
<h5 id="h5_in_section">heading5</h5>
<h6 id="h6_in_section">heading6</h6>
<hgroup>
<h1 id="h1_in_section_in_hgroup">heading1</h1>
<h2 id="h2_in_section_in_hgroup">heading2</h2>
<h3 id="h3_in_section_in_hgroup">heading3</h3>
<h4 id="h4_in_section_in_hgroup">heading4</h4>
<h5 id="h5_in_section_in_hgroup">heading5</h5>
<h6 id="h6_in_section_in_hgroup">heading6</h6>
</hgroup>
</section>
<blockquote>
<header id="header_in_blockquote">Not logo</header>

View File

@ -25,6 +25,8 @@
zoomDocument(document, 2.0);
document.body.offsetTop; // getBounds doesn't flush layout on its own, looks like.
[x, y, width, height] = getBounds(textNode);
testOffsetAtPoint(hyperText, x + width / 2, y + height / 2,
COORDTYPE_SCREEN_RELATIVE,

View File

@ -19,7 +19,7 @@
// __h__e__l__l__o__ __m__y__ __f__r__i__e__n__d__
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var IDs = [ "i1", "d1", "e1", "t1" ];
var IDs = [ "i1", "d1", "d1wrap", "e1", "t1" ];
testCharacterCount(IDs, 15);
@ -96,6 +96,7 @@
<input id="i1" value="hello my friend"/>
<div id="d1">hello my friend</div>
<div id="d1wrap" style="word-wrap:break-word; width:1px">hello my friend</div>
<div id="e1" contenteditable="true">hello my friend</div>
<textarea id="t1">hello my friend</textarea>

View File

@ -167,7 +167,6 @@ pref("browser.uitour.surveyDuration", 7200);
pref("keyword.enabled", false);
pref("browser.fixup.domainwhitelist.localhost", true);
pref("general.smoothScroll", true);
#ifdef UNIX_BUT_NOT_MAC
pref("general.autoScroll", false);
#else

View File

@ -22,7 +22,7 @@ skip-if = (debug && os == "win") || os == "mac" # bug 1393761, macosx1014 due to
[browser_devices_get_user_media_paused.js]
skip-if = (os == "win" && !debug) || (os =="linux" && !debug && bits == 64) || os == 'mac' # macosx1014 due to 1567735, Bug 1440900
[browser_devices_get_user_media_screen.js]
skip-if = (os == 'linux') || os == 'mac' # Bug 1503991, macosx1014 due to 1568135
skip-if = (os == 'linux') || (os == 'win' && debug && webrender) || os == 'mac' # Bug 1503991, macosx1014 due to 1568135, bug 1553579 for WR
[browser_devices_get_user_media_tear_off_tab.js]
[browser_devices_get_user_media_unprompted_access.js]
[browser_devices_get_user_media_unprompted_access_in_frame.js]

View File

@ -1349,7 +1349,6 @@ this.tabs = class extends ExtensionAPI {
printSettings.printSilent = true;
printSettings.showPrintProgress = false;
printSettings.printFrameType = Ci.nsIPrintSettings.kFramesAsIs;
printSettings.outputFormat =
Ci.nsIPrintSettings.kOutputFormatPDF;

View File

@ -82,6 +82,7 @@ skip-if = (verify && (os == 'linux' || os == 'mac'))
[browser_ext_commands_execute_sidebar_action.js]
[browser_ext_commands_getAll.js]
[browser_ext_commands_onCommand.js]
skip-if = (webrender && debug) # bug 1553577
[browser_ext_commands_update.js]
[browser_ext_connect_and_move_tabs.js]
[browser_ext_contentscript_connect.js]

View File

@ -33,14 +33,14 @@ add_task(async function testPageActionPopupResize() {
browser = await awaitExtensionPanel(extension);
async function checkSize(expected) {
async function checkSize(height, width) {
let dims = await promiseContentDimensions(browser);
let { body, root } = dims;
is(
dims.window.innerHeight,
expected,
`Panel window should be ${expected}px tall`
height,
`Panel window should be ${height}px tall`
);
is(
body.clientHeight,
@ -53,16 +53,20 @@ add_task(async function testPageActionPopupResize() {
"Panel root should be tall enough to fit its contents"
);
// Tolerate if it is 1px too wide, as that may happen with the current resizing method.
ok(
Math.abs(dims.window.innerWidth - expected) <= 1,
`Panel window should be ${expected}px wide`
);
is(
body.clientWidth,
body.scrollWidth,
"Panel body should be wide enough to fit its contents"
);
if (width) {
is(
body.clientWidth,
body.scrollWidth,
"Panel body should be wide enough to fit its contents"
);
// Tolerate if it is 1px too wide, as that may happen with the current
// resizing method.
ok(
Math.abs(dims.window.innerWidth - width) <= 1,
`Panel window should be ${width}px wide`
);
}
}
function setSize(size) {
@ -71,11 +75,17 @@ add_task(async function testPageActionPopupResize() {
elem.style.width = `${size}px`;
}
function setHeight(height) {
content.document.body.style.overflow = "hidden";
let elem = content.document.body.firstElementChild;
elem.style.height = `${height}px`;
}
let sizes = [200, 400, 300];
for (let size of sizes) {
await alterContent(browser, setSize, size);
await checkSize(size);
await checkSize(size, size);
}
let dims = await alterContent(browser, setSize, 1400);
@ -95,6 +105,11 @@ add_task(async function testPageActionPopupResize() {
);
is(root.scrollHeight, 1400, "Panel root scroll height");
for (let size of sizes) {
await alterContent(browser, setHeight, size);
await checkSize(size, null);
}
await extension.unload();
});

View File

@ -13,7 +13,7 @@ option(env='CBINDGEN', nargs=1, when=cbindgen_is_needed,
def check_cbindgen_version(cbindgen, fatal=False):
log.debug("trying cbindgen: %s" % cbindgen)
cbindgen_min_version = Version('0.9.1')
cbindgen_min_version = Version('0.11.1')
# cbindgen x.y.z
version = Version(check_cmd_output(cbindgen, '--version').strip().split(" ")[1])

View File

@ -81,6 +81,8 @@ skip-if = os == "mac" # Bug 1569508
fail-if = true # Bug 1547783
[browser_user_agent_input.js]
[browser_viewport_basics.js]
[browser_viewport_changed_meta.js]
[browser_viewport_resizing_after_reload.js]
[browser_viewport_resizing_fixed_width.js]
[browser_viewport_resizing_fixed_width_and_zoom.js]
[browser_viewport_resizing_minimum_scale.js]

View File

@ -0,0 +1,129 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that resolution is as expected when the viewport tag is changed.
// The page content is a 400 x 400 div in a 200 x 200 viewport. Initially,
// the viewport width is set to 800 at initial-scale 1, but then the tag
// content is changed. This triggers various rescale operations that will
// changge the resolution of the page after reflow.
// Chrome handles many of these cases differently. The Chrome results are
// included as TODOs, but labelled as "res_chrome" to indicate that the
// goal is not necessarily to match an agreed-upon standard, but to
// achieve web compatability through changing either Firefox or Chrome
// behavior.
info("--- Starting viewport test output ---");
const WIDTH = 200;
const HEIGHT = 200;
const INITIAL_CONTENT = "width=800, initial-scale=1";
const INITIAL_RES_TARGET = 1.0;
const TESTS = [
// This checks that when the replaced content matches the original content,
// we get the same values as the original values.
{ content: INITIAL_CONTENT, res_target: INITIAL_RES_TARGET },
// Section 1: Check the case of a viewport shrinking with the display width
// staying the same. In this case, the shrink will fit the max of the 400px
// content width and the viewport width into the 200px display area.
{ content: "width=200", res_target: 0.5 }, // fitting 400px content
{ content: "width=400", res_target: 0.5 }, // fitting 400px content/viewport
{ content: "width=500", res_target: 0.4 }, // fitting 500px viewport
// Section 2: Same as Section 1, but adds user-scalable=no. The expected
// results are similar to Section 1, but we ignore the content size and only
// adjust resolution to make the viewport fit into the display area.
{ content: "width=200, user-scalable=no", res_target: 1.0 },
{ content: "width=400, user-scalable=no", res_target: 0.5 },
{ content: "width=500, user-scalable=no", res_target: 0.4 },
// Section 3: Same as Section 1, but adds initial-scale=1. Initial-scale
// prevents content shrink in Firefox, so the viewport is scaled based on its
// changing size relative to the display area. In this case, the resolution
// is increased to maintain the proportional amount of the previously visible
// content. With the initial conditions, the display area was showing 1/4 of
// the content at 0.25x resolution. As the viewport width is shrunk, the
// resolution will increase to ensure that only 1/4 of the content is visible.
// Essentially, the new viewport width times the resolution will equal 800px,
// the original viewport width times resolution.
//
// Chrome treats the initial-scale=1 as inviolable and sets resolution to 1.0.
{ content: "width=200, initial-scale=1", res_target: 4.0, res_chrome: 1.0 },
{ content: "width=400, initial-scale=1", res_target: 2.0, res_chrome: 1.0 },
{ content: "width=500, initial-scale=1", res_target: 1.6, res_chrome: 1.0 },
// Section 4: Same as Section 3, but adds user-scalable=no. The combination
// of this and initial-scale=1 prevents the scaling-up of the resolution to
// keep the proportional amount of the previously visible content.
{ content: "width=200, initial-scale=1, user-scalable=no", res_target: 1.0 },
{ content: "width=400, initial-scale=1, user-scalable=no", res_target: 1.0 },
{ content: "width=500, initial-scale=1, user-scalable=no", res_target: 1.0 },
];
const TEST_URL =
`data:text/html;charset=utf-8,` +
`<html><head><meta name="viewport" content="${INITIAL_CONTENT}"></head>` +
`<body style="margin:0">` +
`<div id="box" style="width:400px;height:400px;background-color:green">` +
`Initial</div></body></html>`;
addRDMTask(
TEST_URL,
async function({ ui, manager, browser }) {
await setViewportSize(ui, manager, WIDTH, HEIGHT);
await setTouchAndMetaViewportSupport(ui, true);
// Check initial resolution value.
const initial_resolution = await spawnViewportTask(ui, {}, () => {
return content.windowUtils.getResolution();
});
is(
initial_resolution.toFixed(2),
INITIAL_RES_TARGET.toFixed(2),
`Initial resolution is as expected.`
);
for (const test of TESTS) {
const { content: content, res_target, res_chrome } = test;
await spawnViewportTask(ui, { content }, args => {
const box = content.document.getElementById("box");
box.textContent = args.content;
const meta = content.document.getElementsByTagName("meta")[0];
info(`Changing meta viewport content to "${args.content}".`);
meta.content = args.content;
});
await promiseContentReflow(ui);
const resolution = await spawnViewportTask(ui, {}, () => {
return content.windowUtils.getResolution();
});
is(
resolution.toFixed(2),
res_target.toFixed(2),
`Replaced meta viewport content "${content}" resolution is as expected.`
);
if (typeof res_chrome !== "undefined") {
todo_is(
resolution.toFixed(2),
res_chrome.toFixed(2),
`Replaced meta viewport content "${content}" resolution matches Chrome resolution.`
);
}
// Reload to prepare for next test.
const reload = waitForViewportLoad(ui);
browser.reload();
await reload;
}
},
{ usingBrowserUI: true }
);

View File

@ -0,0 +1,101 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test viewport resizing, with and without meta viewport support.
const TEST_URL =
"data:text/html;charset=utf-8," +
'<head><meta name="viewport" content="width=device-width"/></head>' +
'<body style="margin:0px;min-width:600px">' +
'<div style="width:100%;height:100px;background-color:black"></div>' +
'<div style="width:100%;height:1100px;background-color:lightblue"></div>' +
"</body>";
addRDMTask(TEST_URL, async function({ ui, manager }) {
// Turn on the pref that allows meta viewport support.
await SpecialPowers.pushPrefEnv({
set: [["devtools.responsive.metaViewport.enabled", true]],
});
const store = ui.toolWindow.store;
// Wait until the viewport has been added.
await waitUntilState(store, state => state.viewports.length == 1);
info("--- Starting viewport test output ---");
// We're going to take a 300,600 viewport (before), reload it,
// then resize it to 600,300 (after) and then resize it back.
// At the before and after points, we'll measure zoom and the
// layout viewport width and height.
const expected = [
{
metaSupport: false,
before: [1.0, 300, 600],
after: [1.0, 600, 300],
},
{
metaSupport: true,
before: [0.5, 600, 1200],
after: [1.0, 600, 300],
},
];
for (const e of expected) {
const b = e.before;
const a = e.after;
const message = "Meta Viewport " + (e.metaSupport ? "ON" : "OFF");
// Ensure meta viewport is set.
info(message + " setting meta viewport support.");
await setTouchAndMetaViewportSupport(ui, e.metaSupport);
// Get to the initial size and check values.
await setViewportSize(ui, manager, 300, 600);
await testViewportZoomWidthAndHeight(
message + " before resize",
ui,
b[0],
b[1],
b[2]
);
// Force a reload.
const reload = waitForViewportLoad(ui);
const browser = ui.getViewportBrowser();
browser.reload();
await reload;
// Check initial values again.
await testViewportZoomWidthAndHeight(
message + " after reload",
ui,
b[0],
b[1],
b[2]
);
// Move to the smaller size.
await setViewportSize(ui, manager, 600, 300);
await testViewportZoomWidthAndHeight(
message + " after resize",
ui,
a[0],
a[1],
a[2]
);
// Go back to the initial size and check again.
await setViewportSize(ui, manager, 300, 600);
await testViewportZoomWidthAndHeight(
message + " return to initial size",
ui,
b[0],
b[1],
b[2]
);
}
});

View File

@ -156,8 +156,11 @@ function addRDMTask(url, task) {
});
}
function spawnViewportTask(ui, args, task) {
return ContentTask.spawn(ui.getViewportBrowser(), args, task);
async function spawnViewportTask(ui, args, task) {
// Await a reflow after the task.
const result = await ContentTask.spawn(ui.getViewportBrowser(), args, task);
await promiseContentReflow(ui);
return result;
}
function waitForFrameLoad(ui, targetURL) {
@ -235,16 +238,7 @@ var setViewportSize = async function(ui, manager, width, height) {
// ensures that reflow of the viewport has completed.
var setViewportSizeAndAwaitReflow = async function(ui, manager, width, height) {
await setViewportSize(ui, manager, width, height);
const reflowed = ContentTask.spawn(
ui.getViewportBrowser(),
{},
async function() {
return new Promise(resolve => {
content.requestAnimationFrame(resolve);
});
}
);
await reflowed;
await promiseContentReflow(ui);
};
function getViewportDevicePixelRatio(ui) {
@ -707,6 +701,7 @@ async function setTouchAndMetaViewportSupport(ui, value) {
const browser = ui.getViewportBrowser();
browser.reload();
await reload;
await promiseContentReflow(ui);
}
return reloadNeeded;
}

View File

@ -154,6 +154,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"-moz-text-size-adjust",
"-webkit-text-stroke-width",
"text-transform",
"text-underline-position",
"touch-action",
"transform-box",
"transform-style",
@ -219,15 +220,12 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"padding-block-start",
"padding-inline-end",
"padding-inline-start",
"rotate",
"scale",
"-moz-script-level",
"-moz-top-layer",
"transition-delay",
"transition-duration",
"transition-property",
"transition-timing-function",
"translate",
"-moz-window-shadow",
]),
],
@ -287,10 +285,13 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"offset-rotate",
"order",
"perspective-origin",
"rotate",
"scale",
"shape-outside",
"stroke-dasharray",
"transform",
"transform-origin",
"translate",
"-moz-window-transform",
"-moz-window-transform-origin",
"-webkit-line-clamp",
@ -310,6 +311,8 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"bottom",
"column-gap",
"column-width",
"cx",
"cy",
"flex-basis",
"height",
"left",
@ -333,6 +336,9 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"padding-right",
"padding-top",
"perspective",
"r",
"rx",
"ry",
"right",
"row-gap",
"scroll-padding-block-start",
@ -362,6 +368,8 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"vertical-align",
"width",
"word-spacing",
"x",
"y",
"z-index",
]),
],

View File

@ -97,13 +97,13 @@ function getDocShellChromeEventHandler(docShell) {
}
function getChildDocShells(parentDocShell) {
const docShellsEnum = parentDocShell.getDocShellEnumerator(
const allDocShells = parentDocShell.getAllDocShellsInSubtree(
Ci.nsIDocShellTreeItem.typeAll,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
const docShells = [];
for (const docShell of docShellsEnum) {
for (const docShell of allDocShells) {
docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);

View File

@ -101,12 +101,12 @@ Timeline.prototype = {
return [];
}
const docShellsEnum = originalDocShell.getDocShellEnumerator(
const docShells = originalDocShell.getAllDocShellsInSubtree(
Ci.nsIDocShellTreeItem.typeAll,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
return Array.from(docShellsEnum);
return docShells;
},
/**

View File

@ -123,7 +123,11 @@ add_task(async function() {
const slottedChildren = await walker.children(shadowChildren.nodes[1]);
ok(slottedChildren.nodes[0].isBeforePseudoElement, "slot has ::before");
ok(slottedChildren.nodes[2].isAfterPseudoElement, "slot has ::after");
ok(
slottedChildren.nodes[slottedChildren.nodes.length - 1]
.isAfterPseudoElement,
"slot has ::after"
);
});
add_task(async function() {

View File

@ -829,6 +829,21 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"-moz-column-span": {
"isInherited": false,
"subproperties": [
"column-span"
],
"supports": [],
"values": [
"all",
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"-moz-column-width": {
"isInherited": false,
"subproperties": [
@ -3217,6 +3232,7 @@ exports.CSS_PROPERTIES = {
"text-rendering",
"-moz-control-character-visibility",
"text-underline-offset",
"text-underline-position",
"text-decoration-skip-ink",
"cursor",
"pointer-events",
@ -3309,6 +3325,13 @@ exports.CSS_PROPERTIES = {
"mask-size",
"mask-composite",
"mask-image",
"x",
"y",
"cx",
"cy",
"rx",
"ry",
"r",
"table-layout",
"text-overflow",
"text-decoration-line",
@ -5670,6 +5693,21 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"column-span": {
"isInherited": false,
"subproperties": [
"column-span"
],
"supports": [],
"values": [
"all",
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"column-width": {
"isInherited": false,
"subproperties": [
@ -5838,6 +5876,32 @@ exports.CSS_PROPERTIES = {
"zoom-out"
]
},
"cx": {
"isInherited": false,
"subproperties": [
"cx"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"cy": {
"isInherited": false,
"subproperties": [
"cy"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"direction": {
"isInherited": true,
"subproperties": [
@ -8246,6 +8310,32 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"offset": {
"isInherited": false,
"subproperties": [
"offset-path",
"offset-distance",
"offset-rotate",
"offset-anchor"
],
"supports": [],
"values": [
"auto",
"bottom",
"center",
"inherit",
"initial",
"left",
"none",
"path",
"ray",
"reverse",
"revert",
"right",
"top",
"unset"
]
},
"offset-anchor": {
"isInherited": false,
"subproperties": [
@ -9014,6 +9104,19 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"r": {
"isInherited": false,
"subproperties": [
"r"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"resize": {
"isInherited": false,
"subproperties": [
@ -9047,6 +9150,20 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"rotate": {
"isInherited": false,
"subproperties": [
"rotate"
],
"supports": [],
"values": [
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"row-gap": {
"isInherited": false,
"subproperties": [
@ -9093,6 +9210,48 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"rx": {
"isInherited": false,
"subproperties": [
"rx"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"ry": {
"isInherited": false,
"subproperties": [
"ry"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"revert",
"unset"
]
},
"scale": {
"isInherited": false,
"subproperties": [
"scale"
],
"supports": [],
"values": [
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"scroll-behavior": {
"isInherited": false,
"subproperties": [
@ -9906,6 +10065,21 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"text-decoration-skip-ink": {
"isInherited": true,
"subproperties": [
"text-decoration-skip-ink"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"text-decoration-style": {
"isInherited": false,
"subproperties": [
@ -9925,6 +10099,21 @@ exports.CSS_PROPERTIES = {
"wavy"
]
},
"text-decoration-thickness": {
"isInherited": false,
"subproperties": [
"text-decoration-thickness"
],
"supports": [],
"values": [
"auto",
"from-font",
"inherit",
"initial",
"revert",
"unset"
]
},
"text-emphasis": {
"isInherited": true,
"subproperties": [
@ -10138,6 +10327,38 @@ exports.CSS_PROPERTIES = {
"uppercase"
]
},
"text-underline-offset": {
"isInherited": true,
"subproperties": [
"text-underline-offset"
],
"supports": [],
"values": [
"auto",
"from-font",
"inherit",
"initial",
"revert",
"unset"
]
},
"text-underline-position": {
"isInherited": true,
"subproperties": [
"text-underline-position"
],
"supports": [],
"values": [
"auto",
"inherit",
"initial",
"left",
"revert",
"right",
"under",
"unset"
]
},
"top": {
"isInherited": false,
"subproperties": [
@ -10350,6 +10571,20 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"translate": {
"isInherited": false,
"subproperties": [
"translate"
],
"supports": [],
"values": [
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"unicode-bidi": {
"isInherited": false,
"subproperties": [
@ -10565,6 +10800,32 @@ exports.CSS_PROPERTIES = {
"vertical-rl"
]
},
"x": {
"isInherited": false,
"subproperties": [
"x"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"y": {
"isInherited": false,
"subproperties": [
"y"
],
"supports": [],
"values": [
"inherit",
"initial",
"revert",
"unset"
]
},
"z-index": {
"isInherited": false,
"subproperties": [
@ -10649,6 +10910,10 @@ exports.PREFERENCES = [
"text-justify",
"layout.css.text-justify.enabled"
],
[
"text-underline-position",
"layout.css.text-underline-position.enabled"
],
[
"touch-action",
"layout.css.touch_action.enabled"
@ -10725,14 +10990,14 @@ exports.PREFERENCES = [
"text-underline-offset",
"layout.css.text-underline-offset.enabled"
],
[
"offset-distance",
"layout.css.motion-path.enabled"
],
[
"-moz-binding",
"layout.css.moz-binding.content.enabled"
],
[
"offset-distance",
"layout.css.motion-path.enabled"
],
[
"overflow-clip-box",
"layout.css.overflow-clip-box.enabled"
@ -10741,6 +11006,14 @@ exports.PREFERENCES = [
"overscroll-behavior",
"layout.css.overscroll-behavior.enabled"
],
[
"offset",
"layout.css.motion-path.enabled"
],
[
"zoom",
"layout.css.zoom-transform-hack.enabled"
],
[
"-moz-transition-duration",
"layout.css.prefixes.transitions"

View File

@ -12,6 +12,7 @@
#include "nsISearchService.h"
#include "nsIURIFixup.h"
#include "nsIURIMutator.h"
#include "nsIWebNavigation.h"
#include "nsDefaultURIFixup.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/ContentChild.h"
@ -359,6 +360,27 @@ nsDefaultURIFixup::GetFixupURIInfo(const nsACString& aStringURI,
return rv;
}
NS_IMETHODIMP
nsDefaultURIFixup::WebNavigationFlagsToFixupFlags(const nsACString& aStringURI,
uint32_t aDocShellFlags,
uint32_t* aFixupFlags) {
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), aStringURI);
if (uri) {
aDocShellFlags &= ~nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
*aFixupFlags = 0;
if (aDocShellFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
*aFixupFlags |= FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
}
if (aDocShellFlags & nsIWebNavigation::LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
*aFixupFlags |= FIXUP_FLAG_FIX_SCHEME_TYPOS;
}
return NS_OK;
}
NS_IMETHODIMP
nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword,
nsIInputStream** aPostData,

View File

@ -1895,38 +1895,23 @@ nsDocShell::GetMayEnableCharacterEncodingMenu(
}
NS_IMETHODIMP
nsDocShell::GetDocShellEnumerator(int32_t aItemType,
DocShellEnumeratorDirection aDirection,
nsISimpleEnumerator** aResult) {
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nullptr;
nsDocShell::GetAllDocShellsInSubtree(int32_t aItemType,
DocShellEnumeratorDirection aDirection,
nsTArray<RefPtr<nsIDocShell>>& aResult) {
aResult.Clear();
RefPtr<nsDocShellEnumerator> docShellEnum;
if (aDirection == ENUMERATE_FORWARDS) {
docShellEnum = new nsDocShellForwardsEnumerator;
} else {
docShellEnum = new nsDocShellBackwardsEnumerator;
}
nsDocShellEnumerator docShellEnum(
(aDirection == ENUMERATE_FORWARDS)
? nsDocShellEnumerator::EnumerationDirection::Forwards
: nsDocShellEnumerator::EnumerationDirection::Backwards,
aItemType, *this);
nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
nsresult rv = docShellEnum.BuildDocShellArray(aResult);
if (NS_FAILED(rv)) {
return rv;
}
rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this);
if (NS_FAILED(rv)) {
return rv;
}
rv = docShellEnum->First();
if (NS_FAILED(rv)) {
return rv;
}
rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator),
(void**)aResult);
return rv;
return NS_OK;
}
NS_IMETHODIMP
@ -3388,6 +3373,15 @@ NS_IMETHODIMP
nsDocShell::GetInProcessChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild) {
NS_ENSURE_ARG_POINTER(aChild);
RefPtr<nsDocShell> child = GetInProcessChildAt(aIndex);
NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
child.forget(aChild);
return NS_OK;
}
nsDocShell* nsDocShell::GetInProcessChildAt(int32_t aIndex) {
#ifdef DEBUG
if (aIndex < 0) {
NS_WARNING("Negative index passed to GetChildAt");
@ -3397,9 +3391,9 @@ nsDocShell::GetInProcessChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild) {
#endif
nsIDocumentLoader* child = ChildAt(aIndex);
NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
return CallQueryInterface(child, aChild);
// child may be nullptr here.
return static_cast<nsDocShell*>(child);
}
NS_IMETHODIMP
@ -3905,10 +3899,6 @@ nsresult nsDocShell::LoadURI(const nsAString& aURI,
nsCOMPtr<nsIInputStream> postData(aLoadURIOptions.mPostData);
nsresult rv = NS_OK;
// Create a URI from our string; if that succeeds, we want to
// change loadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
// flag.
NS_ConvertUTF16toUTF8 uriString(aURI);
// Cleanup the empty spaces that might be on each end.
uriString.Trim(" ");
@ -3920,24 +3910,19 @@ nsresult nsDocShell::LoadURI(const nsAString& aURI,
return NS_ERROR_FAILURE;
}
rv = NS_NewURI(getter_AddRefs(uri), uriString);
if (uri) {
loadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
nsCOMPtr<nsIURIFixupInfo> fixupInfo;
if (sURIFixup) {
// Call the fixup object. This will clobber the rv from NS_NewURI
// above, but that's fine with us. Note that we need to do this even
// if NS_NewURI returned a URI, because fixup handles nested URIs, etc
// (things like view-source:mozilla.org for example).
uint32_t fixupFlags = 0;
if (loadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
}
if (loadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
uint32_t fixupFlags;
rv = sURIFixup->WebNavigationFlagsToFixupFlags(uriString, loadFlags,
&fixupFlags);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
// If we don't allow keyword lookups for this URL string, make sure to
// update loadFlags to indicate this as well.
if (!(fixupFlags & nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) {
loadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
nsCOMPtr<nsIInputStream> fixupStream;
rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
getter_AddRefs(fixupStream),
@ -3962,9 +3947,11 @@ nsresult nsDocShell::LoadURI(const nsAString& aURI,
PromiseFlatString(aURI).get());
}
}
} else {
// No fixup service so just create a URI and see what happens...
rv = NS_NewURI(getter_AddRefs(uri), uriString);
loadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
}
// else no fixup service so just use the URI we created and see
// what happens
if (NS_ERROR_MALFORMED_URI == rv) {
if (DisplayLoadError(rv, uri, PromiseFlatString(aURI).get(), nullptr) &&

View File

@ -471,6 +471,8 @@ class nsDocShell final : public nsDocLoader,
mSkipBrowsingContextDetachOnDestroy = true;
}
nsDocShell* GetInProcessChildAt(int32_t aIndex);
private: // member functions
friend class nsDSURIContentListener;
friend class FramingChecker;
@ -506,8 +508,7 @@ class nsDocShell final : public nsDocLoader,
nsIDocShellTreeItem* aTargetTreeItem);
static inline uint32_t PRTimeToSeconds(PRTime aTimeUsec) {
PRTime usecPerSec = PR_USEC_PER_SEC;
return uint32_t(aTimeUsec /= usecPerSec);
return uint32_t(aTimeUsec / PR_USEC_PER_SEC);
}
static const nsCString FrameTypeToString(uint32_t aFrameType) {

View File

@ -4,135 +4,47 @@
#include "nsDocShellEnumerator.h"
#include "nsIDocShellTreeItem.h"
#include "nsDocShell.h"
nsDocShellEnumerator::nsDocShellEnumerator(int32_t aEnumerationDirection)
: mRootItem(nullptr),
mCurIndex(0),
mDocShellType(nsIDocShellTreeItem::typeAll),
mArrayValid(false),
mEnumerationDirection(aEnumerationDirection) {}
nsDocShellEnumerator::~nsDocShellEnumerator() {}
NS_IMETHODIMP
nsDocShellEnumerator::GetNext(nsISupports** aResult) {
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nullptr;
nsresult rv = EnsureDocShellArray();
if (NS_FAILED(rv)) {
return rv;
}
if (mCurIndex >= mItemArray.Length()) {
return NS_ERROR_FAILURE;
}
// post-increment is important here
nsCOMPtr<nsISupports> item = do_QueryReferent(mItemArray[mCurIndex++], &rv);
item.forget(aResult);
return rv;
}
NS_IMETHODIMP
nsDocShellEnumerator::HasMoreElements(bool* aResult) {
NS_ENSURE_ARG_POINTER(aResult);
*aResult = false;
nsresult rv = EnsureDocShellArray();
if (NS_FAILED(rv)) {
return rv;
}
*aResult = (mCurIndex < mItemArray.Length());
return NS_OK;
}
nsresult nsDocShellEnumerator::GetEnumerationRootItem(
nsIDocShellTreeItem** aEnumerationRootItem) {
NS_ENSURE_ARG_POINTER(aEnumerationRootItem);
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryReferent(mRootItem);
item.forget(aEnumerationRootItem);
return NS_OK;
}
nsresult nsDocShellEnumerator::SetEnumerationRootItem(
nsIDocShellTreeItem* aEnumerationRootItem) {
mRootItem = do_GetWeakReference(aEnumerationRootItem);
ClearState();
return NS_OK;
}
nsresult nsDocShellEnumerator::GetEnumDocShellType(
int32_t* aEnumerationItemType) {
NS_ENSURE_ARG_POINTER(aEnumerationItemType);
*aEnumerationItemType = mDocShellType;
return NS_OK;
}
nsresult nsDocShellEnumerator::SetEnumDocShellType(
int32_t aEnumerationItemType) {
mDocShellType = aEnumerationItemType;
ClearState();
return NS_OK;
}
nsresult nsDocShellEnumerator::First() {
mCurIndex = 0;
return EnsureDocShellArray();
}
nsresult nsDocShellEnumerator::EnsureDocShellArray() {
if (!mArrayValid) {
mArrayValid = true;
return BuildDocShellArray(mItemArray);
}
return NS_OK;
}
nsresult nsDocShellEnumerator::ClearState() {
mItemArray.Clear();
mArrayValid = false;
mCurIndex = 0;
return NS_OK;
}
nsDocShellEnumerator::nsDocShellEnumerator(
nsDocShellEnumerator::EnumerationDirection aDirection,
int32_t aDocShellType, nsDocShell& aRootItem)
: mRootItem(&aRootItem),
mDocShellType(aDocShellType),
mDirection(aDirection) {}
nsresult nsDocShellEnumerator::BuildDocShellArray(
nsTArray<nsWeakPtr>& aItemArray) {
NS_ENSURE_TRUE(mRootItem, NS_ERROR_NOT_INITIALIZED);
nsTArray<RefPtr<nsIDocShell>>& aItemArray) {
MOZ_ASSERT(mRootItem);
aItemArray.Clear();
nsCOMPtr<nsIDocShellTreeItem> item = do_QueryReferent(mRootItem);
return BuildArrayRecursive(item, aItemArray);
if (mDirection == EnumerationDirection::Forwards) {
return BuildArrayRecursiveForwards(mRootItem, aItemArray);
}
MOZ_ASSERT(mDirection == EnumerationDirection::Backwards);
return BuildArrayRecursiveBackwards(mRootItem, aItemArray);
}
nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(
nsIDocShellTreeItem* aItem, nsTArray<nsWeakPtr>& aItemArray) {
nsresult nsDocShellEnumerator::BuildArrayRecursiveForwards(
nsDocShell* aItem, nsTArray<RefPtr<nsIDocShell>>& aItemArray) {
nsresult rv;
// add this item to the array
if (mDocShellType == nsIDocShellTreeItem::typeAll ||
aItem->ItemType() == mDocShellType) {
if (!aItemArray.AppendElement(do_GetWeakReference(aItem))) {
if (!aItemArray.AppendElement(aItem, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
int32_t numChildren;
rv = aItem->GetInProcessChildCount(&numChildren);
if (NS_FAILED(rv)) {
return rv;
}
int32_t numChildren = aItem->ChildCount();
for (int32_t i = 0; i < numChildren; ++i) {
nsCOMPtr<nsIDocShellTreeItem> curChild;
rv = aItem->GetInProcessChildAt(i, getter_AddRefs(curChild));
if (NS_FAILED(rv)) {
return rv;
}
RefPtr<nsDocShell> curChild = aItem->GetInProcessChildAt(i);
MOZ_ASSERT(curChild);
rv = BuildArrayRecursive(curChild, aItemArray);
rv = BuildArrayRecursiveForwards(curChild, aItemArray);
if (NS_FAILED(rv)) {
return rv;
}
@ -141,24 +53,17 @@ nsresult nsDocShellForwardsEnumerator::BuildArrayRecursive(
return NS_OK;
}
nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(
nsIDocShellTreeItem* aItem, nsTArray<nsWeakPtr>& aItemArray) {
nsresult nsDocShellEnumerator::BuildArrayRecursiveBackwards(
nsDocShell* aItem, nsTArray<RefPtr<nsIDocShell>>& aItemArray) {
nsresult rv;
int32_t numChildren;
rv = aItem->GetInProcessChildCount(&numChildren);
if (NS_FAILED(rv)) {
return rv;
}
uint32_t numChildren = aItem->ChildCount();
for (int32_t i = numChildren - 1; i >= 0; --i) {
nsCOMPtr<nsIDocShellTreeItem> curChild;
rv = aItem->GetInProcessChildAt(i, getter_AddRefs(curChild));
if (NS_FAILED(rv)) {
return rv;
}
RefPtr<nsDocShell> curChild = aItem->GetInProcessChildAt(i);
MOZ_ASSERT(curChild);
rv = BuildArrayRecursive(curChild, aItemArray);
rv = BuildArrayRecursiveBackwards(curChild, aItemArray);
if (NS_FAILED(rv)) {
return rv;
}
@ -167,7 +72,7 @@ nsresult nsDocShellBackwardsEnumerator::BuildArrayRecursive(
// add this item to the array
if (mDocShellType == nsIDocShellTreeItem::typeAll ||
aItem->ItemType() == mDocShellType) {
if (!aItemArray.AppendElement(do_GetWeakReference(aItem))) {
if (!aItemArray.AppendElement(aItem)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}

View File

@ -5,89 +5,33 @@
#ifndef nsDocShellEnumerator_h___
#define nsDocShellEnumerator_h___
#include "nsSimpleEnumerator.h"
#include "nsTArray.h"
#include "nsIWeakReferenceUtils.h"
class nsIDocShellTreeItem;
class nsDocShell;
class nsIDocShell;
/*
// {13cbc281-35ae-11d5-be5b-bde0edece43c}
#define NS_DOCSHELL_FORWARDS_ENUMERATOR_CID \
{ 0x13cbc281, 0x35ae, 0x11d5, { 0xbe, 0x5b, 0xbd, 0xe0, 0xed, 0xec, 0xe4, 0x3c }
}
class MOZ_STACK_CLASS nsDocShellEnumerator {
public:
enum class EnumerationDirection : uint8_t { Forwards, Backwards };
#define NS_DOCSHELL_FORWARDS_ENUMERATOR_CONTRACTID \
"@mozilla.org/docshell/enumerator-forwards;1"
// {13cbc282-35ae-11d5-be5b-bde0edece43c}
#define NS_DOCSHELL_BACKWARDS_ENUMERATOR_CID \
{ 0x13cbc282, 0x35ae, 0x11d5, { 0xbe, 0x5b, 0xbd, 0xe0, 0xed, 0xec, 0xe4, 0x3c }
}
#define NS_DOCSHELL_BACKWARDS_ENUMERATOR_CONTRACTID \
"@mozilla.org/docshell/enumerator-backwards;1"
*/
class nsDocShellEnumerator : public nsSimpleEnumerator {
protected:
enum { enumerateForwards, enumerateBackwards };
virtual ~nsDocShellEnumerator();
nsDocShellEnumerator(EnumerationDirection aDirection, int32_t aDocShellType,
nsDocShell& aRootItem);
public:
explicit nsDocShellEnumerator(int32_t aEnumerationDirection);
nsresult BuildDocShellArray(nsTArray<RefPtr<nsIDocShell>>& aItemArray);
// nsISimpleEnumerator
NS_DECL_NSISIMPLEENUMERATOR
private:
nsresult BuildArrayRecursiveForwards(
nsDocShell* aItem, nsTArray<RefPtr<nsIDocShell>>& aItemArray);
nsresult BuildArrayRecursiveBackwards(
nsDocShell* aItem, nsTArray<RefPtr<nsIDocShell>>& aItemArray);
const nsID& DefaultInterface() override { return NS_GET_IID(nsIDocShell); }
private:
const RefPtr<nsDocShell> mRootItem;
public:
nsresult GetEnumerationRootItem(nsIDocShellTreeItem** aEnumerationRootItem);
nsresult SetEnumerationRootItem(nsIDocShellTreeItem* aEnumerationRootItem);
const int32_t mDocShellType; // only want shells of this type
nsresult GetEnumDocShellType(int32_t* aEnumerationItemType);
nsresult SetEnumDocShellType(int32_t aEnumerationItemType);
nsresult First();
protected:
nsresult EnsureDocShellArray();
nsresult ClearState();
nsresult BuildDocShellArray(nsTArray<nsWeakPtr>& aItemArray);
virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* aItem,
nsTArray<nsWeakPtr>& aItemArray) = 0;
protected:
nsWeakPtr mRootItem; // weak ref!
nsTArray<nsWeakPtr> mItemArray; // flattened list of items with matching type
uint32_t mCurIndex;
int32_t mDocShellType; // only want shells of this type
bool mArrayValid; // is mItemArray up to date?
const int8_t mEnumerationDirection;
};
class nsDocShellForwardsEnumerator : public nsDocShellEnumerator {
public:
nsDocShellForwardsEnumerator() : nsDocShellEnumerator(enumerateForwards) {}
protected:
virtual nsresult BuildArrayRecursive(
nsIDocShellTreeItem* aItem, nsTArray<nsWeakPtr>& aItemArray) override;
};
class nsDocShellBackwardsEnumerator : public nsDocShellEnumerator {
public:
nsDocShellBackwardsEnumerator() : nsDocShellEnumerator(enumerateBackwards) {}
protected:
virtual nsresult BuildArrayRecursive(
nsIDocShellTreeItem* aItem, nsTArray<nsWeakPtr>& aItemArray) override;
const EnumerationDirection mDirection;
};
#endif // nsDocShellEnumerator_h___

View File

@ -45,7 +45,6 @@ interface nsIContentSecurityPolicy;
interface nsIDocShellLoadInfo;
interface nsIEditor;
interface nsIEditingSession;
interface nsISimpleEnumerator;
interface nsIInputStream;
interface nsIRequest;
interface nsISHEntry;
@ -250,7 +249,7 @@ interface nsIDocShell : nsIDocShellTreeItem
[infallible] attribute boolean inheritPrivateBrowsingId;
/**
* Get an enumerator over this docShell and its children.
* Get an array of this docShell and its children.
*
* @param aItemType - Only include docShells of this type, or if typeAll,
* include all child shells.
@ -263,8 +262,8 @@ interface nsIDocShell : nsIDocShellTreeItem
ENUMERATE_BACKWARDS = 1
};
nsISimpleEnumerator getDocShellEnumerator(in long aItemType,
in nsIDocShell_DocShellEnumeratorDirection aDirection);
Array<nsIDocShell> getAllDocShellsInSubtree(in long aItemType,
in nsIDocShell_DocShellEnumeratorDirection aDirection);
/**
* The type of application that created this window.

View File

@ -133,6 +133,17 @@ interface nsIURIFixup : nsISupports
in unsigned long aFixupFlags,
[optional] out nsIInputStream aPostData);
/**
* Convert load flags from nsIWebNavigation to URI fixup flags for use in
* createFixupURI or getFixupURIInfo.
*
* @param aURIText Candidate URI; used for determining whether to
* allow keyword lookups.
* @param aDocShellFlags Load flags from nsIDocShell to convert.
*/
unsigned long webNavigationFlagsToFixupFlags(
in AUTF8String aURIText, in unsigned long aDocShellFlags);
/**
* Converts the specified keyword string into a URI. Note that it's the
* caller's responsibility to check whether keywords are enabled and

View File

@ -31,10 +31,8 @@ addEventListener("unload", e => {
});
function getChildDocShells() {
let docShellsEnum = docShell.getDocShellEnumerator(
return docShell.getAllDocShellsInSubtree(
Ci.nsIDocShellTreeItem.typeAll,
Ci.nsIDocShell.ENUMERATE_FORWARDS
);
return Array.from(docShellsEnum);
}

View File

@ -81,17 +81,14 @@ skip-if = (verify && !debug && (os == 'win'))
skip-if = (verify && !debug && (os == 'win'))
[test_bug590573.html]
[test_bug598895.html]
skip-if = toolkit == 'android'
[test_bug634834.html]
[test_bug637644.html]
skip-if = toolkit == 'android'
[test_bug640387_1.html]
[test_bug640387_2.html]
[test_bug653741.html]
[test_bug660404.html]
[test_bug662170.html]
[test_bug668513.html]
skip-if = toolkit == 'android'
support-files = file_bug668513.html
[test_bug669671.html]
[test_bug675587.html]
@ -111,7 +108,6 @@ support-files = file_bug675587.html
[test_close_onpagehide_by_window_close.html]
[test_forceinheritprincipal_overrule_owner.html]
[test_framedhistoryframes.html]
skip-if = toolkit == 'android' # bug 784321
support-files = file_framedhistoryframes.html
[test_pushState_after_document_open.html]
[test_windowedhistoryframes.html]

View File

@ -972,7 +972,7 @@ bool Animation::ShouldBeSynchronizedWithMainThread(
}
return keyframeEffect->ShouldBlockAsyncTransformAnimations(
aFrame, aPerformanceWarning);
aFrame, aPropertySet, aPerformanceWarning);
}
void Animation::UpdateRelevance() {

View File

@ -57,6 +57,9 @@ bool AnimationPerformanceWarning::ToLocalizedString(
case Type::TransformFrameInactive:
key = "CompositorAnimationWarningTransformFrameInactive";
break;
case Type::TransformIsBlockedByImportantRules:
key = "CompositorAnimationWarningTransformIsBlockedByImportantRules";
break;
case Type::OpacityFrameInactive:
key = "CompositorAnimationWarningOpacityFrameInactive";
break;

View File

@ -25,6 +25,7 @@ struct AnimationPerformanceWarning {
TransformWithGeometricProperties,
TransformWithSyncGeometricAnimations,
TransformFrameInactive,
TransformIsBlockedByImportantRules,
OpacityFrameInactive,
HasRenderingObserver,
};

View File

@ -137,14 +137,6 @@ bool FindAnimationsForCompositor(
}
}
// If the property will be added to the animations level of the cascade but
// there is an !important rule for that property in the cascade then the
// animation will not be applied since the !important rule overrides it.
if (effects->PropertiesWithImportantRules().Intersects(aPropertySet) &&
effects->PropertiesForAnimationsLevel().Intersects(aPropertySet)) {
return false;
}
AnimationPerformanceWarning::Type warning =
AnimationPerformanceWarning::Type::None;
if (!EffectCompositor::AllowCompositorAnimationsOnFrame(aFrame, warning)) {
@ -283,15 +275,15 @@ void EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
}
RestyleHint hint = aCascadeLevel == CascadeLevel::Transitions
? StyleRestyleHint_RESTYLE_CSS_TRANSITIONS
: StyleRestyleHint_RESTYLE_CSS_ANIMATIONS;
? RestyleHint::RESTYLE_CSS_TRANSITIONS
: RestyleHint::RESTYLE_CSS_ANIMATIONS;
MOZ_ASSERT(NS_IsMainThread(),
"Restyle request during restyling should be requested only on "
"the main-thread. e.g. after the parallel traversal");
if (ServoStyleSet::IsInServoTraversal() || mIsInPreTraverse) {
MOZ_ASSERT(hint == StyleRestyleHint_RESTYLE_CSS_ANIMATIONS ||
hint == StyleRestyleHint_RESTYLE_CSS_TRANSITIONS);
MOZ_ASSERT(hint == RestyleHint::RESTYLE_CSS_ANIMATIONS ||
hint == RestyleHint::RESTYLE_CSS_TRANSITIONS);
// We can't call Servo_NoteExplicitHints here since AtomicRefCell does not
// allow us mutate ElementData of the |aElement| in SequentialTask.
@ -892,8 +884,8 @@ bool EffectCompositor::PreTraverseInSubtree(ServoTraversalFlags aFlags,
mPresContext->RestyleManager()->PostRestyleEventForAnimations(
target.mElement, target.mPseudoType,
cascadeLevel == CascadeLevel::Transitions
? StyleRestyleHint_RESTYLE_CSS_TRANSITIONS
: StyleRestyleHint_RESTYLE_CSS_ANIMATIONS);
? RestyleHint::RESTYLE_CSS_TRANSITIONS
: RestyleHint::RESTYLE_CSS_ANIMATIONS);
foundElementsNeedingRestyle = true;

View File

@ -279,35 +279,13 @@ const AnimationProperty* KeyframeEffect::GetEffectiveAnimationOfProperty(
bool KeyframeEffect::HasEffectiveAnimationOfPropertySet(
const nsCSSPropertyIDSet& aPropertySet, const EffectSet& aEffectSet) const {
// The various transform properties ('transform', 'scale' etc.) get combined
// on the compositor.
//
// As a result, if we have an animation of 'scale' and 'translate', but the
// 'translate' property is covered by an !important rule, we will not be
// able to combine the result on the compositor since we won't have the
// !important rule to incorporate. In that case we should run all the
// transform-related animations on the main thread (where we have the
// !important rule).
//
// Bug 1534884: Move this check to ShouldBlockAsyncTransformAnimations (or
// similar) and add a performance warning for this case.
bool result = false;
for (const AnimationProperty& property : mProperties) {
if (!aPropertySet.HasProperty(property.mProperty)) {
continue;
}
if (IsEffectiveProperty(aEffectSet, property.mProperty)) {
result = true;
} else if (nsCSSPropertyIDSet::TransformLikeProperties().HasProperty(
property.mProperty)) {
return false;
if (aPropertySet.HasProperty(property.mProperty) &&
IsEffectiveProperty(aEffectSet, property.mProperty)) {
return true;
}
}
return result;
return false;
}
nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
@ -323,22 +301,44 @@ nsCSSPropertyIDSet KeyframeEffect::GetPropertiesForCompositor(
static constexpr nsCSSPropertyIDSet compositorAnimatables =
nsCSSPropertyIDSet::CompositorAnimatables();
static constexpr nsCSSPropertyIDSet transformLikeProperties =
nsCSSPropertyIDSet::TransformLikeProperties();
nsCSSPropertyIDSet transformSet;
AnimationPerformanceWarning::Type dummyWarning;
for (const AnimationProperty& property : mProperties) {
if (!compositorAnimatables.HasProperty(property.mProperty)) {
continue;
}
AnimationPerformanceWarning::Type warning;
// Transform-like properties are combined together on the compositor so we
// need to evaluate them as a group. We build up a separate set here then
// evaluate it as a separate step below.
if (transformLikeProperties.HasProperty(property.mProperty)) {
transformSet.AddProperty(property.mProperty);
continue;
}
KeyframeEffect::MatchForCompositor matchResult = IsMatchForCompositor(
nsCSSPropertyIDSet{property.mProperty}, aFrame, aEffects, warning);
nsCSSPropertyIDSet{property.mProperty}, aFrame, aEffects, dummyWarning);
if (matchResult ==
KeyframeEffect::MatchForCompositor::NoAndBlockThisProperty ||
matchResult == KeyframeEffect::MatchForCompositor::No) {
continue;
}
properties.AddProperty(property.mProperty);
}
if (!transformSet.IsEmpty()) {
KeyframeEffect::MatchForCompositor matchResult =
IsMatchForCompositor(transformSet, aFrame, aEffects, dummyWarning);
if (matchResult == KeyframeEffect::MatchForCompositor::Yes ||
matchResult == KeyframeEffect::MatchForCompositor::IfNeeded) {
properties |= transformSet;
}
}
return properties;
}
@ -1185,7 +1185,25 @@ void KeyframeEffect::GetKeyframes(JSContext*& aCx, nsTArray<JSObject*>& aResult,
}
}
const char* name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
// Basically, we need to do the mapping:
// * eCSSProperty_offset => "cssOffset"
// * eCSSProperty_float => "cssFloat"
// This means if property refers to the CSS "offset"/"float" property,
// return the string "cssOffset"/"cssFloat". (So avoid overlapping
// "offset" property in BaseKeyframe.)
// https://drafts.csswg.org/web-animations/#property-name-conversion
const char* name = nullptr;
switch (propertyValue.mProperty) {
case nsCSSPropertyID::eCSSProperty_offset:
name = "cssOffset";
break;
case nsCSSPropertyID::eCSSProperty_float:
// FIXME: Bug 1582314: Should handle cssFloat manually if we remove it
// from nsCSSProps::PropertyIDLName().
default:
name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
}
JS::Rooted<JS::Value> value(aCx);
if (!ToJSValue(aCx, stringValue, &value) ||
!JS_DefineProperty(aCx, keyframeObject, name, value,
@ -1495,10 +1513,28 @@ bool KeyframeEffect::CanAnimateTransformOnCompositor(
}
bool KeyframeEffect::ShouldBlockAsyncTransformAnimations(
const nsIFrame* aFrame,
const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet,
AnimationPerformanceWarning::Type& aPerformanceWarning /* out */) const {
EffectSet* effectSet =
EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
// The various transform properties ('transform', 'scale' etc.) get combined
// on the compositor.
//
// As a result, if we have an animation of 'scale' and 'translate', but the
// 'translate' property is covered by an !important rule, we will not be
// able to combine the result on the compositor since we won't have the
// !important rule to incorporate. In that case we should run all the
// transform-related animations on the main thread (where we have the
// !important rule).
nsCSSPropertyIDSet blockedProperties =
effectSet->PropertiesWithImportantRules().Intersect(
effectSet->PropertiesForAnimationsLevel());
if (blockedProperties.Intersects(aPropertySet)) {
aPerformanceWarning =
AnimationPerformanceWarning::Type::TransformIsBlockedByImportantRules;
return true;
}
for (const AnimationProperty& property : mProperties) {
// If there is a property for animations level that is overridden by
// !important rules, it should not block other animations from running
@ -1586,7 +1622,8 @@ void KeyframeEffect::CalculateCumulativeChangeHint(
mNeedsStyleData = false;
nsPresContext* presContext =
nsContentUtils::GetContextForContent(mTarget->mElement);
mTarget ? nsContentUtils::GetContextForContent(mTarget->mElement)
: nullptr;
if (!presContext) {
// Change hints make no sense if we're not rendered.
//

View File

@ -200,9 +200,10 @@ class KeyframeEffect : public AnimationEffect {
// this function is typically called for all KeyframeEffects on an element
// so that we can avoid multiple calls of EffectSet::GetEffect().
//
// NOTE: Unlike HasEffectiveAnimationOfPropertySet below, this function does
// not check for the effect of !important rules on animations of related
// transform properties.
// Note that does not consider the interaction between related transform
// properties where an !important rule on another transform property may
// cause all transform properties to be run on the main thread. That check is
// performed by GetPropertiesForCompositor.
bool HasEffectiveAnimationOfProperty(nsCSSPropertyID aProperty,
const EffectSet& aEffect) const {
return GetEffectiveAnimationOfProperty(aProperty, aEffect) != nullptr;
@ -215,16 +216,10 @@ class KeyframeEffect : public AnimationEffect {
// one property in |aPropertySet| that is not overridden by an !important
// rule.
//
// Unlike HasEffectiveAnimationOfProperty, however, when |aPropertySet|
// includes transform-like properties (transform, rotate etc.) this function
// returns true if and only if all the transform-like properties that are
// present are effective.
//
// That is because the transform-like properties, unlike other properties, are
// combined on the compositor and if !important rules affect any of the
// individual properties we will not be able to correctly compose the result
// on the compositor so we should run the animations on the main thread
// instead.
// Note that does not consider the interaction between related transform
// properties where an !important rule on another transform property may
// cause all transform properties to be run on the main thread. That check is
// performed by GetPropertiesForCompositor.
bool HasEffectiveAnimationOfPropertySet(
const nsCSSPropertyIDSet& aPropertySet,
const EffectSet& aEffectSet) const;
@ -278,7 +273,7 @@ class KeyframeEffect : public AnimationEffect {
// When returning true, |aPerformanceWarning| stores the reason why
// we shouldn't run the transform animations.
bool ShouldBlockAsyncTransformAnimations(
const nsIFrame* aFrame,
const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet,
AnimationPerformanceWarning::Type& aPerformanceWarning /* out */) const;
bool HasGeometricProperties() const;
bool AffectsGeometry() const override {

View File

@ -504,8 +504,24 @@ static bool GetPropertyValuesPairs(JSContext* aCx,
if (!propName.init(aCx, ids[i])) {
return false;
}
nsCSSPropertyID property = nsCSSProps::LookupPropertyByIDLName(
propName, CSSEnabledState::ForAllContent);
// Basically, we have to handle "cssOffset" and "cssFloat" specially here:
// "cssOffset" => eCSSProperty_offset
// "cssFloat" => eCSSProperty_float
// This means if the attribute is the string "cssOffset"/"cssFloat", we use
// CSS "offset"/"float" property.
// https://drafts.csswg.org/web-animations/#property-name-conversion
nsCSSPropertyID property = nsCSSPropertyID::eCSSProperty_UNKNOWN;
if (propName.EqualsLiteral("cssOffset")) {
property = nsCSSPropertyID::eCSSProperty_offset;
} else if (propName.EqualsLiteral("cssFloat")) {
property = nsCSSPropertyID::eCSSProperty_float;
} else if (!propName.EqualsLiteral("offset") &&
!propName.EqualsLiteral("float")) {
property = nsCSSProps::LookupPropertyByIDLName(
propName, CSSEnabledState::ForAllContent);
}
if (KeyframeUtils::IsAnimatableProperty(property)) {
AdditionalProperty* p = properties.AppendElement();
p->mProperty = property;

View File

@ -4,6 +4,7 @@ prefs =
dom.animations-api.compositing.enabled=true
gfx.omta.background-color=true
layout.css.individual-transform.enabled=true
layout.css.motion-path.enabled=true
support-files =
testcommon.js
../../imptests/testharness.js

View File

@ -1602,6 +1602,48 @@ function testTransformSVG() {
});
}
function testImportantRuleOverride() {
promise_test(async t => {
const elem = addDiv(t, { class: 'compositable' });
const anim = elem.animate({ translate: [ '0px', '100px' ],
rotate: ['0deg', '90deg'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(anim);
await waitForPaints();
assert_animation_property_state_equals(
anim.effect.getProperties(),
[ { property: 'translate', runningOnCompositor: true },
{ property: 'rotate', runningOnCompositor: true } ]
);
elem.style.setProperty('rotate', '45deg', 'important');
getComputedStyle(elem).rotate;
await waitForFrame();
assert_animation_property_state_equals(
anim.effect.getProperties(),
[
{
property: 'translate',
runningOnCompositor: false,
warning:
'CompositorAnimationWarningTransformIsBlockedByImportantRules'
},
{
property: 'rotate',
runningOnCompositor: false,
warning:
'CompositorAnimationWarningTransformIsBlockedByImportantRules'
},
]
);
}, 'The animations of transform-like properties are not running on the ' +
'compositor because any of the properties has important rules');
}
function start() {
var bundleService = SpecialPowers.Cc['@mozilla.org/intl/stringbundle;1']
.getService(SpecialPowers.Ci.nsIStringBundleService);
@ -1620,6 +1662,7 @@ function start() {
testSynchronizedAnimations();
testTooLargeFrame();
testTransformSVG();
testImportantRuleOverride();
promise_test(async t => {
var div = addDiv(t, { class: 'compositable',

View File

@ -1115,12 +1115,134 @@ promise_test(async t => {
});
}, 'Multiple transform-like properties animation runs on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ offsetPath: ['none', 'none'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'offset-path animation should be running on the compositor even if ' +
'it is always none');
}, 'offset-path none animation runs on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ offsetPath: ['path("M0 0l100 100")',
'path("M0 0l200 200")'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'offset-path animation should be running on the compositor');
}, 'offset-path animation runs on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ offsetDistance: ['0%', '100%'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_not_running_on_compositor(animation,
'offset-distance animation is not running on the compositor because ' +
'offset-path is none');
const newAnim = div.animate({ offsetPath: ['None', 'None'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(newAnim);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'offset-distance animation should be running on the compositor');
assert_animation_is_running_on_compositor(newAnim,
'new added offset-path animation should be running on the compositor');
}, 'offset-distance animation runs on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ offsetRotate: ['0deg', '45deg'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_not_running_on_compositor(animation,
'offset-rotate animation is not running on the compositor because ' +
'offset-path is none');
const newAnim = div.animate({ offsetPath: ['None', 'None'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(newAnim);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'offset-rotate animation should be running on the compositor');
assert_animation_is_running_on_compositor(newAnim,
'new added offset-path animation should be running on the compositor');
}, 'offset-rotate animation runs on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ offsetAnchor: ['0% 0%', '100% 100%'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_not_running_on_compositor(animation,
'offset-anchor animation is not running on the compositor because ' +
'offset-path is none');
const newAnim = div.animate({ offsetPath: ['None', 'None'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(newAnim);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'offset-anchor animation should be running on the compositor');
assert_animation_is_running_on_compositor(newAnim,
'new added offset-path animation should be running on the compositor');
}, 'offset-anchor animation runs on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ translate: ['0px', '100px'],
rotate: ['0deg', '45deg'],
transform: ['translate(0px)',
'translate(100px)'],
offsetDistance: ['0%', '100%'] },
100 * MS_PER_SEC);
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'Animation is running on the compositor even though we do not have ' +
'offset-path');
div.style.offsetPath = 'path("M50 0v100")';
getComputedStyle(div).offsetPath;
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'Animation is running on the compositor');
}, 'Multiple transform-like properties (include motion-path) animation runs ' +
'on the compositor');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ translate: ['0px', '100px'],
rotate: ['0deg', '45deg'],
transform: ['translate(20px)',
'translate(30px)'] },
'translate(30px)'],
offsetDistance: ['0%', '100%'] },
100 * MS_PER_SEC);
div.style.setProperty('translate', '50px', 'important');
@ -1130,8 +1252,8 @@ promise_test(async t => {
await waitForPaints();
assert_animation_is_not_running_on_compositor(animation,
'Animation overridden by an !important rule reports that it is ' +
'NOT running on the compositor');
'Animation overridden by an !important rule reports that it is ' +
'NOT running on the compositor');
const properties = animation.effect.getProperties();
properties.forEach(property => {
@ -1142,5 +1264,94 @@ promise_test(async t => {
'compositor because one of the transform-like property is overridden ' +
'by an !important rule');
// FIXME: Bug 1593106: We should still run the animations on the compositor if
// offset-* doesn't have any effect.
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ translate: ['0px', '100px'],
rotate: ['0deg', '45deg'],
transform: ['translate(0px)',
'translate(100px)'],
offsetDistance: ['0%', '100%'] },
100 * MS_PER_SEC);
div.style.setProperty('offset-distance', '50%', 'important');
getComputedStyle(div).offsetDistance;
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_not_running_on_compositor(animation,
'Animation overridden by an !important rule reports that it is ' +
'NOT running on the compositor');
const properties = animation.effect.getProperties();
properties.forEach(property => {
assert_true(!property.runningOnCompositor,
property.property + ' is not running on the compositor');
});
}, 'Multiple transform-like properties animation does not runs on the ' +
'compositor because one of the offset-* property is overridden ' +
'by an !important rule');
promise_test(async t => {
const div = addDiv(t);
const animation = div.animate({ rotate: ['0deg', '45deg'],
transform: ['translate(20px)',
'translate(30px)'],
offsetDistance: ['0%', '100%'] },
100 * MS_PER_SEC);
div.style.setProperty('translate', '50px', 'important');
getComputedStyle(div).translate;
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'Animation is still running on the compositor');
const properties = animation.effect.getProperties();
properties.forEach(property => {
assert_true(property.runningOnCompositor,
property.property + ' is running on the compositor');
});
}, 'Multiple transform-like properties animation still runs on the ' +
'compositor because the overridden-by-!important property does not have ' +
'animation');
promise_test(async t => {
// We should run the animations on the compositor for this case:
// 1. A transition of 'translate'
// 2. An !important rule on 'translate'
// 3. An animation of 'scale'
const div = addDiv(t, { style: 'translate: 100px !important;' });
const animation = div.animate({ rotate: ['0deg', '45deg'] },
100 * MS_PER_SEC);
div.style.transition = 'translate 100s';
getComputedStyle(div).transition;
await waitForAnimationReadyToRestyle(animation);
await waitForPaints();
assert_animation_is_running_on_compositor(animation,
'rotate animation should be running on the compositor');
div.style.setProperty('translate', '200px', 'important');
getComputedStyle(div).translate;
const anims = div.getAnimations();
await waitForPaints();
assert_animation_is_running_on_compositor(anims[0],
`${anims[0].effect.getProperties()[0].property} animation should be ` +
`running on the compositor`);
assert_animation_is_running_on_compositor(anims[1],
`${anims[1].effect.getProperties()[0].property} animation should be ` +
`running on the compositor`);
}, 'Transform-like animations and transitions still runs on the compositor ' +
'because the !important rule is overridden by a transition, and the ' +
'transition property does not have animations');
</script>
</body>

View File

@ -0,0 +1,24 @@
<style>
@keyframes animation_0 {
88% { }
}
* {
animation-name: animation_0;
animation-delay: 4s;
}
</style>
<script>
function start () {
const input = document.createElement('input')
document.documentElement.appendChild(input)
const animations = input.getAnimations({})
const animation = animations[(3782796448 % animations.length)]
const effect = animation.effect
effect.setKeyframes({ 'borderLeft': ['inherit'] })
effect.target = null
input.contentEditable = 'true'
}
document.addEventListener('DOMContentLoaded', start)
</script>

View File

@ -43,3 +43,4 @@ pref(dom.animations-api.core.enabled,true) pref(dom.animations-api.timelines.ena
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1468294-1.html
pref(dom.animations-api.implicit-keyframes.enabled,true) load 1467277-1.html
load 1524480-1.html
load 1575926.html

View File

@ -365,8 +365,6 @@ waitForAllPaints(() => {
add_task(
async function restyling_transform_animations_in_scrolled_out_element() {
await SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] });
// Make sure we start from the state right after requestAnimationFrame.
await waitForFrame();
@ -1549,8 +1547,6 @@ waitForAllPaints(() => {
add_task(
async function no_overflow_transform_animations_in_scrollable_element() {
await SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] });
const parentElement = addDiv(null,
{ style: 'overflow-y: scroll; height: 100px;' });
const div = addDiv(null);

View File

@ -12,6 +12,7 @@ SpecialPowers.pushPrefEnv(
set: [
['layout.reflow.synthMouseMove', false],
['privacy.reduceTimerPrecision', false],
["ui.showHideScrollbars", 1],
],
},
function() {

View File

@ -328,8 +328,7 @@ Directionality GetDirectionFromText(const char16_t* aText,
uint32_t current = start - aText;
uint32_t ch = *start++;
if (NS_IS_HIGH_SURROGATE(ch) && start < end &&
NS_IS_LOW_SURROGATE(*start)) {
if (start < end && NS_IS_SURROGATE_PAIR(ch, *start)) {
ch = SURROGATE_TO_UCS4(ch, *start++);
current++;
}

View File

@ -5657,7 +5657,7 @@ already_AddRefed<PresShell> Document::CreatePresShell(
AssertNoStaleServoDataIn(*this);
RefPtr<PresShell> presShell = new PresShell;
RefPtr<PresShell> presShell = new PresShell(this);
// Note: we don't hold a ref to the shell (it holds a ref to us)
mPresShell = presShell;
@ -5666,7 +5666,7 @@ already_AddRefed<PresShell> Document::CreatePresShell(
FillStyleSet();
}
presShell->Init(this, aContext, aViewManager);
presShell->Init(aContext, aViewManager);
if (hadStyleSheets) {
// Gaining a shell causes changes in how media queries are evaluated, so
@ -9558,6 +9558,19 @@ nsViewportInfo Document::GetViewportInfo(const ScreenIntSize& aDisplaySize) {
size.height = clamped(size.height, effectiveMinSize.height,
float(kViewportMaxSize.height));
// In cases of user-scalable=no, if we have a positive scale, clamp it to
// min and max, and then use the clamped value for the scale, the min, and
// the max. If we don't have a positive scale, assert that we are setting
// the auto scale flag.
if (effectiveZoomFlag == nsViewportInfo::ZoomFlag::DisallowZoom &&
scaleFloat > CSSToScreenScale(0.0f)) {
scaleFloat = scaleMinFloat = scaleMaxFloat =
clamped(scaleFloat, scaleMinFloat, scaleMaxFloat);
}
MOZ_ASSERT(
scaleFloat > CSSToScreenScale(0.0f) || !mValidScaleFloat,
"If we don't have a positive scale, we should be using auto scale.");
// We need to perform a conversion, but only if the initial or maximum
// scale were set explicitly by the user.
if (mValidScaleFloat && scaleFloat >= scaleMinFloat &&
@ -12996,8 +13009,8 @@ void Document::CleanupFullscreenState() {
// Restore the zoom level that was in place prior to entering fullscreen.
if (PresShell* presShell = GetPresShell()) {
if (presShell->GetMobileViewportManager()) {
presShell->SetResolutionAndScaleTo(mSavedResolution,
ResolutionChangeOrigin::MainThread);
presShell->SetResolutionAndScaleTo(
mSavedResolution, ResolutionChangeOrigin::MainThreadRestore);
}
}
@ -13393,7 +13406,7 @@ bool Document::ApplyFullscreen(UniquePtr<FullscreenRequest> aRequest) {
child->mSavedResolution = presShell->GetResolution();
presShell->SetResolutionAndScaleTo(
manager->ComputeIntrinsicResolution(),
ResolutionChangeOrigin::MainThread);
ResolutionChangeOrigin::MainThreadRestore);
}
}
@ -13791,9 +13804,6 @@ void Document::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const {
mStyleSet->AddSizeOfIncludingThis(aWindowSizes);
aWindowSizes.mDOMOtherSize += mLangGroupFontPrefs.SizeOfExcludingThis(
aWindowSizes.mState.mMallocSizeOf);
aWindowSizes.mPropertyTablesSize +=
mPropertyTable.SizeOfExcludingThis(aWindowSizes.mState.mMallocSizeOf);
@ -15446,6 +15456,12 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) {
}
}
// static
bool Document::UseOverlayScrollbars(const Document* aDocument) {
return LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) ||
(aDocument && aDocument->InRDMPane());
}
bool Document::HasRecentlyStartedForegroundLoads() {
if (!sLoadingForegroundTopLevelContentDocument) {
return false;

View File

@ -38,7 +38,6 @@
#include "nsTHashtable.h" // for member
#include "nsURIHashKey.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/StaticPresData.h"
#include "Units.h"
#include "nsContentListDeclarations.h"
#include "nsExpirationTracker.h"
@ -55,7 +54,6 @@
#include "mozilla/LinkedList.h"
#include "mozilla/NotNull.h"
#include "mozilla/SegmentedVector.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
@ -4056,6 +4054,10 @@ class Document : public nsINode,
bool InRDMPane() const { return mInRDMPane; }
void SetInRDMPane(bool aInRDMPane) { mInRDMPane = aInRDMPane; }
// Returns true if we use overlay scrollbars on the system wide or on the
// given document.
static bool UseOverlayScrollbars(const Document* aDocument);
static bool HasRecentlyStartedForegroundLoads();
static bool AutomaticStorageAccessCanBeGranted(nsIPrincipal* aPrincipal);
@ -5112,13 +5114,6 @@ class Document : public nsINode,
// resolution.
nsTHashtable<nsPtrHashKey<SVGElement>> mLazySVGPresElements;
// Most documents will only use one (or very few) language groups. Rather
// than have the overhead of a hash lookup, we simply look along what will
// typically be a very short (usually of length 1) linked list. There are 31
// language groups, so in the worst case scenario we'll need to traverse 31
// link items.
LangGroupFontPrefs mLangGroupFontPrefs;
nsTHashtable<nsRefPtrHashKey<nsAtom>> mLanguagesUsed;
// TODO(emilio): Is this hot enough to warrant to be cached?

View File

@ -14,6 +14,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/StaticPrefs_full_screen_api.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/BindContext.h"
@ -50,7 +51,10 @@
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/FeaturePolicyUtils.h"
#include "mozilla/dom/HTMLDivElement.h"
#include "mozilla/dom/HTMLParagraphElement.h"
#include "mozilla/dom/HTMLPreElement.h"
#include "mozilla/dom/HTMLSpanElement.h"
#include "mozilla/dom/HTMLTableCellElement.h"
#include "mozilla/dom/KeyframeAnimationOptionsBinding.h"
#include "mozilla/dom/MutationEventBinding.h"
#include "mozilla/AnimationComparator.h"
@ -193,7 +197,10 @@ namespace dom {
// bucket sizes.
ASSERT_NODE_SIZE(Element, 128, 80);
ASSERT_NODE_SIZE(HTMLDivElement, 128, 80);
ASSERT_NODE_SIZE(HTMLParagraphElement, 128, 80);
ASSERT_NODE_SIZE(HTMLPreElement, 128, 80);
ASSERT_NODE_SIZE(HTMLSpanElement, 128, 80);
ASSERT_NODE_SIZE(HTMLTableCellElement, 128, 80);
ASSERT_NODE_SIZE(Text, 120, 64);
#undef ASSERT_NODE_SIZE
@ -632,6 +639,16 @@ nsDOMTokenList* Element::ClassList() {
return slots->mClassList;
}
nsDOMTokenList* Element::Part() {
Element::nsDOMSlots* slots = DOMSlots();
if (!slots->mPart) {
slots->mPart = new nsDOMTokenList(this, nsGkAtoms::part);
}
return slots->mPart;
}
void Element::GetAttributeNames(nsTArray<nsString>& aResult) {
uint32_t count = mAttrs.AttrCount();
for (uint32_t i = 0; i < count; ++i) {
@ -981,7 +998,7 @@ nsRect Element::GetClientAreaRect() {
// The display check is OK even though we're not looking at the style
// frame, because the style frame only differs from "frame" for tables,
// and table wrappers have the same display as the table itself.
(frame->StyleDisplay()->mDisplay != StyleDisplay::Inline ||
(!frame->StyleDisplay()->IsInlineFlow() ||
frame->IsFrameOfType(nsIFrame::eReplaced))) {
// Special case code to make client area work even when there isn't
// a scroll view, see bug 180552, bug 227567.
@ -1737,7 +1754,8 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) {
// XXXbz if we already have a style attr parsed, this won't do
// anything... need to fix that.
// If MayHaveStyle() is true, we must be an nsStyledElement
static_cast<nsStyledElement*>(this)->ReparseStyleAttribute(false, false);
static_cast<nsStyledElement*>(this)->ReparseStyleAttribute(
/* aForceInDataDoc = */ false);
}
// FIXME(emilio): Why is this needed? The element shouldn't even be styled in
@ -2023,7 +2041,7 @@ void Element::SetSMILOverrideStyleDeclaration(DeclarationBlock& aDeclaration) {
// that's been detached since the previous animation sample.)
if (Document* doc = GetComposedDoc()) {
if (PresShell* presShell = doc->GetPresShell()) {
presShell->RestyleForAnimation(this, StyleRestyleHint_RESTYLE_SMIL);
presShell->RestyleForAnimation(this, RestyleHint::RESTYLE_SMIL);
}
}
}
@ -2589,6 +2607,12 @@ bool Element::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
return true;
}
if (aAttribute == nsGkAtoms::exportparts &&
StaticPrefs::layout_css_shadow_parts_enabled()) {
aResult.ParsePartMapping(aValue);
return true;
}
if (aAttribute == nsGkAtoms::id) {
// Store id as an atom. id="" means that the element has no id,
// not that it has an emptystring as the id.
@ -3188,47 +3212,14 @@ nsresult Element::PostHandleEventForLinks(EventChainPostVisitor& aVisitor) {
void Element::GetLinkTarget(nsAString& aTarget) { aTarget.Truncate(); }
static void nsDOMTokenListPropertyDestructor(void* aObject, nsAtom* aProperty,
void* aPropertyValue,
void* aData) {
nsDOMTokenList* list = static_cast<nsDOMTokenList*>(aPropertyValue);
NS_RELEASE(list);
}
static nsStaticAtom* const sPropertiesToTraverseAndUnlink[] = {
nsGkAtoms::sandbox, nsGkAtoms::sizes, nsGkAtoms::dirAutoSetBy, nullptr};
nsGkAtoms::dirAutoSetBy, nullptr};
// static
nsStaticAtom* const* Element::HTMLSVGPropertiesToTraverseAndUnlink() {
return sPropertiesToTraverseAndUnlink;
}
nsDOMTokenList* Element::GetTokenList(
nsAtom* aAtom, const DOMTokenListSupportedTokenArray aSupportedTokens) {
#ifdef DEBUG
const nsStaticAtom* const* props = HTMLSVGPropertiesToTraverseAndUnlink();
bool found = false;
for (uint32_t i = 0; props[i]; ++i) {
if (props[i] == aAtom) {
found = true;
break;
}
}
MOZ_ASSERT(found, "Trying to use an unknown tokenlist!");
#endif
nsDOMTokenList* list = nullptr;
if (HasProperties()) {
list = static_cast<nsDOMTokenList*>(GetProperty(aAtom));
}
if (!list) {
list = new nsDOMTokenList(this, aAtom, aSupportedTokens);
NS_ADDREF(list);
SetProperty(aAtom, list, nsDOMTokenListPropertyDestructor);
}
return list;
}
nsresult Element::CopyInnerTo(Element* aDst, ReparseAttributes aReparse) {
nsresult rv = aDst->mAttrs.EnsureCapacityToClone(mAttrs);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -1026,6 +1026,8 @@ class Element : public FragmentOrElement {
}
nsDOMTokenList* ClassList();
nsDOMTokenList* Part();
nsDOMAttributeMap* Attributes() {
nsDOMSlots* slots = DOMSlots();
if (!slots->mAttributeMap) {
@ -1906,10 +1908,6 @@ class Element : public FragmentOrElement {
*/
virtual void GetLinkTarget(nsAString& aTarget);
nsDOMTokenList* GetTokenList(
nsAtom* aAtom,
const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
enum class ReparseAttributes { No, Yes };
/**
* Copy attributes and state to another element

View File

@ -584,6 +584,9 @@ void FragmentOrElement::nsDOMSlots::Traverse(
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mSlots->mClassList");
aCb.NoteXPCOMChild(mClassList.get());
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mSlots->mPart");
aCb.NoteXPCOMChild(mPart.get());
}
void FragmentOrElement::nsDOMSlots::Unlink() {
@ -595,6 +598,7 @@ void FragmentOrElement::nsDOMSlots::Unlink() {
}
mChildrenList = nullptr;
mClassList = nullptr;
mPart = nullptr;
}
size_t FragmentOrElement::nsDOMSlots::SizeOfIncludingThis(
@ -1103,23 +1107,23 @@ void nsIContent::SetXBLInsertionPoint(nsIContent* aContent) {
#ifdef DEBUG
void nsIContent::AssertAnonymousSubtreeRelatedInvariants() const {
NS_ASSERTION(!IsRootOfNativeAnonymousSubtree() ||
(GetParent() && GetBindingParent() == GetParent()),
"root of native anonymous subtree must have parent equal "
"to binding parent");
NS_ASSERTION(!GetParent() || !IsInComposedDoc() ||
((GetBindingParent() == GetParent()) ==
HasFlag(NODE_IS_ANONYMOUS_ROOT)) ||
// Unfortunately default content for XBL insertion points
// is anonymous content that is bound with the parent of
// the insertion point as the parent but the bound element
// for the binding as the binding parent. So we have to
// complicate the assert a bit here.
(GetBindingParent() &&
(GetBindingParent() == GetParent()->GetBindingParent()) ==
HasFlag(NODE_IS_ANONYMOUS_ROOT)),
"For connected nodes, flag and GetBindingParent() check "
"should match");
MOZ_ASSERT(!IsRootOfNativeAnonymousSubtree() ||
(GetParent() && GetBindingParent() == GetParent()),
"root of native anonymous subtree must have parent equal "
"to binding parent");
MOZ_ASSERT(!GetParent() || !IsInComposedDoc() ||
((GetBindingParent() == GetParent()) ==
HasFlag(NODE_IS_ANONYMOUS_ROOT)) ||
// Unfortunately default content for XBL insertion points
// is anonymous content that is bound with the parent of
// the insertion point as the parent but the bound element
// for the binding as the binding parent. So we have to
// complicate the assert a bit here.
(GetBindingParent() &&
(GetBindingParent() == GetParent()->GetBindingParent()) ==
HasFlag(NODE_IS_ANONYMOUS_ROOT)),
"For connected nodes, flag and GetBindingParent() check "
"should match");
}
#endif

View File

@ -238,6 +238,11 @@ class FragmentOrElement : public nsIContent {
* An object implementing the .classList property for this element.
*/
RefPtr<nsDOMTokenList> mClassList;
/**
* An object implementing the .part property for this element.
*/
RefPtr<nsDOMTokenList> mPart;
};
/**

View File

@ -4,7 +4,6 @@
#include "Link.h"
#include "mozilla/Components.h"
#include "mozilla/EventStates.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Element.h"
@ -92,240 +91,9 @@ void Link::CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
}
}
void Link::GetContentPolicyMimeTypeMedia(nsAttrValue& aAsAttr,
nsContentPolicyType& aPolicyType,
nsString& aMimeType,
nsAString& aMedia) {
nsAutoString as;
mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::as, as);
Link::ParseAsValue(as, aAsAttr);
aPolicyType = AsValueToContentPolicy(aAsAttr);
nsAutoString type;
mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
nsAutoString notUsed;
nsContentUtils::SplitMimeType(type, aMimeType, notUsed);
mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
}
void Link::TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender() {
MOZ_ASSERT(mElement->IsInComposedDoc());
if (!ElementHasHref()) {
return;
}
nsAutoString rel;
if (!mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
return;
}
if (!nsContentUtils::PrefetchPreloadEnabled(
mElement->OwnerDoc()->GetDocShell())) {
return;
}
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel);
if ((linkTypes & nsStyleLinkElement::ePREFETCH) ||
(linkTypes & nsStyleLinkElement::eNEXT) ||
(linkTypes & nsStyleLinkElement::ePRELOAD)) {
nsCOMPtr<nsIPrefetchService> prefetchService(
components::Prefetch::Service());
if (prefetchService) {
nsCOMPtr<nsIURI> uri(GetURI());
if (uri) {
bool preload = !!(linkTypes & nsStyleLinkElement::ePRELOAD);
nsContentPolicyType policyType;
if (preload) {
nsAttrValue asAttr;
nsAutoString mimeType;
nsAutoString media;
GetContentPolicyMimeTypeMedia(asAttr, policyType, mimeType, media);
if (policyType == nsIContentPolicy::TYPE_INVALID) {
// Ignore preload with a wrong or empty as attribute.
return;
}
if (!HTMLLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
mElement->OwnerDoc())) {
policyType = nsIContentPolicy::TYPE_INVALID;
}
}
nsCOMPtr<nsIReferrerInfo> referrerInfo = new ReferrerInfo();
referrerInfo->InitWithNode(mElement);
if (preload) {
prefetchService->PreloadURI(uri, referrerInfo, mElement, policyType);
} else {
prefetchService->PrefetchURI(
uri, referrerInfo, mElement,
linkTypes & nsStyleLinkElement::ePREFETCH);
}
return;
}
}
}
if (linkTypes & nsStyleLinkElement::ePRECONNECT) {
nsCOMPtr<nsIURI> uri(GetURI());
if (uri && mElement->OwnerDoc()) {
mElement->OwnerDoc()->MaybePreconnect(
uri, Element::AttrValueToCORSMode(
mElement->GetParsedAttr(nsGkAtoms::crossorigin)));
return;
}
}
if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
if (nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) {
nsHTMLDNSPrefetch::PrefetchLow(this);
}
}
}
void Link::UpdatePreload(nsAtom* aName, const nsAttrValue* aValue,
const nsAttrValue* aOldValue) {
MOZ_ASSERT(mElement->IsInComposedDoc());
if (!ElementHasHref()) {
return;
}
nsAutoString rel;
if (!mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
return;
}
if (!nsContentUtils::PrefetchPreloadEnabled(
mElement->OwnerDoc()->GetDocShell())) {
return;
}
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel);
if (!(linkTypes & nsStyleLinkElement::ePRELOAD)) {
return;
}
nsCOMPtr<nsIPrefetchService> prefetchService(components::Prefetch::Service());
if (!prefetchService) {
return;
}
nsCOMPtr<nsIURI> uri(GetURI());
if (!uri) {
return;
}
nsAttrValue asAttr;
nsContentPolicyType asPolicyType;
nsAutoString mimeType;
nsAutoString media;
GetContentPolicyMimeTypeMedia(asAttr, asPolicyType, mimeType, media);
if (asPolicyType == nsIContentPolicy::TYPE_INVALID) {
// Ignore preload with a wrong or empty as attribute, but be sure to cancel
// the old one.
prefetchService->CancelPrefetchPreloadURI(uri, mElement);
return;
}
nsContentPolicyType policyType = asPolicyType;
if (!HTMLLinkElement::CheckPreloadAttrs(asAttr, mimeType, media,
mElement->OwnerDoc())) {
policyType = nsIContentPolicy::TYPE_INVALID;
}
if (aName == nsGkAtoms::crossorigin) {
CORSMode corsMode = Element::AttrValueToCORSMode(aValue);
CORSMode oldCorsMode = Element::AttrValueToCORSMode(aOldValue);
if (corsMode != oldCorsMode) {
prefetchService->CancelPrefetchPreloadURI(uri, mElement);
nsCOMPtr<nsIReferrerInfo> referrerInfo = new ReferrerInfo();
referrerInfo->InitWithNode(mElement);
prefetchService->PreloadURI(uri, referrerInfo, mElement, policyType);
}
return;
}
nsContentPolicyType oldPolicyType;
if (aName == nsGkAtoms::as) {
if (aOldValue) {
oldPolicyType = AsValueToContentPolicy(*aOldValue);
if (!HTMLLinkElement::CheckPreloadAttrs(*aOldValue, mimeType, media,
mElement->OwnerDoc())) {
oldPolicyType = nsIContentPolicy::TYPE_INVALID;
}
} else {
oldPolicyType = nsIContentPolicy::TYPE_INVALID;
}
} else if (aName == nsGkAtoms::type) {
nsAutoString oldType;
nsAutoString notUsed;
if (aOldValue) {
aOldValue->ToString(oldType);
} else {
oldType = EmptyString();
}
nsAutoString oldMimeType;
nsContentUtils::SplitMimeType(oldType, oldMimeType, notUsed);
if (HTMLLinkElement::CheckPreloadAttrs(asAttr, oldMimeType, media,
mElement->OwnerDoc())) {
oldPolicyType = asPolicyType;
} else {
oldPolicyType = nsIContentPolicy::TYPE_INVALID;
}
} else {
MOZ_ASSERT(aName == nsGkAtoms::media);
nsAutoString oldMedia;
if (aOldValue) {
aOldValue->ToString(oldMedia);
} else {
oldMedia = EmptyString();
}
if (HTMLLinkElement::CheckPreloadAttrs(asAttr, mimeType, oldMedia,
mElement->OwnerDoc())) {
oldPolicyType = asPolicyType;
} else {
oldPolicyType = nsIContentPolicy::TYPE_INVALID;
}
}
if ((policyType != oldPolicyType) &&
(oldPolicyType != nsIContentPolicy::TYPE_INVALID)) {
prefetchService->CancelPrefetchPreloadURI(uri, mElement);
}
// Trigger a new preload if the policy type has changed.
// Also trigger load if the new policy type is invalid, this will only
// trigger an error event.
if ((policyType != oldPolicyType) ||
(policyType == nsIContentPolicy::TYPE_INVALID)) {
nsCOMPtr<nsIReferrerInfo> referrerInfo = new ReferrerInfo();
referrerInfo->InitWithNode(mElement);
prefetchService->PreloadURI(uri, referrerInfo, mElement, policyType);
}
}
void Link::CancelPrefetchOrPreload() {
nsCOMPtr<nsIPrefetchService> prefetchService(components::Prefetch::Service());
if (prefetchService) {
nsCOMPtr<nsIURI> uri(GetURI());
if (uri) {
prefetchService->CancelPrefetchPreloadURI(uri, mElement);
}
}
}
void Link::SetLinkState(nsLinkState aState) {
NS_ASSERTION(mRegistered, "Setting the link state of an unregistered Link!");
NS_ASSERTION(mLinkState != aState,
"Setting state to the currently set state!");
MOZ_ASSERT(mRegistered, "Setting the link state of an unregistered Link!");
MOZ_ASSERT(mLinkState != aState, "Setting state to the currently set state!");
// Set our current state as appropriate.
mLinkState = aState;
@ -344,6 +112,8 @@ void Link::SetLinkState(nsLinkState aState) {
EventStates Link::LinkState() const {
// We are a constant method, but we are just lazily doing things and have to
// track that state. Cast away that constness!
//
// XXX(emilio): that's evil.
Link* self = const_cast<Link*>(this);
Element* element = self->mElement;
@ -744,8 +514,12 @@ void Link::ResetLinkState(bool aNotify, bool aHasHref) {
}
}
// If we have an href, we should register with the history.
mNeedsRegistration = aHasHref;
// If we have an href, and we're not a <link>, we should register with the
// history.
//
// FIXME(emilio): Do we really want to allow all MathML elements to be
// :visited? That seems not great.
mNeedsRegistration = aHasHref && !mElement->IsHTMLElement(nsGkAtoms::link);
// If we've cached the URI, reset always invalidates it.
UnregisterFromHistory();
@ -827,48 +601,5 @@ size_t Link::SizeOfExcludingThis(mozilla::SizeOfState& aState) const {
return n;
}
static const nsAttrValue::EnumTable kAsAttributeTable[] = {
{"", DESTINATION_INVALID}, {"audio", DESTINATION_AUDIO},
{"font", DESTINATION_FONT}, {"image", DESTINATION_IMAGE},
{"script", DESTINATION_SCRIPT}, {"style", DESTINATION_STYLE},
{"track", DESTINATION_TRACK}, {"video", DESTINATION_VIDEO},
{"fetch", DESTINATION_FETCH}, {nullptr, 0}};
/* static */
void Link::ParseAsValue(const nsAString& aValue, nsAttrValue& aResult) {
DebugOnly<bool> success =
aResult.ParseEnumValue(aValue, kAsAttributeTable, false,
// default value is a empty string
// if aValue is not a value we
// understand
&kAsAttributeTable[0]);
MOZ_ASSERT(success);
}
/* static */
nsContentPolicyType Link::AsValueToContentPolicy(const nsAttrValue& aValue) {
switch (aValue.GetEnumValue()) {
case DESTINATION_INVALID:
return nsIContentPolicy::TYPE_INVALID;
case DESTINATION_AUDIO:
return nsIContentPolicy::TYPE_INTERNAL_AUDIO;
case DESTINATION_TRACK:
return nsIContentPolicy::TYPE_INTERNAL_TRACK;
case DESTINATION_VIDEO:
return nsIContentPolicy::TYPE_INTERNAL_VIDEO;
case DESTINATION_FONT:
return nsIContentPolicy::TYPE_FONT;
case DESTINATION_IMAGE:
return nsIContentPolicy::TYPE_IMAGE;
case DESTINATION_SCRIPT:
return nsIContentPolicy::TYPE_SCRIPT;
case DESTINATION_STYLE:
return nsIContentPolicy::TYPE_STYLESHEET;
case DESTINATION_FETCH:
return nsIContentPolicy::TYPE_OTHER;
}
return nsIContentPolicy::TYPE_INVALID;
}
} // namespace dom
} // namespace mozilla

View File

@ -116,17 +116,11 @@ class Link : public nsISupports {
virtual bool ElementHasHref() const;
// This is called by HTMLAnchorElement.
// This is called by HTMLAnchorElement and HTMLLinkElement.
void TryDNSPrefetch();
void CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
nsWrapperCache::FlagsType aRequestedFlag);
// This is called by HTMLLinkElement.
void TryDNSPrefetchOrPreconnectOrPrefetchOrPreloadOrPrerender();
void UpdatePreload(nsAtom* aName, const nsAttrValue* aValue,
const nsAttrValue* aOldValue);
void CancelPrefetchOrPreload();
bool HasPendingLinkUpdate() const { return mHasPendingLinkUpdate; }
void SetHasPendingLinkUpdate() { mHasPendingLinkUpdate = true; }
void ClearHasPendingLinkUpdate() { mHasPendingLinkUpdate = false; }
@ -141,9 +135,6 @@ class Link : public nsISupports {
void SetIsInDNSPrefetch() { mInDNSPrefetch = true; }
void ClearIsInDNSPrefetch() { mInDNSPrefetch = false; }
static void ParseAsValue(const nsAString& aValue, nsAttrValue& aResult);
static nsContentPolicyType AsValueToContentPolicy(const nsAttrValue& aValue);
protected:
virtual ~Link();
@ -170,10 +161,6 @@ class Link : public nsISupports {
void SetHrefAttribute(nsIURI* aURI);
void GetContentPolicyMimeTypeMedia(nsAttrValue& aAsAttr,
nsContentPolicyType& aPolicyType,
nsString& aMimeType, nsAString& aMedia);
mutable nsCOMPtr<nsIURI> mCachedURI;
Element* const mElement;

View File

@ -30,12 +30,10 @@ void OnPrefChange(const char* aPrefName, void*) {
}
nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
rootDocShell->GetDocShellEnumerator(nsIDocShell::typeAll,
nsIDocShell::ENUMERATE_FORWARDS,
getter_AddRefs(docShellEnumerator));
NS_ENSURE_TRUE_VOID(docShellEnumerator);
for (auto& docShell : SimpleEnumerator<nsIDocShell>(docShellEnumerator)) {
nsTArray<RefPtr<nsIDocShell>> docShells;
rootDocShell->GetAllDocShellsInSubtree(
nsIDocShell::typeAll, nsIDocShell::ENUMERATE_FORWARDS, docShells);
for (auto& docShell : docShells) {
if (nsCOMPtr<nsPIDOMWindowOuter> win = do_GetInterface(docShell)) {
if (dom::Document* doc = win->GetExtantDoc()) {
doc->ResetDocumentDirection();

View File

@ -4,7 +4,6 @@
writing-mode: vertical-rl;
}
body {
-moz-column-count: 2;
column-count: 2;
}
svg {

View File

@ -231,7 +231,7 @@ load 1406109-1.html
load 1411473.html
load 1413815.html
load 1419799.html
skip-if(!browserIsRemote) pref(dom.disable_open_during_load,false) load 1419902.html # skip on non e10s loads, Bug 1419902
skip-if(!browserIsRemote) skip-if(geckoview&&webrender) pref(dom.disable_open_during_load,false) load 1419902.html # skip on non e10s loads, Bug 1419902. Bug 1563013 for GV+WR
load 1422883.html
load 1428053.html
load 1441029.html

View File

@ -18,6 +18,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/ServoUtils.h"
#include "mozilla/ShadowParts.h"
#include "mozilla/DeclarationBlock.h"
#include "nsContentUtils.h"
#include "nsReadableUtils.h"
@ -279,6 +280,7 @@ void nsAttrValue::SetTo(const nsAttrValue& aOther) {
cont->mValue.mColor = otherCont->mValue.mColor;
break;
}
case eShadowParts:
case eCSSDeclaration: {
MOZ_CRASH("These should be refcounted!");
}
@ -299,9 +301,10 @@ void nsAttrValue::SetTo(const nsAttrValue& aOther) {
break;
}
case eIntMarginValue: {
if (otherCont->mValue.mIntMargin)
if (otherCont->mValue.mIntMargin) {
cont->mValue.mIntMargin =
new nsIntMargin(*otherCont->mValue.mIntMargin);
}
break;
}
default: {
@ -1153,7 +1156,7 @@ void nsAttrValue::ParseAtomArray(const nsAString& aValue) {
void nsAttrValue::ParseStringOrAtom(const nsAString& aValue) {
uint32_t len = aValue.Length();
// Don't bother with atoms if it's an empty string since
// we can store those efficently anyway.
// we can store those efficiently anyway.
if (len && len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
ParseAtom(aValue);
} else {
@ -1161,6 +1164,17 @@ void nsAttrValue::ParseStringOrAtom(const nsAString& aValue) {
}
}
void nsAttrValue::ParsePartMapping(const nsAString& aValue) {
ResetIfSet();
MiscContainer* cont = EnsureEmptyMiscContainer();
cont->mType = eShadowParts;
cont->mValue.mShadowParts = new ShadowParts(ShadowParts::Parse(aValue));
NS_ADDREF(cont);
SetMiscAtomOrString(&aValue);
MOZ_ASSERT(cont->mValue.mRefCount == 1);
}
void nsAttrValue::SetIntValueAndType(int32_t aValue, ValueType aType,
const nsAString* aStringValue) {
if (aStringValue || aValue > NS_ATTRVALUE_INTEGERTYPE_MAXVALUE ||
@ -1271,7 +1285,7 @@ bool nsAttrValue::DoParseHTMLDimension(const nsAString& aInput,
// https://html.spec.whatwg.org/multipage/#rules-for-parsing-dimension-values
// Step 1 and 2.
// Steps 1 and 2.
const char16_t* position = aInput.BeginReading();
const char16_t* end = aInput.EndReading();
@ -1280,36 +1294,19 @@ bool nsAttrValue::DoParseHTMLDimension(const nsAString& aInput,
// leading '0' characters, or trailing garbage.
bool canonical = true;
// Step 3
// Step 3.
while (position != end && nsContentUtils::IsHTMLWhitespace(*position)) {
canonical = false; // Leading whitespace
++position;
}
// Step 4
if (position == end) {
// Step 4.
if (position == end || *position < char16_t('0') ||
*position > char16_t('9')) {
return false;
}
// Step 5
if (*position == char16_t('+')) {
canonical = false; // Leading '+'
++position;
// Step 6. The spec has this happening regardless of whether we found '+',
// but there's no point repeating the step 4 test if we didn't advance
// position.
if (position == end) {
return false;
}
}
// Step 7.
if (*position < char16_t('0') || *position > char16_t('9')) {
return false;
}
// Step 8.
// Step 5.
CheckedInt32 value = 0;
// Collect up leading '0' first to avoid extra branching in the main
@ -1332,28 +1329,35 @@ bool nsAttrValue::DoParseHTMLDimension(const nsAString& aInput,
++position;
}
// Step 9 is implemented implicitly via the various "position != end" guards
// Step 6 is implemented implicitly via the various "position != end" guards
// from this point on.
Maybe<double> doubleValue;
// Step 10.
// Step 7. The return in step 7.2 is handled by just falling through to the
// code below this block when we reach end of input or a non-digit, because
// the while loop will terminate at that point.
if (position != end && *position == char16_t('.')) {
canonical = false; // Let's not rely on double serialization reproducing
// the string we started with.
// Step 7.1.
++position;
// If we have a '.' _not_ followed by digits, this is not as efficient as it
// could be, because we will store as a double while we could have stored as
// an int. But that seems like a pretty rare case.
doubleValue.emplace(value.value());
// Step 7.3.
double divisor = 1.0f;
// Per spec we should now return a number if there is no next char or if the
// next char is not a digit, but no one does that. See
// https://github.com/whatwg/html/issues/4736
// Step 7.4.
while (position != end && *position >= char16_t('0') &&
*position <= char16_t('9')) {
// Step 7.4.1.
divisor = divisor * 10.0f;
// Step 7.4.2.
doubleValue.ref() += (*position - char16_t('0')) / divisor;
// Step 7.4.3.
++position;
// Step 7.4.4 and 7.4.5 are captured in the while loop condition and the
// "position != end" checks below.
}
}
@ -1363,7 +1367,7 @@ bool nsAttrValue::DoParseHTMLDimension(const nsAString& aInput,
return false;
}
// Steps 11-13.
// Step 8 and the spec's early return from step 7.2.
ValueType type;
if (position != end && *position == char16_t('%')) {
type = ePercent;
@ -1748,6 +1752,12 @@ MiscContainer* nsAttrValue::ClearMiscContainer() {
NS_RELEASE(cont->mValue.mCSSDeclaration);
break;
}
case eShadowParts: {
MOZ_ASSERT(cont->mValue.mRefCount == 1);
cont->Release();
delete cont->mValue.mShadowParts;
break;
}
case eURL: {
NS_RELEASE(cont->mValue.mURL);
break;

View File

@ -34,6 +34,7 @@ struct MiscContainer;
namespace mozilla {
class DeclarationBlock;
class ShadowParts;
} // namespace mozilla
#define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12
@ -99,6 +100,10 @@ class nsAttrValue {
eAtomArray,
eDoubleValue,
eIntMarginValue,
// eShadowParts is refcounted in the misc container, as we do copy attribute
// values quite a bit (for example to process style invalidation), and the
// underlying value could get expensive to copy.
eShadowParts,
eSVGIntegerPair,
eSVGTypesBegin = eSVGIntegerPair,
eSVGOrient,
@ -206,6 +211,7 @@ class nsAttrValue {
inline nsIURI* GetURLValue() const;
inline double GetDoubleValue() const;
bool GetIntMarginValue(nsIntMargin& aMargin) const;
inline const mozilla::ShadowParts& GetShadowPartsValue() const;
/**
* Returns the string corresponding to the stored enum value.
@ -254,6 +260,13 @@ class nsAttrValue {
void ParseAtomArray(const nsAString& aValue);
void ParseStringOrAtom(const nsAString& aValue);
/**
* Parses an exportparts attribute.
*
* https://drafts.csswg.org/css-shadow-parts/#parsing-mapping-list
*/
void ParsePartMapping(const nsAString&);
/**
* Structure for a mapping from int (enum) values to strings. When you use
* it you generally create an array of them.
@ -417,12 +430,6 @@ class nsAttrValue {
*/
bool ParseDoubleValue(const nsAString& aString);
/**
* Parse a lazy URI. This just sets up the storage for the URI; it
* doesn't actually allocate it.
*/
bool ParseLazyURIValue(const nsAString& aString);
/**
* Parse a margin string of format 'top, right, bottom, left' into
* an nsIntMargin.

View File

@ -12,7 +12,9 @@
#include "mozilla/Attributes.h"
#include "mozilla/ServoUtils.h"
struct MiscContainer;
namespace mozilla {
class ShadowParts;
}
struct MiscContainer final {
typedef nsAttrValue::ValueType ValueType;
@ -41,6 +43,7 @@ struct MiscContainer final {
nsIURI* mURL;
mozilla::AtomArray* mAtomArray;
nsIntMargin* mIntMargin;
const mozilla::ShadowParts* mShadowParts;
const mozilla::SVGAnimatedIntegerPair* mSVGAnimatedIntegerPair;
const mozilla::SVGAnimatedLength* mSVGLength;
const mozilla::SVGAnimatedNumberPair* mSVGAnimatedNumberPair;
@ -95,7 +98,8 @@ struct MiscContainer final {
// Nothing stops us from refcounting (and sharing) other types of
// MiscContainer (except eDoubleValue types) but there's no compelling
// reason to.
return mType == nsAttrValue::eCSSDeclaration;
return mType == nsAttrValue::eCSSDeclaration ||
mType == nsAttrValue::eShadowParts;
}
inline int32_t AddRef() {
@ -247,4 +251,9 @@ inline void nsAttrValue::ToString(mozilla::dom::DOMString& aResult) const {
}
}
inline const mozilla::ShadowParts& nsAttrValue::GetShadowPartsValue() const {
MOZ_ASSERT(Type() == eShadowParts);
return *GetMiscContainer()->mValue.mShadowParts;
}
#endif

View File

@ -797,8 +797,8 @@ void nsContentSink::PrefetchPreloadHref(const nsAString& aHref,
if (preload) {
nsAttrValue asAttr;
Link::ParseAsValue(aAs, asAttr);
policyType = Link::AsValueToContentPolicy(asAttr);
HTMLLinkElement::ParseAsValue(aAs, asAttr);
policyType = HTMLLinkElement::AsValueToContentPolicy(asAttr);
if (policyType == nsIContentPolicy::TYPE_INVALID) {
// Ignore preload with a wrong or empty as attribute.

View File

@ -2872,8 +2872,7 @@ bool nsContentUtils::IsNameWithDash(nsAtom* aName) {
uint32_t i = 1;
while (i < len) {
if (NS_IS_HIGH_SURROGATE(name[i]) && i + 1 < len &&
NS_IS_LOW_SURROGATE(name[i + 1])) {
if (i + 1 < len && NS_IS_SURROGATE_PAIR(name[i], name[i + 1])) {
// Merged two 16-bit surrogate pairs into code point.
char32_t code = SURROGATE_TO_UCS4(name[i], name[i + 1]);

View File

@ -107,6 +107,7 @@
#include "mozilla/PreloadedStyleSheet.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/ResultExtensions.h"
#ifdef XP_WIN
# undef GetClassName
@ -462,16 +463,6 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
new DisplayPortPropertyData(displayport, aPriority),
nsINode::DeleteProperty<DisplayPortPropertyData>);
if (StaticPrefs::layout_scroll_root_frame_containers()) {
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
if (rootScrollFrame && aElement == rootScrollFrame->GetContent() &&
nsLayoutUtils::UsesAsyncScrolling(rootScrollFrame)) {
// We are setting a root displayport for a document.
// The pres shell needs a special flag set.
presShell->SetIgnoreViewportScrolling(true);
}
}
nsLayoutUtils::InvalidateForDisplayPortChange(aElement, hadDisplayPort,
oldDisplayPort, displayport);
@ -559,7 +550,7 @@ nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution) {
}
presShell->SetResolutionAndScaleTo(aResolution,
ResolutionChangeOrigin::MainThread);
ResolutionChangeOrigin::MainThreadRestore);
return NS_OK;
}
@ -3436,7 +3427,11 @@ nsDOMWindowUtils::GetOMTAStyle(Element* aElement, const nsAString& aProperty,
} else if (aProperty.EqualsLiteral("transform") ||
aProperty.EqualsLiteral("translate") ||
aProperty.EqualsLiteral("rotate") ||
aProperty.EqualsLiteral("scale")) {
aProperty.EqualsLiteral("scale") ||
aProperty.EqualsLiteral("offset-path") ||
aProperty.EqualsLiteral("offset-distance") ||
aProperty.EqualsLiteral("offset-rotate") ||
aProperty.EqualsLiteral("offset-anchor")) {
OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_TRANSFORM,
GetWebRenderBridge());
if (value.type() == OMTAValue::TMatrix4x4) {
@ -3663,7 +3658,7 @@ nsDOMWindowUtils::PostRestyleSelfEvent(Element* aElement) {
return NS_ERROR_INVALID_ARG;
}
nsLayoutUtils::PostRestyleEvent(aElement, StyleRestyleHint_RESTYLE_SELF,
nsLayoutUtils::PostRestyleEvent(aElement, RestyleHint::RESTYLE_SELF,
nsChangeHint(0));
return NS_OK;
}
@ -4081,14 +4076,60 @@ NS_IMETHODIMP
nsDOMWindowUtils::SetCompositionRecording(bool aValue) {
if (CompositorBridgeChild* cbc = GetCompositorBridge()) {
if (aValue) {
cbc->SendBeginRecording(TimeStamp::Now());
RefPtr<nsDOMWindowUtils> self = this;
cbc->SendBeginRecording(TimeStamp::Now())
->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[self](const bool& aSuccess) {
if (!aSuccess) {
self->ReportErrorMessageForWindow(
NS_LITERAL_STRING(
"The composition recorder is already running."),
"DOM", true);
}
},
[self](const mozilla::ipc::ResponseRejectReason&) {
self->ReportErrorMessageForWindow(
NS_LITERAL_STRING(
"Could not start the composition recorder."),
"DOM", true);
});
} else {
cbc->SendEndRecording();
bool success = false;
if (!cbc->SendEndRecording(&success)) {
ReportErrorMessageForWindow(
NS_LITERAL_STRING("Could not stop the composition recorder."),
"DOM", true);
} else if (!success) {
ReportErrorMessageForWindow(
NS_LITERAL_STRING("The composition recorder is not running."),
"DOM", true);
}
}
}
return NS_OK;
}
void nsDOMWindowUtils::ReportErrorMessageForWindow(
const nsAString& aErrorMessage, const char* aClassification,
bool aFromChrome) {
bool isPrivateWindow = false;
if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow)) {
if (nsIPrincipal* principal =
nsGlobalWindowOuter::Cast(window)->GetPrincipal()) {
uint32_t privateBrowsingId = 0;
if (NS_SUCCEEDED(principal->GetPrivateBrowsingId(&privateBrowsingId))) {
isPrivateWindow = !!privateBrowsingId;
}
}
}
nsContentUtils::LogSimpleConsoleError(aErrorMessage, aClassification,
isPrivateWindow, aFromChrome);
}
NS_IMETHODIMP
nsDOMWindowUtils::SetSystemFont(const nsACString& aFontName) {
nsIWidget* widget = GetWidget();
@ -4112,3 +4153,9 @@ nsDOMWindowUtils::GetSystemFont(nsACString& aFontName) {
aFontName.Assign(fontName);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetUsesOverlayScrollbars(bool* aResult) {
*aResult = Document::UseOverlayScrollbars(GetDocument());
return NS_OK;
}

View File

@ -99,6 +99,10 @@ class nsDOMWindowUtils final : public nsIDOMWindowUtils,
const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces,
int32_t aModifiers, bool aIgnoreRootScrollFrame, bool aToWindow,
bool* aPreventDefault);
void ReportErrorMessageForWindow(const nsAString& aErrorMessage,
const char* aClassification,
bool aFromChrome);
};
#endif

View File

@ -3877,6 +3877,11 @@ void nsGlobalWindowOuter::SetCSSViewportWidthAndHeight(nscoord aInnerWidth,
shellArea.SetHeight(aInnerHeight);
shellArea.SetWidth(aInnerWidth);
// FIXME(emilio): This doesn't seem to be ok, this doesn't reflow or
// anything... Should go through PresShell::ResizeReflow.
//
// But I don't think this can be reached by content, as we don't allow to set
// inner{Width,Height}.
presContext->SetVisibleArea(shellArea);
}

View File

@ -585,9 +585,12 @@ class nsINode : public mozilla::dom::EventTarget {
nsIContent* GetChildAt_Deprecated(uint32_t aIndex) const;
/**
* Get the index of a child within this content
* Get the index of a child within this content.
*
* @param aPossibleChild the child to get the index of.
* @return the index of the child, or -1 if not a child
* @return the index of the child, or -1 if not a child. Be aware that
* anonymous children (e.g. a <div> child of an <input> element) will
* result in -1.
*
* If the return value is not -1, then calling GetChildAt_Deprecated() with
* that value will return aPossibleChild.
@ -763,6 +766,11 @@ class nsINode : public mozilla::dom::EventTarget {
return isShadowRoot;
}
bool IsHTMLHeadingElement() const {
return IsAnyOfHTMLElements(nsGkAtoms::h1, nsGkAtoms::h2, nsGkAtoms::h3,
nsGkAtoms::h4, nsGkAtoms::h5, nsGkAtoms::h6);
}
/**
* Insert a content node before another or at the end.
* This method handles calling BindToTree on the child appropriately.

View File

@ -39,8 +39,7 @@ static void SetupCapitalization(const char16_t* aWord, uint32_t aLength,
for (uint32_t i = 0; i < aLength; ++i) {
uint32_t ch = aWord[i];
if (capitalizeNextChar) {
if (NS_IS_HIGH_SURROGATE(ch) && i + 1 < aLength &&
NS_IS_LOW_SURROGATE(aWord[i + 1])) {
if (i + 1 < aLength && NS_IS_SURROGATE_PAIR(ch, aWord[i + 1])) {
ch = SURROGATE_TO_UCS4(ch, aWord[i + 1]);
}
if (nsContentUtils::IsAlphanumeric(ch)) {

View File

@ -132,7 +132,7 @@ nsICSSDeclaration* nsStyledElement::Style() {
if (!slots->mStyle) {
// Just in case...
ReparseStyleAttribute(true, false);
ReparseStyleAttribute(/* aForceInDataDoc */ true);
slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
SetMayHaveStyle();
@ -141,14 +141,12 @@ nsICSSDeclaration* nsStyledElement::Style() {
return slots->mStyle;
}
nsresult nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc,
bool aForceIfAlreadyParsed) {
nsresult nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc) {
if (!MayHaveStyle()) {
return NS_OK;
}
const nsAttrValue* oldVal = mAttrs.GetAttr(nsGkAtoms::style);
if (oldVal && (aForceIfAlreadyParsed ||
oldVal->Type() != nsAttrValue::eCSSDeclaration)) {
if (oldVal && oldVal->Type() != nsAttrValue::eCSSDeclaration) {
nsAttrValue attrValue;
nsAutoString stringValue;
oldVal->ToString(stringValue);
@ -164,10 +162,6 @@ nsresult nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc,
return NS_OK;
}
void nsStyledElement::NodeInfoChanged(Document* aOldDoc) {
nsStyledElementBase::NodeInfoChanged(aOldDoc);
}
nsICSSDeclaration* nsStyledElement::GetExistingStyle() {
Element::nsDOMSlots* slots = GetExistingDOMSlots();
if (!slots) {

View File

@ -80,13 +80,9 @@ class nsStyledElement : public nsStyledElementBase {
* Create the style struct from the style attr. Used when an element is
* first put into a document. Only has an effect if the old value is a
* string. If aForceInDataDoc is true, will reparse even if we're in a data
* document. If aForceIfAlreadyParsed is set, this will always reparse even
* if the value has already been parsed.
* document.
*/
nsresult ReparseStyleAttribute(bool aForceInDataDoc,
bool aForceIfAlreadyParsed);
virtual void NodeInfoChanged(mozilla::dom::Document* aOldDoc) override;
nsresult ReparseStyleAttribute(bool aForceInDataDoc);
virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValueOrString* aValue,

View File

@ -225,8 +225,7 @@ class nsTextFragment final {
if (!mState.mIs2b || aIndex + 1 >= mState.mLength) {
return false;
}
return NS_IS_HIGH_SURROGATE(Get2b()[aIndex]) &&
NS_IS_LOW_SURROGATE(Get2b()[aIndex + 1]);
return NS_IS_SURROGATE_PAIR(Get2b()[aIndex], Get2b()[aIndex + 1]);
}
/**
@ -239,8 +238,7 @@ class nsTextFragment final {
if (!mState.mIs2b || aIndex <= 0) {
return false;
}
return NS_IS_LOW_SURROGATE(Get2b()[aIndex]) &&
NS_IS_HIGH_SURROGATE(Get2b()[aIndex - 1]);
return NS_IS_SURROGATE_PAIR(Get2b()[aIndex - 1], Get2b()[aIndex]);
}
/**

View File

@ -9,6 +9,11 @@
using namespace mozilla;
void nsViewportInfo::ConstrainViewportValues() {
// Non-positive zoom factors can produce NaN or negative viewport sizes,
// so we better be sure our constraints will produce positive zoom factors.
MOZ_ASSERT(mMinZoom > CSSToScreenScale(0.0f), "zoom factor must be positive");
MOZ_ASSERT(mMaxZoom > CSSToScreenScale(0.0f), "zoom factor must be positive");
if (mDefaultZoom > mMaxZoom) {
mDefaultZoomValid = false;
mDefaultZoom = mMaxZoom;

View File

@ -348,6 +348,11 @@ static void CollectWindowReports(nsGlobalWindowInner* aWindow,
"allocated in its arena and not measured elsewhere, "
"within a window.");
REPORT_SIZE("/layout/display-list", mLayoutRetainedDisplayListSize,
"Memory used by the retained display list data, "
"along with any structures allocated in its arena and not "
"measured elsewhere, within a window.");
REPORT_SIZE("/layout/style-sets/stylist/rule-tree",
mLayoutStyleSetsStylistRuleTree,
"Memory used by rule trees within style sets within a window.");
@ -415,8 +420,52 @@ static void CollectWindowReports(nsGlobalWindowInner* aWindow,
"Number of event listeners in a window, including event "
"listeners on nodes and other event targets.");
REPORT_SIZE("/layout/line-boxes", mArenaSizes.mLineBoxes,
"Memory used by line boxes within a window.");
// There are many different kinds of frames, but it is very likely
// that only a few matter. Implement a cutoff so we don't bloat
// about:memory with many uninteresting entries.
const size_t ARENA_SUNDRIES_THRESHOLD =
js::MemoryReportingSundriesThreshold();
size_t presArenaSundriesSize = 0;
#define ARENA_OBJECT(name_, sundries_size_, prefix_) \
{ \
size_t size = windowSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_); \
if (size < ARENA_SUNDRIES_THRESHOLD) { \
sundries_size_ += size; \
} else { \
REPORT_SUM_SIZE(prefix_ #name_, size, \
"Memory used by objects of type " #name_ \
" within a window."); \
} \
aWindowTotalSizes->mArenaSizes.NS_ARENA_SIZES_FIELD(name_) += size; \
}
#define PRES_ARENA_OBJECT(name_) \
ARENA_OBJECT(name_, presArenaSundriesSize, "/layout/pres-arena/")
#include "nsPresArenaObjectList.h"
#undef PRES_ARENA_OBJECT
if (presArenaSundriesSize > 0) {
REPORT_SUM_SIZE(
"/layout/pres-arena/sundries", presArenaSundriesSize,
"The sum of all memory used by objects in the arena which were too "
"small to be shown individually.");
}
size_t displayListArenaSundriesSize = 0;
#define DISPLAY_LIST_ARENA_OBJECT(name_) \
ARENA_OBJECT(name_, displayListArenaSundriesSize, \
"/layout/display-list-arena/")
#include "nsDisplayListArenaTypes.h"
#undef DISPLAY_LIST_ARENA_OBJECT
if (displayListArenaSundriesSize > 0) {
REPORT_SUM_SIZE(
"/layout/display-list-arena/sundries", displayListArenaSundriesSize,
"The sum of all memory used by objects in the DL arena which were too "
"small to be shown individually.");
}
#undef ARENA_OBJECT
// There are many different kinds of style structs, but it is likely that
// only a few matter. Implement a cutoff so we don't bloat about:memory with
@ -424,38 +473,6 @@ static void CollectWindowReports(nsGlobalWindowInner* aWindow,
const size_t STYLE_SUNDRIES_THRESHOLD =
js::MemoryReportingSundriesThreshold();
// There are many different kinds of frames, but it is very likely
// that only a few matter. Implement a cutoff so we don't bloat
// about:memory with many uninteresting entries.
const size_t FRAME_SUNDRIES_THRESHOLD =
js::MemoryReportingSundriesThreshold();
size_t frameSundriesSize = 0;
#define FRAME_ID(classname, ...) \
{ \
size_t size = windowSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(classname); \
if (size < FRAME_SUNDRIES_THRESHOLD) { \
frameSundriesSize += size; \
} else { \
REPORT_SUM_SIZE("/layout/frames/" #classname, size, \
"Memory used by frames of type " #classname \
" within a window."); \
} \
aWindowTotalSizes->mArenaSizes.NS_ARENA_SIZES_FIELD(classname) += size; \
}
#define ABSTRACT_FRAME_ID(...)
#include "mozilla/FrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
if (frameSundriesSize > 0) {
REPORT_SUM_SIZE(
"/layout/frames/sundries", frameSundriesSize,
"The sum of all memory used by frames which were too small to be shown "
"individually.");
}
// This is the style structs.
size_t styleSundriesSize = 0;
#define STYLE_STRUCT(name_) \
{ \
@ -637,21 +654,26 @@ nsWindowMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
REPORT("window-objects/property-tables", windowTotalSizes.mPropertyTablesSize,
"This is the sum of all windows' 'property-tables' numbers.");
REPORT("window-objects/layout/line-boxes",
windowTotalSizes.mArenaSizes.mLineBoxes,
"This is the sum of all windows' 'layout/line-boxes' numbers.");
size_t presArenaTotal = 0;
#define PRES_ARENA_OBJECT(name_) \
presArenaTotal += windowTotalSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_);
#include "nsPresArenaObjectList.h"
#undef PRES_ARENA_OBJECT
size_t frameTotal = 0;
#define FRAME_ID(classname, ...) \
frameTotal += windowTotalSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(classname);
#define ABSTRACT_FRAME_ID(...)
#include "mozilla/FrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
REPORT("window-objects/layout/pres-arena", presArenaTotal,
"Memory used for the pres arena within windows. "
"This is the sum of all windows' 'layout/pres-arena/' numbers.");
REPORT("window-objects/layout/frames", frameTotal,
"Memory used for layout frames within windows. "
"This is the sum of all windows' 'layout/frames/' numbers.");
size_t displayListArenaTotal = 0;
#define DISPLAY_LIST_ARENA_OBJECT(name_) \
displayListArenaTotal += \
windowTotalSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_);
#include "nsDisplayListArenaTypes.h"
#undef DISPLAY_LIST_ARENA_OBJECT
REPORT("window-objects/layout/display-list-arena", displayListArenaTotal,
"Memory used for the display list arena within windows. This is the "
"sum of all windows' 'layout/display-list-arena/' numbers.");
size_t styleTotal = 0;
#define STYLE_STRUCT(name_) \

View File

@ -85,56 +85,49 @@ struct nsStyleSizes {
#define NS_ARENA_SIZES_FIELD(classname) mArena##classname
struct nsArenaSizes {
#define FOR_EACH_SIZE(MACRO) MACRO(Other, mLineBoxes)
nsArenaSizes()
: FOR_EACH_SIZE(ZERO_SIZE)
#define FRAME_ID(classname, ...) NS_ARENA_SIZES_FIELD(classname)(0),
#define ABSTRACT_FRAME_ID(...)
#include "mozilla/FrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
dummy() {
:
#define PRES_ARENA_OBJECT(name_) NS_ARENA_SIZES_FIELD(name_)(0),
#define DISPLAY_LIST_ARENA_OBJECT(name_) PRES_ARENA_OBJECT(name_)
#include "nsPresArenaObjectList.h"
#include "nsDisplayListArenaTypes.h"
#undef PRES_ARENA_OBJECT
#undef DISPLAY_LIST_ARENA_OBJECT
dummy() {
}
void addToTabSizes(nsTabSizes* aSizes) const {
FOR_EACH_SIZE(ADD_TO_TAB_SIZES)
#define FRAME_ID(classname, ...) \
aSizes->add(nsTabSizes::Other, NS_ARENA_SIZES_FIELD(classname));
#define ABSTRACT_FRAME_ID(...)
#include "mozilla/FrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
#define PRES_ARENA_OBJECT(name_) \
aSizes->add(nsTabSizes::Other, NS_ARENA_SIZES_FIELD(name_));
#define DISPLAY_LIST_ARENA_OBJECT(name_) PRES_ARENA_OBJECT(name_)
#include "nsPresArenaObjectList.h"
#include "nsDisplayListArenaTypes.h"
#undef PRES_ARENA_OBJECT
#undef DISPLAY_LIST_ARENA_OBJECT
}
size_t getTotalSize() const {
size_t total = 0;
FOR_EACH_SIZE(ADD_TO_TOTAL_SIZE)
#define FRAME_ID(classname, ...) total += NS_ARENA_SIZES_FIELD(classname);
#define ABSTRACT_FRAME_ID(...)
#include "mozilla/FrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
#define PRES_ARENA_OBJECT(name_) total += NS_ARENA_SIZES_FIELD(name_);
#define DISPLAY_LIST_ARENA_OBJECT(name_) PRES_ARENA_OBJECT(name_)
#include "nsPresArenaObjectList.h"
#include "nsDisplayListArenaTypes.h"
#undef PRES_ARENA_OBJECT
#undef DISPLAY_LIST_ARENA_OBJECT
return total;
}
FOR_EACH_SIZE(DECL_SIZE)
#define FRAME_ID(classname, ...) size_t NS_ARENA_SIZES_FIELD(classname);
#define ABSTRACT_FRAME_ID(...)
#include "mozilla/FrameIdList.h"
#undef FRAME_ID
#undef ABSTRACT_FRAME_ID
#define PRES_ARENA_OBJECT(name_) size_t NS_ARENA_SIZES_FIELD(name_);
#define DISPLAY_LIST_ARENA_OBJECT(name_) PRES_ARENA_OBJECT(name_)
#include "nsPresArenaObjectList.h"
#include "nsDisplayListArenaTypes.h"
#undef PRES_ARENA_OBJECT
#undef DISPLAY_LIST_ARENA_OBJECT
// Present just to absorb the trailing comma in the constructor.
int dummy;
#undef FOR_EACH_SIZE
};
class nsWindowSizes {
@ -152,6 +145,7 @@ class nsWindowSizes {
MACRO(Style, mLayoutShadowDomStyleSheetsSize) \
MACRO(Style, mLayoutShadowDomAuthorStyles) \
MACRO(Other, mLayoutPresShellSize) \
MACRO(Other, mLayoutRetainedDisplayListSize) \
MACRO(Style, mLayoutStyleSetsStylistRuleTree) \
MACRO(Style, mLayoutStyleSetsStylistElementAndPseudosMaps) \
MACRO(Style, mLayoutStyleSetsStylistInvalidationMap) \

View File

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=0.5">
<style>
html {
scrollbar-width: none; /* avoid scrollbar width is included in some metrics */
}
html, body {
margin: 0;
width: 100%;
height: 100%;
overflow: none;
}
#twice-width {
width: 200%;
height: 100%;
position: absolute;
}
</style>
<div id="twice-width"></div>
<script>
const is = opener.is.bind(opener);
const todo_is = opener.todo_is.bind(opener);
const add_task = opener.add_task.bind(opener);
const original_finish = opener.SimpleTest.finish;
const SimpleTest = opener.SimpleTest;
SimpleTest.finish = function finish() {
self.close();
original_finish();
}
add_task(async () => {
// Explicitly set to 0.5x so that this test doesn't need to reply on our
// auto initial-scale calculation.
SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(0.5);
is(window.visualViewport.scale, 0.5, "The content should be scaled by 0.5x");
// Now the visual viewport size is same as the layout viewport.
const layoutViewportHeight = window.visualViewport.height;
is(window.innerHeight, layoutViewportHeight,
"window.innerHeight should reflect the layout viewport");
is(document.documentElement.scrollHeight, layoutViewportHeight,
"The root element's scrollHeight should be the layout viewport height");
is(document.documentElement.getBoundingClientRect().height,
layoutViewportHeight / 2,
"The content height should be half of the layout viewport height");
// Set scale to 1.0x so that the visual viport size becomes 0.5x of the layout
// viewport.
SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(1);
is(window.visualViewport.scale, 1, "The content should be scaled by 1.0x");
is(window.visualViewport.height, layoutViewportHeight / 2,
"Now the visual viewport height should be changed to half of the layout " +
"viewport height");
todo_is(window.innerHeight, layoutViewportHeight,
"window.innerHeight shouldn't be changed (Bug 1514429)");
is(document.documentElement.scrollHeight, layoutViewportHeight,
"The root element's scrollHeight shouldn't be changed");
});
</script>
</html>

View File

@ -6,6 +6,7 @@
#include "jsapi.h"
#include "nsContentUtils.h"
#include "nsNetUtil.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/SimpleGlobalObject.h"

View File

@ -837,6 +837,9 @@ support-files = file_title.xul
[test_treewalker_nextsibling.xml]
[test_user_select.html]
skip-if = toolkit == 'android'
[test_viewport_metrics_on_landscape_content.html]
support-files =
file_viewport_metrics_on_landscape_content.html
[test_viewport_scroll.html]
[test_viewsource_forbidden_in_object.html]
[test_w3element_traversal.html]

View File

@ -60,19 +60,19 @@ function checkIndividualResults(testname, expected) {
testname + " test: some image loads required in results object."
);
is(
results["img"].count,
results.img.count,
2,
testname + " Test: Expected 2 loads for image requests."
);
expected.forEach(function(ref) {
ok(
results["img"].referrers.includes(ref),
results.img.referrers.includes(ref),
testname +
" Test: Expected " +
ref +
" referrer policy in test, results were " +
JSON.stringify(results["img"].referrers) +
JSON.stringify(results.img.referrers) +
"."
);
});
@ -100,7 +100,7 @@ function checkExpectedGlobalResults(testName) {
for (policy in response[type][scheme]) {
var expectedResult =
EXPECTED_RESULTS[type] === undefined
? EXPECTED_RESULTS["default"][scheme][policy]
? EXPECTED_RESULTS.default[scheme][policy]
: EXPECTED_RESULTS[type][scheme][policy];
is(
response[type][scheme][policy],

View File

@ -54,7 +54,7 @@ function testCancelPreloadNotCrash(url) {
// Not actually verifying any value, just to ensure cancelPrefetchPreload
// won't cause crash.
prefetch.cancelPrefetchPreloadURI(ios.newURI(url, null, null), link);
prefetch.cancelPrefetchPreloadURI(ios.newURI(url), link);
}
function testChangePrefetchToPreload(url) {

View File

@ -66,7 +66,7 @@ document.addEventListener("DOMContentLoaded", function() {
s = document.createElement('script');
s.src="file_bug28293.sjs?res+='M';";
document.body.appendChild(s);
}, false);
});
res += 'G';
</script>
<script defer="defer">

View File

@ -52,6 +52,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=320799
<select id="s3">
<option>x</option>
</select>
<select id="s4" style="width: 100px; box-sizing: border-box; border: 0; margin: 10px">
<option>This is a test, it really is a test I tell you</option>
</select>
</p>
<div id="content" style="display: none">
@ -63,6 +66,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=320799
is($("s").scrollWidth, 100, "Scroll width should not include dropdown contents");
is($("s2").clientWidth, $("s3").clientWidth,
"Client width should not depend on the dropdown's vertical scrollbar");
is($("s4").scrollWidth, 100, "Scroll width should not include dropdown contents");
</script>
</pre>
</body>

View File

@ -76,17 +76,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
function fn_onmessage(e) {
if (e.currentTarget == e.target && e.target.hits != null)
e.target.hits['fn_onmessage']++;
e.target.hits.fn_onmessage++;
}
function fn_event_listener_message(e) {
if (e.currentTarget == e.target && e.target.hits != null)
e.target.hits['fn_event_listener_message']++;
e.target.hits.fn_event_listener_message++;
}
function fn_other_event_name(e) {
if (e.currentTarget == e.target && e.target.hits != null)
e.target.hits['fn_other_event_name']++;
e.target.hits.fn_other_event_name++;
}
var gEventSourceObj1 = null, gEventSourceObj1_e, gEventSourceObj1_f;
@ -105,9 +105,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
// the test when running in slow machines
function hasBeenHitFor1And2(obj, min) {
if (obj.hits['fn_onmessage'] < min ||
obj.hits['fn_event_listener_message'] < min ||
obj.hits['fn_other_event_name'] < min)
if (obj.hits.fn_onmessage < min ||
obj.hits.fn_event_listener_message < min ||
obj.hits.fn_other_event_name < min)
return false;
return true;
}
@ -130,11 +130,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
function doTest1_b(test_id) {
gEventSourceObj1.hits = [];
gEventSourceObj1.hits['fn_onmessage'] = 0;
gEventSourceObj1.hits.fn_onmessage = 0;
gEventSourceObj1.onmessage = fn_onmessage;
gEventSourceObj1.hits['fn_event_listener_message'] = 0;
gEventSourceObj1.hits.fn_event_listener_message = 0;
gEventSourceObj1.addEventListener('message', fn_event_listener_message, true);
gEventSourceObj1.hits['fn_other_event_name'] = 0;
gEventSourceObj1.hits.fn_other_event_name = 0;
gEventSourceObj1.addEventListener('other_event_name', fn_other_event_name, true);
// the eventsources.res always use a retry of 0.5 second, so for four hits a timeout of 6 seconds is enough
@ -154,9 +154,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
}
function doTest1_d(test_id) {
gEventSourceObj1.hits['fn_onmessage'] = 0;
gEventSourceObj1.hits['fn_event_listener_message'] = 0;
gEventSourceObj1.hits['fn_other_event_name'] = 0;
gEventSourceObj1.hits.fn_onmessage = 0;
gEventSourceObj1.hits.fn_event_listener_message = 0;
gEventSourceObj1.hits.fn_other_event_name = 0;
setTimeout(function(){
bhits = hasBeenHitFor1And2(gEventSourceObj1, 1);
@ -237,10 +237,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_a.onmessage = fn_onmessage;
gEventSourceObj3_a.hits = [];
gEventSourceObj3_a.hits['fn_onmessage'] = 0;
gEventSourceObj3_a.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_a.hits['fn_onmessage'] == 0, "Test 3.a failed");
ok(gEventSourceObj3_a.hits.fn_onmessage == 0, "Test 3.a failed");
gEventSourceObj3_a.close();
setTestHasFinished(test_id);
}, parseInt(1500*stress_factor));
@ -262,10 +262,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_b.onmessage = fn_onmessage;
gEventSourceObj3_b.hits = [];
gEventSourceObj3_b.hits['fn_onmessage'] = 0;
gEventSourceObj3_b.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_b.hits['fn_onmessage'] == 0, "Test 3.b failed");
ok(gEventSourceObj3_b.hits.fn_onmessage == 0, "Test 3.b failed");
gEventSourceObj3_b.close();
setTestHasFinished(test_id);
}, parseInt(1500*stress_factor));
@ -282,10 +282,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_c.onmessage = fn_onmessage;
gEventSourceObj3_c.hits = [];
gEventSourceObj3_c.hits['fn_onmessage'] = 0;
gEventSourceObj3_c.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_c.hits['fn_onmessage'] == 0, "Test 3.c failed");
ok(gEventSourceObj3_c.hits.fn_onmessage == 0, "Test 3.c failed");
gEventSourceObj3_c.close();
setTestHasFinished(test_id);
}, parseInt(1500*stress_factor));
@ -296,10 +296,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_d.onmessage = fn_onmessage;
gEventSourceObj3_d.hits = [];
gEventSourceObj3_d.hits['fn_onmessage'] = 0;
gEventSourceObj3_d.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_d.hits['fn_onmessage'] == 0, "Test 3.d failed");
ok(gEventSourceObj3_d.hits.fn_onmessage == 0, "Test 3.d failed");
gEventSourceObj3_d.close();
setTestHasFinished(test_id);
}, parseInt(1500*stress_factor));
@ -310,10 +310,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_e.onmessage = fn_onmessage;
gEventSourceObj3_e.hits = [];
gEventSourceObj3_e.hits['fn_onmessage'] = 0;
gEventSourceObj3_e.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_e.hits['fn_onmessage'] == 0, "Test 3.e failed");
ok(gEventSourceObj3_e.hits.fn_onmessage == 0, "Test 3.e failed");
gEventSourceObj3_e.close();
setTestHasFinished(test_id);
}, parseInt(1500*stress_factor));
@ -324,10 +324,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_f.onmessage = fn_onmessage;
gEventSourceObj3_f.hits = [];
gEventSourceObj3_f.hits['fn_onmessage'] = 0;
gEventSourceObj3_f.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_f.hits['fn_onmessage'] == 0, "Test 3.f failed");
ok(gEventSourceObj3_f.hits.fn_onmessage == 0, "Test 3.f failed");
gEventSourceObj3_f.close();
setTestHasFinished(test_id);
}, parseInt(1500*stress_factor));
@ -342,10 +342,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_g.onmessage = fn_onmessage;
gEventSourceObj3_g.hits = [];
gEventSourceObj3_g.hits['fn_onmessage'] = 0;
gEventSourceObj3_g.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_g.hits['fn_onmessage'] == 0, "Test 3.g failed");
ok(gEventSourceObj3_g.hits.fn_onmessage == 0, "Test 3.g failed");
gEventSourceObj3_g.close();
setTestHasFinished(test_id);
}, parseInt(1500*stress_factor));
@ -365,11 +365,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj3_h.onmessage = fn_onmessage;
gEventSourceObj3_h.hits = [];
gEventSourceObj3_h.hits['fn_onmessage'] = 0;
gEventSourceObj3_h.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj3_h.hits['fn_onmessage'] > 1, "Test 3.h.1 failed");
if (gEventSourceObj3_h.hits['fn_onmessage'] > 1) {
ok(gEventSourceObj3_h.hits.fn_onmessage > 1, "Test 3.h.1 failed");
if (gEventSourceObj3_h.hits.fn_onmessage > 1) {
ok(fnMessageListenerTest3h.msg_ok, "Test 3.h.2 failed");
ok(fnMessageListenerTest3h.id_ok, "Test 3.h.3 failed");
}
@ -438,10 +438,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj5_a.onmessage = fn_onmessage;
gEventSourceObj5_a.hits = [];
gEventSourceObj5_a.hits['fn_onmessage'] = 0;
gEventSourceObj5_a.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj5_a.hits['fn_onmessage'] != 0, "Test 5.a failed");
ok(gEventSourceObj5_a.hits.fn_onmessage != 0, "Test 5.a failed");
gEventSourceObj5_a.close();
setTestHasFinished(test_id);
}, parseInt(3000*stress_factor));
@ -453,10 +453,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
gEventSourceObj5_b.onmessage = fn_onmessage;
gEventSourceObj5_b.hits = [];
gEventSourceObj5_b.hits['fn_onmessage'] = 0;
gEventSourceObj5_b.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj5_b.hits['fn_onmessage'] == 0, "Test 5.b failed");
ok(gEventSourceObj5_b.hits.fn_onmessage == 0, "Test 5.b failed");
gEventSourceObj5_b.close();
setTestHasFinished(test_id);
}, parseInt(3000*stress_factor));
@ -481,10 +481,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
fn_onmessage(e);
};
gEventSourceObj5_c.hits = [];
gEventSourceObj5_c.hits['fn_onmessage'] = 0;
gEventSourceObj5_c.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj5_c.hits['fn_onmessage'] > 0, "Test 5.c failed");
ok(gEventSourceObj5_c.hits.fn_onmessage > 0, "Test 5.c failed");
gEventSourceObj5_c.close();
doTest5_d(test_id);
}, parseInt(3000*stress_factor));
@ -507,10 +507,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
fn_onmessage(e);
};
gEventSourceObj5_d.hits = [];
gEventSourceObj5_d.hits['fn_onmessage'] = 0;
gEventSourceObj5_d.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj5_d.hits['fn_onmessage'] == 0, "Test 5.d failed");
ok(gEventSourceObj5_d.hits.fn_onmessage == 0, "Test 5.d failed");
gEventSourceObj5_d.close();
setTestHasFinished(test_id);
}, parseInt(3000*stress_factor));
@ -535,10 +535,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
fn_onmessage(e);
};
gEventSourceObj5_e.hits = [];
gEventSourceObj5_e.hits['fn_onmessage'] = 0;
gEventSourceObj5_e.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj5_e.hits['fn_onmessage'] > 0, "Test 5.e failed");
ok(gEventSourceObj5_e.hits.fn_onmessage > 0, "Test 5.e failed");
gEventSourceObj5_e.close();
doTest5_f(test_id);
}, parseInt(5000*stress_factor));
@ -562,10 +562,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583
fn_onmessage(e);
};
gEventSourceObj5_f.hits = [];
gEventSourceObj5_f.hits['fn_onmessage'] = 0;
gEventSourceObj5_f.hits.fn_onmessage = 0;
setTimeout(function() {
ok(gEventSourceObj5_f.hits['fn_onmessage'] == 0, "Test 5.f failed");
ok(gEventSourceObj5_f.hits.fn_onmessage == 0, "Test 5.f failed");
gEventSourceObj5_f.close();
setTestHasFinished(test_id);
}, parseInt(3000*stress_factor));

View File

@ -23,15 +23,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=339494
d.setAttribute("hhh", "testvalue");
document.addEventListener("DOMAttrModified", removeItAgain, false);
document.addEventListener("DOMAttrModified", removeItAgain);
d.removeAttribute("hhh");
document.removeEventListener("DOMAttrModified", removeItAgain, false);
document.removeEventListener("DOMAttrModified", removeItAgain);
function removeItAgain()
{
ok(!d.hasAttribute("hhh"), "Value check 1, there should be no value");
isnot(d.getAttribute("hhh"), "testvalue", "Value check 2");
document.removeEventListener("DOMAttrModified", removeItAgain, false);
document.removeEventListener("DOMAttrModified", removeItAgain);
d.removeAttribute("hhh");
ok(true, "Reachability, We shouldn't have crashed");
}
@ -40,9 +40,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=339494
s.setAttribute("ggg", "testvalue");
document.addEventListener("DOMAttrModified", compareVal, false);
document.addEventListener("DOMAttrModified", compareVal);
s.setAttribute("ggg", "othervalue");
document.removeEventListener("DOMAttrModified", compareVal, false);
document.removeEventListener("DOMAttrModified", compareVal);
function compareVal()
{

View File

@ -157,7 +157,7 @@ function request_document() {
// GeckoView shows an error page for CSP errors, which breaks this test, so just skip in that case.
try {
if (!SpecialPowers.Cc["@mozilla.org/android/bridge;1"].getService(SpecialPowers.Ci.nsIAndroidBridge).isFennec) {
lastContentType = Ci.nsIContentPolicy["TYPE_DOCUMENT"];
lastContentType = Ci.nsIContentPolicy.TYPE_DOCUMENT;
return;
}
} catch (e){}

View File

@ -39,7 +39,7 @@ function logEvent(evt) {
uploadTotal = evt.total
} else {
if (evt.type == "progress") {
is(evt.lengthComputable, evt.total != 0, "event(" + evt.type + ").lengthComputable should be " + (evt.total != 0 ? true : false) + ".");
is(evt.lengthComputable, evt.total != 0, "event(" + evt.type + ").lengthComputable should be " + (evt.total != 0) + ".");
}
if (evt.total != uploadTotal && evt.total != 0) {
ok(false, "event(" + evt.type + ").total should not change during upload except to become 0 on error/abort/timeout.");

View File

@ -50,7 +50,7 @@ function mousedown(event) {
function selectByMouseThenClick(elm,startx,starty) {
// select some text
var ctrl = navigator.platform.indexOf("Linux") ? true : false;
var ctrl = !!navigator.platform.indexOf("Linux");
var alt = true;
var x = startx;
synthesizeMouse(elm, x, starty, { type:"mousedown", ctrlKey:ctrl, altKey:alt });

View File

@ -23,10 +23,10 @@ SimpleTest.waitForExplicitFinish();
var xhr = new XMLHttpRequest();
xhr.onload = function() {
is(xhr.response["foo"], "bar", "Should have gotten bar on baseline");
is(xhr.response.foo, "bar", "Should have gotten bar on baseline");
xhr.onload = function() {
is(xhr.response["foo"], "bar", "Should have gotten bar with BOM");
is(xhr.response.foo, "bar", "Should have gotten bar with BOM");
xhr.onload = function() {
is(xhr.response, null, "Should have gotten null response with UTF-16 JSON");

View File

@ -14,7 +14,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=891952
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var all = document.all;
is(all["content"], $("content"), "Should find the content");
is(all.content, $("content"), "Should find the content");
ok(!("" in all), "Should not have an empty string prop on document.all");
is(all[""], undefined, "Should not get empty string on document.all");
is(all.namedItem(""), null,

View File

@ -122,6 +122,14 @@ let runTests = t.step_func_done(function() {
input.value = "foo";
document.documentElement.appendChild(input);
}, "Native anonymous content isn't exposed in window.find");
testFindable(false, "\0", `
&#0;
`);
testFindable(true, "\0", function(document) {
document.documentElement.appendChild(document.createTextNode("\0"));
}, "Inserted null characters are findable");
});
window.onload = function() {

View File

@ -50,7 +50,7 @@ addLoadEvent(function() {
is(bod.getBoundingClientRect().width, 50, "Width of body should still be 50px");
window.requestAnimationFrame(function() {
is(resizeHandlerRan, true, "Resize handler should have run");
win.removeEventListener("resize", handleResize, false);
win.removeEventListener("resize", handleResize);
SimpleTest.finish();
});
});

View File

@ -0,0 +1,22 @@
<!doctype html>
<meta charset=utf-8>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
<script>
'use strict';
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({
"set": [
["apz.allow_zooming", true],
["dom.meta-viewport.enabled", true],
["layout.viewport_contains_no_contents_area", true],
]
}, () => {
// We need to open a new window to avoid running tests in an iframe since
// we want to test metrics on the root document.
window.open("file_viewport_metrics_on_landscape_content.html");
});
</script>

View File

@ -817,117 +817,117 @@ DOMInterfaces = {
},
'SVGPathSeg': {
'nativeType': 'mozilla::DOMSVGPathSeg',
'nativeType': 'mozilla::dom::DOMSVGPathSeg',
'headerFile': 'DOMSVGPathSeg.h',
},
'SVGPathSegClosePath': {
'nativeType': 'mozilla::DOMSVGPathSegClosePath',
'nativeType': 'mozilla::dom::DOMSVGPathSegClosePath',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegMovetoAbs': {
'nativeType': 'mozilla::DOMSVGPathSegMovetoAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegMovetoAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegMovetoRel': {
'nativeType': 'mozilla::DOMSVGPathSegMovetoRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegMovetoRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoAbs': {
'nativeType': 'mozilla::DOMSVGPathSegLinetoAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoRel': {
'nativeType': 'mozilla::DOMSVGPathSegLinetoRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicAbs': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoCubicAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicRel': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoCubicRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticAbs': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoQuadraticAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticRel': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoQuadraticRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegArcAbs': {
'nativeType': 'mozilla::DOMSVGPathSegArcAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegArcAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegArcRel': {
'nativeType': 'mozilla::DOMSVGPathSegArcRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegArcRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoHorizontalAbs': {
'nativeType': 'mozilla::DOMSVGPathSegLinetoHorizontalAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoHorizontalAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoHorizontalRel': {
'nativeType': 'mozilla::DOMSVGPathSegLinetoHorizontalRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoHorizontalRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoVerticalAbs': {
'nativeType': 'mozilla::DOMSVGPathSegLinetoVerticalAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoVerticalAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegLinetoVerticalRel': {
'nativeType': 'mozilla::DOMSVGPathSegLinetoVerticalRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegLinetoVerticalRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicSmoothAbs': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoCubicSmoothAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicSmoothAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoCubicSmoothRel': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoCubicSmoothRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoCubicSmoothRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticSmoothAbs': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoQuadraticSmoothAbs',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticSmoothAbs',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegCurvetoQuadraticSmoothRel': {
'nativeType': 'mozilla::DOMSVGPathSegCurvetoQuadraticSmoothRel',
'nativeType': 'mozilla::dom::DOMSVGPathSegCurvetoQuadraticSmoothRel',
'headerFile': 'DOMSVGPathSeg.h'
},
'SVGPathSegList': {
'nativeType': 'mozilla::DOMSVGPathSegList',
'nativeType': 'mozilla::dom::DOMSVGPathSegList',
'headerFile': 'DOMSVGPathSegList.h'
},
'SVGPoint': {
'nativeType': 'mozilla::nsISVGPoint',
'nativeType': 'mozilla::dom::nsISVGPoint',
'headerFile': 'nsISVGPoint.h'
},
'SVGPointList': {
'nativeType': 'mozilla::DOMSVGPointList',
'nativeType': 'mozilla::dom::DOMSVGPointList',
'headerFile': 'DOMSVGPointList.h'
},
@ -940,12 +940,8 @@ DOMInterfaces = {
'headerFile': 'mozilla/dom/SVGGradientElement.h',
},
'SVGRect': {
'nativeType': 'mozilla::dom::SVGIRect'
},
'SVGStringList': {
'nativeType': 'mozilla::DOMSVGStringList',
'nativeType': 'mozilla::dom::DOMSVGStringList',
'headerFile': 'DOMSVGStringList.h',
},
@ -955,7 +951,7 @@ DOMInterfaces = {
},
'SVGTransformList': {
'nativeType': 'mozilla::DOMSVGTransformList',
'nativeType': 'mozilla::dom::DOMSVGTransformList',
'headerFile': 'DOMSVGTransformList.h'
},

View File

@ -37,7 +37,8 @@ class BasicRenderingContext2D {
virtual void Transform(double aM11, double aM12, double aM21, double aM22,
double aDx, double aDy,
mozilla::ErrorResult& aError) = 0;
virtual already_AddRefed<DOMMatrix> GetTransform(mozilla::ErrorResult& aError) = 0;
virtual already_AddRefed<DOMMatrix> GetTransform(
mozilla::ErrorResult& aError) = 0;
virtual void SetTransform(double aM11, double aM12, double aM21, double aM22,
double aDx, double aDy,
mozilla::ErrorResult& aError) = 0;

View File

@ -3953,6 +3953,9 @@ gfxFontGroup* CanvasRenderingContext2D::GetCurrentFontStyle() {
NS_ERROR("Default canvas font is invalid");
}
}
} else {
// The fontgroup needs to check if its cached families/faces are valid.
CurrentState().fontGroup->CheckForUpdatedPlatformList();
}
return CurrentState().fontGroup;

View File

@ -94,7 +94,8 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
void Translate(double aX, double aY, mozilla::ErrorResult& aError) override;
void Transform(double aM11, double aM12, double aM21, double aM22, double aDx,
double aDy, mozilla::ErrorResult& aError) override;
already_AddRefed<DOMMatrix> GetTransform(mozilla::ErrorResult& aError) override;
already_AddRefed<DOMMatrix> GetTransform(
mozilla::ErrorResult& aError) override;
void SetTransform(double aM11, double aM12, double aM21, double aM22,
double aDx, double aDy,
mozilla::ErrorResult& aError) override;

View File

@ -47,7 +47,7 @@ load 1305312-1.html
load 1305850.html
load 1334366-1.html
load 1334647-1.html
load 1349067.html
skip-if(geckoview&&webrender) load 1349067.html # Bug 1563214 for GV+WR
pref(gfx.offscreencanvas.enabled,true) load 1348976-1.html
load 1357092.html
load 1441613.html

View File

@ -9,7 +9,7 @@
WEBGL_TYPES = {};
WEBGL_TYPES['experimental-webgl'] = true;
WEBGL_TYPES['webgl'] = true;
WEBGL_TYPES.webgl = true;
function AreBothIn(a, b, set) {
return (a in set) && (b in set);
@ -73,7 +73,7 @@ if (IsWebGLFunctional())
functionalTypeSet['experimental-webgl'] = true;
if (IsWebGLConformant())
functionalTypeSet['webgl'] = true;
functionalTypeSet.webgl = true;
for (var i in typeList) {
var creationType = typeList[i];

View File

@ -4,6 +4,7 @@
#ifndef _mozilla_dom_Client_h
#define _mozilla_dom_Client_h
#include "X11UndefineNone.h"
#include "mozilla/dom/ClientBinding.h"
#include "mozilla/StorageAccess.h"
#include "nsCOMPtr.h"

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