Merge inbound to mozilla-central. a=merge

This commit is contained in:
Gurzau Raul 2018-09-12 14:40:07 +03:00
commit e8d8a7f9a3
40 changed files with 458 additions and 978 deletions

View File

@ -1477,7 +1477,7 @@ var gBrowserInit = {
// Setup click-and-hold gestures access to the session history
// menus if global click-and-hold isn't turned on
if (!getBoolPref("ui.click_hold_context_menus", false))
if (!Services.prefs.getBoolPref("ui.click_hold_context_menus", false))
SetClickAndHoldHandlers();
PlacesToolbarHelper.init();
@ -2148,7 +2148,7 @@ function BrowserGoHome(aEvent) {
case "tabshifted":
case "tab":
urls = homePage.split("|");
var loadInBackground = getBoolPref("browser.tabs.loadBookmarksInBackground", false);
var loadInBackground = Services.prefs.getBoolPref("browser.tabs.loadBookmarksInBackground", false);
// The homepage observer event should only be triggered when the homepage opens
// in the foreground. This is mostly to support the homepage changed by extension
// doorhanger which doesn't currently support background pages. This may change in

View File

@ -5,7 +5,6 @@
const gTests = [
test_eventMatchesKey,
test_getTopWin,
test_getBoolPref,
test_openNewTabWith,
test_openUILink,
];
@ -81,14 +80,6 @@ function test_getTopWin() {
runNextTest();
}
function test_getBoolPref() {
is(getBoolPref("browser.search.openintab", false), false, "getBoolPref");
is(getBoolPref("this.pref.doesnt.exist", true), true, "getBoolPref fallback");
is(getBoolPref("this.pref.doesnt.exist", false), false, "getBoolPref fallback #2");
runNextTest();
}
function test_openNewTabWith() {
openNewTabWith("http://example.com/", null, {triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})});
let tab = gBrowser.selectedTab = gBrowser.tabs[1];

View File

@ -62,14 +62,6 @@ function getTopWin(skipPopups) {
});
}
function getBoolPref(prefname, def) {
try {
return Services.prefs.getBoolPref(prefname);
} catch (er) {
return def;
}
}
function doGetProtocolFlags(aURI) {
let handler = Services.io.getProtocolHandler(aURI.scheme);
// see DoGetProtocolFlags in nsIProtocolHandler.idl
@ -163,7 +155,7 @@ function whereToOpenLink(e, ignoreButton, ignoreAlt) {
// ignoreButton allows "middle-click paste" to use function without always opening in a new window.
var middle = !ignoreButton && e.button == 1;
var middleUsesTabs = getBoolPref("browser.tabs.opentabfor.middleclick", true);
var middleUsesTabs = Services.prefs.getBoolPref("browser.tabs.opentabfor.middleclick", true);
// Don't do anything special with right-mouse clicks. They're probably clicks on context menu items.
@ -171,7 +163,7 @@ function whereToOpenLink(e, ignoreButton, ignoreAlt) {
if (metaKey || (middle && middleUsesTabs))
return shift ? "tabshifted" : "tab";
if (alt && getBoolPref("browser.altClickSave", false))
if (alt && Services.prefs.getBoolPref("browser.altClickSave", false))
return "save";
if (shift || (middle && !middleUsesTabs))
@ -472,7 +464,7 @@ function openLinkIn(url, where, params) {
loadInBackground = aInBackground;
if (loadInBackground == null) {
loadInBackground =
aFromChrome ? false : getBoolPref("browser.tabs.loadInBackground");
aFromChrome ? false : Services.prefs.getBoolPref("browser.tabs.loadInBackground");
}
}
@ -777,7 +769,7 @@ function getShellService() {
function isBidiEnabled() {
// first check the pref.
if (getBoolPref("bidi.browser.ui", false))
if (Services.prefs.getBoolPref("bidi.browser.ui", false))
return true;
// now see if the app locale is an RTL one.
@ -977,7 +969,7 @@ function openHelpLink(aHelpTopic, aCalledFromModal, aWhere) {
function openPrefsHelp() {
// non-instant apply prefwindows are usually modal, so we can't open in the topmost window,
// since its probably behind the window.
var instantApply = getBoolPref("browser.preferences.instantApply");
var instantApply = Services.prefs.getBoolPref("browser.preferences.instantApply");
var helpTopic = document.documentElement.getAttribute("helpTopic");
openHelpLink(helpTopic, !instantApply);

View File

@ -381,8 +381,8 @@ HistoryListener.prototype = {
}
},
OnHistoryGotoIndex(index, gotoURI) { return true; },
OnHistoryPurge(numEntries) { return true; },
OnHistoryGotoIndex(index, gotoURI) {},
OnHistoryPurge(numEntries) {},
OnHistoryReplaceEntry(index) {},
// This will be called for a pending tab when loadURI(uri) is called where
@ -417,14 +417,6 @@ HistoryListener.prototype = {
// Cancel the load.
return false;
},
OnLengthChanged(aCount) {
// Ignore, the method is implemented so that XPConnect doesn't throw!
},
OnIndexChanged(aIndex) {
// Ignore, the method is implemented so that XPConnect doesn't throw!
},
};
/**

View File

@ -301,12 +301,10 @@ class SessionHistoryListener extends Handler {
OnHistoryGotoIndex(index, gotoURI) {
// We ought to collect the previously current entry as well, see bug 1350567.
this.collectFrom(kLastIndex);
return true;
}
OnHistoryPurge(numEntries) {
this.collect();
return true;
}
OnHistoryReload(reloadURI, reloadFlags) {
@ -317,14 +315,6 @@ class SessionHistoryListener extends Handler {
OnHistoryReplaceEntry(index) {
this.collect();
}
OnLengthChanged(aCount) {
// Ignore, the method is implemented so that XPConnect doesn't throw!
}
OnIndexChanged(aIndex) {
// Ignore, the method is implemented so that XPConnect doesn't throw!
}
}
SessionHistoryListener.prototype.QueryInterface =
ChromeUtils.generateQI([Ci.nsISHistoryListener,

View File

@ -19,12 +19,10 @@ var historyListener = {
OnHistoryGotoIndex() {
sendAsyncMessage("ss-test:OnHistoryGotoIndex");
return true;
},
OnHistoryPurge() {
sendAsyncMessage("ss-test:OnHistoryPurge");
return true;
},
OnHistoryReload() {

View File

@ -1,22 +1,20 @@
{
"llvm_revision": "338614",
"llvm_revision": "341816",
"stages": "3",
"build_libcxx": false,
"build_type": "Release",
"assertions": false,
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/trunk",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_700/rc3",
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_700/rc3",
"lld_repo": "https://llvm.org/svn/llvm-project/lld/tags/RELEASE_700/rc3",
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_700/rc3",
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_700/rc3",
"python_path": "c:/mozilla-build/python/python.exe",
"cc": "cl.exe",
"cxx": "cl.exe",
"ml": "ml64.exe",
"patches": [
"workaround-issue38586.patch",
"r339636.patch",
"r341035.patch",
"loosen-msvc-detection.patch"
]
}

View File

@ -1,395 +0,0 @@
Index: lld/COFF/Driver.cpp
===================================================================
--- a/lld/COFF/Driver.cpp (revision 341034)
+++ b/lld/COFF/Driver.cpp (revision 341035)
@@ -116,6 +116,19 @@
});
}
+// Symbol names are mangled by prepending "_" on x86.
+static StringRef mangle(StringRef Sym) {
+ assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
+ if (Config->Machine == I386)
+ return Saver.save("_" + Sym);
+ return Sym;
+}
+
+static bool findUnderscoreMangle(StringRef Sym) {
+ StringRef Entry = Symtab->findMangle(mangle(Sym));
+ return !Entry.empty() && !isa<Undefined>(Symtab->find(Entry));
+}
+
MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
MemoryBufferRef MBRef = *MB;
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
@@ -407,14 +420,6 @@
return B;
}
-// Symbol names are mangled by appending "_" prefix on x86.
-StringRef LinkerDriver::mangle(StringRef Sym) {
- assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
- if (Config->Machine == I386)
- return Saver.save("_" + Sym);
- return Sym;
-}
-
// Windows specific -- find default entry point name.
//
// There are four different entry point functions for Windows executables,
@@ -421,31 +426,23 @@
// each of which corresponds to a user-defined "main" function. This function
// infers an entry point from a user-defined "main" function.
StringRef LinkerDriver::findDefaultEntry() {
+ assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
+ "must handle /subsystem before calling this");
+
// As a special case, if /nodefaultlib is given, we directly look for an
// entry point. This is because, if no default library is linked, users
// need to define an entry point instead of a "main".
- if (Config->NoDefaultLibAll) {
- for (StringRef S : {"mainCRTStartup", "wmainCRTStartup",
- "WinMainCRTStartup", "wWinMainCRTStartup"}) {
- StringRef Entry = Symtab->findMangle(S);
- if (!Entry.empty() && !isa<Undefined>(Symtab->find(Entry)))
- return mangle(S);
- }
- return "";
+ bool FindMain = !Config->NoDefaultLibAll;
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+ if (findUnderscoreMangle(FindMain ? "WinMain" : "WinMainCRTStartup"))
+ return mangle("WinMainCRTStartup");
+ if (findUnderscoreMangle(FindMain ? "wWinMain" : "wWinMainCRTStartup"))
+ return mangle("wWinMainCRTStartup");
}
-
- // User-defined main functions and their corresponding entry points.
- static const char *Entries[][2] = {
- {"main", "mainCRTStartup"},
- {"wmain", "wmainCRTStartup"},
- {"WinMain", "WinMainCRTStartup"},
- {"wWinMain", "wWinMainCRTStartup"},
- };
- for (auto E : Entries) {
- StringRef Entry = Symtab->findMangle(mangle(E[0]));
- if (!Entry.empty() && !isa<Undefined>(Symtab->find(Entry)))
- return mangle(E[1]);
- }
+ if (findUnderscoreMangle(FindMain ? "main" : "mainCRTStartup"))
+ return mangle("mainCRTStartup");
+ if (findUnderscoreMangle(FindMain ? "wmain" : "wmainCRTStartup"))
+ return mangle("wmainCRTStartup");
return "";
}
@@ -452,9 +449,9 @@
WindowsSubsystem LinkerDriver::inferSubsystem() {
if (Config->DLL)
return IMAGE_SUBSYSTEM_WINDOWS_GUI;
- if (Symtab->findUnderscore("main") || Symtab->findUnderscore("wmain"))
+ if (findUnderscoreMangle("main") || findUnderscoreMangle("wmain"))
return IMAGE_SUBSYSTEM_WINDOWS_CUI;
- if (Symtab->findUnderscore("WinMain") || Symtab->findUnderscore("wWinMain"))
+ if (findUnderscoreMangle("WinMain") || findUnderscoreMangle("wWinMain"))
return IMAGE_SUBSYSTEM_WINDOWS_GUI;
return IMAGE_SUBSYSTEM_UNKNOWN;
}
@@ -1335,25 +1332,6 @@
error("/dynamicbase:no is not compatible with " +
machineToStr(Config->Machine));
- // Handle /entry and /dll
- if (auto *Arg = Args.getLastArg(OPT_entry)) {
- Config->Entry = addUndefined(mangle(Arg->getValue()));
- } else if (!Config->Entry && !Config->NoEntry) {
- if (Args.hasArg(OPT_dll)) {
- StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
- : "_DllMainCRTStartup";
- Config->Entry = addUndefined(S);
- } else {
- // Windows specific -- If entry point name is not given, we need to
- // infer that from user-defined entry name.
- StringRef S = findDefaultEntry();
- if (S.empty())
- fatal("entry point must be defined");
- Config->Entry = addUndefined(S);
- log("Entry name inferred: " + S);
- }
- }
-
// Handle /export
for (auto *Arg : Args.filtered(OPT_export)) {
Export E = parseExport(Arg->getValue());
@@ -1379,6 +1357,34 @@
return;
}
+ // Windows specific -- if no /subsystem is given, we need to infer
+ // that from entry point name. Must happen before /entry handling,
+ // and after the early return when just writing an import library.
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
+ Config->Subsystem = inferSubsystem();
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+ fatal("subsystem must be defined");
+ }
+
+ // Handle /entry and /dll
+ if (auto *Arg = Args.getLastArg(OPT_entry)) {
+ Config->Entry = addUndefined(mangle(Arg->getValue()));
+ } else if (!Config->Entry && !Config->NoEntry) {
+ if (Args.hasArg(OPT_dll)) {
+ StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
+ : "_DllMainCRTStartup";
+ Config->Entry = addUndefined(S);
+ } else {
+ // Windows specific -- If entry point name is not given, we need to
+ // infer that from user-defined entry name.
+ StringRef S = findDefaultEntry();
+ if (S.empty())
+ fatal("entry point must be defined");
+ Config->Entry = addUndefined(S);
+ log("Entry name inferred: " + S);
+ }
+ }
+
// Handle /delayload
for (auto *Arg : Args.filtered(OPT_delayload)) {
Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
@@ -1491,14 +1497,6 @@
if (errorCount())
return;
- // Windows specific -- if no /subsystem is given, we need to infer
- // that from entry point name.
- if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
- Config->Subsystem = inferSubsystem();
- if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
- fatal("subsystem must be defined");
- }
-
// Handle /safeseh.
if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
for (ObjFile *File : ObjFile::Instances)
Index: lld/COFF/Driver.h
===================================================================
--- a/lld/COFF/Driver.h (revision 341034)
+++ b/lld/COFF/Driver.h (revision 341035)
@@ -103,7 +103,6 @@
std::set<std::string> VisitedLibs;
Symbol *addUndefined(StringRef Sym);
- StringRef mangle(StringRef Sym);
// Windows specific -- "main" is not the only main function in Windows.
// You can choose one from these four -- {w,}{WinMain,main}.
Index: lld/test/COFF/entry-inference332.test
===================================================================
--- a/lld/test/COFF/entry-inference332.test (nonexistent)
+++ b/lld/test/COFF/entry-inference332.test (revision 341035)
@@ -0,0 +1,39 @@
+# RUN: sed -e s/ENTRYNAME/_mainCRTStartup/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# RUN: sed -e s/ENTRYNAME/?mainCRTStartup@@YAHXZ/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# CHECK: Entry name inferred: _mainCRTStartup
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: "ENTRYNAME"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
Index: lld/test/COFF/entry-inference3.test
===================================================================
--- a/lld/test/COFF/entry-inference3.test (revision 341034)
+++ b/lld/test/COFF/entry-inference3.test (revision 341035)
@@ -1,7 +1,11 @@
-# RUN: yaml2obj < %s > %t.obj
-# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: sed -e s/ENTRYNAME/mainCRTStartup/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
# RUN: FileCheck %s < %t.log
+# RUN: sed -e s/ENTRYNAME/?mainCRTStartup@@YAHXZ/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
# CHECK: Entry name inferred: mainCRTStartup
--- !COFF
@@ -26,7 +30,7 @@
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- - Name: mainCRTStartup
+ - Name: "ENTRYNAME"
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
Index: lld/test/COFF/subsystem-inference32.test
===================================================================
--- a/lld/test/COFF/subsystem-inference32.test (nonexistent)
+++ b/lld/test/COFF/subsystem-inference32.test (revision 341035)
@@ -0,0 +1,74 @@
+# RUN: sed -e s/ENTRYNAME/_main/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MAIN %s
+
+# RUN: sed s/ENTRYNAME/_wmain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WMAIN %s
+
+# RUN: sed s/ENTRYNAME/_WinMain@16/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s
+
+# RUN: sed s/ENTRYNAME/_wWinMain@16/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s
+
+# MAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WINMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+# WWINMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ENTRYNAME
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _wmainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _WinMainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _wWinMainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
Index: lld/test/COFF/entry-inference4.test
===================================================================
--- a/lld/test/COFF/entry-inference4.test (nonexistent)
+++ b/lld/test/COFF/entry-inference4.test (revision 341035)
@@ -0,0 +1,56 @@
+# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:windows /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/wWinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:windows /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:console /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=MAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/wmain/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:console /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
+
+# MAIN: error: <root>: undefined symbol: mainCRTStartup
+# WMAIN: error: <root>: undefined symbol: wmainCRTStartup
+# WINMAIN: error: <root>: undefined symbol: WinMainCRTStartup
+# WWINMAIN: error: <root>: undefined symbol: wWinMainCRTStartup
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: ENTRY1
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: ENTRY2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...

View File

@ -10,19 +10,21 @@ interface nsIURI;
/**
* nsISHistoryListener defines the interface one can implement to receive
* notifications about activities in session history and to be able to
* cancel them.
* notifications about activities in session history and (for reloads) to be
* able to cancel them.
*
* A session history listener will be notified when pages are added, removed
* and loaded from session history. It can prevent any action (except adding
* a new session history entry) from happening by returning false from the
* corresponding callback method.
* and loaded from session history. In the case of reloads, it can prevent them
* from happening by returning false from the corresponding callback method.
*
* A session history listener can be registered on a particular nsISHistory
* instance via the nsISHistory::addSHistoryListener() method.
*
* Listener methods should not alter the session history. Things are likely to
* go haywire if they do.
*/
[scriptable, uuid(125c0833-746a-400e-9b89-d2d18545c08a)]
interface nsISHistoryListener : nsISupports
interface nsISHistoryListener : nsISupports
{
/**
* Called when a new document is added to session history. New documents are
@ -30,71 +32,58 @@ interface nsISHistoryListener : nsISupports
* or content area, for example via nsIWebNavigation::loadURI()
*
* @param aNewURI The URI of the document to be added to session history.
* @param aOldIndex The index of the current history item before the operation.
* @param aOldIndex The index of the current history item before the
* operation.
*/
void OnHistoryNewEntry(in nsIURI aNewURI, in long aOldIndex);
void OnHistoryNewEntry(in nsIURI aNewURI, in long aOldIndex);
/**
* Called when the current document is reloaded, for example due to a
/**
* Called before the current document is reloaded, for example due to a
* nsIWebNavigation::reload() call.
*
* @param aReloadURI The URI of the document to be reloaded.
* @param aReloadFlags Flags that indicate how the document is to be
* @param aReloadFlags Flags that indicate how the document is to be
* refreshed. See constants on the nsIWebNavigation
* interface.
* @return Whether the operation can proceed.
*
* @see nsIWebNavigation
*/
boolean OnHistoryReload(in nsIURI aReloadURI, in unsigned long aReloadFlags);
boolean OnHistoryReload(in nsIURI aReloadURI, in unsigned long aReloadFlags);
/**
* Called when navigating to a session history entry by index, for example,
* Called before navigating to a session history entry by index, for example,
* when nsIWebNavigation::gotoIndex() is called.
*
* @param aIndex The index in session history of the entry to be loaded.
* @param aIndex The index in session history of the entry to be
* loaded.
* @param aGotoURI The URI of the session history entry to be loaded.
* It could be null in case of a grouped session history
* navigation since we have no URI information of entries
* existing in other partial histories.
* @return Whether the operation can proceed.
*/
boolean OnHistoryGotoIndex(in long aIndex, in nsIURI aGotoURI);
void OnHistoryGotoIndex(in long aIndex, in nsIURI aGotoURI);
/**
* Called when entries are removed from session history. Entries can be
* Called before entries are removed from session history. Entries can be
* removed from session history for various reasons, for example to control
* the memory usage of the browser, to prevent users from loading documents
* from history, to erase evidence of prior page loads, etc.
*
* To purge documents from session history call nsISHistory::PurgeHistory()
* To purge documents from session history call nsISHistory::PurgeHistory().
*
* @param aNumEntries The number of entries to be removed from session history.
* @return Whether the operation can proceed.
* @param aNumEntries The number of entries to be removed from session
* history.
*/
boolean OnHistoryPurge(in long aNumEntries);
void OnHistoryPurge(in long aNumEntries);
/**
* Called when an entry is replaced in the session history. Entries are
* Called before an entry is replaced in the session history. Entries are
* replaced when navigating away from non-persistent history entries (such as
* about pages) and when history.replaceState is called.
*
* @param aIndex The index in session history of the entry being
* replaced
* replaced.
*/
void OnHistoryReplaceEntry(in long aIndex);
/**
* Called when nsISHistory::count has been updated. Unlike OnHistoryNewEntry
* and OnHistoryPurge which happen before the modifications are actually done
* and maybe cancellable, this function is called after these modifications.
*/
void OnLengthChanged(in long aCount);
/**
* Called when nsISHistory::index has been updated. Unlike the other methods
* on this interface, which happen before the modifications are actually done
* and maybe cancellable, this function is called after these modifications.
*/
void OnIndexChanged(in long aIndex);
void OnHistoryReplaceEntry(in long aIndex);
};

View File

@ -641,9 +641,6 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist)
mEntries.AppendElement(aSHEntry);
mIndex++;
NOTIFY_LISTENERS(OnLengthChanged, (Length()));
NOTIFY_LISTENERS(OnIndexChanged, (mIndex));
// Purge History list if it is too long
if (gHistoryMaxSize >= 0 && Length() > gHistoryMaxSize) {
PurgeHistory(Length() - gHistoryMaxSize);
@ -677,8 +674,6 @@ nsSHistory::SetIndex(int32_t aIndex)
}
mIndex = aIndex;
NOTIFY_LISTENERS(OnIndexChanged, (mIndex))
return NS_OK;
}
@ -796,14 +791,7 @@ nsSHistory::PurgeHistory(int32_t aNumEntries)
aNumEntries = std::min(aNumEntries, Length());
bool purgeHistory = true;
NOTIFY_LISTENERS_CANCELABLE(OnHistoryPurge, purgeHistory,
(aNumEntries, &purgeHistory));
if (!purgeHistory) {
// Listener asked us not to purge
return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
}
NOTIFY_LISTENERS(OnHistoryPurge, (aNumEntries));
// Remove the first `aNumEntries` entries.
mEntries.RemoveElementsAt(0, aNumEntries);
@ -814,9 +802,6 @@ nsSHistory::PurgeHistory(int32_t aNumEntries)
mRequestedIndex -= aNumEntries;
mRequestedIndex = std::max(mRequestedIndex, -1);
NOTIFY_LISTENERS(OnLengthChanged, (Length()));
NOTIFY_LISTENERS(OnIndexChanged, (mIndex))
if (mRootDocShell) {
mRootDocShell->HistoryPurged(aNumEntries);
}
@ -952,14 +937,9 @@ NS_IMETHODIMP
nsSHistory::ReloadCurrentEntry()
{
// Notify listeners
bool canNavigate = true;
nsCOMPtr<nsIURI> currentURI;
GetCurrentURI(getter_AddRefs(currentURI));
NOTIFY_LISTENERS_CANCELABLE(OnHistoryGotoIndex, canNavigate,
(mIndex, currentURI, &canNavigate));
if (!canNavigate) {
return NS_OK;
}
NOTIFY_LISTENERS(OnHistoryGotoIndex, (mIndex, currentURI));
return LoadEntry(mIndex, LOAD_HISTORY, HIST_CMD_RELOAD);
}
@ -1368,7 +1348,6 @@ nsSHistory::RemoveDuplicate(int32_t aIndex, bool aKeepNext)
// Adjust our indices to reflect the removed entry.
if (mIndex > aIndex) {
mIndex = mIndex - 1;
NOTIFY_LISTENERS(OnIndexChanged, (mIndex));
}
// NB: If the entry we are removing is the entry currently
@ -1386,7 +1365,6 @@ nsSHistory::RemoveDuplicate(int32_t aIndex, bool aKeepNext)
if (mRequestedIndex > aIndex || (mRequestedIndex == aIndex && !aKeepNext)) {
mRequestedIndex = mRequestedIndex - 1;
}
NOTIFY_LISTENERS(OnLengthChanged, (Length()));
return true;
}
return false;
@ -1451,7 +1429,6 @@ nsSHistory::UpdateIndex()
// Update the actual index with the right value.
if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
mIndex = mRequestedIndex;
NOTIFY_LISTENERS(OnIndexChanged, (mIndex))
}
mRequestedIndex = -1;
@ -1529,18 +1506,9 @@ nsSHistory::LoadEntry(int32_t aIndex, long aLoadType, uint32_t aHistCmd)
MOZ_ASSERT((prevEntry && nextEntry && nextURI), "prevEntry, nextEntry and nextURI can't be null");
// Send appropriate listener notifications.
bool canNavigate = true;
if (aHistCmd == HIST_CMD_GOTOINDEX) {
// We are going somewhere else. This is not reload either
NOTIFY_LISTENERS_CANCELABLE(OnHistoryGotoIndex, canNavigate,
(aIndex, nextURI, &canNavigate));
}
if (!canNavigate) {
// If the listener asked us not to proceed with
// the operation, simply return.
mRequestedIndex = -1;
return NS_OK; // XXX Maybe I can return some other error code?
NOTIFY_LISTENERS(OnHistoryGotoIndex, (aIndex, nextURI));
}
if (mRequestedIndex == mIndex) {

View File

@ -34,19 +34,16 @@ add_task(async function test() {
delete content._testListener;
content.setTimeout(() => { content.location.reload(); }, 0);
}
return true;
},
OnHistoryReload: () => true,
OnHistoryGotoIndex: () => true,
OnHistoryPurge: () => true,
OnHistoryGotoIndex: () => {},
OnHistoryPurge: () => {},
OnHistoryReplaceEntry: () => {
// The initial load of about:blank causes a transient entry to be
// created, so our first navigation to a real page is a replace
// instead of a new entry.
++count;
return true;
},
QueryInterface: ChromeUtils.generateQI([Ci.nsISHistoryListener,

View File

@ -13,12 +13,10 @@ SHistoryListener.prototype = {
OnHistoryGotoIndex: function (aIndex, aGotoURI) {
this.last = "gotoindex";
return this.retval;
},
OnHistoryPurge: function (aNumEntries) {
this.last = "purge";
return this.retval;
},
OnHistoryReload: function (aReloadURI, aReloadFlags) {

View File

@ -180,8 +180,12 @@ nsXBLResourceLoader::StyleSheetLoaded(StyleSheet* aSheet,
if (mPendingSheets == 0) {
// All stylesheets are loaded.
mResources->ComputeServoStyles(
*mBoundDocument->GetShell()->StyleSet());
// Our document might have been undisplayed after this sheet load
// was started, so check before building the XBL cascade data.
if (nsIPresShell* shell = mBoundDocument->GetShell()) {
mResources->ComputeServoStyles(*shell->StyleSet());
}
// XXX Check for mPendingScripts when scripts also come online.
if (!mInLoadResourcesFunc)

View File

@ -233,7 +233,7 @@ public:
// weight - [100, 900] (multiples of 100)
// stretch = [FontStretch::UltraCondensed(), FontStretch::UltraExpanded()]
// italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
// language override = result of calling nsRuleNode::ParseFontLanguageOverride
// language override = result of calling nsLayoutUtils::ParseFontLanguageOverride
// TODO: support for unicode ranges not yet implemented
virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,

View File

@ -61,9 +61,10 @@ varying vec2 vPos;
#define BORDER_STYLE_INSET 8
#define BORDER_STYLE_OUTSET 9
#define CLIP_NONE 0
#define CLIP_DASH 1
#define CLIP_DOT 2
#define CLIP_NONE 0
#define CLIP_DASH_CORNER 1
#define CLIP_DASH_EDGE 2
#define CLIP_DOT 3
#ifdef WR_VERTEX_SHADER
@ -356,7 +357,21 @@ void main(void) {
d = distance(vClipParams1.xy, vPos) - vClipParams1.z;
break;
}
case CLIP_DASH: {
case CLIP_DASH_EDGE: {
bool is_vertical = vClipParams1.x == 0.;
float half_dash = is_vertical ? vClipParams1.y : vClipParams1.x;
// We want to draw something like:
// +---+---+---+---+
// |xxx| | |xxx|
// +---+---+---+---+
float pos = is_vertical ? vPos.y : vPos.x;
bool in_dash = pos < half_dash || pos > 3.0 * half_dash;
if (!in_dash) {
d = 1.;
}
break;
}
case CLIP_DASH_CORNER: {
// Get SDF for the two line/tangent clip lines,
// do SDF subtract to get clip distance.
float d0 = distance_to_line(vClipParams1.xy,

View File

@ -235,16 +235,19 @@ impl BorderSideHelpers for BorderSide {
/// The kind of border corner clip.
#[repr(C)]
#[derive(Copy, Debug, Clone, PartialEq)]
pub enum BorderCornerClipKind {
Dash = 1,
Dot = 2,
pub enum BorderClipKind {
DashCorner = 1,
DashEdge = 2,
Dot = 3,
}
/// The source data for a border corner clip mask.
#[derive(Debug, Clone)]
pub struct BorderCornerClipSource {
pub max_clip_count: usize,
kind: BorderCornerClipKind,
struct BorderCornerClipSource {
// FIXME(emilio): the `max_clip_count` name makes no sense for dashed
// borders now that it represents half-dashes.
max_clip_count: usize,
kind: BorderClipKind,
widths: DeviceSize,
radius: DeviceSize,
ellipse: Ellipse<DevicePixel>,
@ -254,7 +257,7 @@ impl BorderCornerClipSource {
pub fn new(
corner_radius: DeviceSize,
widths: DeviceSize,
kind: BorderCornerClipKind,
kind: BorderClipKind,
) -> BorderCornerClipSource {
// Work out a dash length (and therefore dash count)
// based on the width of the border edges. The "correct"
@ -265,24 +268,21 @@ impl BorderCornerClipSource {
// uses for dash length.
let (ellipse, max_clip_count) = match kind {
BorderCornerClipKind::Dash => {
BorderClipKind::DashEdge => unreachable!("not for corners"),
BorderClipKind::DashCorner => {
let ellipse = Ellipse::new(corner_radius);
// The desired dash length is ~3x the border width.
let average_border_width = 0.5 * (widths.width + widths.height);
let desired_dash_arc_length = average_border_width * 3.0;
// Get the ideal number of dashes for that arc length.
// This is scaled by 0.5 since there is an on/off length
// for each dash.
let desired_count = 0.5 * ellipse.total_arc_length / desired_dash_arc_length;
let (_half_dash, num_half_dashes) =
compute_half_dash(average_border_width, ellipse.total_arc_length);
// Round that up to the nearest integer, so that the dash length
// doesn't exceed the ratio above. Add one extra dash to cover
// the last half-dash of the arc.
(ellipse, desired_count.ceil() as usize)
(ellipse, num_half_dashes as usize)
}
BorderCornerClipKind::Dot => {
BorderClipKind::Dot => {
let mut corner_radius = corner_radius;
if corner_radius.width < (widths.width / 2.0) {
corner_radius.width = 0.0;
@ -334,6 +334,10 @@ impl BorderCornerClipSource {
pub fn write(self, segment: BorderSegment) -> Vec<[f32; 8]> {
let mut dot_dash_data = Vec::new();
if self.max_clip_count == 0 {
return dot_dash_data;
}
let outer_scale = match segment {
BorderSegment::TopLeft => DeviceVector2D::new(0.0, 0.0),
BorderSegment::TopRight => DeviceVector2D::new(1.0, 0.0),
@ -353,29 +357,32 @@ impl BorderCornerClipSource {
let max_clip_count = self.max_clip_count.min(MAX_DASH_COUNT);
match self.kind {
BorderCornerClipKind::Dash => {
// Get the correct dash arc length.
let dash_arc_length =
0.5 * self.ellipse.total_arc_length / max_clip_count as f32;
// Start the first dash at one quarter the length of a single dash
// along the arc line. This is arbitrary but looks reasonable in
// most cases. We need to spend some time working on a more
// sophisticated dash placement algorithm that takes into account
// the offset of the dashes along edge segments.
let mut current_arc_length = 0.25 * dash_arc_length;
dot_dash_data.reserve(max_clip_count);
for _ in 0 .. max_clip_count {
let arc_length0 = current_arc_length;
current_arc_length += dash_arc_length;
BorderClipKind::DashEdge => unreachable!("not for corners"),
BorderClipKind::DashCorner => {
// Get the correct half-dash arc length.
let half_dash_arc_length =
self.ellipse.total_arc_length / max_clip_count as f32;
let dash_length = 2. * half_dash_arc_length;
let arc_length1 = current_arc_length;
current_arc_length += dash_arc_length;
let mut current_length = 0.;
dot_dash_data.reserve(max_clip_count / 4 + 1);
for i in 0 .. (max_clip_count / 4 + 1) {
let arc_length0 = current_length;
current_length += if i == 0 {
half_dash_arc_length
} else {
dash_length
};
let arc_length1 = current_length;
current_length += dash_length;
let alpha = self.ellipse.find_angle_for_arc_length(arc_length0);
let beta = self.ellipse.find_angle_for_arc_length(arc_length1);
let beta = self.ellipse.find_angle_for_arc_length(arc_length1);
let (point0, tangent0) = self.ellipse.get_point_and_tangent(alpha);
let (point1, tangent1) = self.ellipse.get_point_and_tangent(beta);
let (point0, tangent0) = self.ellipse.get_point_and_tangent(alpha);
let (point1, tangent1) = self.ellipse.get_point_and_tangent(beta);
let point0 = DevicePoint::new(
outer.x + clip_sign.x * (self.radius.width - point0.x),
@ -409,14 +416,14 @@ impl BorderCornerClipSource {
]);
}
}
BorderCornerClipKind::Dot if max_clip_count == 1 => {
BorderClipKind::Dot if max_clip_count == 1 => {
let dot_diameter = lerp(self.widths.width, self.widths.height, 0.5);
dot_dash_data.push([
self.widths.width / 2.0, self.widths.height / 2.0, 0.5 * dot_diameter, 0.,
0., 0., 0., 0.,
]);
}
BorderCornerClipKind::Dot => {
BorderClipKind::Dot => {
let mut forward_dots = Vec::with_capacity(max_clip_count / 2 + 1);
let mut back_dots = Vec::with_capacity(max_clip_count / 2 + 1);
let mut leftover_arc_length = 0.0;
@ -539,13 +546,14 @@ pub struct BorderRenderTaskInfo {
pub size: DeviceIntSize,
}
// Information needed to place and draw a border edge.
/// Information needed to place and draw a border edge.
#[derive(Debug)]
struct EdgeInfo {
// Offset in local space to place the edge from origin.
/// Offset in local space to place the edge from origin.
local_offset: f32,
// Size of the edge in local space.
/// Size of the edge in local space.
local_size: f32,
// Size in device pixels needed in the render task.
/// Size in device pixels needed in the render task.
device_size: f32,
}
@ -563,6 +571,30 @@ impl EdgeInfo {
}
}
// Given a side width and the available space, compute the half-dash (half of
// the 'on' segment) and the count of them for a given segment.
fn compute_half_dash(side_width: f32, total_size: f32) -> (f32, u32) {
let half_dash = side_width * 1.5;
let num_half_dashes = (total_size / half_dash).ceil() as u32;
if num_half_dashes == 0 {
return (0., 0);
}
// TODO(emilio): Gecko has some other heuristics here to start with a full
// dash when the border side is zero, for example. We might consider those
// in the future.
let num_half_dashes = if num_half_dashes % 4 != 0 {
num_half_dashes + 4 - num_half_dashes % 4
} else {
num_half_dashes
};
let half_dash = total_size / num_half_dashes as f32;
(half_dash, num_half_dashes)
}
// Get the needed size in device pixels for an edge,
// based on the border style of that edge. This is used
// to determine how big the render task should be.
@ -579,14 +611,11 @@ fn get_edge_info(
match style {
BorderStyle::Dashed => {
let dash_size = 3.0 * side_width;
let approx_dash_count = (avail_size - dash_size) / dash_size;
let dash_count = 1.0 + 2.0 * (approx_dash_count / 2.0).floor();
let used_size = dash_count * dash_size;
let extra_space = avail_size - used_size;
let device_size = 2.0 * dash_size * scale;
let offset = (extra_space * 0.5).round();
EdgeInfo::new(offset, used_size, device_size)
// Basically, two times the dash size.
let (half_dash, _num_half_dashes) =
compute_half_dash(side_width, avail_size);
let device_size = (2.0 * 2.0 * half_dash * scale).round();
EdgeInfo::new(0., avail_size, device_size)
}
BorderStyle::Dotted => {
let dot_and_space_size = 2.0 * side_width;
@ -960,7 +989,7 @@ fn add_brush_segment(
brush_segments.push(
BrushSegment::new(
image_rect,
true,
/* may_need_clip_mask = */ true,
edge_flags,
[
task_rect.origin.x,
@ -1014,8 +1043,8 @@ fn add_segment(
}
let clip_kind = match style0 {
BorderStyle::Dashed => Some(BorderCornerClipKind::Dash),
BorderStyle::Dotted => Some(BorderCornerClipKind::Dot),
BorderStyle::Dashed => Some(BorderClipKind::DashCorner),
BorderStyle::Dotted => Some(BorderClipKind::Dot),
_ => None,
};
@ -1031,12 +1060,16 @@ fn add_segment(
// so that we don't allocate a Vec here.
let clip_list = clip_source.write(segment);
for params in clip_list {
instances.push(BorderInstance {
flags: base_flags | ((clip_kind as i32) << 24),
clip_params: params,
..base_instance
});
if clip_list.is_empty() {
instances.push(base_instance);
} else {
for params in clip_list {
instances.push(BorderInstance {
flags: base_flags | ((clip_kind as i32) << 24),
clip_params: params,
..base_instance
});
}
}
}
None => {
@ -1053,32 +1086,19 @@ fn add_segment(
match style0 {
BorderStyle::Dashed => {
let rect = if is_vertical {
let half_dash_size = task_rect.size.height * 0.5;
let y0 = task_rect.origin.y;
let y1 = y0 + half_dash_size.round();
DeviceRect::from_floats(
task_rect.origin.x,
y0,
task_rect.origin.x + task_rect.size.width,
y1,
)
let (x, y) = if is_vertical {
let half_dash_size = task_rect.size.height * 0.25;
(0., half_dash_size)
} else {
let half_dash_size = task_rect.size.width * 0.5;
let x0 = task_rect.origin.x;
let x1 = x0 + half_dash_size.round();
DeviceRect::from_floats(
x0,
task_rect.origin.y,
x1,
task_rect.origin.y + task_rect.size.height,
)
let half_dash_size = task_rect.size.width * 0.25;
(half_dash_size, 0.)
};
instances.push(BorderInstance {
local_rect: rect,
flags: base_flags | ((BorderClipKind::DashEdge as i32) << 24),
clip_params: [
x, y, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
],
..base_instance
});
}
@ -1094,7 +1114,7 @@ fn add_segment(
};
instances.push(BorderInstance {
flags: base_flags | ((BorderCornerClipKind::Dot as i32) << 24),
flags: base_flags | ((BorderClipKind::Dot as i32) << 24),
clip_params: [
x, y, r, 0.0, 0.0, 0.0, 0.0, 0.0,
],

View File

@ -328,6 +328,9 @@ pub struct ClipChainInstance {
pub local_clip_rect: LayoutRect,
pub has_non_root_coord_system: bool,
pub has_non_local_clips: bool,
// If true, this clip chain requires allocation
// of a clip mask.
pub needs_mask: bool,
// Combined clip rect in picture space (may
// be more conservative that local_clip_rect).
pub pic_clip_rect: PictureRect,
@ -524,6 +527,7 @@ impl ClipStore {
let first_clip_node_index = self.clip_node_indices.len() as u32;
let mut has_non_root_coord_system = false;
let mut has_non_local_clips = false;
let mut needs_mask = false;
// For each potential clip node
for node_info in self.clip_node_info.drain(..) {
@ -580,6 +584,26 @@ impl ClipStore {
}
};
// As a special case, a partial accept of a clip rect that is
// in the same coordinate system as the primitive doesn't need
// a clip mask. Instead, it can be handled by the primitive
// vertex shader as part of the local clip rect. This is an
// important optimization for reducing the number of clip
// masks that are allocated on common pages.
needs_mask |= match node.item {
ClipItem::Rectangle(_, ClipMode::ClipOut) |
ClipItem::RoundedRectangle(..) |
ClipItem::Image(..) |
ClipItem::BoxShadow(..) |
ClipItem::LineDecoration(..) => {
true
}
ClipItem::Rectangle(_, ClipMode::Clip) => {
!flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM)
}
};
// Store this in the index buffer for this clip chain instance.
self.clip_node_indices
.push(ClipNodeInstance::new(node_info.node_index, flags));
@ -602,6 +626,7 @@ impl ClipStore {
has_non_local_clips,
local_clip_rect,
pic_clip_rect,
needs_mask,
})
}
}

View File

@ -107,9 +107,6 @@ pub struct DisplayListFlattener<'a> {
/// A stack of stacking context properties.
sc_stack: Vec<FlattenedStackingContext>,
/// A stack of the current pictures.
picture_stack: Vec<PrimitiveIndex>,
/// A stack of the currently active shadows
shadow_stack: Vec<(Shadow, PrimitiveIndex)>,
@ -164,7 +161,6 @@ impl<'a> DisplayListFlattener<'a> {
id_to_index_mapper: ClipIdToIndexMapper::default(),
hit_testing_runs: recycle_vec(old_builder.hit_testing_runs),
scrollbar_prims: recycle_vec(old_builder.scrollbar_prims),
picture_stack: Vec::new(),
shadow_stack: Vec::new(),
sc_stack: Vec::new(),
next_picture_id: old_builder.next_picture_id,
@ -181,7 +177,7 @@ impl<'a> DisplayListFlattener<'a> {
flattener.setup_viewport_offset(view.inner_rect, view.accumulated_scale_factor());
flattener.flatten_root(root_pipeline, &root_pipeline.viewport_size);
debug_assert!(flattener.picture_stack.is_empty());
debug_assert!(flattener.sc_stack.is_empty());
new_scene.root_pipeline_id = Some(root_pipeline_id);
new_scene.pipeline_epochs = scene.pipeline_epochs.clone();
@ -818,7 +814,7 @@ impl<'a> DisplayListFlattener<'a> {
prim_index: PrimitiveIndex,
) {
// Add primitive to the top-most Picture on the stack.
let pic_prim_index = *self.picture_stack.last().unwrap();
let pic_prim_index = self.sc_stack.last().unwrap().leaf_prim_index;
let pic = self.prim_store.get_pic_mut(pic_prim_index);
pic.add_primitive(prim_index);
}
@ -922,51 +918,6 @@ impl<'a> DisplayListFlattener<'a> {
// to correctly handle some CSS cases (see #1957).
let max_clip = LayoutRect::max_rect();
// If there is no root picture, create one for the main framebuffer.
if self.sc_stack.is_empty() {
// Should be no pictures at all if the stack is empty...
debug_assert!(self.prim_store.primitives.is_empty());
debug_assert_eq!(transform_style, TransformStyle::Flat);
// This picture stores primitive runs for items on the
// main framebuffer.
let picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
None,
false,
pipeline_id,
None,
true,
);
let prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
ClipChainId::NONE,
spatial_node_index,
None,
PrimitiveContainer::Brush(BrushPrimitive::new_picture(picture)),
);
self.picture_stack.push(prim_index);
} else if composite_ops.mix_blend_mode.is_some() && self.sc_stack.len() > 2 {
// If we have a mix-blend-mode, and we aren't the primary framebuffer,
// the stacking context needs to be isolated to blend correctly as per
// the CSS spec.
// TODO(gw): The way we detect not being the primary framebuffer (len > 2)
// is hacky and depends on how we create a root stacking context
// during flattening.
let parent_prim_index = *self.picture_stack.last().unwrap();
let parent_pic = self.prim_store.get_pic_mut(parent_prim_index);
// If not already isolated for some other reason,
// make this picture as isolated.
if parent_pic.requested_composite_mode.is_none() {
parent_pic.requested_composite_mode = Some(PictureCompositeMode::Blit);
}
}
// Get the transform-style of the parent stacking context,
// which determines if we *might* need to draw this on
// an intermediate surface for plane splitting purposes.
@ -992,126 +943,13 @@ impl<'a> DisplayListFlattener<'a> {
participating_in_3d_context &&
parent_transform_style == TransformStyle::Flat;
let rendering_context_3d_prim_index = if establishes_3d_context {
// If establishing a 3d context, we need to add a picture
// that will be the container for all the planes and any
// un-transformed content.
let picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
None,
false,
pipeline_id,
None,
true,
);
let prim = BrushPrimitive::new_picture(picture);
let prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
clip_chain_id,
spatial_node_index,
None,
PrimitiveContainer::Brush(prim),
);
let parent_prim_index = *self.picture_stack.last().unwrap();
let pic = self.prim_store.get_pic_mut(parent_prim_index);
pic.add_primitive(prim_index);
self.picture_stack.push(prim_index);
Some(prim_index)
} else {
None
};
let mut parent_prim_index = if !establishes_3d_context && participating_in_3d_context {
// If we're in a 3D context, we will parent the picture
// to the first stacking context we find that is a
// 3D rendering context container. This follows the spec
// by hoisting these items out into the same 3D context
// for plane splitting.
self.sc_stack
.iter()
.rev()
.find(|sc| sc.rendering_context_3d_prim_index.is_some())
.map(|sc| sc.rendering_context_3d_prim_index.unwrap())
.unwrap()
} else {
*self.picture_stack.last().unwrap()
};
// Same for mix-blend-mode.
if let Some(mix_blend_mode) = composite_ops.mix_blend_mode {
let picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
Some(PictureCompositeMode::MixBlend(mix_blend_mode)),
false,
pipeline_id,
None,
true,
);
let src_prim = BrushPrimitive::new_picture(picture);
let src_prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
clip_chain_id,
spatial_node_index,
None,
PrimitiveContainer::Brush(src_prim),
);
let parent_pic = self.prim_store.get_pic_mut(parent_prim_index);
parent_prim_index = src_prim_index;
parent_pic.add_primitive(src_prim_index);
self.picture_stack.push(src_prim_index);
}
// For each filter, create a new image with that composite mode.
for filter in composite_ops.filters.iter().rev() {
let picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
Some(PictureCompositeMode::Filter(*filter)),
false,
pipeline_id,
None,
true,
);
let src_prim = BrushPrimitive::new_picture(picture);
let src_prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
clip_chain_id,
spatial_node_index,
None,
PrimitiveContainer::Brush(src_prim),
);
let parent_pic = self.prim_store.get_pic_mut(parent_prim_index);
parent_prim_index = src_prim_index;
parent_pic.add_primitive(src_prim_index);
self.picture_stack.push(src_prim_index);
}
// By default, this picture will be collapsed into
// the owning target.
let mut composite_mode = None;
let mut frame_output_pipeline_id = None;
// If this stacking context if the root of a pipeline, and the caller
// If this stacking context is the root of a pipeline, and the caller
// has requested it as an output frame, create a render task to isolate it.
let mut frame_output_pipeline_id = None;
if is_pipeline_root && self.output_pipelines.contains(&pipeline_id) {
composite_mode = Some(PictureCompositeMode::Blit);
frame_output_pipeline_id = Some(pipeline_id);
@ -1133,7 +971,7 @@ impl<'a> DisplayListFlattener<'a> {
}
// Add picture for this actual stacking context contents to render into.
let picture = PicturePrimitive::new_image(
let leaf_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
composite_mode,
participating_in_3d_context,
@ -1143,34 +981,112 @@ impl<'a> DisplayListFlattener<'a> {
);
// Create a brush primitive that draws this picture.
let sc_prim = BrushPrimitive::new_picture(picture);
let leaf_prim = BrushPrimitive::new_picture(leaf_picture);
// Add the brush to the parent picture.
let sc_prim_index = self.prim_store.add_primitive(
let leaf_prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
clip_chain_id,
spatial_node_index,
None,
PrimitiveContainer::Brush(sc_prim),
PrimitiveContainer::Brush(leaf_prim),
);
let parent_pic = self.prim_store.get_pic_mut(parent_prim_index);
parent_pic.add_primitive(sc_prim_index);
// Create a chain of pictures based on presence of filters,
// mix-blend-mode and/or 3d rendering context containers.
let mut current_prim_index = leaf_prim_index;
// Add this as the top-most picture for primitives to be added to.
self.picture_stack.push(sc_prim_index);
// For each filter, create a new image with that composite mode.
for filter in &composite_ops.filters {
let mut filter_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
Some(PictureCompositeMode::Filter(*filter)),
false,
pipeline_id,
None,
true,
);
filter_picture.add_primitive(current_prim_index);
let filter_prim = BrushPrimitive::new_picture(filter_picture);
current_prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
clip_chain_id,
spatial_node_index,
None,
PrimitiveContainer::Brush(filter_prim),
);
}
// Same for mix-blend-mode.
if let Some(mix_blend_mode) = composite_ops.mix_blend_mode {
let mut blend_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
Some(PictureCompositeMode::MixBlend(mix_blend_mode)),
false,
pipeline_id,
None,
true,
);
blend_picture.add_primitive(current_prim_index);
let blend_prim = BrushPrimitive::new_picture(blend_picture);
current_prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
clip_chain_id,
spatial_node_index,
None,
PrimitiveContainer::Brush(blend_prim),
);
}
if establishes_3d_context {
// If establishing a 3d context, we need to add a picture
// that will be the container for all the planes and any
// un-transformed content.
let mut container_picture = PicturePrimitive::new_image(
self.get_next_picture_id(),
None,
false,
pipeline_id,
None,
true,
);
container_picture.add_primitive(current_prim_index);
let container_prim = BrushPrimitive::new_picture(container_picture);
current_prim_index = self.prim_store.add_primitive(
&LayoutRect::zero(),
&max_clip,
true,
clip_chain_id,
spatial_node_index,
None,
PrimitiveContainer::Brush(container_prim),
);
}
// Push the SC onto the stack, so we know how to handle things in
// pop_stacking_context.
let sc = FlattenedStackingContext {
composite_ops,
is_backface_visible,
pipeline_id,
transform_style,
rendering_context_3d_prim_index,
establishes_3d_context,
participating_in_3d_context,
leaf_prim_index,
root_prim_index: current_prim_index,
glyph_raster_space,
has_mix_blend_mode: composite_ops.mix_blend_mode.is_some(),
};
self.sc_stack.push(sc);
@ -1179,30 +1095,47 @@ impl<'a> DisplayListFlattener<'a> {
pub fn pop_stacking_context(&mut self) {
let sc = self.sc_stack.pop().unwrap();
// Always pop at least the main picture for this stacking context.
let mut pop_count = 1;
// Remove the picture for any filter/mix-blend-mode effects.
pop_count += sc.composite_ops.count();
// Remove the 3d context container if created
if sc.rendering_context_3d_prim_index.is_some() {
pop_count += 1;
}
for _ in 0 .. pop_count {
let prim_index = self
.picture_stack
.pop()
.expect("bug: mismatched picture stack");
// Run the optimize pass on each picture in the chain,
// to see if we can collapse opacity and avoid drawing
// to an off-screen surface.
for i in sc.leaf_prim_index.0 .. sc.root_prim_index.0 + 1 {
let prim_index = PrimitiveIndex(i);
self.prim_store.optimize_picture_if_possible(prim_index);
}
// By the time the stacking context stack is empty, we should
// also have cleared the picture stack.
if self.sc_stack.is_empty() {
self.picture_stack.pop().expect("bug: picture stack invalid");
debug_assert!(self.picture_stack.is_empty());
// This must be the root stacking context
return;
}
let parent_prim_index = if !sc.establishes_3d_context && sc.participating_in_3d_context {
// If we're in a 3D context, we will parent the picture
// to the first stacking context we find that is a
// 3D rendering context container. This follows the spec
// by hoisting these items out into the same 3D context
// for plane splitting.
self.sc_stack
.iter()
.rev()
.find(|sc| sc.establishes_3d_context)
.map(|sc| sc.root_prim_index)
.unwrap()
} else {
self.sc_stack.last().unwrap().leaf_prim_index
};
let parent_pic = self.prim_store.get_pic_mut(parent_prim_index);
parent_pic.add_primitive(sc.root_prim_index);
// If we have a mix-blend-mode, and we aren't the primary framebuffer,
// the stacking context needs to be isolated to blend correctly as per
// the CSS spec.
// If not already isolated for some other reason,
// make this picture as isolated.
if sc.has_mix_blend_mode &&
self.sc_stack.len() > 2 &&
parent_pic.requested_composite_mode.is_none() {
parent_pic.requested_composite_mode = Some(PictureCompositeMode::Blit);
}
assert!(
@ -2006,9 +1939,6 @@ struct FlattenedStackingContext {
/// Pipeline this stacking context belongs to.
pipeline_id: PipelineId,
/// Filters / mix-blend-mode effects
composite_ops: CompositeOps,
/// If true, visible when backface is visible.
is_backface_visible: bool,
@ -2019,10 +1949,14 @@ struct FlattenedStackingContext {
/// CSS transform-style property.
transform_style: TransformStyle,
/// If Some(..), this stacking context establishes a new
/// 3d rendering context, and the value is the picture
// index of the 3d context container.
rendering_context_3d_prim_index: Option<PrimitiveIndex>,
root_prim_index: PrimitiveIndex,
leaf_prim_index: PrimitiveIndex,
/// If true, this stacking context establishes a new
/// 3d rendering context.
establishes_3d_context: bool,
participating_in_3d_context: bool,
has_mix_blend_mode: bool,
}
#[derive(Debug)]

View File

@ -2245,7 +2245,7 @@ impl Primitive {
match segment_clip_chain {
Some(segment_clip_chain) => {
if segment_clip_chain.clips_range.count == 0 ||
if !segment_clip_chain.needs_mask ||
(!segment.may_need_clip_mask && !segment_clip_chain.has_non_local_clips) {
segment.clip_task_id = BrushSegmentTaskId::Opaque;
continue;
@ -2794,7 +2794,7 @@ impl Primitive {
return;
}
if clip_chain.clips_range.count > 0 {
if clip_chain.needs_mask {
if let Some((device_rect, _, _)) = get_raster_rects(
clip_chain.pic_clip_rect,
&pic_state.map_pic_to_raster,

View File

@ -753,7 +753,31 @@ impl RenderBackend {
window_size: doc.view.window_size,
};
tx.send(captured).unwrap();
// notify the active recorder
if let Some(ref mut r) = self.recorder {
let pipeline_id = doc.scene.root_pipeline_id.unwrap();
let epoch = doc.scene.pipeline_epochs[&pipeline_id];
let pipeline = &doc.scene.pipelines[&pipeline_id];
let scene_msg = SceneMsg::SetDisplayList {
list_descriptor: pipeline.display_list.descriptor().clone(),
epoch,
pipeline_id,
background: pipeline.background_color,
viewport_size: pipeline.viewport_size,
content_size: pipeline.content_size,
preserve_frame_state: false,
};
let txn = TransactionMsg::scene_message(scene_msg);
r.write_msg(*frame_counter, &ApiMsg::UpdateDocument(*id, txn));
r.write_payload(*frame_counter, &Payload::construct_data(
epoch,
pipeline_id,
pipeline.display_list.data(),
));
}
}
// Note: we can't pass `LoadCapture` here since it needs to arrive
// before the `PublishDocument` messages sent by `load_capture`.
return true;

View File

@ -2048,10 +2048,7 @@ impl Renderer {
);
for alpha_batch_container in &target.alpha_batch_containers {
for batch in alpha_batch_container
.opaque_batches
.iter()
.rev() {
for batch in alpha_batch_container.opaque_batches.iter().rev() {
debug_target.add(
debug_server::BatchKind::Opaque,
batch.key.kind.debug_name(),
@ -2059,8 +2056,7 @@ impl Renderer {
);
}
for batch in &alpha_batch_container
.alpha_batches {
for batch in &alpha_batch_container.alpha_batches {
debug_target.add(
debug_server::BatchKind::Alpha,
batch.key.kind.debug_name(),

View File

@ -382,7 +382,7 @@ impl TransactionMsg {
}
// TODO: We only need this for a few RenderApi methods which we should remove.
fn frame_message(msg: FrameMsg) -> Self {
pub fn frame_message(msg: FrameMsg) -> Self {
TransactionMsg {
scene_ops: Vec::new(),
frame_ops: vec![msg],
@ -393,7 +393,7 @@ impl TransactionMsg {
}
}
fn scene_message(msg: SceneMsg) -> Self {
pub fn scene_message(msg: SceneMsg) -> Self {
TransactionMsg {
scene_ops: vec![msg],
frame_ops: Vec::new(),

View File

@ -22,23 +22,28 @@ pub struct Payload {
}
impl Payload {
/// Convert the payload to a raw byte vector, in order for it to be
/// efficiently shared via shmem, for example.
/// This is a helper static method working on a slice.
pub fn construct_data(epoch: Epoch, pipeline_id: PipelineId, dl_data: &[u8]) -> Vec<u8> {
let mut data = Vec::with_capacity(
mem::size_of::<u32>() + 2 * mem::size_of::<u32>() + mem::size_of::<u64>() + dl_data.len(),
);
data.write_u32::<LittleEndian>(epoch.0).unwrap();
data.write_u32::<LittleEndian>(pipeline_id.0).unwrap();
data.write_u32::<LittleEndian>(pipeline_id.1).unwrap();
data.write_u64::<LittleEndian>(dl_data.len() as u64)
.unwrap();
data.extend_from_slice(dl_data);
data
}
/// Convert the payload to a raw byte vector, in order for it to be
/// efficiently shared via shmem, for example.
///
/// TODO(emilio, #1049): Consider moving the IPC boundary to the
/// constellation in Servo and remove this complexity from WR.
pub fn to_data(&self) -> Vec<u8> {
let mut data = Vec::with_capacity(
mem::size_of::<u32>() + 2 * mem::size_of::<u32>() + mem::size_of::<u64>() +
self.display_list_data.len(),
);
data.write_u32::<LittleEndian>(self.epoch.0).unwrap();
data.write_u32::<LittleEndian>(self.pipeline_id.0).unwrap();
data.write_u32::<LittleEndian>(self.pipeline_id.1).unwrap();
data.write_u64::<LittleEndian>(self.display_list_data.len() as u64)
.unwrap();
data.extend_from_slice(&self.display_list_data);
data
Self::construct_data(self.epoch, self.pipeline_id, &self.display_list_data)
}
/// Deserializes the given payload from a raw byte vector.

View File

@ -1 +1 @@
04d63e7d73b9661d9eb934a0933c8f9751a9a3db
02f14d0f333ef125d1abff7b1146039a0ba75f43

View File

@ -1,38 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Linked list node for undisplayed element */
#ifndef mozilla_UndisplayedNode_h
#define mozilla_UndisplayedNode_h
#include "nsIContent.h"
#include "mozilla/ComputedStyle.h"
namespace mozilla {
/**
* Node in a linked list, containing the style for an element that
* does not have a frame but whose parent does have a frame.
*/
struct UndisplayedNode : public LinkedListElement<UndisplayedNode>
{
UndisplayedNode(nsIContent* aContent, ComputedStyle* aStyle)
: mContent(aContent)
, mStyle(aStyle)
{
MOZ_COUNT_CTOR(mozilla::UndisplayedNode);
}
~UndisplayedNode() { MOZ_COUNT_DTOR(mozilla::UndisplayedNode); }
nsCOMPtr<nsIContent> mContent;
RefPtr<ComputedStyle> mStyle;
};
} // namespace mozilla
#endif // mozilla_UndisplayedNode_h

View File

@ -83,7 +83,6 @@ EXPORTS.mozilla += [
'ScrollStyles.h',
'ShapeUtils.h',
'StaticPresData.h',
'UndisplayedNode.h',
]
UNIFIED_SOURCES += [

View File

@ -3270,7 +3270,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
break;
default: {
MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,
"bug in nsRuleNode::ComputeDisplayData?");
"bug in StyleAdjuster::adjust_for_fieldset_content?");
contentFrame = NS_NewBlockFormattingContext(mPresShell, fieldsetContentStyle);
contentFrameTop =
@ -4897,9 +4897,10 @@ nsCSSFrameConstructor::FindMathMLData(const Element& aElement,
// Handle <math> specially, because it sometimes produces inlines
if (tag == nsGkAtoms::math) {
// This needs to match the test in EnsureBlockDisplay in
// nsRuleNode.cpp. Though the behavior here for the display:table
// case is pretty weird...
// The IsBlockOutsideStyle() check must match what
// specified::Display::equivalent_block_display is checking for
// already-block-outside things. Though the behavior here for the
// display:table case is pretty weird...
if (aStyle.StyleDisplay()->IsBlockOutsideStyle()) {
static const FrameConstructionData sBlockMathData =
FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |

View File

@ -18,7 +18,6 @@
#include "mozilla/PresState.h"
#include "mozilla/ComputedStyle.h"
#include "mozilla/dom/Element.h"
#include "mozilla/UndisplayedNode.h"
#include "nsIDocument.h"
#include "nsError.h"

View File

@ -12,12 +12,7 @@
PRES_ARENA_OBJECT(GeckoComputedStyle)
PRES_ARENA_OBJECT(nsLineBox)
PRES_ARENA_OBJECT(nsRuleNode)
PRES_ARENA_OBJECT(DisplayItemData)
PRES_ARENA_OBJECT(nsInheritedStyleData)
PRES_ARENA_OBJECT(nsResetStyleData)
PRES_ARENA_OBJECT(nsConditionalResetStyleData)
PRES_ARENA_OBJECT(nsConditionalResetStyleDataEntry)
PRES_ARENA_OBJECT(nsFrameList)
PRES_ARENA_OBJECT(CustomCounterStyle)
PRES_ARENA_OBJECT(DependentBuiltinCounterStyle)

View File

@ -837,13 +837,6 @@ ReflowInput::InitFrameType(LayoutFrameType aFrameType)
const nsStyleDisplay *disp = mStyleDisplay;
nsCSSFrameType frameType;
// Section 9.7 of the CSS2 spec indicates that absolute position
// takes precedence over float which takes precedence over display.
// XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
// Make sure the frame was actually moved out of the flow, and don't
// just assume what the style says, because we might not have had a
// useful float/absolute containing block
DISPLAY_INIT_TYPE(mFrame, this);
if (aFrameType == LayoutFrameType::Table) {

View File

@ -46,22 +46,20 @@ enum class CSSPseudoElementType : uint8_t;
class ComputedStyle;
/**
* A ComputedStyle represents the computed style data for an element. The
* computed style data are stored in a set of structs (see nsStyleStruct.h) that
* are cached either on the ComputedStyle or in the rule tree (see nsRuleNode.h
* for a description of this caching and how the cached structs are shared).
* A ComputedStyle represents the computed style data for an element.
*
* Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable (with a few
* exceptions, like system color changes), the data in an ComputedStyle are also
* immutable (with the additional exception of GetUniqueStyleData). When style
* data change, ElementRestyler::Restyle creates a new ComputedStyle.
* The computed style data are stored in a set of reference counted structs
* (see nsStyleStruct.h) that are stored directly on the ComputedStyle.
*
* Style structs are immutable once they have been produced, so when any change
* is made that needs a restyle, we create a new ComputedStyle.
*
* ComputedStyles are reference counted. References are generally held by:
* 1. the |nsIFrame|s that are using the ComputedStyle and
* 2. any *child* ComputedStyle (this might be the reverse of
* expectation, but it makes sense in this case)
*
* FIXME(emilio): This comment is somewhat outdated now.
* 1. nsIFrame::mComputedStyle, for every frame
* 2. Element::mServoData, for every element not inside a display:none subtree
* 3. nsComputedDOMStyle, when created for elements in display:none subtrees
* 4. media_queries::Device, which holds the initial value of every property
*/
enum class ComputedStyleBit : uint8_t

View File

@ -146,22 +146,11 @@ ProcessTranslatePart(const nsCSSValue& aValue,
percent = aValue.GetPercentValue();
} else if (aValue.GetUnit() == eCSSUnit_Pixel ||
aValue.GetUnit() == eCSSUnit_Number) {
// Handle this here (even though nsRuleNode::CalcLength handles it
// fine) so that callers are allowed to pass a null ComputedStyle
// and pres context to SetToTransformFunction if they know (as
// StyleAnimationValue does) that all lengths within the transform
// function have already been computed to pixels and percents.
//
// Raw numbers are treated as being pixels.
//
// Don't convert to aValue to AppUnits here to avoid precision issues.
return aValue.GetFloatValue();
} else if (aValue.IsCalcUnit()) {
// Servo backend. We can retrieve the Calc value directly because it has
// been computed from Servo side and set by nsCSSValue::SetCalcValue().
// We don't use nsRuleNode::SpecifiedCalcToComputedCalc() because it
// asserts for null context and we always pass null context for Servo
// backend.
// We can retrieve the Calc value directly because it has been computed
// from the Servo side and set by nsCSSValue::SetCalcValue().
nsStyleCoord::CalcValue calc = aValue.GetCalcValue();
percent = calc.mPercent;
offset = calc.mLength;

View File

@ -11,7 +11,7 @@
@namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
*|*::-moz-fieldset-content {
display: block; /* nsRuleNode::ComputeDisplayData overrules this in some cases */
display: block; /* StyleAdjuster::adjust_for_fieldset_content overrides this in some cases */
unicode-bidi: inherit;
text-overflow: inherit;
overflow: inherit;

View File

@ -20,18 +20,19 @@
<script class="testbody" type="text/javascript">
/**
* The purpose of this test is to test that nsRuleNode::Compute*Data
* functions are written correctly. In particular, in these functions,
* when the specified value of a property has unit eCSSUnit_Null,
* touching the computed data is forbidden. This is because we
* sometimes stop walking up the rule tree when we find computed data
* for an initial subsequence of our rules (i.e., an ancestor rule node)
* that we can use as a starting point (aStartStruct) for the
* computation for the current rule node.
* The purpose of this test was to test that in the old style system
* the nsRuleNode::Compute*Data functions were written correctly.
* In particular, in these functions, when the specified value of a
* property had unit eCSSUnit_Null, touching the computed data is
* forbidden. This is because we sometimes would stop walking up the
* rule tree when we find computed data for an initial subsequence of
* our rules (i.e., an ancestor rule node) that we can use as a starting
* point (aStartStruct) for the computation for the current rule node.
*
* If one of these tests fails, you should look for a case where the
* property's code in nsRuleNode::Compute*Data touches the computed
* value when the specified value has eCSSUnit_Null, and fix it.
* However, we don't cache style structs in the rule tree in the current
* style system code, and property cascading no longer relies on hand
* written functions, so this particular failure mode isn't as likely to
* happen.
*
* The test works by maintaining one style rule that has every CSS
* property specified, and a second style rule that has different values

View File

@ -102,14 +102,20 @@ function test_property(property)
isnot(other_computed_f, initial_computed_f,
"should be testing with values that compute to different things " +
"for '" + property + "'");
// It's important (given the current design of nsRuleNode) that we're
// modifying the most specific rule that matches the element, and that
// we've already requested style while that rule was empty. This
// means we'll have a cached aStartStruct from the parent in the rule
// tree (caching the "other" value), so we'll make sure we don't get
// the initial value from the luck of default-initialization.
// This means that it's important that we set the prereqs on
// It used to be important for values that are supposed to compute to the
// initial value (given the design of the old rule tree, nsRuleNode) that
// we're modifying the most specific rule that matches the element, and
// that we've already requested style while that rule was empty. This
// means we'd have a cached aStartStruct from the parent in the rule
// tree (caching the "other" value), so we'd make sure we don't get the
// initial value from the luck of default-initialization. This means
// that it would've been important that we set the prereqs on
// gRule1.style rather than on gElement.style.
//
// However, the rule tree no longer stores cached structs, and we only
// temporarily cache reset structs during a single restyle. So the
// particular failure mode this was designed to test for isn't as
// likely to eventuate.
gRule2.style.setProperty(property, keyword, "");
var initial_val_computed_n = get_computed_value(getComputedStyle(gElementN, ""), property);
var initial_val_computed_f = get_computed_value(getComputedStyle(gElementF, ""), property);

View File

@ -156,15 +156,20 @@ function test_value(property, val, is_initial)
"should be testing with values that compute to different things " +
"for '" + property + "'");
}
// It's important for values that are supposed to compute to the
// initial value (given the current design of nsRuleNode) that we're
// modifying the most specific rule that matches the element, and that
// we've already requested style while that rule was empty. This
// means we'll have a cached aStartStruct from the parent in the rule
// tree (caching the "other" value), so we'll make sure we don't get
// the initial value from the luck of default-initialization.
// This means that it's important that we set the prereqs on
// It used to be important for values that are supposed to compute to the
// initial value (given the design of the old rule tree, nsRuleNode) that
// we're modifying the most specific rule that matches the element, and
// that we've already requested style while that rule was empty. This
// means we'd have a cached aStartStruct from the parent in the rule
// tree (caching the "other" value), so we'd make sure we don't get the
// initial value from the luck of default-initialization. This means
// that it would've been important that we set the prereqs on
// gRule1.style rather than on gElement.style.
//
// However, the rule tree no longer stores cached structs, and we only
// temporarily cache reset structs during a single restyle. So the
// particular failure mode this was designed to test for isn't as
// likely to eventuate.
gRule2.style.setProperty(property, val, "");
var val_computed_n = get_computed_value(getComputedStyle(gElementN, ""), property);
var val_computed_f = get_computed_value(getComputedStyle(gElementF, ""), property);

View File

@ -4677,26 +4677,16 @@ Tab.prototype = {
OnHistoryGotoIndex: function(index, gotoURI) {
Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
return true;
},
OnHistoryPurge: function(numEntries) {
Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
return true;
},
OnHistoryReplaceEntry: function(index) {
Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
},
OnLengthChanged: function(aCount) {
// Ignore, the method is implemented so that XPConnect doesn't throw!
},
OnIndexChanged: function(aIndex) {
// Ignore, the method is implemented so that XPConnect doesn't throw!
},
UpdateMediaPlaybackRelatedObserver: function(active) {
// Media control is only used for the tab which has playing media, so we
// only need to register observer after having the active media. And the

View File

@ -2403,7 +2403,8 @@ fn static_assert() {
/// Calculates the constrained and unconstrained font sizes to be inherited
/// from the parent.
///
/// See ComputeScriptLevelSize in Gecko's nsRuleNode.cpp
/// This is a port of Gecko's old ComputeScriptLevelSize function:
/// https://dxr.mozilla.org/mozilla-central/rev/35fbf14b9/layout/style/nsRuleNode.cpp#3197-3254
///
/// scriptlevel is a property that affects how font-size is inherited. If scriptlevel is
/// +1, for example, it will inherit as the script size multiplier times
@ -2511,17 +2512,18 @@ fn static_assert() {
= self.calculate_script_level_size(parent, device);
if adjusted_size.0 != parent.gecko.mSize ||
adjusted_unconstrained_size.0 != parent.gecko.mScriptUnconstrainedSize {
// This is incorrect. When there is both a keyword size being inherited
// and a scriptlevel change, we must handle the keyword size the same
// way we handle em units. This complicates things because we now have
// to keep track of the adjusted and unadjusted ratios in the kw font size.
// This only affects the use case of a generic font being used in MathML.
// FIXME(Manishearth): This is incorrect. When there is both a
// keyword size being inherited and a scriptlevel change, we must
// handle the keyword size the same way we handle em units. This
// complicates things because we now have to keep track of the
// adjusted and unadjusted ratios in the kw font size. This only
// affects the use case of a generic font being used in MathML.
//
// If we were to fix this I would prefer doing it by removing the
// ruletree walk on the Gecko side in nsRuleNode::SetGenericFont
// and instead using extra bookkeeping in the mSize and mScriptUnconstrainedSize
// values, and reusing those instead of font_size_keyword.
// If we were to fix this I would prefer doing it not doing
// something like the ruletree walk that Gecko used to do in
// nsRuleNode::SetGenericFont and instead using extra bookkeeping in
// the mSize and mScriptUnconstrainedSize values, and reusing those
// instead of font_size_keyword.
// In the case that MathML has given us an adjusted size, apply it.
// Keep track of the unconstrained adjusted size.

View File

@ -1200,9 +1200,6 @@ impl StrongRuleNode {
}
}
/// Implementation of `nsRuleNode::HasAuthorSpecifiedRules` for Servo rule
/// nodes.
///
/// Returns true if any properties specified by `rule_type_mask` was set by
/// an author rule.
#[cfg(feature = "gecko")]

View File

@ -746,7 +746,12 @@ impl ToComputedValue for KeywordSize {
fn to_computed_value(&self, cx: &Context) -> NonNegativeLength {
use context::QuirksMode;
use values::specified::length::au_to_int_px;
// Data from nsRuleNode.cpp in Gecko
// The tables in this function are originally from
// nsRuleNode::CalcFontPointSize in Gecko:
//
// https://dxr.mozilla.org/mozilla-central/rev/35fbf14b9/layout/style/nsRuleNode.cpp#3262-3336
// Mapping from base size and HTML size to pixels
// The first index is (base_size - 9), the second is the
// HTML size. "0" is CSS keyword xx-small, not HTML size 0,
@ -765,9 +770,6 @@ impl ToComputedValue for KeywordSize {
[9, 10, 13, 16, 18, 24, 32, 48],
];
// Data from nsRuleNode.cpp in Gecko
// (https://dxr.mozilla.org/mozilla-central/rev/35fbf14b9/layout/style/nsRuleNode.cpp#3303)
//
// This table gives us compatibility with WinNav4 for the default fonts only.
// In WinNav4, the default fonts were:
//