Merge inbound to mozilla-central. a=merge

This commit is contained in:
Margareta Eliza Balazs 2018-10-18 13:20:43 +03:00
commit c56977420d
327 changed files with 3915 additions and 2397 deletions

View File

@ -19,6 +19,16 @@
/>
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="mozglue"
version="1.0.0.0"
language="*"
/>
</dependentAssembly>
</dependency>
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:security>
<ms_asmv3:requestedPrivileges>

View File

@ -30,6 +30,7 @@ ac_add_options --target=i686-w64-mingw32
ac_add_options --with-toolchain-prefix=i686-w64-mingw32-
ac_add_options --disable-warnings-as-errors
MOZ_COPY_PDBS=1
# Temporary config settings until we get these working on mingw
ac_add_options --disable-accessibility # https://sourceforge.net/p/mingw-w64/bugs/648/

View File

@ -30,6 +30,7 @@ ac_add_options --target=x86_64-w64-mingw32
ac_add_options --with-toolchain-prefix=x86_64-w64-mingw32-
ac_add_options --disable-warnings-as-errors
MOZ_COPY_PDBS=1
# Temporary config settings until we get these working on mingw
ac_add_options --disable-accessibility # https://sourceforge.net/p/mingw-w64/bugs/648/

View File

@ -711,6 +711,14 @@ async function sanitizeSessionPrincipals() {
return;
}
// When PREF_COOKIE_LIFETIME is set to ACCEPT_SESSION, any new cookie will be
// marked as session only. But we don't touch the existing ones. For this
// reason, here we delete any existing cookie, at shutdown.
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_COOKIES,
resolve);
});
let principals = await new Promise(resolve => {
quotaManagerService.getUsage(request => {
if (request.resultCode != Cr.NS_OK) {

View File

@ -1126,11 +1126,13 @@ def check_have_64_bit(have_64_bit, compiler_have_64_bit):
'about the target bitness.')
@depends(c_compiler)
def default_debug_flags(compiler_info):
@depends(c_compiler, target)
def default_debug_flags(compiler_info, target):
# Debug info is ON by default.
if compiler_info.type in ('msvc', 'clang-cl'):
return '-Zi'
elif target.kernel == 'WINNT' and compiler_info.type == 'clang':
return '-g -gcodeview'
return '-g'
@ -1992,11 +1994,16 @@ add_old_configure_assignment('LIBFUZZER_FLAGS', libfuzzer_flags.use_flags)
@depends(target, c_compiler)
def make_shared_library(target, compiler):
if target.os == 'WINNT':
if compiler.type in ('gcc', 'clang'):
if compiler.type == 'gcc':
return namespace(
mkshlib=['$(CXX)', '$(DSO_LDOPTS)', '-o', '$@'],
mkcshlib=['$(CC)', '$(DSO_LDOPTS)', '-o', '$@'],
)
elif compiler.type == 'clang':
return namespace(
mkshlib=['$(CXX)', '$(DSO_LDOPTS)', '-Wl,-pdb,$(LINK_PDBFILE)', '-o', '$@'],
mkcshlib=['$(CC)', '$(DSO_LDOPTS)', '-Wl,-pdb,$(LINK_PDBFILE)', '-o', '$@'],
)
else:
linker = [
'$(LINKER)',

View File

@ -7,6 +7,7 @@ if [ -d "$topsrcdir/clang" ]; then
mk_export_correct_style LIB
export LDFLAGS="clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib"
export MOZ_COPY_PDBS=1
export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer.exe"
export MOZ_CLANG_RT_ASAN_LIB_PATH="${CLANG_LIB_DIR}/clang_rt.asan_dynamic-x86_64.dll"
fi

View File

@ -126,6 +126,9 @@ endif # MKSHLIB
endif # FORCE_SHARED_LIB
ifeq ($(OS_ARCH),WINNT)
LINK_PDBFILE ?= $(basename $(@F)).pdb
ifndef GNU_CC
#
@ -147,7 +150,6 @@ endif
COMPILE_CFLAGS += $(COMPILE_PDB_FLAG)
COMPILE_CXXFLAGS += $(COMPILE_PDB_FLAG)
LINK_PDBFILE ?= $(basename $(@F)).pdb
ifdef MOZ_DEBUG
CODFILE=$(basename $(@F)).cod
endif
@ -161,6 +163,12 @@ MOZ_PROGRAM_LDFLAGS += -Wl,-rpath -Wl,@executable_path/Frameworks
endif
endif
ifeq ($(OS_ARCH),WINNT)
ifeq ($(CC_TYPE),clang)
MOZ_PROGRAM_LDFLAGS += -Wl,-pdb,$(dir $@)/$(LINK_PDBFILE)
endif
endif
ifeq ($(HOST_OS_ARCH),WINNT)
HOST_PDBFILE=$(basename $(@F)).pdb
HOST_PDB_FLAG ?= -Fd$(HOST_PDBFILE)
@ -819,13 +827,13 @@ DUMP_SYMS_TARGETS :=
endif
endif
ifdef MOZ_CRASHREPORTER
$(foreach file,$(DUMP_SYMS_TARGETS),$(eval $(call syms_template,$(file),$(notdir $(file))_syms.track)))
else ifneq (,$(and $(LLVM_SYMBOLIZER),$(filter WINNT,$(OS_ARCH)),$(MOZ_AUTOMATION)))
ifdef MOZ_COPY_PDBS
PDB_FILES = $(addsuffix .pdb,$(basename $(DUMP_SYMS_TARGETS)))
PDB_DEST ?= $(FINAL_TARGET)
PDB_TARGET = syms
INSTALL_TARGETS += PDB
else ifdef MOZ_CRASHREPORTER
$(foreach file,$(DUMP_SYMS_TARGETS),$(eval $(call syms_template,$(file),$(notdir $(file))_syms.track)))
endif
cargo_host_flag := --target=$(RUST_HOST_TARGET)

View File

@ -274,12 +274,14 @@ print RCFILE qq{
my $versionlevel=0;
my $insideversion=0;
my $has_manifest=0;
if (open(RCINCLUDE, "<$rcinclude"))
{
print RCFILE "// From included resource $rcinclude\n";
# my $mstring="";
while (<RCINCLUDE>)
{
$has_manifest = 1 if /^1 (24|RT_MANIFEST) "$binary.manifest"/;
$_ =~ s/\@MOZ_APP_DISPLAYNAME\@/$displayname/g;
print RCFILE $_;
# my $instr=$_;
@ -330,6 +332,10 @@ if (open(RCINCLUDE, "<$rcinclude"))
my $fileflags = join(' | ', @fileflags);
print RCFILE qq{
1 RT_MANIFEST "$binary.manifest"
} if !$has_manifest && $binary =~ /\.exe$/ && -e "$objdir/$binary.manifest";
print RCFILE qq{

View File

@ -876,7 +876,7 @@ Inspector.prototype = {
let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
if (this.is3PaneModeEnabled && defaultTab === "ruleview") {
defaultTab = "computedview";
defaultTab = "layoutview";
}
// Append all side panels

View File

@ -181,6 +181,7 @@ skip-if = (os == "win" && debug) # bug 963492: win.
[browser_rules_grid-toggle_02.js]
[browser_rules_grid-toggle_03.js]
[browser_rules_grid-toggle_04.js]
[browser_rules_grid-toggle_05.js]
[browser_rules_gridline-names-autocomplete.js]
[browser_rules_guessIndentation.js]
[browser_rules_highlight-used-fonts.js]

View File

@ -29,7 +29,7 @@ add_task(async function() {
const gridToggle = container.querySelector(".ruleview-grid");
info("Checking the initial state of the CSS grid toggle in the rule-view.");
ok(gridToggle, "Grid highlighter toggle is visible.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
@ -41,6 +41,7 @@ add_task(async function() {
info("Checking the CSS grid highlighter is created and toggle button is active in " +
"the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(gridToggle.classList.contains("active"),
"Grid highlighter toggle is active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
@ -52,6 +53,7 @@ add_task(async function() {
info("Checking the CSS grid highlighter is not shown and toggle button is not active " +
"in the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");

View File

@ -29,7 +29,7 @@ add_task(async function() {
const gridToggle = container.querySelector(".ruleview-grid");
info("Checking the initial state of the CSS grid toggle in the rule-view.");
ok(gridToggle, "Grid highlighter toggle is visible.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
@ -41,6 +41,7 @@ add_task(async function() {
info("Checking the CSS grid highlighter is created and toggle button is active in " +
"the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(gridToggle.classList.contains("active"),
"Grid highlighter toggle is active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
@ -52,6 +53,7 @@ add_task(async function() {
info("Checking the CSS grid highlighter is not shown and toggle button is not active " +
"in the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");

View File

@ -34,7 +34,9 @@ add_task(async function() {
const overriddenGridToggle = overriddenContainer.querySelector(".ruleview-grid");
info("Checking the initial state of the CSS grid toggle in the rule-view.");
ok(gridToggle && overriddenGridToggle, "Grid highlighter toggles are visible.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!overriddenGridToggle.hasAttribute("disabled"),
"Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active") &&
!overriddenGridToggle.classList.contains("active"),
"Grid highlighter toggle buttons are not active.");

View File

@ -35,7 +35,7 @@ add_task(async function() {
info("Checking the state of the CSS grid toggle for the first grid container in the " +
"rule-view.");
ok(gridToggle, "Grid highlighter toggle is visible.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
@ -48,6 +48,7 @@ add_task(async function() {
info("Checking the CSS grid highlighter is created and toggle button is active in " +
"the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(gridToggle.classList.contains("active"),
"Grid highlighter toggle is active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
@ -60,7 +61,7 @@ add_task(async function() {
info("Checking the state of the CSS grid toggle for the second grid container in the " +
"rule-view.");
ok(gridToggle, "Grid highlighter toggle is visible.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is still shown.");
@ -85,7 +86,7 @@ add_task(async function() {
info("Checking the state of the CSS grid toggle for the first grid container in the " +
"rule-view.");
ok(gridToggle, "Grid highlighter toggle is visible.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
});

View File

@ -29,7 +29,7 @@ add_task(async function() {
const gridToggle = container.querySelector(".ruleview-grid");
info("Checking the initial state of the CSS grid toggle in the rule-view.");
ok(gridToggle, "Grid highlighter toggle is visible.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
@ -41,6 +41,7 @@ add_task(async function() {
info("Checking the CSS grid highlighter is created and toggle button is active in " +
"the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(gridToggle.classList.contains("active"),
"Grid highlighter toggle is active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
@ -52,6 +53,7 @@ add_task(async function() {
info("Checking the CSS grid highlighter is not shown and toggle button is not active " +
"in the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");

View File

@ -0,0 +1,102 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the grid toggle is hidden when the maximum number of grid highlighters
// have been reached.
const TEST_URI = `
<style type='text/css'>
.grid {
display: grid;
}
</style>
<div id="grid1" class="grid">
<div class="cell1">cell1</div>
<div class="cell2">cell2</div>
</div>
<div id="grid2" class="grid">
<div class="cell1">cell1</div>
<div class="cell2">cell2</div>
</div>
<div id="grid3" class="grid">
<div class="cell1">cell1</div>
<div class="cell2">cell2</div>
</div>
`;
add_task(async function() {
await pushPref("devtools.gridinspector.maxHighlighters", 2);
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
const { inspector, gridInspector } = await openLayoutView();
const ruleView = selectRuleView(inspector);
const { document: doc } = gridInspector;
const { highlighters } = inspector;
await selectNode("#grid1", inspector);
const gridList = doc.getElementById("grid-list");
const checkbox2 = gridList.children[1].querySelector("input");
const checkbox3 = gridList.children[2].querySelector("input");
const container = getRuleViewProperty(ruleView, ".grid", "display").valueSpan;
const gridToggle = container.querySelector(".ruleview-grid");
info("Checking the initial state of the CSS grid toggle in the rule-view.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
ok(!highlighters.gridHighlighters.size, "No CSS grid highlighter is shown.");
info("Toggling ON the CSS grid highlighter for #grid2.");
let onHighlighterShown = highlighters.once("grid-highlighter-shown");
checkbox2.click();
await onHighlighterShown;
info("Checking the CSS grid toggle for #grid1 is not disabled and not active.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
info("Toggling ON the CSS grid highlighter for #grid3.");
onHighlighterShown = highlighters.once("grid-highlighter-shown");
checkbox3.click();
await onHighlighterShown;
info("Checking the CSS grid toggle for #grid1 is disabled.");
ok(gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is disabled.");
is(highlighters.gridHighlighters.size, 2, "CSS grid highlighters are shown.");
info("Toggling OFF the CSS grid highlighter for #grid3.");
let onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
checkbox3.click();
await onHighlighterHidden;
info("Checking the CSS grid toggle for #grid1 is not disabled and not active.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
info("Toggling ON the CSS grid highlighter for #grid1 from the rule-view.");
onHighlighterShown = highlighters.once("grid-highlighter-shown");
gridToggle.click();
await onHighlighterShown;
info("Checking the CSS grid toggle for #grid1 is not disabled.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(gridToggle.classList.contains("active"), "Grid highlighter toggle is active.");
is(highlighters.gridHighlighters.size, 2, "CSS grid highlighters are shown.");
info("Toggling OFF the CSS grid highlighter for #grid1 from the rule-view.");
onHighlighterHidden = highlighters.once("grid-highlighter-hidden");
gridToggle.click();
await onHighlighterHidden;
info("Checking the CSS grid toggle for #grid1 is not disabled and not active.");
ok(!gridToggle.hasAttribute("disabled"), "Grid highlighter toggle is not disabled.");
ok(!gridToggle.classList.contains("active"),
"Grid highlighter toggle button is not active.");
is(highlighters.gridHighlighters.size, 1, "CSS grid highlighter is shown.");
});

View File

@ -76,6 +76,7 @@ function TextPropertyEditor(ruleEditor, property) {
this.prop = property;
this.prop.editor = this;
this.browserWindow = this.doc.defaultView.top;
this._populatedComputed = false;
this._hasPendingClick = false;
this._clickedElementOptions = null;
@ -521,22 +522,22 @@ TextPropertyEditor.prototype = {
}
}
const nodeFront = this.ruleView.inspector.selection.nodeFront;
const flexToggle = this.valueSpan.querySelector(".ruleview-flex");
if (flexToggle) {
flexToggle.setAttribute("title", l10n("rule.flexToggle.tooltip"));
if (this.ruleView.highlighters.flexboxHighlighterShown ===
this.ruleView.inspector.selection.nodeFront) {
flexToggle.classList.add("active");
}
flexToggle.classList.toggle("active",
this.ruleView.highlighters.flexboxHighlighterShown === nodeFront);
}
const gridToggle = this.valueSpan.querySelector(".ruleview-grid");
if (gridToggle) {
gridToggle.setAttribute("title", l10n("rule.gridToggle.tooltip"));
if (this.ruleView.highlighters.gridHighlighters.has(
this.ruleView.inspector.selection.nodeFront)) {
gridToggle.classList.add("active");
}
gridToggle.classList.toggle("active",
this.ruleView.highlighters.gridHighlighters.has(nodeFront));
gridToggle.toggleAttribute("disabled",
!this.ruleView.highlighters.canGridHighlighterToggle(nodeFront));
}
const shapeToggle = this.valueSpan.querySelector(".ruleview-shapeswatch");

View File

@ -28,6 +28,8 @@ class HighlightersOverlay {
this.highlighterUtils = this.inspector.toolbox.highlighterUtils;
this.store = this.inspector.store;
this.telemetry = inspector.telemetry;
this.maxGridHighlighters =
Services.prefs.getIntPref("devtools.gridinspector.maxHighlighters");
// Collection of instantiated highlighter actors like FlexboxHighlighter,
// ShapesHighlighter and GeometryEditorHighlighter.
@ -432,19 +434,16 @@ class HighlightersOverlay {
* "rule" represents the rule view.
*/
async showGridHighlighter(node, options, trigger) {
const maxHighlighters =
Services.prefs.getIntPref("devtools.gridinspector.maxHighlighters");
// When the grid highlighter has the given node, it is probably called with new
// highlighting options, so skip any extra grid highlighter handling.
if (!this.gridHighlighters.has(node)) {
if (maxHighlighters === 1) {
if (this.maxGridHighlighters === 1) {
// Only one grid highlighter can be shown at a time. Hides any instantiated
// grid highlighters.
for (const nodeFront of this.gridHighlighters.keys()) {
await this.hideGridHighlighter(nodeFront);
}
} else if (this.gridHighlighters.size === maxHighlighters) {
} else if (this.gridHighlighters.size === this.maxGridHighlighters) {
// The maximum number of grid highlighters shown have been reached. Don't show
// any additional grid highlighters.
return;
@ -496,8 +495,6 @@ class HighlightersOverlay {
return;
}
this._toggleRuleViewIcon(node, false, ".ruleview-grid");
// Hide the highlighter and put it in the pool of extra grid highlighters
// so that it can be reused.
const highlighter = this.gridHighlighters.get(node);
@ -507,6 +504,8 @@ class HighlightersOverlay {
this.state.grids.delete(node);
this.gridHighlighters.delete(node);
this._toggleRuleViewIcon(node, false, ".ruleview-grid");
// Emit the NodeFront of the grid container element that the grid highlighter was
// hidden for.
this.emit("grid-highlighter-hidden", node);
@ -790,12 +789,22 @@ class HighlightersOverlay {
* The selector of the rule view icon to toggle.
*/
_toggleRuleViewIcon(node, active, selector) {
if (this.inspector.selection.nodeFront != node) {
const ruleViewEl = this.inspector.getPanel("ruleview").view.element;
if (this.inspector.selection.nodeFront !== node) {
if (selector === ".ruleview-grid") {
for (const icon of ruleViewEl.querySelectorAll(selector)) {
if (this.canGridHighlighterToggle(this.inspector.selection.nodeFront)) {
icon.removeAttribute("disabled");
} else {
icon.setAttribute("disabled", true);
}
}
}
return;
}
const ruleViewEl = this.inspector.getPanel("ruleview").view.element;
for (const icon of ruleViewEl.querySelectorAll(selector)) {
icon.classList.toggle("active", active);
}

View File

@ -8,16 +8,6 @@ const TEST_URI = "data:text/html;charset=UTF-8," +
const OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
const TELEMETRY_DATA = [
{
timestamp: null,
category: "devtools.main",
method: "tool_timer",
object: "computedview",
value: null,
extra: {
time_open: ""
}
},
{
timestamp: null,
category: "devtools.main",
@ -32,7 +22,17 @@ const TELEMETRY_DATA = [
timestamp: null,
category: "devtools.main",
method: "tool_timer",
object: "ruleview",
object: "fontinspector",
value: null,
extra: {
time_open: ""
}
},
{
timestamp: null,
category: "devtools.main",
method: "tool_timer",
object: "computedview",
value: null,
extra: {
time_open: ""
@ -50,18 +50,18 @@ add_task(async function() {
let { inspector, toolbox } = await openInspectorForURL(TEST_URI);
info("Selecting font inspector.");
inspector.sidebar.select("fontinspector");
is(inspector.sidebar.getCurrentTabID(), "fontinspector",
"Font Inspector is selected");
info("Selecting computed view.");
inspector.sidebar.select("computedview");
is(inspector.sidebar.getCurrentTabID(), "computedview",
"Computed View is selected");
info("Selecting layout view.");
inspector.sidebar.select("layoutview");
is(inspector.sidebar.getCurrentTabID(), "layoutview",
"Layout View is selected");
info("Closing inspector.");
await toolbox.destroy();
@ -73,8 +73,8 @@ add_task(async function() {
await inspector.sidebar.once("select");
}
is(inspector.sidebar.getCurrentTabID(), "layoutview",
"Layout view is selected by default.");
is(inspector.sidebar.getCurrentTabID(), "computedview",
"Computed view is selected by default.");
checkTelemetryResults();
});

View File

@ -33,7 +33,7 @@ pref("devtools.command-button-noautohide.enabled", false);
// Enable the Inspector
pref("devtools.inspector.enabled", true);
// What was the last active sidebar in the inspector
pref("devtools.inspector.activeSidebar", "ruleview");
pref("devtools.inspector.activeSidebar", "layoutview");
pref("devtools.inspector.remote", false);
// Enable the 3 pane mode in the inspector

View File

@ -19,7 +19,7 @@ const DATA = [
object: "inspector",
value: null,
extra: {
oldpanel: "computedview",
oldpanel: "layoutview",
newpanel: "animationinspector"
}
},
@ -156,8 +156,8 @@ function checkResults() {
// here.
checkTelemetry("DEVTOOLS_INSPECTOR_OPENED_COUNT", "", [1, 0, 0], "array");
checkTelemetry("DEVTOOLS_RULEVIEW_OPENED_COUNT", "", [1, 0, 0], "array");
checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT", "", [3, 0, 0], "array");
checkTelemetry("DEVTOOLS_LAYOUTVIEW_OPENED_COUNT", "", [2, 0, 0], "array");
checkTelemetry("DEVTOOLS_COMPUTEDVIEW_OPENED_COUNT", "", [2, 0, 0], "array");
checkTelemetry("DEVTOOLS_LAYOUTVIEW_OPENED_COUNT", "", [3, 0, 0], "array");
checkTelemetry("DEVTOOLS_FONTINSPECTOR_OPENED_COUNT", "", [2, 0, 0], "array");
checkTelemetry("DEVTOOLS_COMPUTEDVIEW_TIME_ACTIVE_SECONDS", "", null, "hasentries");
checkTelemetry("DEVTOOLS_LAYOUTVIEW_TIME_ACTIVE_SECONDS", "", null, "hasentries");

View File

@ -440,6 +440,11 @@
border-radius: 0;
}
.ruleview-grid[disabled] {
cursor: default;
opacity: 0.5;
}
.ruleview-shape-point.active,
.ruleview-shapeswatch.active + .ruleview-shape > .ruleview-shape-point:hover {
background-color: var(--rule-highlight-background-color);

View File

@ -56,22 +56,18 @@ TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
nsresult rv = NS_OK;
if (!mTimer) {
mTimer = NS_NewTimer();
mTimer = NS_NewTimer(mOwner->EventTarget());
NS_ENSURE_TRUE(mTimer, NS_ERROR_OUT_OF_MEMORY);
uint32_t earlyMicros = 0;
MOZ_ALWAYS_SUCCEEDS(mTimer->GetAllowedEarlyFiringMicroseconds(&earlyMicros));
mAllowedEarlyFiringTime = TimeDuration::FromMicroseconds(earlyMicros);
} else {
// Always call Cancel() in case we are re-using a timer.
rv = mTimer->Cancel();
NS_ENSURE_SUCCESS(rv, rv);
}
// Always call Cancel() in case we are re-using a timer. Otherwise
// the subsequent SetTarget() may fail.
rv = mTimer->Cancel();
NS_ENSURE_SUCCESS(rv, rv);
rv = mTimer->SetTarget(mOwner->EventTarget());
NS_ENSURE_SUCCESS(rv, rv);
// Calculate the delay based on the deadline and current time. If we have
// a minimum delay set then clamp to that value.
//

View File

@ -531,14 +531,13 @@ void
FileReader::StartProgressEventTimer()
{
if (!mProgressNotifier) {
mProgressNotifier = NS_NewTimer();
mProgressNotifier = NS_NewTimer(mTarget);
}
if (mProgressNotifier) {
mProgressEventWasDelayed = false;
mTimerIsActive = true;
mProgressNotifier->Cancel();
mProgressNotifier->SetTarget(mTarget);
mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
nsITimer::TYPE_ONE_SHOT);
}

View File

@ -1592,7 +1592,7 @@ ContentParent::MarkAsDead()
void
ContentParent::OnChannelError()
{
RefPtr<ContentParent> content(this);
RefPtr<ContentParent> kungFuDeathGrip(this);
PContentParent::OnChannelError();
}
@ -1738,14 +1738,14 @@ struct DelayedDeleteContentParentTask : public Runnable
{
explicit DelayedDeleteContentParentTask(ContentParent* aObj)
: Runnable("dom::DelayedDeleteContentParentTask")
, mObj(aObj)
, mKungFuDeathGrip(aObj)
{
}
// No-op
NS_IMETHOD Run() override { return NS_OK; }
RefPtr<ContentParent> mObj;
RefPtr<ContentParent> mKungFuDeathGrip;
};
} // namespace

View File

@ -23,16 +23,16 @@ struct FeatureMap {
*/
static FeatureMap sSupportedFeatures[] = {
{ "autoplay", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "camera", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "encrypted-media", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "fullscreen", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "geolocation", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "microphone", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "midi", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "payment", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "camera", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "encrypted-media", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "fullscreen", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "geolocation", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "microphone", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "midi", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "payment", FeaturePolicyUtils::FeaturePolicyValue::eAll },
// TODO: not supported yet!!!
{ "speaker", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "vr", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "speaker", FeaturePolicyUtils::FeaturePolicyValue::eAll },
{ "vr", FeaturePolicyUtils::FeaturePolicyValue::eAll },
};
/* static */ bool

View File

@ -3142,13 +3142,13 @@ XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
}
}
void
XMLHttpRequestMainThread::SetTimerEventTarget(nsITimer* aTimer)
nsIEventTarget*
XMLHttpRequestMainThread::GetTimerEventTarget()
{
if (nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal()) {
nsCOMPtr<nsIEventTarget> target = global->EventTargetFor(TaskCategory::Other);
aTimer->SetTarget(target);
return global->EventTargetFor(TaskCategory::Other);
}
return nullptr;
}
nsresult
@ -3183,8 +3183,7 @@ XMLHttpRequestMainThread::StartTimeoutTimer()
}
if (!mTimeoutTimer) {
mTimeoutTimer = NS_NewTimer();
SetTimerEventTarget(mTimeoutTimer);
mTimeoutTimer = NS_NewTimer(GetTimerEventTarget());
}
uint32_t elapsed =
(uint32_t)((PR_Now() - mRequestSentTime) / PR_USEC_PER_MSEC);
@ -3601,8 +3600,7 @@ void
XMLHttpRequestMainThread::StartProgressEventTimer()
{
if (!mProgressNotifier) {
mProgressNotifier = NS_NewTimer();
SetTimerEventTarget(mProgressNotifier);
mProgressNotifier = NS_NewTimer(GetTimerEventTarget());
}
if (mProgressNotifier) {
mProgressTimerIsActive = true;
@ -3628,8 +3626,7 @@ XMLHttpRequestMainThread::MaybeStartSyncTimeoutTimer()
return eErrorOrExpired;
}
mSyncTimeoutTimer = NS_NewTimer();
SetTimerEventTarget(mSyncTimeoutTimer);
mSyncTimeoutTimer = NS_NewTimer(GetTimerEventTarget());
if (!mSyncTimeoutTimer) {
return eErrorOrExpired;
}

View File

@ -514,7 +514,7 @@ protected:
nsresult OnRedirectVerifyCallback(nsresult result);
void SetTimerEventTarget(nsITimer* aTimer);
nsIEventTarget* GetTimerEventTarget();
nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable);

View File

@ -737,6 +737,7 @@ WebRenderMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
helper.ReportTexture(aReport.vertex_data_textures, "vertex-data");
helper.ReportTexture(aReport.render_target_textures, "render-targets");
helper.ReportTexture(aReport.texture_cache_textures, "texture-cache");
helper.ReportTexture(aReport.depth_target_textures, "depth-targets");
FinishAsyncMemoryReport();
},

View File

@ -22,6 +22,7 @@ void brush_vs(
#define BRUSH_FLAG_SEGMENT_RELATIVE 2
#define BRUSH_FLAG_SEGMENT_REPEAT_X 4
#define BRUSH_FLAG_SEGMENT_REPEAT_Y 8
#define BRUSH_FLAG_TEXEL_RECT 16
void main(void) {
// Load the brush instance from vertex attributes.

View File

@ -51,7 +51,7 @@ void brush_vs(
mat4 transform,
PictureTask pic_task,
int brush_flags,
vec4 texel_rect
vec4 segment_data
) {
ImageBrushData image_data = fetch_image_data(prim_address);
@ -76,19 +76,18 @@ void brush_vs(
local_rect = segment_rect;
stretch_size = local_rect.size;
// Note: Here we can assume that texels in device
// space map to local space, due to how border-image
// works. That assumption may not hold if this
// is used for other purposes in the future.
if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_X) != 0) {
stretch_size.x = (texel_rect.z - texel_rect.x) / pic_task.common_data.device_pixel_scale;
stretch_size.x = (segment_data.z - segment_data.x);
}
if ((brush_flags & BRUSH_FLAG_SEGMENT_REPEAT_Y) != 0) {
stretch_size.y = (texel_rect.w - texel_rect.y) / pic_task.common_data.device_pixel_scale;
stretch_size.y = (segment_data.w - segment_data.y);
}
uv0 = res.uv_rect.p0 + texel_rect.xy;
uv1 = res.uv_rect.p0 + texel_rect.zw;
// If the extra data is a texel rect, modify the UVs.
if ((brush_flags & BRUSH_FLAG_TEXEL_RECT) != 0) {
uv0 = res.uv_rect.p0 + segment_data.xy;
uv1 = res.uv_rect.p0 + segment_data.zw;
}
}
vUv.z = res.layer;

View File

@ -10,7 +10,6 @@ flat varying vec4 vUvSampleBounds;
#ifdef WR_VERTEX_SHADER
struct SplitGeometry {
vec2 local[4];
RectWithSize local_rect;
};
SplitGeometry fetch_split_geometry(int address) {
@ -18,7 +17,6 @@ SplitGeometry fetch_split_geometry(int address) {
vec4 data0 = TEXEL_FETCH(sGpuCache, uv, 0, ivec2(0, 0));
vec4 data1 = TEXEL_FETCH(sGpuCache, uv, 0, ivec2(1, 0));
vec4 data2 = TEXEL_FETCH(sGpuCache, uv, 0, ivec2(2, 0));
SplitGeometry geo;
geo.local = vec2[4](
@ -27,7 +25,6 @@ SplitGeometry fetch_split_geometry(int address) {
data1.xy,
data1.zw
);
geo.local_rect = RectWithSize(data2.xy, data2.zw);
return geo;
}
@ -98,7 +95,7 @@ void main(void) {
max_uv - vec2(0.5)
) / texture_size.xyxy;
vec2 f = (local_pos - geometry.local_rect.p0) / geometry.local_rect.size;
vec2 f = (local_pos - ph.local_rect.p0) / ph.local_rect.size;
f = bilerp(
extra_data.st_tl, extra_data.st_tr,

View File

@ -20,12 +20,13 @@ use plane_split::{BspSplitter, Clipper, Polygon, Splitter};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentTaskId, DeferredResolve};
use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveIndex};
use prim_store::{VisibleGradientTile, PrimitiveInstance};
use prim_store::{BorderSource, Primitive, PrimitiveDetails};
use prim_store::{BrushSegment, BorderSource, Primitive, PrimitiveDetails};
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree};
use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
use renderer::BLOCKS_PER_UV_RECT;
use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache, ImageProperties};
use scene::FilterOpHelpers;
use smallvec::SmallVec;
use std::{f32, i32, usize};
use tiling::{RenderTargetContext};
use util::{MatrixHelpers, TransformedRectKind};
@ -419,6 +420,15 @@ impl AlphaBatchContainer {
}
}
/// Each segment can optionally specify a per-segment
/// texture set and one user data field.
#[derive(Debug, Copy, Clone)]
struct SegmentInstanceData {
textures: BatchTextures,
user_data: i32,
is_opaque_override: Option<bool>,
}
/// Encapsulates the logic of building batches for items that are blended.
pub struct AlphaBatchBuilder {
pub batch_list: BatchList,
@ -551,7 +561,6 @@ impl AlphaBatchBuilder {
let gpu_blocks = [
[local_points[0].x, local_points[0].y, local_points[1].x, local_points[1].y].into(),
[local_points[2].x, local_points[2].y, local_points[3].x, local_points[3].y].into(),
pic_metadata.local_rect.into(),
];
let gpu_handle = gpu_cache.push_per_frame_blocks(&gpu_blocks);
@ -1103,37 +1112,29 @@ impl AlphaBatchBuilder {
);
}
_ => {
// TODO(gw): As an interim step, just return one value for the
// per-segment user data. In the future, this method
// will be expanded to optionally return a list of
// (BatchTextures, user_data) per segment, which will
// allow a different texture / render task to be used
// per segment.
if let Some((batch_kind, textures, user_data, segment_user_data)) = brush.get_batch_params(
ctx.resource_cache,
gpu_cache,
deferred_resolves,
ctx.prim_store.chase_id == Some(prim_instance.prim_index),
if let Some(params) = brush.get_batch_params(
ctx.resource_cache,
gpu_cache,
deferred_resolves,
ctx.prim_store.chase_id == Some(prim_instance.prim_index),
) {
let prim_header_index = prim_headers.push(&prim_header, user_data);
let prim_header_index = prim_headers.push(&prim_header, params.prim_user_data);
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_instance.prim_index) {
println!("\t{:?} {:?}, task relative bounds {:?}",
batch_kind, prim_header_index, bounding_rect);
params.batch_kind, prim_header_index, bounding_rect);
}
self.add_brush_to_batch(
brush,
&params,
prim_instance,
batch_kind,
specified_blend_mode,
non_segmented_blend_mode,
textures,
prim_header_index,
clip_task_address,
bounding_rect,
transform_kind,
render_tasks,
segment_user_data,
);
}
}
@ -1270,80 +1271,147 @@ impl AlphaBatchBuilder {
);
}
/// Add a single segment instance to a batch.
fn add_segment_to_batch(
&mut self,
segment: &BrushSegment,
segment_data: &SegmentInstanceData,
segment_index: i32,
batch_kind: BrushBatchKind,
prim_instance: &PrimitiveInstance,
prim_header_index: PrimitiveHeaderIndex,
alpha_blend_mode: BlendMode,
bounding_rect: &WorldRect,
transform_kind: TransformedRectKind,
render_tasks: &RenderTaskTree,
) {
let clip_task_address = match segment.clip_task_id {
BrushSegmentTaskId::RenderTaskId(id) =>
render_tasks.get_task_address(id),
BrushSegmentTaskId::Opaque => OPAQUE_TASK_ADDRESS,
BrushSegmentTaskId::Empty => return,
};
// If the segment instance data specifies opacity for that
// segment, use it. Otherwise, assume opacity for the segment
// from the overall primitive opacity.
let is_segment_opaque = match segment_data.is_opaque_override {
Some(is_opaque) => is_opaque,
None => prim_instance.opacity.is_opaque,
};
let is_inner = segment.edge_flags.is_empty();
let needs_blending = !is_segment_opaque ||
segment.clip_task_id.needs_blending() ||
(!is_inner && transform_kind == TransformedRectKind::Complex);
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index,
edge_flags: segment.edge_flags,
clip_task_address,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION | segment.brush_flags,
prim_header_index,
user_data: segment_data.user_data,
});
let batch_key = BatchKey {
blend_mode: if needs_blending { alpha_blend_mode } else { BlendMode::None },
kind: BatchKind::Brush(batch_kind),
textures: segment_data.textures,
};
self.batch_list.push_single_instance(
batch_key,
bounding_rect,
prim_instance.prim_index,
instance,
);
}
/// Add any segment(s) from a brush to batches.
fn add_brush_to_batch(
&mut self,
brush: &BrushPrimitive,
params: &BrushBatchParameters,
prim_instance: &PrimitiveInstance,
batch_kind: BrushBatchKind,
alpha_blend_mode: BlendMode,
non_segmented_blend_mode: BlendMode,
textures: BatchTextures,
prim_header_index: PrimitiveHeaderIndex,
clip_task_address: RenderTaskAddress,
bounding_rect: &WorldRect,
transform_kind: TransformedRectKind,
render_tasks: &RenderTaskTree,
user_data: i32,
) {
let base_instance = BrushInstance {
prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
};
match brush.segment_desc {
Some(ref segment_desc) => {
for (i, segment) in segment_desc.segments.iter().enumerate() {
let is_inner = segment.edge_flags.is_empty();
let needs_blending = !prim_instance.opacity.is_opaque ||
segment.clip_task_id.needs_blending() ||
(!is_inner && transform_kind == TransformedRectKind::Complex);
let clip_task_address = match segment.clip_task_id {
BrushSegmentTaskId::RenderTaskId(id) =>
render_tasks.get_task_address(id),
BrushSegmentTaskId::Opaque => OPAQUE_TASK_ADDRESS,
BrushSegmentTaskId::Empty => continue,
};
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index: i as i32,
edge_flags: segment.edge_flags,
clip_task_address,
brush_flags: base_instance.brush_flags | segment.brush_flags,
..base_instance
});
let batch_key = BatchKey {
blend_mode: if needs_blending { alpha_blend_mode } else { BlendMode::None },
kind: BatchKind::Brush(batch_kind),
textures,
};
self.batch_list.push_single_instance(
batch_key,
match (&brush.segment_desc, &params.segment_data) {
(Some(ref segment_desc), SegmentDataKind::Instanced(ref segment_data)) => {
// In this case, we have both a list of segments, and a list of
// per-segment instance data. Zip them together to build batches.
debug_assert_eq!(segment_desc.segments.len(), segment_data.len());
for (segment_index, (segment, segment_data)) in segment_desc.segments
.iter()
.zip(segment_data.iter())
.enumerate() {
self.add_segment_to_batch(
segment,
segment_data,
segment_index as i32,
params.batch_kind,
prim_instance,
prim_header_index,
alpha_blend_mode,
bounding_rect,
prim_instance.prim_index,
instance,
transform_kind,
render_tasks,
);
}
}
None => {
(Some(ref segment_desc), SegmentDataKind::Shared(ref segment_data)) => {
// A list of segments, but the per-segment data is common
// between all segments.
for (segment_index, segment) in segment_desc.segments
.iter()
.enumerate() {
self.add_segment_to_batch(
segment,
segment_data,
segment_index as i32,
params.batch_kind,
prim_instance,
prim_header_index,
alpha_blend_mode,
bounding_rect,
transform_kind,
render_tasks,
);
}
}
(None, SegmentDataKind::Shared(ref segment_data)) => {
// No segments, and thus no per-segment instance data.
let batch_key = BatchKey {
blend_mode: non_segmented_blend_mode,
kind: BatchKind::Brush(batch_kind),
textures,
kind: BatchKind::Brush(params.batch_kind),
textures: segment_data.textures,
};
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(),
clip_task_address,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
user_data: segment_data.user_data,
});
self.batch_list.push_single_instance(
batch_key,
bounding_rect,
prim_instance.prim_index,
PrimitiveInstanceData::from(base_instance),
PrimitiveInstanceData::from(instance),
);
}
(None, SegmentDataKind::Instanced(..)) => {
// We should never hit the case where there are no segments,
// but a list of segment instance data.
unreachable!();
}
}
}
}
@ -1426,6 +1494,58 @@ fn get_image_tile_params(
}
}
/// Either a single texture / user data for all segments,
/// or a list of one per segment.
enum SegmentDataKind {
Shared(SegmentInstanceData),
Instanced(SmallVec<[SegmentInstanceData; 8]>),
}
/// The parameters that are specific to a kind of brush,
/// used by the common method to add a brush to batches.
struct BrushBatchParameters {
batch_kind: BrushBatchKind,
prim_user_data: [i32; 3],
segment_data: SegmentDataKind,
}
impl BrushBatchParameters {
/// This brush instance has a list of per-segment
/// instance data.
fn instanced(
batch_kind: BrushBatchKind,
prim_user_data: [i32; 3],
segment_data: SmallVec<[SegmentInstanceData; 8]>,
) -> Self {
BrushBatchParameters {
batch_kind,
prim_user_data,
segment_data: SegmentDataKind::Instanced(segment_data),
}
}
/// This brush instance shares the per-segment data
/// across all segments.
fn shared(
batch_kind: BrushBatchKind,
textures: BatchTextures,
prim_user_data: [i32; 3],
segment_user_data: i32,
) -> Self {
BrushBatchParameters {
batch_kind,
prim_user_data,
segment_data: SegmentDataKind::Shared(
SegmentInstanceData {
textures,
user_data: segment_user_data,
is_opaque_override: None,
}
),
}
}
}
impl BrushPrimitive {
fn get_batch_params(
&self,
@ -1433,7 +1553,7 @@ impl BrushPrimitive {
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>,
is_chased: bool,
) -> Option<(BrushBatchKind, BatchTextures, [i32; 3], i32)> {
) -> Option<BrushBatchParameters> {
match self.kind {
BrushKind::Image { request, ref source, .. } => {
let cache_item = match *source {
@ -1463,7 +1583,7 @@ impl BrushPrimitive {
} else {
let textures = BatchTextures::color(cache_item.texture_id);
Some((
Some(BrushBatchParameters::shared(
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
textures,
[
@ -1478,7 +1598,7 @@ impl BrushPrimitive {
BrushKind::LineDecoration { ref handle, style, .. } => {
match style {
LineStyle::Solid => {
Some((
Some(BrushBatchParameters::shared(
BrushBatchKind::Solid,
BatchTextures::no_texture(),
[0; 3],
@ -1492,7 +1612,7 @@ impl BrushPrimitive {
.get_cached_render_task(handle.as_ref().unwrap());
let cache_item = resource_cache.get_texture_cache_item(&rt_cache_entry.handle);
let textures = BatchTextures::color(cache_item.texture_id);
Some((
Some(BrushBatchParameters::shared(
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
textures,
[
@ -1506,48 +1626,69 @@ impl BrushPrimitive {
}
}
BrushKind::Border { ref source, .. } => {
let cache_item = match *source {
match *source {
BorderSource::Image(request) => {
resolve_image(
let cache_item = resolve_image(
request,
resource_cache,
gpu_cache,
deferred_resolves,
)
}
BorderSource::Border { ref handle, .. } => {
let rt_handle = match *handle {
Some(ref handle) => handle,
None => return None,
};
let rt_cache_entry = resource_cache
.get_cached_render_task(rt_handle);
resource_cache.get_texture_cache_item(&rt_cache_entry.handle)
}
};
);
if cache_item.texture_id == TextureSource::Invalid {
None
} else {
let textures = BatchTextures::color(cache_item.texture_id);
if cache_item.texture_id == TextureSource::Invalid {
return None;
}
Some((
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
textures,
[
ShaderColorMode::Image as i32,
RasterizationSpace::Local as i32,
0,
],
cache_item.uv_rect_handle.as_int(gpu_cache),
))
let textures = BatchTextures::color(cache_item.texture_id);
Some(BrushBatchParameters::shared(
BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)),
textures,
[
ShaderColorMode::Image as i32,
RasterizationSpace::Local as i32,
0,
],
cache_item.uv_rect_handle.as_int(gpu_cache),
))
}
BorderSource::Border { ref segments, .. } => {
let mut segment_data = SmallVec::new();
// Collect the segment instance data from each render
// task for each valid edge / corner of the border.
for segment in segments {
let rt_cache_entry = resource_cache
.get_cached_render_task(segment.handle.as_ref().unwrap());
let cache_item = resource_cache
.get_texture_cache_item(&rt_cache_entry.handle);
segment_data.push(
SegmentInstanceData {
textures: BatchTextures::color(cache_item.texture_id),
user_data: cache_item.uv_rect_handle.as_int(gpu_cache),
is_opaque_override: Some(segment.is_opaque),
}
);
}
Some(BrushBatchParameters::instanced(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
[
ShaderColorMode::Image as i32,
RasterizationSpace::Local as i32,
0,
],
segment_data,
))
}
}
}
BrushKind::Picture { .. } => {
panic!("bug: get_batch_key is handled at higher level for pictures");
}
BrushKind::Solid { .. } => {
Some((
Some(BrushBatchParameters::shared(
BrushBatchKind::Solid,
BatchTextures::no_texture(),
[0; 3],
@ -1555,7 +1696,7 @@ impl BrushPrimitive {
))
}
BrushKind::Clear => {
Some((
Some(BrushBatchParameters::shared(
BrushBatchKind::Solid,
BatchTextures::no_texture(),
[0; 3],
@ -1563,7 +1704,7 @@ impl BrushPrimitive {
))
}
BrushKind::RadialGradient { ref stops_handle, .. } => {
Some((
Some(BrushBatchParameters::shared(
BrushBatchKind::RadialGradient,
BatchTextures::no_texture(),
[
@ -1575,7 +1716,7 @@ impl BrushPrimitive {
))
}
BrushKind::LinearGradient { ref stops_handle, .. } => {
Some((
Some(BrushBatchParameters::shared(
BrushBatchKind::LinearGradient,
BatchTextures::no_texture(),
[
@ -1631,7 +1772,7 @@ impl BrushPrimitive {
color_space,
);
Some((
Some(BrushBatchParameters::shared(
kind,
textures,
[

File diff suppressed because it is too large Load Diff

View File

@ -405,8 +405,8 @@ impl ClipScrollTree {
pt.add_item(format!("scrollable_size: {:?}", scrolling_info.scrollable_size));
pt.add_item(format!("scroll offset: {:?}", scrolling_info.offset));
}
SpatialNodeType::ReferenceFrame(ref info) => {
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
SpatialNodeType::ReferenceFrame(ref _info) => {
pt.new_level(format!("ReferenceFrame"));
pt.add_item(format!("index: {:?}", index));
}
}

View File

@ -3,18 +3,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::super::shader_source;
use api::{ColorF, ImageFormat};
use api::{ColorF, ImageFormat, MemoryReport};
use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize};
use api::TextureTarget;
#[cfg(any(feature = "debug_renderer", feature="capture"))]
use api::ImageDescriptor;
use euclid::Transform3D;
use gleam::gl;
use internal_types::{FastHashMap, RenderTargetInfo};
use internal_types::{FastHashMap, LayerIndex, RenderTargetInfo};
use log::Level;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::cmp;
use std::collections::hash_map::Entry;
use std::fs::File;
use std::io::Read;
use std::marker::PhantomData;
@ -442,9 +443,28 @@ pub struct Texture {
width: u32,
height: u32,
filter: TextureFilter,
render_target: Option<RenderTargetInfo>,
fbo_ids: Vec<FBOId>,
depth_rb: Option<RBOId>,
/// Framebuffer Objects, one for each layer of the texture, allowing this
/// texture to be rendered to. Empty if this texture is not used as a render
/// target.
fbos: Vec<FBOId>,
/// Same as the above, but with a depth buffer attached.
///
/// FBOs are cheap to create but expensive to reconfigure (since doing so
/// invalidates framebuffer completeness caching). Moreover, rendering with
/// a depth buffer attached but the depth write+test disabled relies on the
/// driver to optimize it out of the rendering pass, which most drivers
/// probably do but, according to jgilbert, is best not to rely on.
///
/// So we lazily generate a second list of FBOs with depth. This list is
/// empty if this texture is not used as a render target _or_ if it is, but
/// the depth buffer has never been requested.
///
/// Note that we always fill fbos, and then lazily create fbos_with_depth
/// when needed. We could make both lazy (i.e. render targets would have one
/// or the other, but not both, unless they were actually used in both
/// configurations). But that would complicate a lot of logic in this module,
/// and FBOs are cheap enough to create.
fbos_with_depth: Vec<FBOId>,
last_frame_used: FrameId,
}
@ -453,10 +473,6 @@ impl Texture {
DeviceUintSize::new(self.width, self.height)
}
pub fn get_render_target_layer_count(&self) -> usize {
self.fbo_ids.len()
}
pub fn get_layer_count(&self) -> i32 {
self.layer_count
}
@ -470,17 +486,8 @@ impl Texture {
self.filter
}
#[cfg(any(feature = "debug_renderer", feature = "capture"))]
pub fn get_render_target(&self) -> Option<RenderTargetInfo> {
self.render_target.clone()
}
pub fn has_depth(&self) -> bool {
self.depth_rb.is_some()
}
pub fn get_rt_info(&self) -> Option<&RenderTargetInfo> {
self.render_target.as_ref()
pub fn supports_depth(&self) -> bool {
!self.fbos_with_depth.is_empty()
}
pub fn used_in_frame(&self, frame_id: FrameId) -> bool {
@ -713,6 +720,22 @@ pub enum ShaderError {
Link(String, String), // name, error message
}
/// A refcounted depth target, which may be shared by multiple textures across
/// the device.
struct SharedDepthTarget {
/// The Render Buffer Object representing the depth target.
rbo_id: RBOId,
/// Reference count. When this drops to zero, the RBO is deleted.
refcount: usize,
}
#[cfg(feature = "debug")]
impl Drop for SharedDepthTarget {
fn drop(&mut self) {
debug_assert!(thread::panicking() || self.refcount == 0);
}
}
pub struct Device {
gl: Rc<gl::Gl>,
// device state
@ -735,6 +758,12 @@ pub struct Device {
bgra_format_internal: gl::GLuint,
bgra_format_external: gl::GLuint,
/// Map from texture dimensions to shared depth buffers for render targets.
///
/// Render targets often have the same width/height, so we can save memory
/// by sharing these across targets.
depth_targets: FastHashMap<DeviceUintSize, SharedDepthTarget>,
// debug
inside_frame: bool,
@ -759,6 +788,35 @@ pub struct Device {
extensions: Vec<String>,
}
/// Contains the parameters necessary to bind a texture-backed draw target.
#[derive(Clone, Copy)]
pub struct TextureDrawTarget<'a> {
/// The target texture.
pub texture: &'a Texture,
/// The slice within the texture array to draw to.
pub layer: LayerIndex,
/// Whether to draw with the texture's associated depth target.
pub with_depth: bool,
}
/// Contains the parameters necessary to bind a texture-backed read target.
#[derive(Clone, Copy)]
pub struct TextureReadTarget<'a> {
/// The source texture.
pub texture: &'a Texture,
/// The slice within the texture array to read from.
pub layer: LayerIndex,
}
impl<'a> From<TextureDrawTarget<'a>> for TextureReadTarget<'a> {
fn from(t: TextureDrawTarget<'a>) -> Self {
TextureReadTarget {
texture: t.texture,
layer: t.layer,
}
}
}
impl Device {
pub fn new(
gl: Rc<gl::Gl>,
@ -829,6 +887,8 @@ impl Device {
bgra_format_internal,
bgra_format_external,
depth_targets: FastHashMap::default(),
bound_textures: [0; 16],
bound_program: 0,
bound_vao: 0,
@ -1006,9 +1066,9 @@ impl Device {
}
}
pub fn bind_read_target(&mut self, texture_and_layer: Option<(&Texture, i32)>) {
let fbo_id = texture_and_layer.map_or(FBOId(self.default_read_fbo), |texture_and_layer| {
texture_and_layer.0.fbo_ids[texture_and_layer.1 as usize]
pub fn bind_read_target(&mut self, texture_target: Option<TextureReadTarget>) {
let fbo_id = texture_target.map_or(FBOId(self.default_read_fbo), |target| {
target.texture.fbos[target.layer]
});
self.bind_read_target_impl(fbo_id)
@ -1025,11 +1085,15 @@ impl Device {
pub fn bind_draw_target(
&mut self,
texture_and_layer: Option<(&Texture, i32)>,
texture_target: Option<TextureDrawTarget>,
dimensions: Option<DeviceUintSize>,
) {
let fbo_id = texture_and_layer.map_or(FBOId(self.default_draw_fbo), |texture_and_layer| {
texture_and_layer.0.fbo_ids[texture_and_layer.1 as usize]
let fbo_id = texture_target.map_or(FBOId(self.default_draw_fbo), |target| {
if target.with_depth {
target.texture.fbos_with_depth[target.layer]
} else {
target.texture.fbos[target.layer]
}
});
self.bind_draw_target_impl(fbo_id);
@ -1232,9 +1296,8 @@ impl Device {
layer_count,
format,
filter,
render_target,
fbo_ids: vec![],
depth_rb: None,
fbos: vec![],
fbos_with_depth: vec![],
last_frame_used: self.frame_id,
};
self.bind_texture(DEFAULT_TEXTURE, &texture);
@ -1309,7 +1372,10 @@ impl Device {
// Set up FBOs, if required.
if let Some(rt_info) = render_target {
self.init_fbos(&mut texture, rt_info);
self.init_fbos(&mut texture, false);
if rt_info.has_depth {
self.init_fbos(&mut texture, true);
}
}
texture
@ -1349,7 +1415,7 @@ impl Device {
debug_assert!(dst.height >= src.height);
let rect = DeviceIntRect::new(DeviceIntPoint::zero(), src.get_dimensions().to_i32());
for (read_fbo, draw_fbo) in src.fbo_ids.iter().zip(&dst.fbo_ids) {
for (read_fbo, draw_fbo) in src.fbos.iter().zip(&dst.fbos) {
self.bind_read_target_impl(*read_fbo);
self.bind_draw_target_impl(*draw_fbo);
self.blit_render_target(rect, rect);
@ -1359,15 +1425,19 @@ impl Device {
/// Notifies the device that the contents of a render target are no longer
/// needed.
///
/// FIXME(bholley): We could/should invalidate the depth targets earlier
/// than the color targets, i.e. immediately after each pass.
pub fn invalidate_render_target(&mut self, texture: &Texture) {
let attachments: &[gl::GLenum] = if texture.has_depth() {
&[gl::COLOR_ATTACHMENT0, gl::DEPTH_ATTACHMENT]
let (fbos, attachments) = if texture.supports_depth() {
(&texture.fbos_with_depth,
&[gl::COLOR_ATTACHMENT0, gl::DEPTH_ATTACHMENT] as &[gl::GLenum])
} else {
&[gl::COLOR_ATTACHMENT0]
(&texture.fbos, &[gl::COLOR_ATTACHMENT0] as &[gl::GLenum])
};
let original_bound_fbo = self.bound_draw_fbo;
for fbo_id in texture.fbo_ids.iter() {
for fbo_id in fbos.iter() {
// Note: The invalidate extension may not be supported, in which
// case this is a no-op. That's ok though, because it's just a
// hint.
@ -1386,42 +1456,28 @@ impl Device {
rt_info: RenderTargetInfo,
) {
texture.last_frame_used = self.frame_id;
texture.render_target = Some(rt_info);
// If the depth target requirements changed, just drop the FBOs and
// reinitialize.
//
// FIXME(bholley): I have a patch to do this better.
if rt_info.has_depth != texture.has_depth() {
self.deinit_fbos(texture);
self.init_fbos(texture, rt_info);
// Add depth support if needed.
if rt_info.has_depth && !texture.supports_depth() {
self.init_fbos(texture, true);
}
}
fn init_fbos(&mut self, texture: &mut Texture, rt_info: RenderTargetInfo) {
// Generate the FBOs.
assert!(texture.fbo_ids.is_empty());
texture.fbo_ids.extend(
self.gl.gen_framebuffers(texture.layer_count).into_iter().map(FBOId)
);
fn init_fbos(&mut self, texture: &mut Texture, with_depth: bool) {
let (fbos, depth_rb) = if with_depth {
let depth_target = self.acquire_depth_target(texture.get_dimensions());
(&mut texture.fbos_with_depth, Some(depth_target))
} else {
(&mut texture.fbos, None)
};
// Optionally generate a depth target.
if rt_info.has_depth {
let renderbuffer_ids = self.gl.gen_renderbuffers(1);
let depth_rb = renderbuffer_ids[0];
texture.depth_rb = Some(RBOId(depth_rb));
self.gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
self.gl.renderbuffer_storage(
gl::RENDERBUFFER,
gl::DEPTH_COMPONENT24,
texture.width as _,
texture.height as _,
);
}
// Generate the FBOs.
assert!(fbos.is_empty());
fbos.extend(self.gl.gen_framebuffers(texture.layer_count).into_iter().map(FBOId));
// Bind the FBOs.
let original_bound_fbo = self.bound_draw_fbo;
for (fbo_index, &fbo_id) in texture.fbo_ids.iter().enumerate() {
for (fbo_index, &fbo_id) in fbos.iter().enumerate() {
self.bind_external_draw_target(fbo_id);
match texture.target {
gl::TEXTURE_2D_ARRAY => {
@ -1445,7 +1501,7 @@ impl Device {
}
}
if let Some(depth_rb) = texture.depth_rb {
if let Some(depth_rb) = depth_rb {
self.gl.framebuffer_renderbuffer(
gl::DRAW_FRAMEBUFFER,
gl::DEPTH_ATTACHMENT,
@ -1457,15 +1513,9 @@ impl Device {
self.bind_external_draw_target(original_bound_fbo);
}
fn deinit_fbos(&mut self, texture: &mut Texture) {
if let Some(RBOId(depth_rb)) = texture.depth_rb.take() {
self.gl.delete_renderbuffers(&[depth_rb]);
texture.depth_rb = None;
}
if !texture.fbo_ids.is_empty() {
let fbo_ids: Vec<_> = texture
.fbo_ids
fn deinit_fbos(&mut self, fbos: &mut Vec<FBOId>) {
if !fbos.is_empty() {
let fbo_ids: SmallVec<[gl::GLuint; 8]> = fbos
.drain(..)
.map(|FBOId(fbo_id)| fbo_id)
.collect();
@ -1473,6 +1523,40 @@ impl Device {
}
}
fn acquire_depth_target(&mut self, dimensions: DeviceUintSize) -> RBOId {
let gl = &self.gl;
let target = self.depth_targets.entry(dimensions).or_insert_with(|| {
let renderbuffer_ids = gl.gen_renderbuffers(1);
let depth_rb = renderbuffer_ids[0];
gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
gl.renderbuffer_storage(
gl::RENDERBUFFER,
gl::DEPTH_COMPONENT24,
dimensions.width as _,
dimensions.height as _,
);
SharedDepthTarget {
rbo_id: RBOId(depth_rb),
refcount: 0,
}
});
target.refcount += 1;
target.rbo_id
}
fn release_depth_target(&mut self, dimensions: DeviceUintSize) {
let mut entry = match self.depth_targets.entry(dimensions) {
Entry::Occupied(x) => x,
Entry::Vacant(..) => panic!("Releasing unknown depth target"),
};
debug_assert!(entry.get().refcount != 0);
entry.get_mut().refcount -= 1;
if entry.get().refcount == 0 {
let t = entry.remove();
self.gl.delete_renderbuffers(&[t.rbo_id.0]);
}
}
pub fn blit_render_target(&mut self, src_rect: DeviceIntRect, dest_rect: DeviceIntRect) {
debug_assert!(self.inside_frame);
@ -1492,7 +1576,13 @@ impl Device {
pub fn delete_texture(&mut self, mut texture: Texture) {
debug_assert!(self.inside_frame);
self.deinit_fbos(&mut texture);
let had_depth = texture.supports_depth();
self.deinit_fbos(&mut texture.fbos);
self.deinit_fbos(&mut texture.fbos_with_depth);
if had_depth {
self.release_depth_target(texture.get_dimensions());
}
self.gl.delete_textures(&[texture.id]);
for bound_texture in &mut self.bound_textures {
@ -2317,6 +2407,18 @@ impl Device {
},
}
}
/// Generates a memory report for the resources managed by the device layer.
pub fn report_memory(&self) -> MemoryReport {
let mut report = MemoryReport::default();
for dim in self.depth_targets.keys() {
// DEPTH24 textures generally reserve 3 bytes for depth and 1 byte
// for stencil, so we measure them as 32 bytes.
let pixels: u32 = dim.width * dim.height;
report.depth_target_textures += (pixels as usize) * 4;
}
report
}
}
struct FormatDesc {

View File

@ -5,7 +5,7 @@
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, ClipAndScrollInfo};
use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
use api::{DevicePixelScale, DeviceUintRect, DisplayItemRef, ExtendMode, ExternalScrollId};
use api::{DisplayItemRef, ExtendMode, ExternalScrollId};
use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop};
use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, ColorDepth};
use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
@ -32,7 +32,7 @@ use render_backend::{DocumentView};
use resource_cache::{FontInstanceMap, ImageRequest};
use scene::{Scene, ScenePipeline, StackingContextHelpers};
use scene_builder::DocumentResources;
use spatial_node::{SpatialNodeType, StickyFrameInfo};
use spatial_node::{StickyFrameInfo};
use std::{f32, mem};
use std::collections::vec_deque::VecDeque;
use tiling::{CompositeOps};
@ -209,7 +209,6 @@ impl<'a> DisplayListFlattener<'a> {
&root_pipeline.viewport_size,
&root_pipeline.content_size,
);
flattener.setup_viewport_offset(view.inner_rect, view.accumulated_scale_factor());
flattener.flatten_root(root_pipeline, &root_pipeline.viewport_size);
debug_assert!(flattener.sc_stack.is_empty());
@ -1257,20 +1256,6 @@ impl<'a> DisplayListFlattener<'a> {
index
}
pub fn setup_viewport_offset(
&mut self,
inner_rect: DeviceUintRect,
device_pixel_scale: DevicePixelScale,
) {
let viewport_offset = (inner_rect.origin.to_vector().to_f32() / device_pixel_scale).round();
let root_id = self.clip_scroll_tree.root_reference_frame_index();
let root_node = &mut self.clip_scroll_tree.spatial_nodes[root_id.0];
if let SpatialNodeType::ReferenceFrame(ref mut info) = root_node.node_type {
info.resolved_transform =
LayoutVector2D::new(viewport_offset.x, viewport_offset.y).into();
}
}
pub fn push_root(
&mut self,
pipeline_id: PipelineId,
@ -1484,7 +1469,10 @@ impl<'a> DisplayListFlattener<'a> {
&info,
pending_primitive.clip_and_scroll.clip_chain_id,
pending_primitive.clip_and_scroll.spatial_node_index,
pending_primitive.container.create_shadow(&pending_shadow.shadow),
pending_primitive.container.create_shadow(
&pending_shadow.shadow,
&info.rect,
),
);
// Add the new primitive to the shadow picture.
@ -1687,7 +1675,9 @@ impl<'a> DisplayListFlattener<'a> {
// Use segment relative interpolation for all
// instances in this primitive.
let mut brush_flags = BrushFlags::SEGMENT_RELATIVE;
let mut brush_flags =
BrushFlags::SEGMENT_RELATIVE |
BrushFlags::SEGMENT_TEXEL_RECT;
// Enable repeat modes on the segment.
if repeat_horizontal == RepeatMode::Repeat {
@ -1845,7 +1835,12 @@ impl<'a> DisplayListFlattener<'a> {
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
}
BorderDetails::Normal(ref border) => {
self.add_normal_border(info, border, &border_item.widths, clip_and_scroll);
self.add_normal_border(
info,
border,
border_item.widths,
clip_and_scroll,
);
}
}
}

View File

@ -7,7 +7,7 @@
use api::{DeviceIntPoint, DeviceIntRect, DeviceUintSize, FontRenderMode};
use api::{ImageFormat, TextureTarget};
use debug_colors;
use device::{Device, Texture, TextureFilter, VAO};
use device::{Device, Texture, TextureDrawTarget, TextureFilter, VAO};
use euclid::{Point2D, Size2D, Transform3D, TypedVector2D, Vector2D};
use internal_types::RenderTargetInfo;
use pathfinder_gfx_utils::ShelfBinPacker;
@ -194,7 +194,11 @@ impl Renderer {
projection,
&mut self.renderer_errors);
self.device.bind_draw_target(Some((&current_page.texture, 0)), Some(*target_size));
self.device.bind_draw_target(Some(TextureDrawTarget {
texture: &current_page.texture,
layer: 0,
with_depth: false,
}), Some(*target_size));
self.device.clear_target(Some([0.0, 0.0, 0.0, 0.0]), None, None);
self.device.set_blend(true);

View File

@ -89,7 +89,7 @@ pub struct ScalingInstance {
pub src_task_address: RenderTaskAddress,
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@ -318,6 +318,8 @@ bitflags! {
const SEGMENT_REPEAT_X = 0x4;
/// Repeat UVs vertically.
const SEGMENT_REPEAT_Y = 0x8;
/// The extra segment data is a texel rect.
const SEGMENT_TEXEL_RECT = 0x10;
}
}

View File

@ -38,6 +38,19 @@ pub type FastHashSet<K> = HashSet<K, BuildHasherDefault<FxHasher>>;
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CacheTextureId(pub u64);
/// Canonical type for texture layer indices.
///
/// WebRender is currently not very consistent about layer index types. Some
/// places use i32 (since that's the type used in various OpenGL APIs), some
/// places use u32 (since having it be signed is non-sensical, but the
/// underlying graphics APIs generally operate on 32-bit integers) and some
/// places use usize (since that's most natural in Rust).
///
/// Going forward, we aim to us usize throughout the codebase, since that allows
/// operations like indexing without a cast, and convert to the required type in
/// the device module when making calls into the platform layer.
pub type LayerIndex = usize;
/// Identifies a render pass target that is persisted until the end of the frame.
///
/// By default, only the targets of the immediately-preceding pass are bound as

View File

@ -131,9 +131,20 @@ impl FontContext {
}
let system_fc = dwrote::FontCollection::system();
let font = match system_fc.get_font_from_descriptor(&font_handle) {
Some(font) => font,
None => { panic!("missing descriptor {:?}", font_handle) }
// A version of get_font_from_descriptor() that panics early to help with bug 1455848
let font = if let Some(family) = system_fc.get_font_family_by_name(&font_handle.family_name) {
let font = family.get_first_matching_font(font_handle.weight, font_handle.stretch, font_handle.style);
// Exact matches only here
if font.weight() == font_handle.weight &&
font.stretch() == font_handle.stretch &&
font.style() == font_handle.style
{
font
} else {
panic!("font mismatch for descriptor {:?} {:?}", font_handle, font.to_descriptor())
}
} else {
panic!("missing font family for descriptor {:?}", font_handle)
};
let face = font.create_font_face();
self.fonts.insert(*font_key, face);

View File

@ -7,10 +7,10 @@ use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, ExtendMode, DeviceRect
use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, TileOffset};
use api::{RasterSpace, LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, LayoutToWorldTransform};
use api::{LayoutVector2D, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat};
use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, LayoutToWorldScale, NormalBorder, WorldRect};
use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale};
use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers};
use app_units::Au;
use border::{BorderCacheKey, BorderRenderTaskInfo};
use border::{get_max_scale_for_border, build_border_instances, create_normal_border_prim};
use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId, SpatialNodeIndex};
use clip::{ClipNodeFlags, ClipChainId, ClipChainInstance, ClipItem, ClipNodeCollector};
use euclid::{TypedTransform3D, TypedRect, TypedScale};
@ -25,7 +25,7 @@ use intern;
use picture::{PictureCompositeMode, PicturePrimitive};
#[cfg(debug_assertions)]
use render_backend::FrameId;
use render_task::{BlitSource, RenderTask, RenderTaskCacheKey};
use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, to_cache_size};
use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle};
use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
use resource_cache::{ImageProperties, ImageRequest, ResourceCache};
@ -345,13 +345,21 @@ pub struct VisibleGradientTile {
pub local_clip_rect: LayoutRect,
}
/// Information about how to cache a border segment,
/// along with the current render task cache entry.
#[derive(Debug)]
pub struct BorderSegmentInfo {
pub handle: Option<RenderTaskCacheEntryHandle>,
pub local_task_size: LayoutSize,
pub cache_key: RenderTaskCacheKey,
pub is_opaque: bool,
}
#[derive(Debug)]
pub enum BorderSource {
Image(ImageRequest),
Border {
handle: Option<RenderTaskCacheEntryHandle>,
cache_key: BorderCacheKey,
task_info: Option<BorderRenderTaskInfo>,
segments: SmallVec<[BorderSegmentInfo; 8]>,
border: NormalBorder,
widths: LayoutSideOffsets,
},
@ -456,18 +464,19 @@ impl BrushKind {
// Construct a brush that is a border with `border` style and `widths`
// dimensions.
pub fn new_border(mut border: NormalBorder, widths: LayoutSideOffsets) -> BrushKind {
pub fn new_border(
mut border: NormalBorder,
widths: LayoutSideOffsets,
segments: SmallVec<[BorderSegmentInfo; 8]>,
) -> BrushKind {
// FIXME(emilio): Is this the best place to do this?
border.normalize(&widths);
let cache_key = BorderCacheKey::new(&border, &widths);
BrushKind::Border {
source: BorderSource::Border {
border,
widths,
cache_key,
task_info: None,
handle: None,
segments,
}
}
}
@ -1412,7 +1421,11 @@ impl PrimitiveContainer {
// Create a clone of this PrimitiveContainer, applying whatever
// changes are necessary to the primitive to support rendering
// it as part of the supplied shadow.
pub fn create_shadow(&self, shadow: &Shadow) -> PrimitiveContainer {
pub fn create_shadow(
&self,
shadow: &Shadow,
prim_rect: &LayoutRect,
) -> PrimitiveContainer {
match *self {
PrimitiveContainer::TextRun(ref info) => {
let mut font = FontInstance {
@ -1440,22 +1453,25 @@ impl PrimitiveContainer {
))
}
BrushKind::Border { ref source } => {
let source = match *source {
let prim = match *source {
BorderSource::Image(request) => {
BrushKind::Border {
source: BorderSource::Image(request)
}
},
BrushPrimitive::new(
BrushKind::Border {
source: BorderSource::Image(request)
},
None,
)
}
BorderSource::Border { border, widths, .. } => {
let border = border.with_color(shadow.color);
BrushKind::new_border(border, widths)
create_normal_border_prim(
prim_rect,
border,
widths,
)
}
};
PrimitiveContainer::Brush(BrushPrimitive::new(
source,
None,
))
PrimitiveContainer::Brush(prim)
}
BrushKind::LineDecoration { style, orientation, wavy_line_thickness, .. } => {
PrimitiveContainer::Brush(BrushPrimitive::new_line_decoration(
@ -1960,13 +1976,6 @@ impl PrimitiveStore {
prim_instance.clipped_world_rect = Some(clipped_world_rect);
prim.build_prim_segments_if_needed(
prim_instance,
pic_state,
frame_state,
frame_context,
);
prim.update_clip_task(
prim_instance,
prim_context,
@ -2839,9 +2848,46 @@ impl Primitive {
);
}
}
BorderSource::Border { .. } => {
// Handled earlier since we need to update the segment
// descriptor *before* update_clip_task() is called.
BorderSource::Border { ref border, ref widths, ref mut segments, .. } => {
// TODO(gw): When drawing in screen raster mode, we should also incorporate a
// scale factor from the world transform to get an appropriately
// sized border task.
let world_scale = LayoutToWorldScale::new(1.0);
let mut scale = world_scale * frame_context.device_pixel_scale;
let max_scale = get_max_scale_for_border(&border.radius, widths);
scale.0 = scale.0.min(max_scale.0);
// For each edge and corner, request the render task by content key
// from the render task cache. This ensures that the render task for
// this segment will be available for batching later in the frame.
for segment in segments {
// Update the cache key device size based on requested scale.
segment.cache_key.size = to_cache_size(segment.local_task_size * scale);
segment.handle = Some(frame_state.resource_cache.request_render_task(
segment.cache_key.clone(),
frame_state.gpu_cache,
frame_state.render_tasks,
None,
segment.is_opaque,
|render_tasks| {
let task = RenderTask::new_border_segment(
segment.cache_key.size,
build_border_instances(
&segment.cache_key,
border,
scale,
),
);
let task_id = render_tasks.add(task);
pic_state.tasks.push(task_id);
task_id
}
));
}
}
}
}
@ -3092,95 +3138,6 @@ impl Primitive {
}
}
}
fn build_prim_segments_if_needed(
&mut self,
prim_instance: &mut PrimitiveInstance,
pic_state: &mut PictureState,
frame_state: &mut FrameBuildingState,
frame_context: &FrameBuildingContext,
) {
let brush = match self.details {
PrimitiveDetails::Brush(ref mut brush) => brush,
PrimitiveDetails::TextRun(..) => return,
};
if let BrushKind::Border {
source: BorderSource::Border {
ref border,
ref mut cache_key,
ref widths,
ref mut handle,
ref mut task_info,
..
}
} = brush.kind {
// TODO(gw): When drawing in screen raster mode, we should also incorporate a
// scale factor from the world transform to get an appropriately
// sized border task.
let world_scale = LayoutToWorldScale::new(1.0);
let mut scale = world_scale * frame_context.device_pixel_scale;
let max_scale = BorderRenderTaskInfo::get_max_scale(&border.radius, &widths);
scale.0 = scale.0.min(max_scale.0);
let scale_au = Au::from_f32_px(scale.0);
// NOTE(emilio): This `needs_update` relies on the local rect for a
// given primitive being immutable. If that changes, this code
// should probably handle changes to it as well, retaining the old
// size in cache_key.
let needs_update = scale_au != cache_key.scale;
let mut new_segments = BrushSegmentVec::new();
let local_rect = &self.metadata.local_rect;
if needs_update {
cache_key.scale = scale_au;
*task_info = BorderRenderTaskInfo::new(
local_rect,
border,
widths,
scale,
&mut new_segments,
);
}
*handle = task_info.as_ref().map(|task_info| {
frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
size: task_info.cache_key_size(&local_rect.size, scale),
kind: RenderTaskCacheKeyKind::Border(cache_key.clone()),
},
frame_state.gpu_cache,
frame_state.render_tasks,
None,
false, // todo
|render_tasks| {
let task = RenderTask::new_border(
task_info.size,
task_info.build_instances(border),
);
let task_id = render_tasks.add(task);
pic_state.tasks.push(task_id);
task_id
}
)
});
if needs_update {
brush.segment_desc = Some(BrushSegmentDescriptor {
segments: new_segments,
});
// The segments have changed, so force the GPU cache to
// re-upload the primitive information.
frame_state.gpu_cache.invalidate(&mut prim_instance.gpu_location);
}
}
}
}
pub fn get_raster_rects(

View File

@ -277,6 +277,12 @@ impl Document {
FrameMsg::AppendDynamicProperties(property_bindings) => {
self.dynamic_properties.add_properties(property_bindings);
}
FrameMsg::SetPinchZoom(factor) => {
if self.view.pinch_zoom_factor != factor.get() {
self.view.pinch_zoom_factor = factor.get();
self.frame_is_valid = false;
}
}
}
DocumentOps::nop()
@ -508,9 +514,6 @@ impl RenderBackend {
SceneMsg::SetPageZoom(factor) => {
doc.view.page_zoom_factor = factor.get();
}
SceneMsg::SetPinchZoom(factor) => {
doc.view.pinch_zoom_factor = factor.get();
}
SceneMsg::SetWindowParameters {
window_size,
inner_rect,

View File

@ -7,7 +7,7 @@ use api::{DevicePixelScale, ImageDescriptor, ImageFormat};
use api::{LineStyle, LineOrientation, LayoutSize};
#[cfg(feature = "pathfinder")]
use api::FontRenderMode;
use border::BorderCacheKey;
use border::{BorderCornerCacheKey, BorderEdgeCacheKey};
use box_shadow::{BoxShadowCacheKey};
use clip::{ClipDataStore, ClipItem, ClipStore, ClipNodeRange};
use clip_scroll_tree::SpatialNodeIndex;
@ -18,7 +18,7 @@ use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use glyph_rasterizer::GpuGlyphCacheKey;
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
use gpu_types::{BorderInstance, ImageSource, UvRectKind};
use internal_types::{CacheTextureId, FastHashMap, SavedTargetIndex};
use internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex};
#[cfg(feature = "pathfinder")]
use pathfinder_partitioner::mesh::Mesh;
use picture::PictureCacheKey;
@ -113,7 +113,7 @@ impl RenderTaskTree {
debug_assert!(pass_index == passes.len() - 1);
}
RenderTaskLocation::Dynamic(..) |
RenderTaskLocation::TextureCache(..) => {
RenderTaskLocation::TextureCache { .. } => {
debug_assert!(pass_index < passes.len() - 1);
}
}
@ -192,7 +192,14 @@ pub enum RenderTaskLocation {
Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize),
/// The output of the `RenderTask` will be persisted beyond this frame, and
/// thus should be drawn into the `TextureCache`.
TextureCache(CacheTextureId, i32, DeviceIntRect),
TextureCache {
/// Which texture in the texture cache should be drawn into.
texture: CacheTextureId,
/// The target layer in the above texture.
layer: LayerIndex,
/// The target region within the above layer.
rect: DeviceIntRect,
},
}
#[derive(Debug)]
@ -386,7 +393,7 @@ impl RenderTask {
let size = match location {
RenderTaskLocation::Dynamic(_, size) => size,
RenderTaskLocation::Fixed(rect) => rect.size,
RenderTaskLocation::TextureCache(_, _, rect) => rect.size,
RenderTaskLocation::TextureCache { rect, .. } => rect.size,
};
render_task_sanity_check(&size);
@ -655,7 +662,7 @@ impl RenderTask {
)
}
pub fn new_border(
pub fn new_border_segment(
size: DeviceIntSize,
instances: Vec<BorderInstance>,
) -> Self {
@ -839,7 +846,7 @@ impl RenderTask {
match self.location {
RenderTaskLocation::Fixed(..) => DeviceIntSize::zero(),
RenderTaskLocation::Dynamic(_, size) => size,
RenderTaskLocation::TextureCache(_, _, rect) => rect.size,
RenderTaskLocation::TextureCache { rect, .. } => rect.size,
}
}
@ -868,7 +875,7 @@ impl RenderTask {
RenderTaskLocation::Dynamic(None, _) => {
(DeviceIntRect::zero(), RenderTargetIndex(0))
}
RenderTaskLocation::TextureCache(_, layer, rect) => {
RenderTaskLocation::TextureCache {layer, rect, .. } => {
(rect, RenderTargetIndex(layer as usize))
}
}
@ -1044,7 +1051,7 @@ impl RenderTask {
RenderTaskLocation::Dynamic(..) => {
self.saved_index = Some(SavedTargetIndex::PENDING);
}
RenderTaskLocation::TextureCache(..) => {
RenderTaskLocation::TextureCache { .. } => {
panic!("Unable to mark a permanently cached task for saving!");
}
}
@ -1060,7 +1067,8 @@ pub enum RenderTaskCacheKeyKind {
#[allow(dead_code)]
Glyph(GpuGlyphCacheKey),
Picture(PictureCacheKey),
Border(BorderCacheKey),
BorderEdge(BorderEdgeCacheKey),
BorderCorner(BorderCornerCacheKey),
LineDecoration(LineDecorationCacheKey),
}
@ -1161,7 +1169,7 @@ impl RenderTaskCache {
// Find out what size to alloc in the texture cache.
let size = match render_task.location {
RenderTaskLocation::Fixed(..) |
RenderTaskLocation::TextureCache(..) => {
RenderTaskLocation::TextureCache { .. } => {
panic!("BUG: dynamic task was expected");
}
RenderTaskLocation::Dynamic(_, size) => size,
@ -1203,11 +1211,11 @@ impl RenderTaskCache {
let (texture_id, texture_layer, uv_rect) =
texture_cache.get_cache_location(&entry.handle);
render_task.location = RenderTaskLocation::TextureCache(
texture_id,
texture_layer,
uv_rect.to_i32()
);
render_task.location = RenderTaskLocation::TextureCache {
texture: texture_id,
layer: texture_layer,
rect: uv_rect.to_i32(),
};
}
}
}

View File

@ -36,7 +36,7 @@ use batch::{BatchKind, BatchTextures, BrushBatchKind};
use capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
use debug_colors;
use device::{DepthFunction, Device, FrameId, Program, UploadMethod, Texture, PBO};
use device::{ExternalTexture, FBOId, TextureSlot};
use device::{ExternalTexture, FBOId, TextureDrawTarget, TextureReadTarget, TextureSlot};
use device::{ShaderError, TextureFilter,
VertexUsageHint, VAO, VBO, CustomVAO};
use device::{ProgramCache, ReadPixelsFormat};
@ -54,7 +54,7 @@ use gpu_glyph_renderer::GpuGlyphRenderer;
use gpu_types::ScalingInstance;
use internal_types::{TextureSource, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg};
use internal_types::{TextureUpdateList, TextureUpdateOp, TextureUpdateSource};
use internal_types::{LayerIndex, TextureUpdateList, TextureUpdateOp, TextureUpdateSource};
use internal_types::{RenderTargetInfo, SavedTargetIndex};
use prim_store::DeferredResolve;
use profiler::{BackendProfileCounters, FrameProfileCounters,
@ -1337,7 +1337,11 @@ impl GpuCacheTexture {
device.bind_program(program);
device.bind_custom_vao(vao);
device.bind_draw_target(
Some((texture, 0)),
Some(TextureDrawTarget {
texture,
layer: 0,
with_depth: false,
}),
Some(texture.get_dimensions()),
);
device.draw_nonindexed_points(0, count as _);
@ -2918,7 +2922,7 @@ impl Renderer {
fn handle_readback_composite(
&mut self,
render_target: Option<(&Texture, i32)>,
render_target: Option<TextureDrawTarget>,
framebuffer_size: DeviceUintSize,
scissor_rect: Option<DeviceIntRect>,
source: &RenderTask,
@ -2951,7 +2955,11 @@ impl Renderer {
// Called per-instance in case the layer (and therefore FBO)
// changes. The device will skip the GL call if the requested
// target is already bound.
let cache_draw_target = (cache_texture, readback_layer.0 as i32);
let cache_draw_target = TextureDrawTarget {
texture: cache_texture,
layer: readback_layer.0 as usize,
with_depth: false,
};
self.device.bind_draw_target(Some(cache_draw_target), None);
let mut src = DeviceIntRect::new(
@ -2968,7 +2976,7 @@ impl Renderer {
dest.size.height = -dest.size.height;
}
self.device.bind_read_target(render_target);
self.device.bind_read_target(render_target.map(|r| r.into()));
self.device.blit_render_target(src, dest);
// Restore draw target to current pass render target + layer.
@ -2997,22 +3005,22 @@ impl Renderer {
let source_rect = match blit.source {
BlitJobSource::Texture(texture_id, layer, source_rect) => {
// A blit from a texture into this target.
let src_texture = self.texture_resolver
let texture = self.texture_resolver
.resolve(&texture_id)
.expect("BUG: invalid source texture");
self.device.bind_read_target(Some((src_texture, layer)));
self.device.bind_read_target(Some(TextureReadTarget { texture, layer: layer as usize }));
source_rect
}
BlitJobSource::RenderTask(task_id) => {
// A blit from the child render task into this target.
// TODO(gw): Support R8 format here once we start
// creating mips for alpha masks.
let src_texture = self.texture_resolver
let texture = self.texture_resolver
.resolve(&TextureSource::PrevPassColor)
.expect("BUG: invalid source texture");
let source = &render_tasks[task_id];
let (source_rect, layer) = source.get_target_rect();
self.device.bind_read_target(Some((src_texture, layer.0 as i32)));
self.device.bind_read_target(Some(TextureReadTarget { texture, layer: layer.0 }));
source_rect
}
};
@ -3059,7 +3067,7 @@ impl Renderer {
fn draw_color_target(
&mut self,
render_target: Option<(&Texture, i32)>,
render_target: Option<TextureDrawTarget>,
target: &ColorRenderTarget,
framebuffer_target_rect: DeviceUintRect,
target_size: DeviceUintSize,
@ -3074,8 +3082,8 @@ impl Renderer {
let _gm = self.gpu_profile.start_marker("color target");
// sanity check for the depth buffer
if let Some((texture, _)) = render_target {
assert!(texture.has_depth() >= target.needs_depth());
if let Some(t) = render_target {
assert!(t.texture.supports_depth() >= target.needs_depth());
}
let framebuffer_kind = if render_target.is_none() {
@ -3372,7 +3380,7 @@ impl Renderer {
dest_rect.origin.y += dest_rect.size.height;
dest_rect.size.height *= -1;
self.device.bind_read_target(render_target);
self.device.bind_read_target(render_target.map(|r| r.into()));
self.device.bind_external_draw_target(fbo_id);
self.device.blit_render_target(src_rect, dest_rect);
handler.unlock(output.pipeline_id);
@ -3382,7 +3390,7 @@ impl Renderer {
fn draw_alpha_target(
&mut self,
render_target: (&Texture, i32),
render_target: TextureDrawTarget,
target: &AlphaRenderTarget,
target_size: DeviceUintSize,
projection: &Transform3D<f32>,
@ -3527,7 +3535,7 @@ impl Renderer {
fn draw_texture_cache_target(
&mut self,
texture: &CacheTextureId,
layer: i32,
layer: LayerIndex,
target: &TextureCacheRenderTarget,
render_tasks: &RenderTaskTree,
stats: &mut RendererStats,
@ -3561,8 +3569,11 @@ impl Renderer {
let texture = self.texture_resolver
.resolve(&texture_source)
.expect("BUG: invalid target texture");
self.device
.bind_draw_target(Some((texture, layer)), Some(target_size));
self.device.bind_draw_target(Some(TextureDrawTarget {
texture,
layer,
with_depth: false,
}), Some(target_size));
}
self.device.disable_depth();
@ -3801,7 +3812,7 @@ impl Renderer {
// create a new texture.
let selector = TargetSelector {
size: list.max_size,
num_layers: list.targets.len() as _,
num_layers: list.targets.len(),
format: list.format,
};
let index = self.texture_resolver.render_target_pool
@ -3809,7 +3820,7 @@ impl Renderer {
.position(|texture| {
selector == TargetSelector {
size: texture.get_dimensions(),
num_layers: texture.get_render_target_layer_count(),
num_layers: texture.get_layer_count() as usize,
format: texture.get_format(),
}
});
@ -3980,7 +3991,11 @@ impl Renderer {
);
self.draw_alpha_target(
(&alpha_tex.as_ref().unwrap().texture, target_index as i32),
TextureDrawTarget {
texture: &alpha_tex.as_ref().unwrap().texture,
layer: target_index,
with_depth: false,
},
target,
alpha.max_size,
&projection,
@ -4002,7 +4017,11 @@ impl Renderer {
);
self.draw_color_target(
Some((&color_tex.as_ref().unwrap().texture, target_index as i32)),
Some(TextureDrawTarget {
texture: &color_tex.as_ref().unwrap().texture,
layer: target_index,
with_depth: target.needs_depth(),
}),
target,
frame.inner_rect,
color.max_size,
@ -4106,7 +4125,7 @@ impl Renderer {
let fb_width = framebuffer_size.width as i32;
let num_layers: i32 = self.texture_resolver.render_target_pool
.iter()
.map(|texture| texture.get_render_target_layer_count() as i32)
.map(|texture| texture.get_layer_count() as i32)
.sum();
if num_layers * (size + spacing) > fb_width {
@ -4120,10 +4139,9 @@ impl Renderer {
let dimensions = texture.get_dimensions();
let src_rect = DeviceIntRect::new(DeviceIntPoint::zero(), dimensions.to_i32());
let layer_count = texture.get_render_target_layer_count();
for layer_index in 0 .. layer_count {
self.device
.bind_read_target(Some((texture, layer_index as i32)));
let layer_count = texture.get_layer_count() as usize;
for layer in 0 .. layer_count {
self.device.bind_read_target(Some(TextureReadTarget { texture, layer }));
let x = fb_width - (spacing + size) * (target_index + 1);
let y = spacing;
@ -4168,9 +4186,9 @@ impl Renderer {
DeviceIntSize::new(dimensions.width as i32, dimensions.height as i32),
);
let layer_count = texture.get_layer_count();
for layer_index in 0 .. layer_count {
self.device.bind_read_target(Some((texture, layer_index)));
let layer_count = texture.get_layer_count() as usize;
for layer in 0 .. layer_count {
self.device.bind_read_target(Some(TextureReadTarget { texture, layer}));
let x = fb_width - (spacing + size) * (i as i32 + 1);
@ -4277,7 +4295,7 @@ impl Renderer {
let size = texture.get_dimensions();
let mut texels = vec![0; (size.width * size.height * 16) as usize];
self.device.begin_frame();
self.device.bind_read_target(Some((texture, 0)));
self.device.bind_read_target(Some(TextureReadTarget { texture, layer: 0 }));
self.device.read_pixels_into(
DeviceUintRect::new(DeviceUintPoint::zero(), size),
ReadPixelsFormat::Standard(ImageFormat::RGBAF32),
@ -4362,6 +4380,9 @@ impl Renderer {
// Texture cache and render target GPU memory.
report += self.texture_resolver.report_memory();
// Textures held internally within the device layer.
report += self.device.report_memory();
report
}
@ -4631,7 +4652,6 @@ struct PlainTexture {
size: (u32, u32, i32),
format: ImageFormat,
filter: TextureFilter,
render_target: Option<RenderTargetInfo>,
}
@ -4741,7 +4761,6 @@ impl Renderer {
size: (rect.size.width, rect.size.height, texture.get_layer_count()),
format: texture.get_format(),
filter: texture.get_filter(),
render_target: texture.get_render_target(),
}
}
@ -4749,6 +4768,7 @@ impl Renderer {
fn load_texture(
target: TextureTarget,
plain: &PlainTexture,
rt_info: Option<RenderTargetInfo>,
root: &PathBuf,
device: &mut Device
) -> (Texture, Vec<u8>)
@ -4768,7 +4788,7 @@ impl Renderer {
plain.size.0,
plain.size.1,
plain.filter,
plain.render_target,
rt_info,
plain.size.2,
);
device.upload_texture_immediate(&texture, &texels);
@ -4939,6 +4959,7 @@ impl Renderer {
let t = Self::load_texture(
TextureTarget::Array,
&texture,
Some(RenderTargetInfo { has_depth: false }),
&root,
&mut self.device
);
@ -4952,6 +4973,7 @@ impl Renderer {
let (t, gpu_cache_data) = Self::load_texture(
TextureTarget::Default,
&renderer.gpu_cache,
Some(RenderTargetInfo { has_depth: false }),
&root,
&mut self.device,
);
@ -4996,11 +5018,11 @@ impl Renderer {
size: (descriptor.size.width, descriptor.size.height, layer_count),
format: descriptor.format,
filter,
render_target: None,
};
let t = Self::load_texture(
target,
&plain_tex,
None,
&root,
&mut self.device
);

View File

@ -122,7 +122,6 @@ impl SpatialNode {
let source_perspective = source_perspective.map_or_else(
LayoutFastTransform::identity, |perspective| perspective.into());
let info = ReferenceFrameInfo {
resolved_transform: LayoutFastTransform::identity(),
source_transform: source_transform.unwrap_or(PropertyBinding::Value(identity)),
source_perspective,
origin_in_parent_reference_frame,
@ -256,7 +255,7 @@ impl SpatialNode {
let scrolled_perspective = info.source_perspective
.pre_translate(&state.parent_accumulated_scroll_offset)
.post_translate(-state.parent_accumulated_scroll_offset);
info.resolved_transform =
let resolved_transform =
LayoutFastTransform::with_vector(info.origin_in_parent_reference_frame)
.pre_mul(&source_transform.into())
.pre_mul(&scrolled_perspective);
@ -265,7 +264,7 @@ impl SpatialNode {
// our parent reference frame, plus any accumulated scrolling offsets from nodes
// between our reference frame and this node. Finally, we also include
// whatever local transformation this reference frame provides.
let relative_transform = info.resolved_transform
let relative_transform = resolved_transform
.post_translate(state.parent_accumulated_scroll_offset)
.to_transform()
.with_destination::<LayoutPixel>();
@ -622,10 +621,6 @@ impl ScrollFrameInfo {
/// Contains information about reference frames.
#[derive(Copy, Clone, Debug)]
pub struct ReferenceFrameInfo {
/// The transformation that establishes this reference frame, relative to the parent
/// reference frame. The origin of the reference frame is included in the transformation.
pub resolved_transform: LayoutFastTransform,
/// The source transform and perspective matrices provided by the stacking context
/// that forms this reference frame. We maintain the property binding information
/// here so that we can resolve the animated transform and update the tree each

View File

@ -9,7 +9,7 @@ use device::TextureFilter;
use freelist::{FreeList, FreeListHandle, UpsertResult, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle};
use gpu_types::{ImageSource, UvRectKind};
use internal_types::{CacheTextureId, TextureUpdateList, TextureUpdateSource};
use internal_types::{CacheTextureId, LayerIndex, TextureUpdateList, TextureUpdateSource};
use internal_types::{RenderTargetInfo, TextureSource, TextureUpdate, TextureUpdateOp};
use profiler::{ResourceProfileCounter, TextureCacheProfileCounters};
use render_backend::FrameId;
@ -541,12 +541,14 @@ impl TextureCache {
}
}
// A more detailed version of get(). This allows access to the actual
// device rect of the cache allocation.
/// A more detailed version of get(). This allows access to the actual
/// device rect of the cache allocation.
///
/// Returns a tuple identifying the texture, the layer, and the region.
pub fn get_cache_location(
&self,
handle: &TextureCacheHandle,
) -> (CacheTextureId, i32, DeviceUintRect) {
) -> (CacheTextureId, LayerIndex, DeviceUintRect) {
let handle = handle
.entry
.as_ref()
@ -567,7 +569,7 @@ impl TextureCache {
} => (layer_index, origin),
};
(entry.texture_id,
layer_index as i32,
layer_index as usize,
DeviceUintRect::new(origin, entry.size))
}

View File

@ -285,10 +285,8 @@ impl<T: RenderTarget> RenderTargetList<T> {
pub fn check_ready(&self, t: &Texture) {
assert_eq!(t.get_dimensions(), self.max_size);
assert_eq!(t.get_format(), self.format);
assert_eq!(t.get_render_target_layer_count(), self.targets.len());
assert_eq!(t.get_layer_count() as usize, self.targets.len());
assert_eq!(t.has_depth(), t.get_rt_info().unwrap().has_depth);
assert_eq!(t.has_depth(), self.needs_depth());
assert!(t.supports_depth() >= self.needs_depth());
}
}
@ -821,7 +819,7 @@ pub enum RenderPassKind {
OffScreen {
alpha: RenderTargetList<AlphaRenderTarget>,
color: RenderTargetList<ColorRenderTarget>,
texture_cache: FastHashMap<(CacheTextureId, i32), TextureCacheRenderTarget>,
texture_cache: FastHashMap<(CacheTextureId, usize), TextureCacheRenderTarget>,
},
}
@ -950,8 +948,8 @@ impl RenderPass {
// Find a target to assign this task to, or create a new
// one if required.
let texture_target = match task.location {
RenderTaskLocation::TextureCache(texture_id, layer, _) => {
Some((texture_id, layer))
RenderTaskLocation::TextureCache { texture, layer, .. } => {
Some((texture, layer))
}
RenderTaskLocation::Fixed(..) => {
None

View File

@ -232,7 +232,7 @@ impl Transaction {
}
pub fn set_pinch_zoom(&mut self, pinch_zoom: ZoomFactor) {
self.scene_ops.push(SceneMsg::SetPinchZoom(pinch_zoom));
self.frame_ops.push(FrameMsg::SetPinchZoom(pinch_zoom));
}
pub fn set_pan(&mut self, pan: DeviceIntPoint) {
@ -523,7 +523,6 @@ pub struct AddFontInstance {
pub enum SceneMsg {
UpdateEpoch(PipelineId, Epoch),
SetPageZoom(ZoomFactor),
SetPinchZoom(ZoomFactor),
SetRootPipeline(PipelineId),
RemovePipeline(PipelineId),
SetDisplayList {
@ -554,6 +553,7 @@ pub enum FrameMsg {
GetScrollNodeState(MsgSender<Vec<ScrollNodeState>>),
UpdateDynamicProperties(DynamicProperties),
AppendDynamicProperties(DynamicProperties),
SetPinchZoom(ZoomFactor),
}
impl fmt::Debug for SceneMsg {
@ -562,7 +562,6 @@ impl fmt::Debug for SceneMsg {
SceneMsg::UpdateEpoch(..) => "SceneMsg::UpdateEpoch",
SceneMsg::SetDisplayList { .. } => "SceneMsg::SetDisplayList",
SceneMsg::SetPageZoom(..) => "SceneMsg::SetPageZoom",
SceneMsg::SetPinchZoom(..) => "SceneMsg::SetPinchZoom",
SceneMsg::RemovePipeline(..) => "SceneMsg::RemovePipeline",
SceneMsg::SetWindowParameters { .. } => "SceneMsg::SetWindowParameters",
SceneMsg::SetRootPipeline(..) => "SceneMsg::SetRootPipeline",
@ -582,6 +581,7 @@ impl fmt::Debug for FrameMsg {
FrameMsg::EnableFrameOutput(..) => "FrameMsg::EnableFrameOutput",
FrameMsg::UpdateDynamicProperties(..) => "FrameMsg::UpdateDynamicProperties",
FrameMsg::AppendDynamicProperties(..) => "FrameMsg::AppendDynamicProperties",
FrameMsg::SetPinchZoom(..) => "FrameMsg::SetPinchZoom",
})
}
}
@ -791,6 +791,7 @@ pub struct MemoryReport {
pub vertex_data_textures: usize,
pub render_target_textures: usize,
pub texture_cache_textures: usize,
pub depth_target_textures: usize,
}
impl ::std::ops::AddAssign for MemoryReport {
@ -808,6 +809,7 @@ impl ::std::ops::AddAssign for MemoryReport {
self.vertex_data_textures += other.vertex_data_textures;
self.render_target_textures += other.render_target_textures;
self.texture_cache_textures += other.texture_cache_textures;
self.depth_target_textures += other.depth_target_textures;
}
}

View File

@ -435,6 +435,29 @@ impl BorderStyle {
pub fn is_hidden(&self) -> bool {
*self == BorderStyle::Hidden || *self == BorderStyle::None
}
/// Returns true if the border style itself is opaque. Other
/// factors (such as color, or border radii) may mean that
/// the border segment isn't opaque regardless of this.
pub fn is_opaque(&self) -> bool {
match *self {
BorderStyle::None |
BorderStyle::Double |
BorderStyle::Dotted |
BorderStyle::Dashed |
BorderStyle::Hidden => {
false
}
BorderStyle::Solid |
BorderStyle::Groove |
BorderStyle::Ridge |
BorderStyle::Inset |
BorderStyle::Outset => {
true
}
}
}
}
#[repr(u32)]

View File

@ -1 +1 @@
98d507003c07c003ef0e0297dc4d29ee896a5868
74f265e447d2927c27d4320c676779956d39eaf0

View File

@ -542,6 +542,7 @@ struct MemoryReport {
uintptr_t vertex_data_textures;
uintptr_t render_target_textures;
uintptr_t texture_cache_textures;
uintptr_t depth_target_textures;
bool operator==(const MemoryReport& aOther) const {
return primitive_stores == aOther.primitive_stores &&
@ -556,7 +557,8 @@ struct MemoryReport {
gpu_cache_textures == aOther.gpu_cache_textures &&
vertex_data_textures == aOther.vertex_data_textures &&
render_target_textures == aOther.render_target_textures &&
texture_cache_textures == aOther.texture_cache_textures;
texture_cache_textures == aOther.texture_cache_textures &&
depth_target_textures == aOther.depth_target_textures;
}
};

View File

@ -18,6 +18,16 @@
language="*"
/>
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="mozglue"
version="1.0.0.0"
language="*"
/>
</dependentAssembly>
</dependency>
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:security>

View File

@ -7,7 +7,6 @@
#ifndef mozilla_ipc_backgroundchild_h__
#define mozilla_ipc_backgroundchild_h__
#include "base/process.h"
#include "mozilla/Attributes.h"
#include "mozilla/ipc/Transport.h"
@ -47,7 +46,6 @@ class BackgroundChild final
friend class mozilla::dom::ContentChild;
friend class mozilla::dom::ContentParent;
typedef base::ProcessId ProcessId;
typedef mozilla::ipc::Transport Transport;
public:

View File

@ -412,9 +412,6 @@ js::GetElementsWithAdder(JSContext* cx, HandleObject obj, HandleObject receiver,
return true;
}
static bool
ObjectMayHaveExtraIndexedProperties(JSObject* obj);
static inline bool
IsPackedArrayOrNoExtraIndexedProperties(JSObject* obj, uint64_t length)
{
@ -1050,8 +1047,8 @@ ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj)
* elements. This includes other indexed properties in its shape hierarchy, and
* indexed properties or elements along its prototype chain.
*/
static bool
ObjectMayHaveExtraIndexedProperties(JSObject* obj)
bool
js::ObjectMayHaveExtraIndexedProperties(JSObject* obj)
{
MOZ_ASSERT_IF(obj->hasDynamicPrototype(), !obj->isNative());

View File

@ -196,6 +196,9 @@ array_construct(JSContext* cx, unsigned argc, Value* vp);
extern bool
IsCrossRealmArrayConstructor(JSContext* cx, const Value& v, bool* result);
extern bool
ObjectMayHaveExtraIndexedProperties(JSObject* obj);
class MOZ_NON_TEMPORARY_CLASS ArraySpeciesLookup final
{
/*

View File

@ -0,0 +1,125 @@
setJitCompilerOption("ion.forceinlineCaches", 1);
let offsets = [213, 559, 255, 515, 30, 507, 252, 329, 487, 7];
function update_index(i, j) {
var offset = offsets[j % offsets.length];
return i + offset;
}
function compute_index(initial, count) {
for (var i = 0; i < count; i++) {
initial = update_index(initial, i);
}
return initial;
}
// This is written so that the IC added in the bug activates.
function mutate_array(array, count, epsilon = 0) {
var index = 0;
for (var i = 0; i < count; i++) {
index = update_index(index, i);
array[index] = i + epsilon;
}
return array[offsets[0]+offsets[1]] === (1 + epsilon) &&
array[10] === undefined;
}
// Monomorphizing mutate_array to ensure we get the IC chains we want
function create_variant(variant) {
var source = mutate_array.toString().replace("mutate_array", "mutate_array_"+variant);
return source;
}
function test_basic() {
eval(create_variant("basic"));
var x = [];
var count = 100;
assertEq(mutate_array_basic(x, count), true);
var end = compute_index(0, count);
assertEq(x[end], count - 1);
assertEq(x[end - 1], undefined);
}
// Ensure the IC respects frozen.
function test_frozen() {
eval(create_variant("frozen"));
var x = [];
Object.freeze(x);
var count = 100;
assertEq(mutate_array_frozen(x, count), false);
assertEq(x.length, 0);
var end = compute_index(0, count);
var y = [];
assertEq(mutate_array_frozen(y, count), true);
assertEq(y[end], count - 1);
Object.freeze(y);
// After a mutated array is frozen, can't subsequently modify elements
assertEq(mutate_array_frozen(x, count, 10), false);
assertEq(y[end], count - 1);
}
// Let's make sure updates to the array happen as expected.
function test_update() {
eval(create_variant("update"));
var x = [];
var count = 100;
assertEq(mutate_array_update(x, count), true);
var end = compute_index(0, count);
assertEq(x[end], count - 1);
assertEq(x[end - 1], undefined);
var epsilon = 2;
mutate_array_update(x, 200, epsilon);
assertEq(x[end], count -1 + epsilon)
}
// Elements may be non-writable, let us not write them.
function test_nonwritable() {
eval(create_variant("nonwritable"));
var x = [];
var count = 100;
var index = compute_index(0, 10);
Object.defineProperty(x, index, {value: -10, writable: false});
mutate_array_nonwritable(x, count);
assertEq(x[index], -10);
}
// Random indices can get setters, let's make sure we honour those.
function test_setter() {
eval(create_variant("setter"));
var x = [];
var count = 100;
var index = compute_index(0, 80);
var sigil = 0;
Object.defineProperty(x, index, {set(newVal) {sigil++; }});
mutate_array_setter(x, count);
assertEq(sigil, 1);
assertEq(x[index], undefined);
}
// Ensure indexes on the prototype don't break things;
//
function test_proto_indices() {
eval(create_variant("proto_indices"));
var x = [];
var count = 100;
var index = compute_index(0, 80);
x.__proto__[index] = "hello";
mutate_array_proto_indices(x, count);
assertEq(x.__proto__[index], "hello");
assertEq(x[index], 79);
}
test_basic();
test_frozen();
test_update();
test_nonwritable();
test_setter();
test_proto_indices();

View File

@ -1879,6 +1879,33 @@ BaselineCacheIRCompiler::emitCallProxySetByValue()
return true;
}
bool
BaselineCacheIRCompiler::emitCallAddOrUpdateSparseElementHelper()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register id = allocator.useRegister(masm, reader.int32OperandId());
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
bool strict = reader.readBool();
AutoScratchRegister scratch(allocator, masm);
allocator.discardStack(masm);
AutoStubFrame stubFrame(*this);
stubFrame.enter(masm, scratch);
masm.Push(Imm32(strict));
masm.Push(val);
masm.Push(id);
masm.Push(obj);
if (!callVM(masm, AddOrUpdateSparseElementHelperInfo)) {
return false;
}
stubFrame.leave(masm);
return true;
}
bool
BaselineCacheIRCompiler::emitMegamorphicSetElement()
{

View File

@ -3450,6 +3450,9 @@ SetPropIRGenerator::tryAttachStub()
if (tryAttachSetTypedElement(obj, objId, index, indexId, rhsValId)) {
return true;
}
if (tryAttachAddOrUpdateSparseElement(obj, objId, index, indexId, rhsValId)) {
return true;
}
return false;
}
return false;
@ -4066,6 +4069,89 @@ SetPropIRGenerator::tryAttachSetDenseElementHole(HandleObject obj, ObjOperandId
return true;
}
// Add an IC for adding or updating a sparse array element.
bool
SetPropIRGenerator::tryAttachAddOrUpdateSparseElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId,
ValOperandId rhsId)
{
JSOp op = JSOp(*pc_);
MOZ_ASSERT(IsPropertySetOp(op) || IsPropertyInitOp(op));
if (op != JSOP_SETELEM && op != JSOP_STRICTSETELEM) {
return false;
}
if (!obj->isNative()) {
return false;
}
RootedNativeObject nobj(cx_, &obj->as<NativeObject>());
// We cannot attach a stub to a non-extensible object
if (!nobj->isExtensible()) {
return false;
}
// Stub doesn't handle negative indices.
if (index > INT_MAX) {
return false;
}
// We also need to be past the end of the dense capacity, to ensure sparse.
if (index < nobj->getDenseInitializedLength()) {
return false;
}
// Only handle Array objects in this stub.
if (!nobj->is<ArrayObject>()) {
return false;
}
RootedArrayObject aobj(cx_, &obj->as<ArrayObject>());
// Don't attach if we're adding to an array with non-writable length.
bool isAdd = (index >= aobj->length());
if (isAdd && !aobj->lengthIsWritable()) {
return false;
}
// Indexed properties on the prototype chain aren't handled by the helper.
if (ObjectMayHaveExtraIndexedProperties(aobj->staticPrototype())) {
return false;
}
// Ensure we are still talking about an array class.
writer.guardClass(objId, GuardClassKind::Array);
// The helper we are going to call only applies to non-dense elements.
writer.guardIndexGreaterThanDenseInitLength(objId, indexId);
// Guard extensible: We may be trying to add a new element, and so we'd best
// be able to do so safely.
writer.guardIsExtensible(objId);
// Ensures we are able to efficiently able to map to an integral jsid.
writer.guardIndexIsNonNegative(indexId);
// Shape guard the prototype chain to avoid shadowing indexes from appearing.
// Dense elements may appear on the prototype chain (and prototypes may
// have a different notion of which elements are dense), but they can
// only be data properties, so our specialized Set handler is ok to bind
// to them.
ShapeGuardProtoChain(writer, obj, objId);
// Ensure that if we're adding an element to the object, the object's
// length is writable.
writer.guardIndexIsValidUpdateOrAdd(objId, indexId);
writer.callAddOrUpdateSparseElementHelper(objId, indexId, rhsId,
/* strict = */op == JSOP_STRICTSETELEM);
writer.returnFromIC();
trackAttached("AddOrUpdateSparseElement");
return true;
}
bool
SetPropIRGenerator::tryAttachSetTypedElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId,

View File

@ -201,6 +201,7 @@ extern const char* const CacheKindNames[];
_(GuardClass) /* Guard an object class, per GuardClassKind */ \
_(GuardAnyClass) /* Guard an arbitrary class for an object */ \
_(GuardCompartment) \
_(GuardIsExtensible) \
_(GuardIsNativeFunction) \
_(GuardIsNativeObject) \
_(GuardIsProxy) \
@ -222,6 +223,9 @@ extern const char* const CacheKindNames[];
_(GuardHasGetterSetter) \
_(GuardGroupHasUnanalyzedNewScript) \
_(GuardIndexIsNonNegative) \
_(GuardIndexGreaterThanDenseCapacity) \
_(GuardIndexGreaterThanArrayLength) \
_(GuardIndexIsValidUpdateOrAdd) \
_(GuardIndexGreaterThanDenseInitLength) \
_(GuardTagNotEqual) \
_(GuardXrayExpandoShapeAndDefaultProto) \
@ -267,6 +271,7 @@ extern const char* const CacheKindNames[];
_(CallSetArrayLength) \
_(CallProxySet) \
_(CallProxySetByValue) \
_(CallAddOrUpdateSparseElementHelper) \
_(CallInt32ToString) \
_(CallNumberToString) \
\
@ -765,6 +770,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
// Use RawWord, because compartments never move and it can't be GCed.
addStubField(uintptr_t(compartment), StubField::Type::RawWord);
}
void guardIsExtensible(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsExtensible, obj);
}
void guardNoDetachedTypedObjects() {
writeOp(CacheOp::GuardNoDetachedTypedObjects);
}
@ -811,6 +819,18 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOpWithOperandId(CacheOp::GuardIndexGreaterThanDenseInitLength, obj);
writeOperandId(index);
}
void guardIndexGreaterThanDenseCapacity(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexGreaterThanDenseCapacity, obj);
writeOperandId(index);
}
void guardIndexGreaterThanArrayLength(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexGreaterThanArrayLength, obj);
writeOperandId(index);
}
void guardIndexIsValidUpdateOrAdd(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexIsValidUpdateOrAdd, obj);
writeOperandId(index);
}
void guardTagNotEqual(ValueTagOperandId lhs, ValueTagOperandId rhs) {
writeOpWithOperandId(CacheOp::GuardTagNotEqual, lhs);
writeOperandId(rhs);
@ -1041,6 +1061,12 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
writeOperandId(rhs);
buffer_.writeByte(uint32_t(strict));
}
void callAddOrUpdateSparseElementHelper(ObjOperandId obj, Int32OperandId id, ValOperandId rhs, bool strict) {
writeOpWithOperandId(CacheOp::CallAddOrUpdateSparseElementHelper, obj);
writeOperandId(id);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(strict));
}
StringOperandId callInt32ToString(Int32OperandId id) {
StringOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::CallInt32ToString, id);
@ -1753,6 +1779,10 @@ class MOZ_RAII SetPropIRGenerator : public IRGenerator
bool tryAttachSetDenseElementHole(HandleObject obj, ObjOperandId objId, uint32_t index,
Int32OperandId indexId, ValOperandId rhsId);
bool tryAttachAddOrUpdateSparseElement(HandleObject obj, ObjOperandId objId, uint32_t index,
Int32OperandId indexId, ValOperandId rhsId);
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId, bool handleDOMProxies);
bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id,

View File

@ -1734,6 +1734,35 @@ CacheIRCompiler::emitGuardClass()
return true;
}
bool
CacheIRCompiler::emitGuardIsExtensible()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
AutoScratchRegister scratch(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure)) {
return false;
}
Address shape(obj, ShapedObject::offsetOfShape());
masm.loadPtr(shape, scratch);
Address baseShape(scratch, Shape::offsetOfBaseShape());
masm.loadPtr(baseShape, scratch);
Address baseShapeFlags(scratch, BaseShape::offsetOfFlags());
masm.loadPtr(baseShapeFlags, scratch);
masm.and32(Imm32(js::BaseShape::NOT_EXTENSIBLE), scratch);
// Spectre-style checks are not needed here because we do not
// interpret data based on this check.
masm.branch32(Assembler::Equal, scratch, Imm32(js::BaseShape::NOT_EXTENSIBLE),
failure->label());
return true;
}
bool
CacheIRCompiler::emitGuardIsNativeFunction()
{
@ -2836,7 +2865,7 @@ CacheIRCompiler::emitGuardIndexGreaterThanDenseInitLength()
// Load obj->elements.
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
// Ensure index >= capacity.
// Ensure index >= initLength.
Label outOfBounds;
Address capacity(scratch, ObjectElements::offsetOfInitializedLength());
masm.spectreBoundsCheck32(index, capacity, scratch2, &outOfBounds);
@ -2846,6 +2875,89 @@ CacheIRCompiler::emitGuardIndexGreaterThanDenseInitLength()
return true;
}
bool
CacheIRCompiler::emitGuardIndexGreaterThanDenseCapacity()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register index = allocator.useRegister(masm, reader.int32OperandId());
AutoScratchRegister scratch(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure)) {
return false;
}
// Load obj->elements.
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
// Ensure index >= capacity.
Label outOfBounds;
Address capacity(scratch, ObjectElements::offsetOfCapacity());
masm.spectreBoundsCheck32(index, capacity, scratch2, &outOfBounds);
masm.jump(failure->label());
masm.bind(&outOfBounds);
return true;
}
bool
CacheIRCompiler::emitGuardIndexGreaterThanArrayLength()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register index = allocator.useRegister(masm, reader.int32OperandId());
AutoScratchRegister scratch(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure)) {
return false;
}
// Load obj->elements.
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
// Ensure index >= length;
Label outOfBounds;
Address length(scratch, ObjectElements::offsetOfLength());
masm.spectreBoundsCheck32(index, length, scratch2, &outOfBounds);
masm.jump(failure->label());
masm.bind(&outOfBounds);
return true;
}
bool
CacheIRCompiler::emitGuardIndexIsValidUpdateOrAdd()
{
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register index = allocator.useRegister(masm, reader.int32OperandId());
AutoScratchRegister scratch(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure)) {
return false;
}
// Load obj->elements.
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
Label success;
// If length is writable, branch to &success. All indices are writable.
Address flags(scratch, ObjectElements::offsetOfFlags());
masm.branchTest32(Assembler::Zero, flags,
Imm32(ObjectElements::Flags::NONWRITABLE_ARRAY_LENGTH),
&success);
// Otherwise, ensure index is in bounds.
Address length(scratch, ObjectElements::offsetOfLength());
masm.spectreBoundsCheck32(index, length, scratch2,
/* failure = */ failure->label());
masm.bind(&success);
return true;
}
bool
CacheIRCompiler::emitGuardTagNotEqual()
{

View File

@ -32,6 +32,7 @@ namespace jit {
_(GuardType) \
_(GuardClass) \
_(GuardGroupHasUnanalyzedNewScript) \
_(GuardIsExtensible) \
_(GuardIsNativeFunction) \
_(GuardFunctionPrototype) \
_(GuardIsNativeObject) \
@ -46,6 +47,9 @@ namespace jit {
_(GuardAndGetNumberFromString) \
_(GuardAndGetIndexFromString) \
_(GuardIndexIsNonNegative) \
_(GuardIndexGreaterThanDenseCapacity) \
_(GuardIndexGreaterThanArrayLength) \
_(GuardIndexIsValidUpdateOrAdd) \
_(GuardIndexGreaterThanDenseInitLength) \
_(GuardTagNotEqual) \
_(GuardXrayExpandoShapeAndDefaultProto)\

View File

@ -2265,6 +2265,28 @@ IonCacheIRCompiler::emitCallProxySetByValue()
return callVM(masm, ProxySetPropertyByValueInfo);
}
bool
IonCacheIRCompiler::emitCallAddOrUpdateSparseElementHelper()
{
AutoSaveLiveRegisters save(*this);
Register obj = allocator.useRegister(masm, reader.objOperandId());
Register id = allocator.useRegister(masm, reader.int32OperandId());
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
bool strict = reader.readBool();
Label done;
prepareVMCall(masm, save);
masm.Push(Imm32(strict));
masm.Push(val);
masm.Push(id);
masm.Push(obj);
return callVM(masm, AddOrUpdateSparseElementHelperInfo);
}
bool
IonCacheIRCompiler::emitMegamorphicSetElement()
{

View File

@ -2072,5 +2072,10 @@ typedef bool (*NativeGetElementFn)(JSContext*, HandleNativeObject, HandleValue,
const VMFunction NativeGetElementInfo =
FunctionInfo<NativeGetElementFn>(NativeGetElement, "NativeGetProperty");
typedef bool (*AddOrUpdateSparseElementHelperFn)(JSContext* cx, HandleArrayObject obj,
int32_t int_id, HandleValue v, bool strict);
const VMFunction AddOrUpdateSparseElementHelperInfo =
FunctionInfo<AddOrUpdateSparseElementHelperFn>(AddOrUpdateSparseElementHelper, "AddOrUpdateSparseElementHelper");
} // namespace jit
} // namespace js

View File

@ -982,6 +982,8 @@ extern const VMFunction ProxyHasOwnInfo;
extern const VMFunction NativeGetElementInfo;
extern const VMFunction AddOrUpdateSparseElementHelperInfo;
// TailCall VMFunctions
extern const VMFunction DoConcatStringObjectInfo;

View File

@ -459,20 +459,11 @@ class Assembler : public AssemblerX86Shared
MOZ_ASSERT(dest.size() == 16);
masm.vhaddpd_rr(src.encoding(), dest.encoding());
}
void vsubpd(const Operand& src1, FloatRegister src0, FloatRegister dest) {
void vsubpd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
MOZ_ASSERT(HasSSE2());
MOZ_ASSERT(src0.size() == 16);
MOZ_ASSERT(dest.size() == 16);
switch (src1.kind()) {
case Operand::MEM_REG_DISP:
masm.vsubpd_mr(src1.disp(), src1.base(), src0.encoding(), dest.encoding());
break;
case Operand::MEM_ADDRESS32:
masm.vsubpd_mr(src1.address(), src0.encoding(), dest.encoding());
break;
default:
MOZ_CRASH("unexpected operand kind");
}
masm.vsubpd_rr(src1.encoding(), src0.encoding(), dest.encoding());
}
void vpunpckldq(FloatRegister src1, FloatRegister src0, FloatRegister dest) {

View File

@ -176,14 +176,6 @@ class BaseAssemblerX86 : public BaseAssembler
{
twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, src1, src0, dst);
}
void vsubpd_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst)
{
twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, offset, base, src0, dst);
}
void vsubpd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst)
{
twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, address, src0, dst);
}
void vpunpckldq_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) {
twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, src1, src0, dst);

View File

@ -1120,15 +1120,6 @@ MacroAssembler::wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 outp
// ========================================================================
// Convert floating point.
// vpunpckldq requires 16-byte boundary for memory operand.
// See convertUInt64ToDouble for the details.
MOZ_ALIGNED_DECL(static const uint64_t, 16) TO_DOUBLE[4] = {
0x4530000043300000LL,
0x0LL,
0x4330000000000000LL,
0x4530000000000000LL
};
bool
MacroAssembler::convertUInt64ToDoubleNeedsTemp()
{
@ -1187,8 +1178,16 @@ MacroAssembler::convertUInt64ToDouble(Register64 src, FloatRegister dest, Regist
// here, each 64-bit part of dest represents following double:
// HI(dest) = 0x 1.00000HHHHHHHH * 2**84 == 2**84 + 0x HHHHHHHH 00000000
// LO(dest) = 0x 1.00000LLLLLLLL * 2**52 == 2**52 + 0x 00000000 LLLLLLLL
movePtr(ImmWord((uintptr_t)TO_DOUBLE), temp);
vpunpckldq(Operand(temp, 0), dest128, dest128);
// See convertUInt64ToDouble for the details.
static const int32_t CST1[4] = {
0x43300000,
0x45300000,
0x0,
0x0,
};
loadConstantSimd128Int(SimdConstant::CreateX4(CST1), ScratchSimd128Reg);
vpunpckldq(ScratchSimd128Reg, dest128, dest128);
// Subtract a constant C2 from dest, for each 64-bit part:
// C2 = 0x 45300000 00000000 43300000 00000000
@ -1198,7 +1197,15 @@ MacroAssembler::convertUInt64ToDouble(Register64 src, FloatRegister dest, Regist
// after the operation each 64-bit part of dest represents following:
// HI(dest) = double(0x HHHHHHHH 00000000)
// LO(dest) = double(0x 00000000 LLLLLLLL)
vsubpd(Operand(temp, sizeof(uint64_t) * 2), dest128, dest128);
static const int32_t CST2[4] = {
0x0,
0x43300000,
0x0,
0x45300000,
};
loadConstantSimd128Int(SimdConstant::CreateX4(CST2), ScratchSimd128Reg);
vsubpd(ScratchSimd128Reg, dest128, dest128);
// Add HI(dest) and LO(dest) in double and store it into LO(dest),
// LO(dest) = double(0x HHHHHHHH 00000000) + double(0x 00000000 LLLLLLLL)

View File

@ -2107,6 +2107,48 @@ DefineNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
return result.succeed();
}
bool
js::AddOrUpdateSparseElementHelper(JSContext* cx, HandleArrayObject obj, int32_t int_id,
HandleValue v, bool strict)
{
MOZ_ASSERT(INT_FITS_IN_JSID(int_id));
RootedId id(cx, INT_TO_JSID(int_id));
// This helper doesn't handle the case where the index may be in the dense elements
MOZ_ASSERT(int_id >= 0);
MOZ_ASSERT(uint32_t(int_id) >= obj->getDenseInitializedLength());
// First decide if this is an add or an update. Because the IC guards have
// already ensured this exists exterior to the dense array range, and the
// prototype checks have ensured there are no indexes on the prototype, we
// can use the shape lineage to find the element if it exists:
RootedShape shape(cx, obj->lastProperty()->search(cx, id));
// If we didn't find the shape, we're on the add path: delegate to
// AddSparseElement:
if (shape == nullptr) {
Rooted<PropertyDescriptor> desc(cx);
desc.setDataDescriptor(v, JSPROP_ENUMERATE);
desc.assertComplete();
return AddOrChangeProperty<IsAddOrChange::Add>(cx, obj, id, desc);
}
// At this point we're updating a property: See SetExistingProperty
if (shape->writable() && shape->isDataProperty()) {
// While all JSID_INT properties use a single TI entry,
// nothing yet has inspected the updated value so we *must* use setSlotWithType().
obj->setSlotWithType(cx, shape, v, /* overwriting = */ true);
return true;
}
// We don't know exactly what this object looks like, hit the slowpath.
RootedValue receiver(cx, ObjectValue(*obj));
JS::ObjectOpResult result;
return SetProperty(cx, obj, id, v, receiver, result) &&
result.checkStrictErrorOrWarning(cx, obj, id, strict);
}
/*** [[HasProperty]] *****************************************************************************/

View File

@ -1622,6 +1622,10 @@ bool
SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result);
bool
AddOrUpdateSparseElementHelper(JSContext* cx, HandleArrayObject obj, int32_t int_id,
HandleValue v, bool strict);
/*
* Indicates whether an assignment operation is qualified (`x.y = 0`) or
* unqualified (`y = 0`). In strict mode, the latter is an error if no such

View File

@ -1159,8 +1159,10 @@ class Shape : public gc::TenuredCell
void fixupGetterSetterForBarrier(JSTracer* trc);
void updateBaseShapeAfterMovingGC();
#ifdef DEBUG
// For JIT usage.
static inline size_t offsetOfBaseShape() { return offsetof(Shape, base_); }
#ifdef DEBUG
static inline size_t offsetOfImmutableFlags() { return offsetof(Shape, immutableFlags); }
static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; }
#endif

View File

@ -11,6 +11,8 @@
namespace js {
namespace jit { class CacheIRCompiler; }
/*
* Shaped objects are a variant of JSObject that use a GCPtrShape for their
* |shapeOrExpando_| field. All objects that point to a js::Shape as their
@ -58,6 +60,8 @@ class ShapedObject : public JSObject
// See JSObject::offsetOfGroup() comment.
friend class js::jit::MacroAssembler;
friend class js::jit::CacheIRCompiler;
static constexpr size_t offsetOfShape() {
static_assert(offsetOfShapeOrExpando() == offsetof(shadow::Object, shape),
"shadow shape must match actual shape");

View File

@ -366,7 +366,6 @@ class SCInput {
static void getPair(uint64_t data, uint32_t* tagp, uint32_t* datap);
MOZ_MUST_USE bool read(uint64_t* p);
MOZ_MUST_USE bool readNativeEndian(uint64_t* p);
MOZ_MUST_USE bool readPair(uint32_t* tagp, uint32_t* datap);
MOZ_MUST_USE bool readDouble(double* p);
MOZ_MUST_USE bool readBytes(void* p, size_t nbytes);
@ -702,18 +701,6 @@ SCInput::read(uint64_t* p)
return true;
}
bool
SCInput::readNativeEndian(uint64_t* p)
{
if (!point.canPeek()) {
*p = 0; // initialize to shut GCC up
return reportTruncated();
}
*p = point.peek();
point.next();
return true;
}
bool
SCInput::readPair(uint32_t* tagp, uint32_t* datap)
{
@ -854,7 +841,7 @@ bool
SCInput::readPtr(void** p)
{
uint64_t u;
if (!readNativeEndian(&u)) {
if (!read(&u)) {
return false;
}
*p = reinterpret_cast<void*>(u);

View File

@ -12,6 +12,16 @@
type="win32"
/>
<description>XPConnect Shell</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="mozglue"
version="1.0.0.0"
language="*"
/>
</dependentAssembly>
</dependency>
<ms_asmv3:trustInfo xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<ms_asmv3:security>
<ms_asmv3:requestedPrivileges>

View File

@ -39,6 +39,12 @@ def imply_disable_compile_environment(value):
if value:
return False
option(env='MOZ_COPY_PDBS',
help='For builds that do not support symbols in the normal fashion,'
' generate and copy them into the resulting build archive.')
set_config('MOZ_COPY_PDBS', depends_if('MOZ_COPY_PDBS')(lambda _: True))
imply_option('--enable-compile-environment', imply_disable_compile_environment)
option('--disable-compile-environment',

View File

@ -11,6 +11,12 @@ mozglue.def: mozglue.def.in $(GLOBAL_DEPS)
$(call py_action,preprocessor,$(if $(MOZ_REPLACE_MALLOC),-DMOZ_REPLACE_MALLOC) $(ACDEFINES) $< -o $@)
GARBAGE += mozglue.def
# Rebuild mozglue.dll if the manifest changes - it's included by mozglue.rc.
# (this dependency should really be just for mozglue.dll, not other targets)
# Note the manifest file exists in the tree, so we use the explicit filename
# here.
EXTRA_DEPS += mozglue.dll.manifest
endif
include $(topsrcdir)/mozglue/build/replace_malloc.mk

View File

@ -35,6 +35,7 @@ if CONFIG['OS_TARGET'] == 'WINNT':
DELAYLOAD_DLLS += [
'user32.dll',
]
RCINCLUDE = 'mozglue.rc'
if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
SOURCES += ['cygprofile.cpp']

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
name="mozglue"
type="win32"
/>
<file name="mozglue.dll"/>
</assembly>

6
mozglue/build/mozglue.rc Normal file
View File

@ -0,0 +1,6 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
1 RT_MANIFEST "mozglue.dll.manifest"

View File

@ -177,14 +177,13 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
, mFeedChardet(false)
, mInitialEncodingWasFromParentFrame(false)
, mHasHadErrors(false)
, mFlushTimer(NS_NewTimer())
, mFlushTimer(NS_NewTimer(mEventTarget))
, mFlushTimerMutex("nsHtml5StreamParser mFlushTimerMutex")
, mFlushTimerArmed(false)
, mFlushTimerEverFired(false)
, mMode(aMode)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mFlushTimer->SetTarget(mEventTarget);
#ifdef DEBUG
mAtomTable.SetPermittedLookupEventTarget(mEventTarget);
#endif

View File

@ -39,6 +39,7 @@ TARGET = {
'readelf': '{}readelf'.format(
buildconfig.substs.get('TOOLCHAIN_PREFIX', '')),
'nm': '{}nm'.format(buildconfig.substs.get('TOOLCHAIN_PREFIX', '')),
'readobj': '{}readobj'.format(buildconfig.substs.get('TOOLCHAIN_PREFIX', '')),
}
if buildconfig.substs.get('HAVE_64BIT_BUILD'):
@ -190,7 +191,24 @@ def check_nsmodules(target, binary):
symbols.append((int(data[2], 16), GUESSED_NSMODULE_SIZE,
name))
else:
for line in get_output(target['nm'], '-P', binary):
# MinGW-Clang, when building pdbs, doesn't include the symbol table into
# the final module. To get the NSModule info, we can look at the exported
# symbols. (#1475562)
if buildconfig.substs['OS_ARCH'] == 'WINNT' and \
buildconfig.substs['HOST_OS_ARCH'] != 'WINNT':
readobj_output = get_output(target['readobj'], '-coff-exports', binary)
# Transform the output of readobj into nm-like output
output = []
for line in readobj_output:
if "Name" in line:
name = line.replace("Name:", "").strip()
elif "RVA" in line:
rva = line.replace("RVA:", "").strip()
output.append("%s r %s" % (name, rva))
else:
output = get_output(target['nm'], '-P', binary)
for line in output:
data = line.split()
# Some symbols may not have a size listed at all.
if len(data) == 3:

View File

@ -275,6 +275,11 @@ build_windres() {
# Manually install only nm and windres
cp binutils/windres $INSTALL_DIR/bin/$machine-w64-mingw32-windres
cp binutils/nm-new $INSTALL_DIR/bin/$machine-w64-mingw32-nm
pushd $INSTALL_DIR/bin/
ln -s llvm-readobj $machine-w64-mingw32-readobj
popd
popd
}

View File

@ -97,7 +97,7 @@ reftest.Runner = class {
let reftestWin = this.parentWindow.open(
"chrome://marionette/content/reftest.xul",
"reftest",
"chrome,dialog,height=600,width=600");
"chrome,height=600,width=600");
await new Promise(resolve => {
reftestWin.addEventListener("load", resolve, {once: true});

View File

@ -1,2 +1,5 @@
<window id="reftest" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window id="reftest"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
hidechrome="true"
style="background-color:white; overflow:hidden">
</window>

View File

@ -4,3 +4,4 @@ skip-if = python == 3
[test_socket_connection.py]
[test_is_app_installed.py]
[test_chown.py]
[test_escape_command_line.py]

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
from __future__ import absolute_import
import mozunit
def test_escape_command_line(mock_adb_object, redirect_stdout_and_assert):
"""Test _escape_command_line."""
cases = {
# expected output : test input
'adb shell ls -l': ['adb', 'shell', 'ls', '-l'],
'adb shell "ls -l"': ['adb', 'shell', 'ls -l'],
'-e "if (true)"': ['-e', 'if (true)'],
'-e "if (x === \\"hello\\")"': ['-e', 'if (x === "hello")'],
'-e "if (x === \'hello\')"': ['-e', "if (x === 'hello')"],
}
for expected, input in cases.items():
assert mock_adb_object._escape_command_line(input) == expected
if __name__ == '__main__':
mozunit.main()

View File

@ -0,0 +1,7 @@
[abort.https.window.html]
[Calling BackgroundFetchRegistration.abort sets the correct fields and responses are still available]
expected: FAIL
[Aborting the same registration twice fails]
expected: FAIL

View File

@ -38,3 +38,6 @@
[Requests with PUT method require CORS Preflight and succeed.]
expected: FAIL
[Registration object gets updated values when a background fetch completes.]
expected: FAIL

View File

@ -0,0 +1,3 @@
[mix-blend-mode-parent-element-overflow-scroll.html]
disabled:
if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1499779

View File

@ -0,0 +1,7 @@
[self-utils.html]
[Default initial values of generated properties are valid (self-test).]
expected: FAIL
[Generated properties respect inherits flag]
expected: FAIL

View File

@ -88,7 +88,6 @@
expected: FAIL
[interfaces.html?1-1000]
[Test driver]
expected: FAIL
@ -103,7 +102,6 @@
[Test driver]
expected: FAIL
[Document interface: attribute origin]
expected: FAIL
@ -175,7 +173,6 @@
[interfaces.html?exclude=Node]
prefs: [dom.window.event.enabled:true]
[Document interface: attribute origin]
expected: FAIL
@ -242,3 +239,6 @@
[Range interface: existence and properties of interface prototype object]
expected: FAIL
[Document interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL

View File

@ -0,0 +1,4 @@
[lazyload-image-attribute-on-sanity-check-tentative.sub.html]
[Verify 'lazyload' attribute state 'on' works as expected: image loads only when in viewport.]
expected: FAIL

View File

@ -5,3 +5,6 @@
[Untitled]
expected: FAIL
[Feature-Policy allow="picture-in-picture" disallows cross-origin navigation in an iframe.]
expected: FAIL

View File

@ -2,3 +2,12 @@
[Untitled]
expected: FAIL
[Feature-Policy header: picture-in-picture "none" disallows cross-origin iframes.]
expected: FAIL
[Feature-Policy header: picture-in-picture "none" disallows same-origin iframes.]
expected: FAIL
[Feature-Policy header: picture-in-picture "none" disallows the top-level document.]
expected: FAIL

View File

@ -0,0 +1,4 @@
[generic-sensor-reporting.https.html]
[Generic Sensor Report Format]
expected: FAIL

View File

@ -0,0 +1,5 @@
[fetch-destination.https.html]
[HTMLLinkElement with rel=preload and as=audio fetches with a "audio" Request.destination]
expected:
if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): FAIL

View File

@ -1,5 +1,3 @@
[cols-zero.html]
disabled:
if verify and (os == "mac"): fails in verify mode
expected:
if os == "mac": FAIL

View File

@ -1,5 +1,3 @@
[rows-zero.html]
disabled:
if verify and (os == "mac"): fails in verify mode
expected:
if e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL

View File

@ -1,5 +1,3 @@
[ol-type-unsupported-invalid.html]
disabled:
if verify and (os == "mac"): fails in verify mode
expected:
if e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL

View File

@ -1,5 +1,3 @@
[ul-type-supported-xhtml.xhtml]
disabled:
if verify and (os == "mac"): fails in verify mode
expected:
if e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL

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