Merge inbound to mozilla-central. a=merge

This commit is contained in:
Gurzau Raul 2018-09-21 07:13:51 +03:00
commit b1522a7bf0
35 changed files with 810 additions and 360 deletions

View File

@ -327,6 +327,9 @@ class TabTracker extends TabTrackerBase {
}
setId(nativeTab, id) {
if (!nativeTab.parentNode) {
throw new Error("Cannot attach ID to a destroyed tab.");
}
this._tabs.set(nativeTab, id);
if (nativeTab.linkedBrowser) {
this._browsers.set(nativeTab.linkedBrowser, id);

View File

@ -10,6 +10,7 @@ import subprocess
import platform
import json
import argparse
import fnmatch
import glob
import errno
import re
@ -222,6 +223,9 @@ def build_one_stage(cc, cxx, asm, ld, ar, ranlib, libtool,
if is_windows():
cmake_args.insert(-1, "-DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON")
cmake_args.insert(-1, "-DLLVM_USE_CRT_RELEASE=MT")
else:
# libllvm as a shared library is not supported on Windows
cmake_args += ["-DLLVM_LINK_LLVM_DYLIB=ON"]
if ranlib is not None:
cmake_args += ["-DCMAKE_RANLIB=%s" % slashify_path(ranlib)]
if libtool is not None:
@ -366,11 +370,17 @@ def prune_final_dir_for_clang_tidy(final_dir):
# Keep include/ intact.
# In lib/, only keep lib/clang/N.M.O/include.
# In lib/, only keep lib/clang/N.M.O/include and the LLVM shared library.
re_ver_num = re.compile(r"^\d+\.\d+\.\d+$", re.I)
for f in glob.glob("%s/lib/*" % final_dir):
if os.path.basename(f) != "clang":
delete(f)
name = os.path.basename(f)
if name == "clang":
continue
if is_darwin() and name == 'libLLVM.dylib':
continue
if is_linux() and fnmatch.fnmatch(name, 'libLLVM*.so'):
continue
delete(f)
for f in glob.glob("%s/lib/clang/*" % final_dir):
if re_ver_num.search(os.path.basename(f)) is None:
delete(f)
@ -600,11 +610,11 @@ if __name__ == "__main__":
extra_asmflags = []
extra_ldflags = []
elif is_linux():
extra_cflags = ["-static-libgcc"]
extra_cxxflags = ["-static-libgcc", "-static-libstdc++"]
extra_cflags = []
extra_cxxflags = []
extra_cflags2 = ["-fPIC"]
# Silence clang's warnings about arguments not being used in compilation.
extra_cxxflags2 = ["-fPIC", '-Qunused-arguments', "-static-libstdc++"]
extra_cxxflags2 = ["-fPIC", '-Qunused-arguments']
extra_asmflags = []
extra_ldflags = []

View File

@ -16,6 +16,7 @@
"cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"patches": [
"static-llvm-symbolizer.patch",
"find_symbolizer_linux.patch",
"r322325.patch",
"r322401.patch",

View File

@ -21,6 +21,7 @@
"libtool": "/builds/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-libtool",
"ld": "/builds/worker/workspace/build/src/clang/bin/clang",
"patches": [
"static-llvm-symbolizer.patch",
"compiler-rt-cross-compile.patch",
"compiler-rt-no-codesign.patch",
"r322401.patch",

View File

@ -16,6 +16,7 @@
"cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
"patches": [
"static-llvm-symbolizer.patch",
"find_symbolizer_linux.patch",
"rename_gcov_flush.patch"
]

View File

@ -0,0 +1,12 @@
diff --git a/llvm/tools/llvm-symbolizer/CMakeLists.txt b/llvm/tools/llvm-symbolizer/CMakeLists.txt
index 8185c296c50..13c7419fa47 100644
--- a/llvm/tools/llvm-symbolizer/CMakeLists.txt
+++ b/llvm/tools/llvm-symbolizer/CMakeLists.txt
@@ -13,6 +13,7 @@ set(LLVM_LINK_COMPONENTS
)
add_llvm_tool(llvm-symbolizer
+ DISABLE_LLVM_LINK_LLVM_DYLIB
llvm-symbolizer.cpp
)

View File

@ -6,10 +6,13 @@
#include "DocumentOrShadowRoot.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/StyleSheetList.h"
#include "nsDocument.h"
#include "nsFocusManager.h"
#include "nsIRadioVisitor.h"
#include "nsIFormControl.h"
#include "nsLayoutUtils.h"
#include "nsSVGUtils.h"
#include "nsWindowSizes.h"
@ -398,5 +401,205 @@ DocumentOrShadowRoot::ReportEmptyGetElementByIdArg()
nsContentUtils::ReportEmptyGetElementByIdArg(AsNode().OwnerDoc());
}
/**
* A struct that holds all the information about a radio group.
*/
struct nsRadioGroupStruct
{
nsRadioGroupStruct()
: mRequiredRadioCount(0)
, mGroupSuffersFromValueMissing(false)
{}
/**
* A strong pointer to the currently selected radio button.
*/
RefPtr<HTMLInputElement> mSelectedRadioButton;
nsCOMArray<nsIFormControl> mRadioButtons;
uint32_t mRequiredRadioCount;
bool mGroupSuffersFromValueMissing;
};
nsresult
DocumentOrShadowRoot::WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor,
bool aFlushContent)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) {
return NS_OK;
}
}
return NS_OK;
}
void
DocumentOrShadowRoot::SetCurrentRadioButton(const nsAString& aName,
HTMLInputElement* aRadio)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mSelectedRadioButton = aRadio;
}
HTMLInputElement*
DocumentOrShadowRoot::GetCurrentRadioButton(const nsAString& aName)
{
return GetOrCreateRadioGroup(aName)->mSelectedRadioButton;
}
nsresult
DocumentOrShadowRoot::GetNextRadioButton(const nsAString& aName,
const bool aPrevious,
HTMLInputElement* aFocusedRadio,
HTMLInputElement** aRadioOut)
{
// XXX Can we combine the HTML radio button method impls of
// nsDocument and nsHTMLFormControl?
// XXX Why is HTML radio button stuff in nsDocument, as
// opposed to nsHTMLDocument?
*aRadioOut = nullptr;
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
// Return the radio button relative to the focused radio button.
// If no radio is focused, get the radio relative to the selected one.
RefPtr<HTMLInputElement> currentRadio;
if (aFocusedRadio) {
currentRadio = aFocusedRadio;
} else {
currentRadio = radioGroup->mSelectedRadioButton;
if (!currentRadio) {
return NS_ERROR_FAILURE;
}
}
int32_t index = radioGroup->mRadioButtons.IndexOf(currentRadio);
if (index < 0) {
return NS_ERROR_FAILURE;
}
int32_t numRadios = radioGroup->mRadioButtons.Count();
RefPtr<HTMLInputElement> radio;
do {
if (aPrevious) {
if (--index < 0) {
index = numRadios -1;
}
} else if (++index >= numRadios) {
index = 0;
}
NS_ASSERTION(static_cast<nsGenericHTMLFormElement*>(radioGroup->mRadioButtons[index])->IsHTMLElement(nsGkAtoms::input),
"mRadioButtons holding a non-radio button");
radio = static_cast<HTMLInputElement*>(radioGroup->mRadioButtons[index]);
} while (radio->Disabled() && radio != currentRadio);
radio.forget(aRadioOut);
return NS_OK;
}
void
DocumentOrShadowRoot::AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mRadioButtons.AppendObject(aRadio);
if (aRadio->IsRequired()) {
radioGroup->mRequiredRadioCount++;
}
}
void
DocumentOrShadowRoot::RemoveFromRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mRadioButtons.RemoveObject(aRadio);
if (aRadio->IsRequired()) {
NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
"mRequiredRadioCount about to wrap below 0!");
radioGroup->mRequiredRadioCount--;
}
}
uint32_t
DocumentOrShadowRoot::GetRequiredRadioCount(const nsAString& aName) const
{
nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
return radioGroup ? radioGroup->mRequiredRadioCount : 0;
}
void
DocumentOrShadowRoot::RadioRequiredWillChange(const nsAString& aName,
bool aRequiredAdded)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
if (aRequiredAdded) {
radioGroup->mRequiredRadioCount++;
} else {
NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
"mRequiredRadioCount about to wrap below 0!");
radioGroup->mRequiredRadioCount--;
}
}
bool
DocumentOrShadowRoot::GetValueMissingState(const nsAString& aName) const
{
nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
return radioGroup && radioGroup->mGroupSuffersFromValueMissing;
}
void
DocumentOrShadowRoot::SetValueMissingState(const nsAString& aName, bool aValue)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mGroupSuffersFromValueMissing = aValue;
}
nsRadioGroupStruct*
DocumentOrShadowRoot::GetRadioGroup(const nsAString& aName) const
{
nsRadioGroupStruct* radioGroup = nullptr;
mRadioGroups.Get(aName, &radioGroup);
return radioGroup;
}
nsRadioGroupStruct*
DocumentOrShadowRoot::GetOrCreateRadioGroup(const nsAString& aName)
{
return mRadioGroups.LookupForAdd(aName).OrInsert(
[] () { return new nsRadioGroupStruct(); });
}
void
DocumentOrShadowRoot::Traverse(DocumentOrShadowRoot* tmp,
nsCycleCollectionTraversalCallback &cb)
{
for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
nsRadioGroupStruct* radioGroup = iter.UserData();
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "mRadioGroups entry->mSelectedRadioButton");
cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
uint32_t i, count = radioGroup->mRadioButtons.Count();
for (i = 0; i < count; ++i) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "mRadioGroups entry->mRadioButtons[i]");
cb.NoteXPCOMChild(radioGroup->mRadioButtons[i]);
}
}
}
void
DocumentOrShadowRoot::Unlink(DocumentOrShadowRoot* tmp)
{
tmp->mRadioGroups.Clear();
}
}
}

View File

@ -8,13 +8,16 @@
#define mozilla_dom_DocumentOrShadowRoot_h__
#include "mozilla/dom/NameSpaceConstants.h"
#include "nsClassHashtable.h"
#include "nsContentListDeclarations.h"
#include "nsTArray.h"
#include "nsIdentifierMapEntry.h"
class nsContentList;
class nsCycleCollectionTraversalCallback;
class nsIDocument;
class nsINode;
class nsIRadioVisitor;
class nsWindowSizes;
namespace mozilla {
@ -23,6 +26,9 @@ class StyleSheet;
namespace dom {
class Element;
class DocumentOrShadowRoot;
class HTMLInputElement;
struct nsRadioGroupStruct;
class StyleSheetList;
class ShadowRoot;
@ -45,6 +51,11 @@ public:
explicit DocumentOrShadowRoot(nsIDocument&);
explicit DocumentOrShadowRoot(mozilla::dom::ShadowRoot&);
// Unusual argument naming is because of cycle collection macros.
static void Traverse(DocumentOrShadowRoot* tmp,
nsCycleCollectionTraversalCallback &cb);
static void Unlink(DocumentOrShadowRoot* tmp);
nsINode& AsNode()
{
return mAsNode;
@ -186,6 +197,31 @@ public:
void ReportEmptyGetElementByIdArg();
// nsIRadioGroupContainer
NS_IMETHOD WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor,
bool aFlushContent);
void SetCurrentRadioButton(const nsAString& aName,
HTMLInputElement* aRadio);
HTMLInputElement* GetCurrentRadioButton(const nsAString& aName);
nsresult GetNextRadioButton(const nsAString& aName,
const bool aPrevious,
HTMLInputElement* aFocusedRadio,
HTMLInputElement** aRadioOut);
void AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio);
void RemoveFromRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio);
uint32_t GetRequiredRadioCount(const nsAString& aName) const;
void RadioRequiredWillChange(const nsAString& aName,
bool aRequiredAdded);
bool GetValueMissingState(const nsAString& aName) const;
void SetValueMissingState(const nsAString& aName, bool aValue);
// for radio group
nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
protected:
// Returns the reference to the sheet, if found in mStyleSheets.
already_AddRefed<StyleSheet> RemoveSheet(StyleSheet& aSheet);
@ -218,6 +254,8 @@ protected:
*/
nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
nsINode& mAsNode;
const Kind mKind;
};

View File

@ -41,6 +41,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot, DocumentFragment)
iter.Next()) {
iter.Get()->Traverse(&cb);
}
DocumentOrShadowRoot::Traverse(tmp, cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
@ -49,11 +50,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
tmp->mIdentifierMap.Clear();
DocumentOrShadowRoot::Unlink(tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ShadowRoot)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
NS_INTERFACE_MAP_END_INHERITING(DocumentFragment)
NS_IMPL_ADDREF_INHERITED(ShadowRoot, DocumentFragment)

View File

@ -16,6 +16,7 @@
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIdentifierMapEntry.h"
#include "nsIRadioGroupContainer.h"
#include "nsStubMutationObserver.h"
#include "nsTHashtable.h"
@ -35,10 +36,12 @@ class Rule;
namespace dom {
class Element;
class HTMLInputElement;
class ShadowRoot final : public DocumentFragment,
public DocumentOrShadowRoot,
public nsStubMutationObserver
public nsStubMutationObserver,
public nsIRadioGroupContainer
{
public:
NS_IMPL_FROMNODE_HELPER(ShadowRoot, IsShadowRoot());
@ -207,6 +210,61 @@ public:
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
// nsIRadioGroupContainer
NS_IMETHOD WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor,
bool aFlushContent) override
{
return DocumentOrShadowRoot::WalkRadioGroup(aName, aVisitor, aFlushContent);
}
virtual void
SetCurrentRadioButton(const nsAString& aName,
HTMLInputElement* aRadio) override
{
DocumentOrShadowRoot::SetCurrentRadioButton(aName, aRadio);
}
virtual HTMLInputElement*
GetCurrentRadioButton(const nsAString& aName) override
{
return DocumentOrShadowRoot::GetCurrentRadioButton(aName);
}
NS_IMETHOD
GetNextRadioButton(const nsAString& aName,
const bool aPrevious,
HTMLInputElement* aFocusedRadio,
HTMLInputElement** aRadioOut) override
{
return DocumentOrShadowRoot::GetNextRadioButton(aName, aPrevious,
aFocusedRadio, aRadioOut);
}
virtual void AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio) override
{
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio);
}
virtual void RemoveFromRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio) override
{
DocumentOrShadowRoot::RemoveFromRadioGroup(aName, aRadio);
}
virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const override
{
return DocumentOrShadowRoot::GetRequiredRadioCount(aName);
}
virtual void RadioRequiredWillChange(const nsAString& aName,
bool aRequiredAdded) override
{
DocumentOrShadowRoot::RadioRequiredWillChange(aName, aRequiredAdded);
}
virtual bool GetValueMissingState(const nsAString& aName) const override
{
return DocumentOrShadowRoot::GetValueMissingState(aName);
}
virtual void SetValueMissingState(const nsAString& aName, bool aValue) override
{
return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
}
protected:
// FIXME(emilio): This will need to become more fine-grained.
void ApplicableRulesChanged();

View File

@ -119,10 +119,6 @@
#include "nsFocusManager.h"
#include "nsICookieService.h"
// for radio group stuff
#include "nsIRadioVisitor.h"
#include "nsIFormControl.h"
#include "nsBidiUtils.h"
#include "nsContentCreatorFunctions.h"
@ -724,26 +720,6 @@ public:
nsIDocument *mSubDocument;
};
/**
* A struct that holds all the information about a radio group.
*/
struct nsRadioGroupStruct
{
nsRadioGroupStruct()
: mRequiredRadioCount(0)
, mGroupSuffersFromValueMissing(false)
{}
/**
* A strong pointer to the currently selected radio button.
*/
RefPtr<HTMLInputElement> mSelectedRadioButton;
nsCOMArray<nsIFormControl> mRadioButtons;
uint32_t mRequiredRadioCount;
bool mGroupSuffersFromValueMissing;
};
// nsOnloadBlocker implementation
NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
@ -1924,19 +1900,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
nsRadioGroupStruct* radioGroup = iter.UserData();
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "mRadioGroups entry->mSelectedRadioButton");
cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
uint32_t i, count = radioGroup->mRadioButtons.Count();
for (i = 0; i < count; ++i) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
cb, "mRadioGroups entry->mRadioButtons[i]");
cb.NoteXPCOMChild(radioGroup->mRadioButtons[i]);
}
}
DocumentOrShadowRoot::Traverse(tmp, cb);
// The boxobject for an element will only exist as long as it's in the
// document, so we'll traverse the table here instead of from the element.
@ -2092,7 +2056,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
"How did we get here without our presshell going away "
"first?");
tmp->mRadioGroups.Clear();
DocumentOrShadowRoot::Unlink(tmp);
// nsDocument has a pretty complex destructor, so we're going to
// assume that *most* cycles you actually want to break somewhere
@ -7713,163 +7677,6 @@ nsIDocument::IsScriptEnabled()
return xpc::Scriptability::Get(globalObject->GetGlobalJSObject()).Allowed();
}
nsRadioGroupStruct*
nsDocument::GetRadioGroup(const nsAString& aName) const
{
nsRadioGroupStruct* radioGroup = nullptr;
mRadioGroups.Get(aName, &radioGroup);
return radioGroup;
}
nsRadioGroupStruct*
nsDocument::GetOrCreateRadioGroup(const nsAString& aName)
{
return mRadioGroups.LookupForAdd(aName).OrInsert(
[] () { return new nsRadioGroupStruct(); });
}
void
nsDocument::SetCurrentRadioButton(const nsAString& aName,
HTMLInputElement* aRadio)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mSelectedRadioButton = aRadio;
}
HTMLInputElement*
nsDocument::GetCurrentRadioButton(const nsAString& aName)
{
return GetOrCreateRadioGroup(aName)->mSelectedRadioButton;
}
NS_IMETHODIMP
nsDocument::GetNextRadioButton(const nsAString& aName,
const bool aPrevious,
HTMLInputElement* aFocusedRadio,
HTMLInputElement** aRadioOut)
{
// XXX Can we combine the HTML radio button method impls of
// nsDocument and nsHTMLFormControl?
// XXX Why is HTML radio button stuff in nsDocument, as
// opposed to nsHTMLDocument?
*aRadioOut = nullptr;
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
// Return the radio button relative to the focused radio button.
// If no radio is focused, get the radio relative to the selected one.
RefPtr<HTMLInputElement> currentRadio;
if (aFocusedRadio) {
currentRadio = aFocusedRadio;
}
else {
currentRadio = radioGroup->mSelectedRadioButton;
if (!currentRadio) {
return NS_ERROR_FAILURE;
}
}
int32_t index = radioGroup->mRadioButtons.IndexOf(currentRadio);
if (index < 0) {
return NS_ERROR_FAILURE;
}
int32_t numRadios = radioGroup->mRadioButtons.Count();
RefPtr<HTMLInputElement> radio;
do {
if (aPrevious) {
if (--index < 0) {
index = numRadios -1;
}
}
else if (++index >= numRadios) {
index = 0;
}
NS_ASSERTION(static_cast<nsGenericHTMLFormElement*>(radioGroup->mRadioButtons[index])->IsHTMLElement(nsGkAtoms::input),
"mRadioButtons holding a non-radio button");
radio = static_cast<HTMLInputElement*>(radioGroup->mRadioButtons[index]);
} while (radio->Disabled() && radio != currentRadio);
radio.forget(aRadioOut);
return NS_OK;
}
void
nsDocument::AddToRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mRadioButtons.AppendObject(aRadio);
if (aRadio->IsRequired()) {
radioGroup->mRequiredRadioCount++;
}
}
void
nsDocument::RemoveFromRadioGroup(const nsAString& aName,
HTMLInputElement* aRadio)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mRadioButtons.RemoveObject(aRadio);
if (aRadio->IsRequired()) {
NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
"mRequiredRadioCount about to wrap below 0!");
radioGroup->mRequiredRadioCount--;
}
}
NS_IMETHODIMP
nsDocument::WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor,
bool aFlushContent)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) {
return NS_OK;
}
}
return NS_OK;
}
uint32_t
nsDocument::GetRequiredRadioCount(const nsAString& aName) const
{
nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
return radioGroup ? radioGroup->mRequiredRadioCount : 0;
}
void
nsDocument::RadioRequiredWillChange(const nsAString& aName, bool aRequiredAdded)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
if (aRequiredAdded) {
radioGroup->mRequiredRadioCount++;
} else {
NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
"mRequiredRadioCount about to wrap below 0!");
radioGroup->mRequiredRadioCount--;
}
}
bool
nsDocument::GetValueMissingState(const nsAString& aName) const
{
nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
return radioGroup && radioGroup->mGroupSuffersFromValueMissing;
}
void
nsDocument::SetValueMissingState(const nsAString& aName, bool aValue)
{
nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
radioGroup->mGroupSuffersFromValueMissing = aValue;
}
void
nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
{

View File

@ -66,9 +66,7 @@
class nsDOMStyleSheetSetList;
class nsDocument;
class nsIRadioVisitor;
class nsIFormControl;
struct nsRadioGroupStruct;
class nsOnloadBlocker;
class nsDOMNavigationTiming;
class nsWindowSizes;
@ -147,30 +145,57 @@ public:
// nsIRadioGroupContainer
NS_IMETHOD WalkRadioGroup(const nsAString& aName,
nsIRadioVisitor* aVisitor,
bool aFlushContent) override;
bool aFlushContent) override
{
return DocumentOrShadowRoot::WalkRadioGroup(aName, aVisitor, aFlushContent);
}
virtual void
SetCurrentRadioButton(const nsAString& aName,
mozilla::dom::HTMLInputElement* aRadio) override;
mozilla::dom::HTMLInputElement* aRadio) override
{
DocumentOrShadowRoot::SetCurrentRadioButton(aName, aRadio);
}
virtual mozilla::dom::HTMLInputElement*
GetCurrentRadioButton(const nsAString& aName) override;
GetCurrentRadioButton(const nsAString& aName) override
{
return DocumentOrShadowRoot::GetCurrentRadioButton(aName);
}
NS_IMETHOD
GetNextRadioButton(const nsAString& aName,
const bool aPrevious,
mozilla::dom::HTMLInputElement* aFocusedRadio,
mozilla::dom::HTMLInputElement** aRadioOut) override;
mozilla::dom::HTMLInputElement* aFocusedRadio,
mozilla::dom::HTMLInputElement** aRadioOut) override
{
return DocumentOrShadowRoot::GetNextRadioButton(aName, aPrevious,
aFocusedRadio, aRadioOut);
}
virtual void AddToRadioGroup(const nsAString& aName,
mozilla::dom::HTMLInputElement* aRadio) override;
mozilla::dom::HTMLInputElement* aRadio) override
{
DocumentOrShadowRoot::AddToRadioGroup(aName, aRadio);
}
virtual void RemoveFromRadioGroup(const nsAString& aName,
mozilla::dom::HTMLInputElement* aRadio) override;
virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const override;
mozilla::dom::HTMLInputElement* aRadio) override
{
DocumentOrShadowRoot::RemoveFromRadioGroup(aName, aRadio);
}
virtual uint32_t GetRequiredRadioCount(const nsAString& aName) const override
{
return DocumentOrShadowRoot::GetRequiredRadioCount(aName);
}
virtual void RadioRequiredWillChange(const nsAString& aName,
bool aRequiredAdded) override;
virtual bool GetValueMissingState(const nsAString& aName) const override;
virtual void SetValueMissingState(const nsAString& aName, bool aValue) override;
// for radio group
nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
bool aRequiredAdded) override
{
DocumentOrShadowRoot::RadioRequiredWillChange(aName, aRequiredAdded);
}
virtual bool GetValueMissingState(const nsAString& aName) const override
{
return DocumentOrShadowRoot::GetValueMissingState(aName);
}
virtual void SetValueMissingState(const nsAString& aName, bool aValue) override
{
return DocumentOrShadowRoot::SetValueMissingState(aName, aValue);
}
// Check whether shadow DOM is enabled for aGlobal.
static bool IsShadowDOMEnabled(JSContext* aCx, JSObject* aGlobal);
@ -262,8 +287,6 @@ public:
// include https://github.com/rust-lang-nursery/rust-bindgen/pull/1271.
js::ExpandoAndGeneration mExpandoAndGeneration;
nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
friend class nsCallRequestFullscreen;
// The application cache that this document is associated with, if

View File

@ -66,6 +66,10 @@
using namespace mozilla::tasktracer;
#endif
#ifdef MOZ_GECKO_PROFILER
#include "ProfilerMarkerPayload.h"
#endif
namespace mozilla {
using namespace dom;
@ -1109,8 +1113,49 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
EventChainPostVisitor postVisitor(preVisitor);
MOZ_RELEASE_ASSERT(!aEvent->mPath);
aEvent->mPath = &chain;
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
aCallback, cd);
#ifdef MOZ_GECKO_PROFILER
if (profiler_is_active()) {
// Add a profiler label and a profiler marker for the actual
// dispatch of the event.
// This is a very hot code path, so we need to make sure not to
// do this extra work when we're not profiling.
if (!postVisitor.mDOMEvent) {
// This is tiny bit slow, but happens only once per event.
// Similar code also in EventListenerManager.
nsCOMPtr<EventTarget> et = aEvent->mOriginalTarget;
RefPtr<Event> event = EventDispatcher::CreateEvent(et, aPresContext,
aEvent,
EmptyString());
event.swap(postVisitor.mDOMEvent);
}
nsAutoString typeStr;
postVisitor.mDOMEvent->GetType(typeStr);
AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
"EventDispatcher::Dispatch", OTHER, typeStr);
profiler_add_marker(
"DOMEvent",
MakeUnique<DOMEventMarkerPayload>(typeStr,
aEvent->mTimeStamp,
"DOMEvent",
TRACING_INTERVAL_START));
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
aCallback, cd);
profiler_add_marker(
"DOMEvent",
MakeUnique<DOMEventMarkerPayload>(typeStr,
aEvent->mTimeStamp,
"DOMEvent",
TRACING_INTERVAL_END));
} else
#endif
{
EventTargetChainItem::HandleEventTargetChain(chain, postVisitor,
aCallback, cd);
}
aEvent->mPath = nullptr;
preVisitor.mEventStatus = postVisitor.mEventStatus;

View File

@ -29,7 +29,6 @@
#include "mozilla/TimeStamp.h"
#include "EventListenerService.h"
#include "GeckoProfiler.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
@ -52,10 +51,6 @@
#include "nsIFrame.h"
#include "nsDisplayList.h"
#ifdef MOZ_GECKO_PROFILER
#include "ProfilerMarkerPayload.h"
#endif
namespace mozilla {
using namespace dom;
@ -1249,6 +1244,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
(aEvent->IsTrusted() || listener->mFlags.mAllowUntrustedEvents)) {
if (!*aDOMEvent) {
// This is tiny bit slow, but happens only once per event.
// Similar code also in EventDispatcher.
nsCOMPtr<EventTarget> et = aEvent->mOriginalTarget;
RefPtr<Event> event = EventDispatcher::CreateEvent(et, aPresContext,
aEvent,
@ -1301,46 +1297,16 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
hasRemovedListener = true;
}
nsresult rv = NS_OK;
nsCOMPtr<nsPIDOMWindowInner> innerWindow =
WindowFromListener(listener, aItemInShadowTree);
mozilla::dom::Event* oldWindowEvent = nullptr;
if (innerWindow) {
oldWindowEvent = innerWindow->SetEvent(*aDOMEvent);
}
#ifdef MOZ_GECKO_PROFILER
if (profiler_is_active()) {
// Add a profiler label and a profiler marker for the actual
// dispatch of the event.
// This is a very hot code path, so we need to make sure not to
// do this extra work when we're not profiling.
nsAutoString typeStr;
(*aDOMEvent)->GetType(typeStr);
AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
"EventListenerManager::HandleEventInternal", OTHER, typeStr);
uint16_t phase = (*aDOMEvent)->EventPhase();
profiler_add_marker(
"DOMEvent",
MakeUnique<DOMEventMarkerPayload>(typeStr, phase,
aEvent->mTimeStamp,
"DOMEvent",
TRACING_INTERVAL_START));
nsresult rv =
HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);
rv = HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);
phase = (*aDOMEvent)->EventPhase();
profiler_add_marker(
"DOMEvent",
MakeUnique<DOMEventMarkerPayload>(typeStr, phase,
aEvent->mTimeStamp,
"DOMEvent",
TRACING_INTERVAL_END));
} else
#endif
{
rv = HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);
}
if (innerWindow) {
Unused << innerWindow->SetEvent(oldWindowEvent);
}

View File

@ -3052,8 +3052,14 @@ HTMLInputElement::GetRadioGroupContainer() const
return nullptr;
}
//XXXsmaug It isn't clear how this should work in Shadow DOM.
return static_cast<nsDocument*>(GetUncomposedDoc());
DocumentOrShadowRoot* docOrShadow = GetUncomposedDocOrConnectedShadowRoot();
if (!docOrShadow) {
return nullptr;
}
nsCOMPtr<nsIRadioGroupContainer> container =
do_QueryInterface(&(docOrShadow->AsNode()));
return container;
}
HTMLInputElement*
@ -4632,7 +4638,8 @@ HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
// Add radio to document if we don't have a form already (if we do it's
// already been added into that group)
if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) {
if (!mForm && mType == NS_FORM_INPUT_RADIO &&
GetUncomposedDocOrConnectedShadowRoot()) {
AddedToRadioGroup();
}
@ -6567,7 +6574,7 @@ HTMLInputElement::AddedToRadioGroup()
{
// If the element is neither in a form nor a document, there is no group so we
// should just stop here.
if (!mForm && (!IsInUncomposedDoc() || IsInAnonymousSubtree())) {
if (!mForm && (!GetUncomposedDocOrConnectedShadowRoot() || IsInAnonymousSubtree())) {
return;
}

View File

@ -621,7 +621,16 @@ AsyncImagePipelineManager::ProcessPipelineRemoved(const wr::PipelineId& aPipelin
return;
}
if (auto entry = mPipelineTexturesHolders.Lookup(wr::AsUint64(aPipelineId))) {
if (entry.Data()->mDestroyedEpoch.isSome()) {
PipelineTexturesHolder* holder = entry.Data();
if (holder->mDestroyedEpoch.isSome()) {
// Explicitly release all of the shared surfaces.
while (!holder->mExternalImages.empty()) {
DebugOnly<bool> released =
SharedSurfacesParent::Release(holder->mExternalImages.front().mImageId);
MOZ_ASSERT(released);
holder->mExternalImages.pop();
}
// Remove Pipeline
entry.Remove();
}

View File

@ -546,6 +546,7 @@ private:
DECL_GFX_PREF(Live, "image.animated.generate-full-frames", ImageAnimatedGenerateFullFrames, bool, false);
DECL_GFX_PREF(Live, "image.animated.resume-from-last-displayed", ImageAnimatedResumeFromLastDisplayed, bool, false);
DECL_GFX_PREF(Live, "image.cache.factor2.threshold-surfaces", ImageCacheFactor2ThresholdSurfaces, int32_t, -1);
DECL_GFX_PREF(Live, "image.cache.max-rasterized-svg-threshold-kb", ImageCacheMaxRasterizedSVGThresholdKB, int32_t, 90*1024);
DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024);
DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500);
DECL_GFX_PREF(Live, "image.decode-immediately.enabled", ImageDecodeImmediatelyEnabled, bool, false);

View File

@ -160,6 +160,7 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
case ImgDrawResult::SUCCESS:
case ImgDrawResult::BAD_IMAGE:
case ImgDrawResult::BAD_ARGS:
case ImgDrawResult::NOT_SUPPORTED:
container.forget(aOutContainer);
return entry->mLastDrawResult;
case ImgDrawResult::NOT_READY:
@ -218,6 +219,7 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager,
case ImgDrawResult::SUCCESS:
case ImgDrawResult::BAD_IMAGE:
case ImgDrawResult::BAD_ARGS:
case ImgDrawResult::NOT_SUPPORTED:
container.forget(aOutContainer);
return entry->mLastDrawResult;
case ImgDrawResult::NOT_READY:

View File

@ -337,6 +337,24 @@ protected:
bool mAnimating:1; // Are we currently animating?
bool mError:1; // Error handling
/**
* Attempt to find a matching cached surface in the SurfaceCache, and if not
* available, request the production of such a surface (either synchronously
* or asynchronously).
*
* If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be
* the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the
* size is a hint as to what we expect the surface size to be, once the best
* fitting size is available. It may or may not match the size of the surface
* returned at this moment. This is useful for choosing how to store the final
* result (e.g. if going into an ImageContainer, ideally we would share the
* same container for many requested sizes, if they all end up with the same
* best fit size in the end).
*
* A valid surface should only be returned for SUCCESS and INCOMPLETE.
*
* Any other draw result is invalid.
*/
virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
GetFrameInternal(const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,

View File

@ -109,8 +109,11 @@ private:
DrawableSurface mSurface;
MatchType mMatchType;
/// If given, the size the caller should request a decode at. This may or may
/// not match the size the caller requested from the cache.
/// mSuggestedSize will be the size of the returned surface if the result is
/// SUBSTITUTE_BECAUSE_BEST. It will be empty for EXACT, and can contain a
/// non-empty size possibly different from the returned surface (if any) for
/// all other results. If non-empty, it will always be the size the caller
/// should request any decodes at.
gfx::IntSize mSuggestedSize;
};

View File

@ -24,7 +24,8 @@ struct SVGDrawingParameters
typedef mozilla::gfx::SamplingFilter SamplingFilter;
SVGDrawingParameters(gfxContext* aContext,
const nsIntSize& aSize,
const nsIntSize& aRasterSize,
const nsIntSize& aDrawSize,
const ImageRegion& aRegion,
SamplingFilter aSamplingFilter,
const Maybe<SVGImageContext>& aSVGContext,
@ -32,11 +33,12 @@ struct SVGDrawingParameters
uint32_t aFlags,
float aOpacity)
: context(aContext)
, size(aSize.width, aSize.height)
, size(aRasterSize)
, drawSize(aDrawSize)
, region(aRegion)
, samplingFilter(aSamplingFilter)
, svgContext(aSVGContext)
, viewportSize(aSize)
, viewportSize(aRasterSize)
, animationTime(aAnimationTime)
, flags(aFlags)
, opacity(aOpacity)
@ -50,7 +52,8 @@ struct SVGDrawingParameters
}
gfxContext* context;
IntSize size;
IntSize size; // Size to rasterize a surface at.
IntSize drawSize; // Size to draw the given surface at.
ImageRegion region;
SamplingFilter samplingFilter;
const Maybe<SVGImageContext>& svgContext;

View File

@ -12,6 +12,7 @@
#include <algorithm>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Likely.h"
#include "mozilla/Move.h"
@ -251,10 +252,11 @@ class ImageSurfaceCache
{
~ImageSurfaceCache() { }
public:
ImageSurfaceCache()
explicit ImageSurfaceCache(const ImageKey aImageKey)
: mLocked(false)
, mFactor2Mode(false)
, mFactor2Pruned(false)
, mIsVectorImage(aImageKey->GetType() == imgIContainer::TYPE_VECTOR)
{ }
MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageSurfaceCache)
@ -330,7 +332,7 @@ public:
// Try for a best match second, if using compact.
IntSize suggestedSize = SuggestedSize(aIdealKey.Size());
if (mFactor2Mode) {
if (suggestedSize != aIdealKey.Size()) {
if (!exactMatch) {
SurfaceKey compactKey = aIdealKey.CloneWithSize(suggestedSize);
mSurfaces.Get(compactKey, getter_AddRefs(exactMatch));
@ -401,7 +403,7 @@ public:
} else if (aIdealKey.Size() != bestMatch->GetSurfaceKey().Size()) {
// The best factor of 2 match is still decoding, but the best we've got.
MOZ_ASSERT(suggestedSize != aIdealKey.Size());
MOZ_ASSERT(mFactor2Mode);
MOZ_ASSERT(mFactor2Mode || mIsVectorImage);
matchType = MatchType::SUBSTITUTE_BECAUSE_BEST;
} else {
// The exact match is still decoding, but it's the best we've got.
@ -433,20 +435,18 @@ public:
return;
}
// Determine how many native surfaces this image has. Zero means we either
// don't know yet (in which case do nothing), or we don't want to limit the
// number of surfaces for this image.
//
// XXX(aosmond): Vector images have zero native sizes. This is because they
// are regenerated at the given size. There isn't an equivalent concept to
// the native size (and w/h ratio) to provide a frame of reference to what
// are "good" sizes. While it is desirable to have a similar mechanism as
// that for raster images, it will need a different approach.
// Determine how many native surfaces this image has. If it is zero, and it
// is a vector image, then we should impute a single native size. Otherwise,
// it may be zero because we don't know yet, or the image has an error, or
// it isn't supported.
auto first = ConstIter();
NotNull<CachedSurface*> current = WrapNotNull(first.UserData());
Image* image = static_cast<Image*>(current->GetImageKey());
size_t nativeSizes = image->GetNativeSizesLength();
if (nativeSizes == 0) {
if (mIsVectorImage) {
MOZ_ASSERT(nativeSizes == 0);
nativeSizes = 1;
} else if (nativeSizes == 0) {
return;
}
@ -530,6 +530,33 @@ public:
}
IntSize SuggestedSize(const IntSize& aSize) const
{
IntSize suggestedSize = SuggestedSizeInternal(aSize);
if (mIsVectorImage) {
// Whether or not we are in factor of 2 mode, vector image rasterization is
// clamped at a configured maximum if the caller is willing to accept
// substitutes.
MOZ_ASSERT(SurfaceCache::IsLegalSize(suggestedSize));
// If we exceed the maximum, we need to scale the size downwards to fit.
// It shouldn't get here if it is significantly larger because
// VectorImage::UseSurfaceCacheForSize should prevent us from requesting
// a rasterized version of a surface greater than 4x the maximum.
int32_t maxSizeKB = gfxPrefs::ImageCacheMaxRasterizedSVGThresholdKB();
int32_t proposedKB = suggestedSize.width * suggestedSize.height / 256;
if (maxSizeKB >= proposedKB) {
return suggestedSize;
}
double scale = sqrt(double(maxSizeKB) / proposedKB);
suggestedSize.width = int32_t(scale * suggestedSize.width);
suggestedSize.height = int32_t(scale * suggestedSize.height);
}
return suggestedSize;
}
IntSize SuggestedSizeInternal(const IntSize& aSize) const
{
// When not in factor of 2 mode, we can always decode at the given size.
if (!mFactor2Mode) {
@ -552,11 +579,48 @@ public:
NS_FAILED(image->GetHeight(&factorSize.height)) ||
factorSize.IsEmpty()) {
// We should not have entered factor of 2 mode without a valid size, and
// several successfully decoded surfaces.
// several successfully decoded surfaces. Note that valid vector images
// may have a default size of 0x0, and those are not yet supported.
MOZ_ASSERT_UNREACHABLE("Expected valid native size!");
return aSize;
}
if (mIsVectorImage) {
// Ensure the aspect ratio matches the native size before forcing the
// caller to accept a factor of 2 size. The difference between the aspect
// ratios is:
//
// delta = nativeWidth/nativeHeight - desiredWidth/desiredHeight
//
// delta*nativeHeight*desiredHeight = nativeWidth*desiredHeight
// - desiredWidth*nativeHeight
//
// Using the maximum accepted delta as a constant, we can avoid the
// floating point division and just compare after some integer ops.
int32_t delta = factorSize.width * aSize.height - aSize.width * factorSize.height;
int32_t maxDelta = (factorSize.height * aSize.height) >> 4;
if (delta > maxDelta || delta < -maxDelta) {
return aSize;
}
// If the requested size is bigger than the native size, we actually need
// to grow the native size instead of shrinking it.
if (factorSize.width < aSize.width) {
do {
IntSize candidate(factorSize.width * 2, factorSize.height * 2);
if (!SurfaceCache::IsLegalSize(candidate)) {
break;
}
factorSize = candidate;
} while (factorSize.width < aSize.width);
return factorSize;
}
// Otherwise we can find the best fit as normal.
}
// Start with the native size as the best first guess.
IntSize bestSize = factorSize;
factorSize.width /= 2;
@ -674,6 +738,10 @@ private:
// True if all non-factor of 2 surfaces have been removed from the cache. Note
// that this excludes unsubstitutable sizes.
bool mFactor2Pruned;
// True if the surfaces are produced from a vector image. If so, it must match
// the aspect ratio when using factor of 2 mode.
bool mIsVectorImage;
};
/**
@ -760,9 +828,10 @@ public:
// Locate the appropriate per-image cache. If there's not an existing cache
// for this image, create it.
RefPtr<ImageSurfaceCache> cache = GetImageCache(aProvider->GetImageKey());
const ImageKey imageKey = aProvider->GetImageKey();
RefPtr<ImageSurfaceCache> cache = GetImageCache(imageKey);
if (!cache) {
cache = new ImageSurfaceCache;
cache = new ImageSurfaceCache(imageKey);
mImageCaches.Put(aProvider->GetImageKey(), cache);
}
@ -1014,7 +1083,7 @@ public:
{
RefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache) {
cache = new ImageSurfaceCache;
cache = new ImageSurfaceCache(aImageKey);
mImageCaches.Put(aImageKey, cache);
}
@ -1630,5 +1699,30 @@ SurfaceCache::MaximumCapacity()
return sInstance->MaximumCapacity();
}
/* static */ bool
SurfaceCache::IsLegalSize(const IntSize& aSize)
{
// reject over-wide or over-tall images
const int32_t k64KLimit = 0x0000FFFF;
if (MOZ_UNLIKELY(aSize.width > k64KLimit || aSize.height > k64KLimit )) {
NS_WARNING("image too big");
return false;
}
// protect against invalid sizes
if (MOZ_UNLIKELY(aSize.height <= 0 || aSize.width <= 0)) {
return false;
}
// check to make sure we don't overflow a 32-bit
CheckedInt32 requiredBytes = CheckedInt32(aSize.width) *
CheckedInt32(aSize.height) * 4;
if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
NS_WARNING("width or height too large");
return false;
}
return true;
}
} // namespace image
} // namespace mozilla

View File

@ -443,6 +443,11 @@ struct SurfaceCache
*/
static size_t MaximumCapacity();
/**
* @return true if the given size is valid.
*/
static bool IsLegalSize(const IntSize& aSize);
private:
virtual ~SurfaceCache() = 0; // Forbid instantiation.
};

View File

@ -807,15 +807,21 @@ VectorImage::GetFrameInternal(const IntSize& aSize,
RefPtr<SourceSurface>());
}
RefPtr<SourceSurface> sourceSurface =
// We don't allow large surfaces to be rasterized on the Draw and
// GetImageContainerAtSize paths, because those have alternatives. If we get
// here however, then we know it came from GetFrame(AtSize) and that path does
// not have any fallback method, so we don't check UseSurfaceCacheForSize.
RefPtr<SourceSurface> sourceSurface;
IntSize decodeSize;
Tie(sourceSurface, decodeSize) =
LookupCachedSurface(aSize, aSVGContext, aFlags);
if (sourceSurface) {
return MakeTuple(ImgDrawResult::SUCCESS, aSize, std::move(sourceSurface));
return MakeTuple(ImgDrawResult::SUCCESS, decodeSize, std::move(sourceSurface));
}
if (mIsDrawing) {
NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, aSize,
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, decodeSize,
RefPtr<SourceSurface>());
}
@ -824,7 +830,8 @@ VectorImage::GetFrameInternal(const IntSize& aSize,
// flags, having an animation, etc). Otherwise CreateSurface will assume that
// the caller is capable of drawing directly to its own draw target if we
// cannot cache.
SVGDrawingParameters params(nullptr, aSize, ImageRegion::Create(aSize),
SVGDrawingParameters params(nullptr, decodeSize, aSize,
ImageRegion::Create(decodeSize),
SamplingFilter::POINT, aSVGContext,
mSVGDocumentWrapper->GetCurrentTime(),
aFlags, 1.0);
@ -840,12 +847,12 @@ VectorImage::GetFrameInternal(const IntSize& aSize,
CreateSurface(params, svgDrawable, didCache);
if (!surface) {
MOZ_ASSERT(!didCache);
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, aSize,
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, decodeSize,
RefPtr<SourceSurface>());
}
SendFrameComplete(didCache, params.flags);
return MakeTuple(ImgDrawResult::SUCCESS, aSize, std::move(surface));
return MakeTuple(ImgDrawResult::SUCCESS, decodeSize, std::move(surface));
}
//******************************************************************************
@ -904,7 +911,9 @@ VectorImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
{
// Since we only support image containers with WebRender, and it can handle
// textures larger than the hw max texture size, we don't need to check aSize.
return !aSize.IsEmpty() && IsImageContainerAvailable(aManager, aFlags);
return !aSize.IsEmpty() &&
UseSurfaceCacheForSize(aSize) &&
IsImageContainerAvailable(aManager, aFlags);
}
//******************************************************************************
@ -915,15 +924,16 @@ VectorImage::GetImageContainerAtSize(layers::LayerManager* aManager,
uint32_t aFlags,
layers::ImageContainer** aOutContainer)
{
if (!UseSurfaceCacheForSize(aSize)) {
return ImgDrawResult::NOT_SUPPORTED;
}
Maybe<SVGImageContext> newSVGContext;
MaybeRestrictSVGContext(newSVGContext, aSVGContext, aFlags);
// Since we do not support high quality scaling with SVG, we mask it off so
// that container requests with and without it map to the same container.
// Similarly the aspect ratio flag was already handled as part of the SVG
// context restriction above.
uint32_t flags = aFlags & ~(FLAG_HIGH_QUALITY_SCALING |
FLAG_FORCE_PRESERVEASPECTRATIO_NONE);
// The aspect ratio flag was already handled as part of the SVG context
// restriction above.
uint32_t flags = aFlags & ~(FLAG_FORCE_PRESERVEASPECTRATIO_NONE);
return GetImageContainerImpl(aManager, aSize,
newSVGContext ? newSVGContext : aSVGContext,
flags, aOutContainer);
@ -1002,10 +1012,13 @@ VectorImage::Draw(gfxContext* aContext,
SendOnUnlockedDraw(aFlags);
}
// We should always bypass the cache when using DrawTargetRecording because
// we prefer the drawing commands in general to the rasterized surface. This
// allows blob images to avoid rasterized SVGs with WebRender.
if (aContext->GetDrawTarget()->GetBackendType() == BackendType::RECORDING) {
// We should bypass the cache when:
// - We are using a DrawTargetRecording because we prefer the drawing commands
// in general to the rasterized surface. This allows blob images to avoid
// rasterized SVGs with WebRender.
// - The size exceeds what we are will to cache as a rasterized surface.
if (aContext->GetDrawTarget()->GetBackendType() == BackendType::RECORDING ||
!UseSurfaceCacheForSize(aSize)) {
aFlags |= FLAG_BYPASS_SURFACE_CACHE;
}
@ -1021,18 +1034,19 @@ VectorImage::Draw(gfxContext* aContext,
bool contextPaint =
MaybeRestrictSVGContext(newSVGContext, aSVGContext, aFlags);
SVGDrawingParameters params(aContext, aSize, aRegion, aSamplingFilter,
SVGDrawingParameters params(aContext, aSize, aSize, aRegion, aSamplingFilter,
newSVGContext ? newSVGContext : aSVGContext,
animTime, aFlags, aOpacity);
// If we have an prerasterized version of this image that matches the
// drawing parameters, use that.
RefPtr<SourceSurface> sourceSurface =
RefPtr<SourceSurface> sourceSurface;
Tie(sourceSurface, params.size) =
LookupCachedSurface(aSize, params.svgContext, aFlags);
if (sourceSurface) {
RefPtr<gfxDrawable> svgDrawable =
new gfxSurfaceDrawable(sourceSurface, sourceSurface->GetSize());
Show(svgDrawable, params);
RefPtr<gfxDrawable> drawable =
new gfxSurfaceDrawable(sourceSurface, params.size);
Show(drawable, params);
return ImgDrawResult::SUCCESS;
}
@ -1076,29 +1090,56 @@ VectorImage::CreateSVGDrawable(const SVGDrawingParameters& aParams)
return svgDrawable.forget();
}
already_AddRefed<SourceSurface>
bool
VectorImage::UseSurfaceCacheForSize(const IntSize& aSize) const
{
int32_t maxSizeKB = gfxPrefs::ImageCacheMaxRasterizedSVGThresholdKB();
if (maxSizeKB <= 0) {
return true;
}
if (!SurfaceCache::IsLegalSize(aSize)) {
return false;
}
// With factor of 2 mode, we should be willing to use a surface which is up
// to twice the width, and twice the height, of the maximum sized surface
// before switching to drawing to the target directly. That means the size in
// KB works out to be:
// width * height * 4 [bytes/pixel] * / 1024 [bytes/KB] <= 2 * 2 * maxSizeKB
return aSize.width * aSize.height / 1024 <= maxSizeKB;
}
Tuple<RefPtr<SourceSurface>, IntSize>
VectorImage::LookupCachedSurface(const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags)
{
// If we're not allowed to use a cached surface, don't attempt a lookup.
if (aFlags & FLAG_BYPASS_SURFACE_CACHE) {
return nullptr;
return MakeTuple(RefPtr<SourceSurface>(), aSize);
}
// We don't do any caching if we have animation, so don't bother with a lookup
// in this case either.
if (mHaveAnimations) {
return nullptr;
return MakeTuple(RefPtr<SourceSurface>(), aSize);
}
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
VectorSurfaceKey(aSize, aSVGContext));
LookupResult result(MatchType::NOT_FOUND);
SurfaceKey surfaceKey = VectorSurfaceKey(aSize, aSVGContext);
if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) {
result = SurfaceCache::Lookup(ImageKey(this), surfaceKey);
} else {
result = SurfaceCache::LookupBestMatch(ImageKey(this), surfaceKey);
}
MOZ_ASSERT(result.SuggestedSize().IsEmpty(), "SVG should not substitute!");
if (!result) {
return nullptr; // No matching surface, or the OS freed the volatile buffer.
IntSize rasterSize = result.SuggestedSize().IsEmpty()
? aSize : result.SuggestedSize();
MOZ_ASSERT(result.Type() != MatchType::SUBSTITUTE_BECAUSE_PENDING);
if (!result || result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND) {
// No matching surface, or the OS freed the volatile buffer.
return MakeTuple(RefPtr<SourceSurface>(), rasterSize);
}
RefPtr<SourceSurface> sourceSurface = result.Surface()->GetSourceSurface();
@ -1106,10 +1147,10 @@ VectorImage::LookupCachedSurface(const IntSize& aSize,
// Something went wrong. (Probably a GPU driver crash or device reset.)
// Attempt to recover.
RecoverFromLossOfSurfaces();
return nullptr;
return MakeTuple(RefPtr<SourceSurface>(), rasterSize);
}
return sourceSurface.forget();
return MakeTuple(std::move(sourceSurface), rasterSize);
}
already_AddRefed<SourceSurface>
@ -1189,7 +1230,15 @@ VectorImage::CreateSurface(const SVGDrawingParameters& aParams,
SurfaceKey surfaceKey = VectorSurfaceKey(aParams.size, aParams.svgContext);
NotNull<RefPtr<ISurfaceProvider>> provider =
MakeNotNull<SimpleSurfaceProvider*>(ImageKey(this), surfaceKey, frame);
SurfaceCache::Insert(provider);
if (SurfaceCache::Insert(provider) == InsertOutcome::SUCCESS &&
aParams.size != aParams.drawSize) {
// We created a new surface that wasn't the size we requested, which means
// we entered factor-of-2 mode. We should purge any surfaces we no longer
// need rather than waiting for the cache to expire them.
SurfaceCache::PruneImage(ImageKey(this));
}
return surface.forget();
}
@ -1224,10 +1273,21 @@ VectorImage::SendFrameComplete(bool aDidCache, uint32_t aFlags)
void
VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams)
{
// The surface size may differ from the size at which we wish to draw. As
// such, we may need to adjust the context/region to take this into account.
gfxContextMatrixAutoSaveRestore saveMatrix(aParams.context);
ImageRegion region(aParams.region);
if (aParams.drawSize != aParams.size) {
gfx::Size scale(double(aParams.drawSize.width) / aParams.size.width,
double(aParams.drawSize.height) / aParams.size.height);
aParams.context->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
region.Scale(1.0 / scale.width, 1.0 / scale.height);
}
MOZ_ASSERT(aDrawable, "Should have a gfxDrawable by now");
gfxUtils::DrawPixelSnapped(aParams.context, aDrawable,
SizeDouble(aParams.size),
aParams.region,
region,
SurfaceFormat::B8G8R8A8,
aParams.samplingFilter,
aParams.flags, aParams.opacity, false);

View File

@ -92,8 +92,12 @@ private:
const IntSize& aSize,
uint32_t aFlags) override;
/// Attempt to find a matching cached surface in the SurfaceCache.
already_AddRefed<SourceSurface>
/**
* Attempt to find a matching cached surface in the SurfaceCache. Returns the
* cached surface, if found, and the size to rasterize at, if applicable.
* If we cannot rasterize, it will be the requested size to draw at (aSize).
*/
Tuple<RefPtr<SourceSurface>, IntSize>
LookupCachedSurface(const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
uint32_t aFlags);
@ -106,6 +110,9 @@ private:
already_AddRefed<gfxDrawable>
CreateSVGDrawable(const SVGDrawingParameters& aParams);
/// Returns true if we use the surface cache to store rasterized copies.
bool UseSurfaceCacheForSize(const IntSize& aSize) const;
/// Rasterize the SVG into a surface. aWillCache will be set to whether or
/// not the new surface was put into the cache.
already_AddRefed<SourceSurface>

View File

@ -7,6 +7,7 @@
#include "imgFrame.h"
#include "ImageRegion.h"
#include "ShutdownTracker.h"
#include "SurfaceCache.h"
#include "prenv.h"
@ -157,38 +158,13 @@ ClearSurface(DataSourceSurface* aSurface, const IntSize& aSize, SurfaceFormat aF
return true;
}
// Returns true if an image of aWidth x aHeight is allowed and legal.
static bool
AllowedImageSize(int32_t aWidth, int32_t aHeight)
{
// reject over-wide or over-tall images
const int32_t k64KLimit = 0x0000FFFF;
if (MOZ_UNLIKELY(aWidth > k64KLimit || aHeight > k64KLimit )) {
NS_WARNING("image too big");
return false;
}
// protect against invalid sizes
if (MOZ_UNLIKELY(aHeight <= 0 || aWidth <= 0)) {
return false;
}
// check to make sure we don't overflow a 32-bit
CheckedInt32 requiredBytes = CheckedInt32(aWidth) * CheckedInt32(aHeight) * 4;
if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
NS_WARNING("width or height too large");
return false;
}
return true;
}
static bool AllowedImageAndFrameDimensions(const nsIntSize& aImageSize,
const nsIntRect& aFrameRect)
{
if (!AllowedImageSize(aImageSize.width, aImageSize.height)) {
if (!SurfaceCache::IsLegalSize(aImageSize)) {
return false;
}
if (!AllowedImageSize(aFrameRect.Width(), aFrameRect.Height())) {
if (!SurfaceCache::IsLegalSize(aFrameRect.Size())) {
return false;
}
nsIntRect imageRect(0, 0, aImageSize.width, aImageSize.height);
@ -337,7 +313,7 @@ imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
{
// Assert for properties that should be verified by decoders,
// warn for properties related to bad content.
if (!AllowedImageSize(aSize.width, aSize.height)) {
if (!SurfaceCache::IsLegalSize(aSize)) {
NS_WARNING("Should have legal image size");
mAborted = true;
return NS_ERROR_FAILURE;

View File

@ -4620,6 +4620,10 @@ pref("image.animated.resume-from-last-displayed", true);
// same data at different sizes.
pref("image.cache.factor2.threshold-surfaces", 4);
// Maximum number of pixels in either dimension that we are willing to upscale
// an SVG to when we are in "factor of 2" mode.
pref("image.cache.max-rasterized-svg-threshold-kb", 92160);
// The maximum size, in bytes, of the decoded images we cache
pref("image.cache.size", 5242880);

View File

@ -64,7 +64,7 @@ jobs:
PERFHERDER_EXTRA_OPTIONS: searchfox
run:
using: mozharness
actions: [get-secrets build update]
actions: [get-secrets build]
config:
- builds/releng_base_firefox.py
- builds/releng_base_mac_64_cross_builds.py

View File

@ -1,4 +1,9 @@
#!/bin/bash
# cctools sometimes needs to be rebuilt when clang is modified.
# Until bug 1471905 is addressed, increase the following number
# when a forced rebuild of cctools is necessary: 1
set -x -e -v
# This script is for building cctools (Apple's binutils) for Mac OS X on

View File

@ -1,4 +1,9 @@
#!/bin/bash
# cctools sometimes needs to be rebuilt when clang is modified.
# Until bug 1471905 is addressed, increase the following number
# when a forced rebuild of cctools is necessary: 1
set -x -e -v
# This script is for building cctools (Apple's binutils) for Linux using
@ -35,7 +40,7 @@ cd $WORKSPACE/build/src
cd $CROSSTOOLS_CCTOOLS_DIR
export CC=$CLANG_DIR/bin/clang
export CXX=$CLANG_DIR/bin/clang++
export LDFLAGS=-lpthread
export LDFLAGS="-lpthread -Wl,-rpath-link,$CLANG_DIR/lib"
./autogen.sh
./configure --prefix=$CROSSTOOLS_BUILD_DIR --target=x86_64-apple-darwin11 --with-llvm-config=$CLANG_DIR/bin/llvm-config

View File

@ -397866,6 +397866,12 @@
{}
]
],
"shadow-dom/input-type-radio.html": [
[
"/shadow-dom/input-type-radio.html",
{}
]
],
"shadow-dom/leaktests/get-elements.html": [
[
"/shadow-dom/leaktests/get-elements.html",
@ -646387,6 +646393,10 @@
"b571534eb0d6f3f57cfbec3e706648b19848b6d6",
"testharness"
],
"shadow-dom/input-type-radio.html": [
"bd5d8e43b0fd9d0c9f1e078ed97a1bbd18b7b0be",
"testharness"
],
"shadow-dom/layout-slot-no-longer-assigned.html": [
"dfcac99da023ec2bbd94835f71efaef952a62341",
"reftest"

View File

@ -2,4 +2,4 @@
disabled:
if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1477342
if os == "mac": https://bugzilla.mozilla.org/show_bug.cgi?id=1477342
if (os == "win") and (version == "10.0.15603"): https://bugzilla.mozilla.org/show_bug.cgi?id=1477342
if os == "win": https://bugzilla.mozilla.org/show_bug.cgi?id=1477342

View File

@ -0,0 +1,73 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<input type="radio" name="group" id="lightRadio1">
<input type="radio" name="group" id="lightRadio2">
<div id="host"></div>
<script>
test(() => {
var lightRadio1 = document.getElementById("lightRadio1");
var lightRadio2 = document.getElementById("lightRadio2");
var host = document.getElementById("host");
var sr = host.attachShadow({mode: "closed"});
var shadowRadio1 = document.createElement("input");
shadowRadio1.name = "group";
shadowRadio1.id = "shadowRadio1";
shadowRadio1.type = "radio";
sr.appendChild(shadowRadio1);
var shadowRadio2 = document.createElement("input");
shadowRadio2.name = "group";
shadowRadio2.id = "shadowRadio2";
shadowRadio2.type = "radio";
sr.appendChild(shadowRadio2);
assert_false(lightRadio1.checked);
assert_false(lightRadio2.checked);
assert_false(shadowRadio1.checked);
assert_false(shadowRadio2.checked);
lightRadio1.click();
assert_true(lightRadio1.checked);
assert_false(lightRadio2.checked);
assert_false(shadowRadio1.checked);
assert_false(shadowRadio2.checked);
lightRadio2.click();
assert_false(lightRadio1.checked);
assert_true(lightRadio2.checked);
assert_false(shadowRadio1.checked);
assert_false(shadowRadio2.checked);
shadowRadio1.click();
assert_false(lightRadio1.checked);
assert_true(lightRadio2.checked);
assert_true(shadowRadio1.checked);
assert_false(shadowRadio2.checked);
shadowRadio2.click();
assert_false(lightRadio1.checked);
assert_true(lightRadio2.checked);
assert_false(shadowRadio1.checked);
assert_true(shadowRadio2.checked);
// Ensure radio groups work even when modifying shadow DOM.
shadowRadio2.remove();
sr.appendChild(shadowRadio2);
shadowRadio2.click();
assert_false(lightRadio1.checked);
assert_true(lightRadio2.checked);
assert_false(shadowRadio1.checked);
assert_true(shadowRadio2.checked);
shadowRadio1.click();
assert_false(lightRadio1.checked);
assert_true(lightRadio2.checked);
assert_true(shadowRadio1.checked);
assert_false(shadowRadio2.checked);
}, "input type=radio elements should form a group inside shadow DOM.");
</script>

View File

@ -112,7 +112,6 @@ DOMEventMarkerPayload::StreamPayload(SpliceableJSONWriter& aWriter,
WriteTime(aWriter, aProcessStartTime, mTimeStamp, "timeStamp");
aWriter.StringProperty("eventType", NS_ConvertUTF16toUTF8(mEventType).get());
aWriter.IntProperty("phase", mPhase);
}
void

View File

@ -125,13 +125,12 @@ private:
class DOMEventMarkerPayload : public TracingMarkerPayload
{
public:
DOMEventMarkerPayload(const nsAString& aEventType, uint16_t aPhase,
DOMEventMarkerPayload(const nsAString& aEventType,
const mozilla::TimeStamp& aTimeStamp,
const char* aCategory, TracingKind aKind)
: TracingMarkerPayload(aCategory, aKind)
, mTimeStamp(aTimeStamp)
, mEventType(aEventType)
, mPhase(aPhase)
{}
DECL_STREAM_PAYLOAD
@ -139,7 +138,6 @@ public:
private:
mozilla::TimeStamp mTimeStamp;
nsString mEventType;
uint16_t mPhase;
};
class UserTimingMarkerPayload : public ProfilerMarkerPayload