зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
--HG-- rename : third_party/rust/euclid/src/matrix2d.rs => third_party/rust/euclid-0.13.0/src/matrix2d.rs rename : third_party/rust/euclid/src/matrix4d.rs => third_party/rust/euclid-0.13.0/src/matrix4d.rs
This commit is contained in:
Коммит
865741ad85
|
@ -697,6 +697,12 @@ getRoleCB(AtkObject *aAtkObj)
|
||||||
aAtkObj->role = ATK_ROLE_LIST_ITEM;
|
aAtkObj->role = ATK_ROLE_LIST_ITEM;
|
||||||
else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12))
|
else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12))
|
||||||
aAtkObj->role = ATK_ROLE_SECTION;
|
aAtkObj->role = ATK_ROLE_SECTION;
|
||||||
|
else if (aAtkObj->role == ATK_ROLE_COMMENT && !IsAtkVersionAtLeast(2, 12))
|
||||||
|
aAtkObj->role = ATK_ROLE_SECTION;
|
||||||
|
else if (aAtkObj->role == ATK_ROLE_LANDMARK && !IsAtkVersionAtLeast(2, 12))
|
||||||
|
aAtkObj->role = ATK_ROLE_SECTION;
|
||||||
|
else if (aAtkObj->role == ATK_ROLE_FOOTNOTE && !IsAtkVersionAtLeast(2, 25, 2))
|
||||||
|
aAtkObj->role = ATK_ROLE_SECTION;
|
||||||
else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16))
|
else if (aAtkObj->role == ATK_ROLE_STATIC && !IsAtkVersionAtLeast(2, 16))
|
||||||
aAtkObj->role = ATK_ROLE_TEXT;
|
aAtkObj->role = ATK_ROLE_TEXT;
|
||||||
else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION ||
|
else if ((aAtkObj->role == ATK_ROLE_MATH_FRACTION ||
|
||||||
|
|
|
@ -26,7 +26,7 @@ extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_in
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::a11y;
|
using namespace mozilla::a11y;
|
||||||
|
|
||||||
int atkMajorVersion = 1, atkMinorVersion = 12;
|
int atkMajorVersion = 1, atkMinorVersion = 12, atkMicroVersion = 0;
|
||||||
|
|
||||||
GType (*gAtkTableCellGetTypeFunc)();
|
GType (*gAtkTableCellGetTypeFunc)();
|
||||||
|
|
||||||
|
@ -168,8 +168,11 @@ a11y::PlatformInit()
|
||||||
if (version) {
|
if (version) {
|
||||||
char* endPtr = nullptr;
|
char* endPtr = nullptr;
|
||||||
atkMajorVersion = strtol(version, &endPtr, 10);
|
atkMajorVersion = strtol(version, &endPtr, 10);
|
||||||
if (*endPtr == '.')
|
if (atkMajorVersion != 0L) {
|
||||||
atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
|
atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
|
||||||
|
if (atkMinorVersion != 0L)
|
||||||
|
atkMicroVersion = strtol(endPtr + 1, &endPtr, 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,17 +75,19 @@ mozilla::a11y::AccessibleOrProxy GetInternalObj(AtkObject* aObj);
|
||||||
AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
|
AtkObject* GetWrapperFor(mozilla::a11y::ProxyAccessible* aProxy);
|
||||||
AtkObject* GetWrapperFor(mozilla::a11y::AccessibleOrProxy aObj);
|
AtkObject* GetWrapperFor(mozilla::a11y::AccessibleOrProxy aObj);
|
||||||
|
|
||||||
extern int atkMajorVersion, atkMinorVersion;
|
extern int atkMajorVersion, atkMinorVersion, atkMicroVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the loaded version of libatk-1.0.so is at least
|
* Return true if the loaded version of libatk-1.0.so is at least
|
||||||
* aMajor.aMinor.0.
|
* aMajor.aMinor.aMicro.
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static inline bool
|
||||||
IsAtkVersionAtLeast(int aMajor, int aMinor)
|
IsAtkVersionAtLeast(int aMajor, int aMinor, int aMicro=0)
|
||||||
{
|
{
|
||||||
return aMajor < atkMajorVersion ||
|
return aMajor < atkMajorVersion ||
|
||||||
(aMajor == atkMajorVersion && aMinor <= atkMinorVersion);
|
(aMajor == atkMajorVersion &&
|
||||||
|
(aMinor < atkMinorVersion ||
|
||||||
|
(aMinor == atkMinorVersion && aMicro <= atkMicroVersion)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
|
// This is or'd with the pointer in MaiAtkObject::accWrap if the wrap-ee is a
|
||||||
|
|
|
@ -186,6 +186,396 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
|
||||||
eList,
|
eList,
|
||||||
states::READONLY
|
states::READONLY
|
||||||
},
|
},
|
||||||
|
{ // doc-abstract
|
||||||
|
&nsGkAtoms::docAbstract,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-acknowledgments
|
||||||
|
&nsGkAtoms::docAcknowledgments,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-afterword
|
||||||
|
&nsGkAtoms::docAfterword,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-appendix
|
||||||
|
&nsGkAtoms::docAppendix,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-backlink
|
||||||
|
&nsGkAtoms::docBacklink,
|
||||||
|
roles::LINK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eJumpAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
states::LINKED
|
||||||
|
},
|
||||||
|
{ // doc-biblioentry
|
||||||
|
&nsGkAtoms::docBiblioentry,
|
||||||
|
roles::LISTITEM,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
states::READONLY
|
||||||
|
},
|
||||||
|
{ // doc-bibliography
|
||||||
|
&nsGkAtoms::docBibliography,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-biblioref
|
||||||
|
&nsGkAtoms::docBiblioref,
|
||||||
|
roles::LINK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eJumpAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
states::LINKED
|
||||||
|
},
|
||||||
|
{ // doc-chapter
|
||||||
|
&nsGkAtoms::docChapter,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-colophon
|
||||||
|
&nsGkAtoms::docColophon,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-conclusion
|
||||||
|
&nsGkAtoms::docConclusion,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-cover
|
||||||
|
&nsGkAtoms::docCover,
|
||||||
|
roles::GRAPHIC,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-credit
|
||||||
|
&nsGkAtoms::docCredit,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-credits
|
||||||
|
&nsGkAtoms::docCredits,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-dedication
|
||||||
|
&nsGkAtoms::docDedication,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-endnote
|
||||||
|
&nsGkAtoms::docEndnote,
|
||||||
|
roles::LISTITEM,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
states::READONLY
|
||||||
|
},
|
||||||
|
{ // doc-endnotes
|
||||||
|
&nsGkAtoms::docEndnotes,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-epigraph
|
||||||
|
&nsGkAtoms::docEpigraph,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-epilogue
|
||||||
|
&nsGkAtoms::docEpilogue,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-errata
|
||||||
|
&nsGkAtoms::docErrata,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-example
|
||||||
|
&nsGkAtoms::docExample,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-footnote
|
||||||
|
&nsGkAtoms::docFootnote,
|
||||||
|
roles::FOOTNOTE,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-foreword
|
||||||
|
&nsGkAtoms::docForeword,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-glossary
|
||||||
|
&nsGkAtoms::docGlossary,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-glossref
|
||||||
|
&nsGkAtoms::docGlossref,
|
||||||
|
roles::LINK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eJumpAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
states::LINKED
|
||||||
|
},
|
||||||
|
{ // doc-index
|
||||||
|
&nsGkAtoms::docIndex,
|
||||||
|
roles::NAVIGATION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-introduction
|
||||||
|
&nsGkAtoms::docIntroduction,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-noteref
|
||||||
|
&nsGkAtoms::docNoteref,
|
||||||
|
roles::LINK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eJumpAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
states::LINKED
|
||||||
|
},
|
||||||
|
{ // doc-notice
|
||||||
|
&nsGkAtoms::docNotice,
|
||||||
|
roles::NOTE,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-pagebreak
|
||||||
|
&nsGkAtoms::docPagebreak,
|
||||||
|
roles::SEPARATOR,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-pagelist
|
||||||
|
&nsGkAtoms::docPagelist,
|
||||||
|
roles::NAVIGATION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-part
|
||||||
|
&nsGkAtoms::docPart,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-preface
|
||||||
|
&nsGkAtoms::docPreface,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-prologue
|
||||||
|
&nsGkAtoms::docPrologue,
|
||||||
|
roles::LANDMARK,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-pullquote
|
||||||
|
&nsGkAtoms::docPullquote,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-qna
|
||||||
|
&nsGkAtoms::docQna,
|
||||||
|
roles::SECTION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-subtitle
|
||||||
|
&nsGkAtoms::docSubtitle,
|
||||||
|
roles::HEADING,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-tip
|
||||||
|
&nsGkAtoms::docTip,
|
||||||
|
roles::NOTE,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
kGenericAccType,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
|
{ // doc-toc
|
||||||
|
&nsGkAtoms::docToc,
|
||||||
|
roles::NAVIGATION,
|
||||||
|
kUseMapRole,
|
||||||
|
eNoValue,
|
||||||
|
eNoAction,
|
||||||
|
eNoLiveAttr,
|
||||||
|
eLandmark,
|
||||||
|
kNoReqStates
|
||||||
|
},
|
||||||
{ // document
|
{ // document
|
||||||
&nsGkAtoms::document,
|
&nsGkAtoms::document,
|
||||||
roles::DOCUMENT,
|
roles::DOCUMENT,
|
||||||
|
|
|
@ -982,7 +982,25 @@ enum Role {
|
||||||
*/
|
*/
|
||||||
SUMMARY = 168,
|
SUMMARY = 168,
|
||||||
|
|
||||||
LAST_ROLE = SUMMARY
|
/**
|
||||||
|
* An ARIA landmark. See related NAVIGATION role.
|
||||||
|
*/
|
||||||
|
LANDMARK = 169,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specific type of ARIA landmark. The ability to distinguish navigation
|
||||||
|
* landmarks from other types of landmarks is, for example, needed on macOS
|
||||||
|
* where specific AXSubrole and AXRoleDescription for navigation landmarks
|
||||||
|
* are used.
|
||||||
|
*/
|
||||||
|
NAVIGATION = 170,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that contains the text of a footnote.
|
||||||
|
*/
|
||||||
|
FOOTNOTE = 171,
|
||||||
|
|
||||||
|
LAST_ROLE = FOOTNOTE
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace role
|
} // namespace role
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ ROLE(EMBEDDED_OBJECT,
|
||||||
|
|
||||||
ROLE(NOTE,
|
ROLE(NOTE,
|
||||||
"note",
|
"note",
|
||||||
ATK_ROLE_SECTION,
|
ATK_ROLE_COMMENT,
|
||||||
NSAccessibilityGroupRole,
|
NSAccessibilityGroupRole,
|
||||||
USE_ROLE_STRING,
|
USE_ROLE_STRING,
|
||||||
IA2_ROLE_NOTE,
|
IA2_ROLE_NOTE,
|
||||||
|
@ -1368,3 +1368,26 @@ ROLE(SUMMARY,
|
||||||
ROLE_SYSTEM_PUSHBUTTON,
|
ROLE_SYSTEM_PUSHBUTTON,
|
||||||
eNameFromSubtreeRule)
|
eNameFromSubtreeRule)
|
||||||
|
|
||||||
|
ROLE(LANDMARK,
|
||||||
|
"landmark",
|
||||||
|
ATK_ROLE_LANDMARK,
|
||||||
|
NSAccessibilityGroupRole,
|
||||||
|
USE_ROLE_STRING,
|
||||||
|
IA2_ROLE_LANDMARK,
|
||||||
|
eNoNameRule)
|
||||||
|
|
||||||
|
ROLE(NAVIGATION,
|
||||||
|
"navigation",
|
||||||
|
ATK_ROLE_LANDMARK,
|
||||||
|
NSAccessibilityGroupRole,
|
||||||
|
USE_ROLE_STRING,
|
||||||
|
IA2_ROLE_LANDMARK,
|
||||||
|
eNoNameRule)
|
||||||
|
|
||||||
|
ROLE(FOOTNOTE,
|
||||||
|
"footnote",
|
||||||
|
ATK_ROLE_FOOTNOTE,
|
||||||
|
NSAccessibilityGroupRole,
|
||||||
|
USE_ROLE_STRING,
|
||||||
|
IA2_ROLE_FOOTNOTE,
|
||||||
|
eNoNameRule)
|
||||||
|
|
|
@ -977,4 +977,21 @@ interface nsIAccessibleRole : nsISupports
|
||||||
* SUMMARY role.
|
* SUMMARY role.
|
||||||
*/
|
*/
|
||||||
const unsigned long ROLE_SUMMARY = 168;
|
const unsigned long ROLE_SUMMARY = 168;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ARIA landmark. See related NAVIGATION role.
|
||||||
|
*/
|
||||||
|
const unsigned long ROLE_LANDMARK = 169;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specific type of ARIA landmark. The ability to distinguish navigation
|
||||||
|
* landmarks from other types of landmarks is needed because macOS has a
|
||||||
|
* specific AXSubrole and AXRoleDescription for navigation landmarks.
|
||||||
|
*/
|
||||||
|
const unsigned long ROLE_NAVIGATION = 170;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that contains the text of a footnote.
|
||||||
|
*/
|
||||||
|
const unsigned long ROLE_FOOTNOTE = 171;
|
||||||
};
|
};
|
||||||
|
|
|
@ -726,6 +726,8 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||||
else if (proxy)
|
else if (proxy)
|
||||||
landmark = proxy->LandmarkRole();
|
landmark = proxy->LandmarkRole();
|
||||||
|
|
||||||
|
// HTML Elements treated as landmarks
|
||||||
|
// XXX bug 1371712
|
||||||
if (landmark) {
|
if (landmark) {
|
||||||
if (landmark == nsGkAtoms::application)
|
if (landmark == nsGkAtoms::application)
|
||||||
return @"AXLandmarkApplication";
|
return @"AXLandmarkApplication";
|
||||||
|
@ -747,6 +749,13 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||||
return @"AXSearchField";
|
return @"AXSearchField";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// macOS groups the specific landmark types of DPub ARIA into two broad
|
||||||
|
// categories with corresponding subroles: Navigation and region/container.
|
||||||
|
if (mRole == roles::NAVIGATION)
|
||||||
|
return @"AXLandmarkNavigation";
|
||||||
|
if (mRole == roles::LANDMARK)
|
||||||
|
return @"AXLandmarkRegion";
|
||||||
|
|
||||||
// Now, deal with widget roles
|
// Now, deal with widget roles
|
||||||
nsIAtom* roleAtom = nullptr;
|
nsIAtom* roleAtom = nullptr;
|
||||||
if (accWrap && accWrap->HasARIARole()) {
|
if (accWrap && accWrap->HasARIARole()) {
|
||||||
|
@ -889,6 +898,17 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
||||||
case roles::SUMMARY:
|
case roles::SUMMARY:
|
||||||
return @"AXSummary";
|
return @"AXSummary";
|
||||||
|
|
||||||
|
case roles::NOTE:
|
||||||
|
return @"AXDocumentNote";
|
||||||
|
|
||||||
|
// macOS added an AXSubrole value to distinguish generic AXGroup objects
|
||||||
|
// from those which are AXGroups as a result of an explicit ARIA role,
|
||||||
|
// such as the non-landmark, non-listitem text containers in DPub ARIA.
|
||||||
|
case roles::SECTION:
|
||||||
|
if (roleAtom)
|
||||||
|
return @"AXApplicationGroup";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
support-files =
|
support-files =
|
||||||
!/accessible/tests/mochitest/*.js
|
!/accessible/tests/mochitest/*.js
|
||||||
|
|
||||||
|
[test_dpub_aria_xml-roles.html]
|
||||||
[test_obj.html]
|
[test_obj.html]
|
||||||
[test_obj_css.html]
|
[test_obj_css.html]
|
||||||
[test_obj_css.xul]
|
[test_obj_css.xul]
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>XML roles tests</title>
|
||||||
|
<link rel="stylesheet" type="text/css"
|
||||||
|
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../common.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../role.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../attributes.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function doTest()
|
||||||
|
{
|
||||||
|
// DPub ARIA roles should be exposed via the xml-roles object attribute.
|
||||||
|
let dpub_attrs = [
|
||||||
|
'doc-abstract',
|
||||||
|
'doc-acknowledgments',
|
||||||
|
'doc-afterword',
|
||||||
|
'doc-appendix',
|
||||||
|
'doc-backlink',
|
||||||
|
'doc-biblioentry',
|
||||||
|
'doc-bibliography',
|
||||||
|
'doc-biblioref',
|
||||||
|
'doc-chapter',
|
||||||
|
'doc-colophon',
|
||||||
|
'doc-conclusion',
|
||||||
|
'doc-cover',
|
||||||
|
'doc-credit',
|
||||||
|
'doc-credits',
|
||||||
|
'doc-dedication',
|
||||||
|
'doc-endnote',
|
||||||
|
'doc-endnotes',
|
||||||
|
'doc-epigraph',
|
||||||
|
'doc-epilogue',
|
||||||
|
'doc-errata',
|
||||||
|
'doc-example',
|
||||||
|
'doc-footnote',
|
||||||
|
'doc-foreword',
|
||||||
|
'doc-glossary',
|
||||||
|
'doc-glossref',
|
||||||
|
'doc-index',
|
||||||
|
'doc-introduction',
|
||||||
|
'doc-noteref',
|
||||||
|
'doc-notice',
|
||||||
|
'doc-pagebreak',
|
||||||
|
'doc-pagelist',
|
||||||
|
'doc-part',
|
||||||
|
'doc-preface',
|
||||||
|
'doc-prologue',
|
||||||
|
'doc-pullquote',
|
||||||
|
'doc-qna',
|
||||||
|
'doc-subtitle',
|
||||||
|
'doc-tip',
|
||||||
|
'doc-toc'
|
||||||
|
];
|
||||||
|
for (let attr of dpub_attrs) {
|
||||||
|
testAttrs(attr, {"xml-roles" : attr}, true);
|
||||||
|
}
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
addA11yLoadEvent(doTest);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1343537"
|
||||||
|
title="implement ARIA DPUB extension">
|
||||||
|
Bug 1343537
|
||||||
|
</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test"></pre>
|
||||||
|
<div id="doc-abstract" role="doc-abstract">abstract</div>
|
||||||
|
<div id="doc-acknowledgments" role="doc-acknowledgments">acknowledgments</div>
|
||||||
|
<div id="doc-afterword" role="doc-afterword">afterword</div>
|
||||||
|
<div id="doc-appendix" role="doc-appendix">appendix</div>
|
||||||
|
<div id="doc-backlink" role="doc-backlink">backlink</div>
|
||||||
|
<div id="doc-biblioentry" role="doc-biblioentry">biblioentry</div>
|
||||||
|
<div id="doc-bibliography" role="doc-bibliography">bibliography</div>
|
||||||
|
<div id="doc-biblioref" role="doc-biblioref">biblioref</div>
|
||||||
|
<div id="doc-chapter" role="doc-chapter">chapter</div>
|
||||||
|
<div id="doc-colophon" role="doc-colophon">colophon</div>
|
||||||
|
<div id="doc-conclusion" role="doc-conclusion">conclusion</div>
|
||||||
|
<div id="doc-cover" role="doc-cover">cover</div>
|
||||||
|
<div id="doc-credit" role="doc-credit">credit</div>
|
||||||
|
<div id="doc-credits" role="doc-credits">credits</div>
|
||||||
|
<div id="doc-dedication" role="doc-dedication">dedication</div>
|
||||||
|
<div id="doc-endnote" role="doc-endnote">endnote</div>
|
||||||
|
<div id="doc-endnotes" role="doc-endnotes">endnotes</div>
|
||||||
|
<div id="doc-epigraph" role="doc-epigraph">epigraph</div>
|
||||||
|
<div id="doc-epilogue" role="doc-epilogue">epilogue</div>
|
||||||
|
<div id="doc-errata" role="doc-errata">errata</div>
|
||||||
|
<div id="doc-example" role="doc-example">example</div>
|
||||||
|
<div id="doc-footnote" role="doc-footnote">footnote</div>
|
||||||
|
<div id="doc-foreword" role="doc-foreword">foreword</div>
|
||||||
|
<div id="doc-glossary" role="doc-glossary">glossary</div>
|
||||||
|
<div id="doc-glossref" role="doc-glossref">glossref</div>
|
||||||
|
<div id="doc-index" role="doc-index">index</div>
|
||||||
|
<div id="doc-introduction" role="doc-introduction">introduction</div>
|
||||||
|
<div id="doc-noteref" role="doc-noteref">noteref</div>
|
||||||
|
<div id="doc-notice" role="doc-notice">notice</div>
|
||||||
|
<div id="doc-pagebreak" role="doc-pagebreak">pagebreak</div>
|
||||||
|
<div id="doc-pagelist" role="doc-pagelist">pagelist</div>
|
||||||
|
<div id="doc-part" role="doc-part">part</div>
|
||||||
|
<div id="doc-preface" role="doc-preface">preface</div>
|
||||||
|
<div id="doc-prologue" role="doc-prologue">prologue</div>
|
||||||
|
<div id="doc-pullquote" role="doc-pullquote">pullquote</div>
|
||||||
|
<div id="doc-qna" role="doc-qna">qna</div>
|
||||||
|
<div id="doc-subtitle" role="doc-subtitle">subtitle</div>
|
||||||
|
<div id="doc-tip" role="doc-tip">tip</div>
|
||||||
|
<div id="doc-toc" role="doc-toc">toc</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -28,6 +28,7 @@ const ROLE_ENTRY = nsIAccessibleRole.ROLE_ENTRY;
|
||||||
const ROLE_EQUATION = nsIAccessibleRole.ROLE_EQUATION;
|
const ROLE_EQUATION = nsIAccessibleRole.ROLE_EQUATION;
|
||||||
const ROLE_FIGURE = nsIAccessibleRole.ROLE_FIGURE;
|
const ROLE_FIGURE = nsIAccessibleRole.ROLE_FIGURE;
|
||||||
const ROLE_FOOTER = nsIAccessibleRole.ROLE_FOOTER;
|
const ROLE_FOOTER = nsIAccessibleRole.ROLE_FOOTER;
|
||||||
|
const ROLE_FOOTNOTE = nsIAccessibleRole.ROLE_FOOTNOTE;
|
||||||
const ROLE_FLAT_EQUATION = nsIAccessibleRole.ROLE_FLAT_EQUATION;
|
const ROLE_FLAT_EQUATION = nsIAccessibleRole.ROLE_FLAT_EQUATION;
|
||||||
const ROLE_FORM = nsIAccessibleRole.ROLE_FORM;
|
const ROLE_FORM = nsIAccessibleRole.ROLE_FORM;
|
||||||
const ROLE_GRAPHIC = nsIAccessibleRole.ROLE_GRAPHIC;
|
const ROLE_GRAPHIC = nsIAccessibleRole.ROLE_GRAPHIC;
|
||||||
|
@ -38,6 +39,7 @@ const ROLE_HEADING = nsIAccessibleRole.ROLE_HEADING;
|
||||||
const ROLE_IMAGE_MAP = nsIAccessibleRole.ROLE_IMAGE_MAP;
|
const ROLE_IMAGE_MAP = nsIAccessibleRole.ROLE_IMAGE_MAP;
|
||||||
const ROLE_INTERNAL_FRAME = nsIAccessibleRole.ROLE_INTERNAL_FRAME;
|
const ROLE_INTERNAL_FRAME = nsIAccessibleRole.ROLE_INTERNAL_FRAME;
|
||||||
const ROLE_LABEL = nsIAccessibleRole.ROLE_LABEL;
|
const ROLE_LABEL = nsIAccessibleRole.ROLE_LABEL;
|
||||||
|
const ROLE_LANDMARK = nsIAccessibleRole.ROLE_LANDMARK;
|
||||||
const ROLE_LINK = nsIAccessibleRole.ROLE_LINK;
|
const ROLE_LINK = nsIAccessibleRole.ROLE_LINK;
|
||||||
const ROLE_LIST = nsIAccessibleRole.ROLE_LIST;
|
const ROLE_LIST = nsIAccessibleRole.ROLE_LIST;
|
||||||
const ROLE_LISTBOX = nsIAccessibleRole.ROLE_LISTBOX;
|
const ROLE_LISTBOX = nsIAccessibleRole.ROLE_LISTBOX;
|
||||||
|
@ -79,6 +81,7 @@ const ROLE_MATHML_STACK_LINE = nsIAccessibleRole.ROLE_MATHML_STACK_LINE;
|
||||||
const ROLE_MENUBAR = nsIAccessibleRole.ROLE_MENUBAR;
|
const ROLE_MENUBAR = nsIAccessibleRole.ROLE_MENUBAR;
|
||||||
const ROLE_MENUITEM = nsIAccessibleRole.ROLE_MENUITEM;
|
const ROLE_MENUITEM = nsIAccessibleRole.ROLE_MENUITEM;
|
||||||
const ROLE_MENUPOPUP = nsIAccessibleRole.ROLE_MENUPOPUP;
|
const ROLE_MENUPOPUP = nsIAccessibleRole.ROLE_MENUPOPUP;
|
||||||
|
const ROLE_NAVIGATION = nsIAccessibleRole.ROLE_NAVIGATION;
|
||||||
const ROLE_NOTHING = nsIAccessibleRole.ROLE_NOTHING;
|
const ROLE_NOTHING = nsIAccessibleRole.ROLE_NOTHING;
|
||||||
const ROLE_NOTE = nsIAccessibleRole.ROLE_NOTE;
|
const ROLE_NOTE = nsIAccessibleRole.ROLE_NOTE;
|
||||||
const ROLE_OPTION = nsIAccessibleRole.ROLE_OPTION;
|
const ROLE_OPTION = nsIAccessibleRole.ROLE_OPTION;
|
||||||
|
|
|
@ -5,6 +5,7 @@ support-files =
|
||||||
|
|
||||||
[test_aria.html]
|
[test_aria.html]
|
||||||
[test_aria.xul]
|
[test_aria.xul]
|
||||||
|
[test_dpub_aria.html]
|
||||||
[test_general.html]
|
[test_general.html]
|
||||||
[test_general.xul]
|
[test_general.xul]
|
||||||
[test_svg.html]
|
[test_svg.html]
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Test DPub ARIA roles</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../common.js"></script>
|
||||||
|
<script type="application/javascript"
|
||||||
|
src="../role.js"></script>
|
||||||
|
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function doTest()
|
||||||
|
{
|
||||||
|
// DPub ARIA role map.
|
||||||
|
testRole("doc-abstract", ROLE_SECTION);
|
||||||
|
testRole("doc-acknowledgments", ROLE_LANDMARK);
|
||||||
|
testRole("doc-afterword", ROLE_LANDMARK);
|
||||||
|
testRole("doc-appendix", ROLE_LANDMARK);
|
||||||
|
testRole("doc-backlink", ROLE_LINK);
|
||||||
|
testRole("doc-biblioentry", ROLE_LISTITEM);
|
||||||
|
testRole("doc-bibliography", ROLE_LANDMARK);
|
||||||
|
testRole("doc-biblioref", ROLE_LINK);
|
||||||
|
testRole("doc-chapter", ROLE_LANDMARK);
|
||||||
|
testRole("doc-colophon", ROLE_SECTION);
|
||||||
|
testRole("doc-conclusion", ROLE_LANDMARK);
|
||||||
|
testRole("doc-cover", ROLE_GRAPHIC);
|
||||||
|
testRole("doc-credit", ROLE_SECTION);
|
||||||
|
testRole("doc-credits", ROLE_LANDMARK);
|
||||||
|
testRole("doc-dedication", ROLE_SECTION);
|
||||||
|
testRole("doc-endnote", ROLE_LISTITEM);
|
||||||
|
testRole("doc-endnotes", ROLE_LANDMARK);
|
||||||
|
testRole("doc-epigraph", ROLE_SECTION);
|
||||||
|
testRole("doc-epilogue", ROLE_LANDMARK);
|
||||||
|
testRole("doc-errata", ROLE_LANDMARK);
|
||||||
|
testRole("doc-example", ROLE_SECTION);
|
||||||
|
testRole("doc-footnote", ROLE_FOOTNOTE);
|
||||||
|
testRole("doc-foreword", ROLE_LANDMARK);
|
||||||
|
testRole("doc-glossary", ROLE_LANDMARK);
|
||||||
|
testRole("doc-glossref", ROLE_LINK);
|
||||||
|
testRole("doc-index", ROLE_NAVIGATION);
|
||||||
|
testRole("doc-introduction", ROLE_LANDMARK);
|
||||||
|
testRole("doc-noteref", ROLE_LINK);
|
||||||
|
testRole("doc-notice", ROLE_NOTE);
|
||||||
|
testRole("doc-pagebreak", ROLE_SEPARATOR);
|
||||||
|
testRole("doc-pagelist", ROLE_NAVIGATION);
|
||||||
|
testRole("doc-part", ROLE_LANDMARK);
|
||||||
|
testRole("doc-preface", ROLE_LANDMARK);
|
||||||
|
testRole("doc-prologue", ROLE_LANDMARK);
|
||||||
|
testRole("doc-pullquote", ROLE_SECTION);
|
||||||
|
testRole("doc-qna", ROLE_SECTION);
|
||||||
|
testRole("doc-subtitle", ROLE_HEADING);
|
||||||
|
testRole("doc-tip", ROLE_NOTE);
|
||||||
|
testRole("doc-toc", ROLE_NAVIGATION);
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
addA11yLoadEvent(doTest);
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank"
|
||||||
|
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1343537"
|
||||||
|
title="implement ARIA DPUB extension">
|
||||||
|
Bug 1343537
|
||||||
|
</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test"></pre>
|
||||||
|
<div id="doc-abstract" role="doc-abstract">abstract</div>
|
||||||
|
<div id="doc-acknowledgments" role="doc-acknowledgments">acknowledgments</div>
|
||||||
|
<div id="doc-afterword" role="doc-afterword">afterword</div>
|
||||||
|
<div id="doc-appendix" role="doc-appendix">appendix</div>
|
||||||
|
<div id="doc-backlink" role="doc-backlink">backlink</div>
|
||||||
|
<div id="doc-biblioentry" role="doc-biblioentry">biblioentry</div>
|
||||||
|
<div id="doc-bibliography" role="doc-bibliography">bibliography</div>
|
||||||
|
<div id="doc-biblioref" role="doc-biblioref">biblioref</div>
|
||||||
|
<div id="doc-chapter" role="doc-chapter">chapter</div>
|
||||||
|
<div id="doc-colophon" role="doc-colophon">colophon</div>
|
||||||
|
<div id="doc-conclusion" role="doc-conclusion">conclusion</div>
|
||||||
|
<div id="doc-cover" role="doc-cover">cover</div>
|
||||||
|
<div id="doc-credit" role="doc-credit">credit</div>
|
||||||
|
<div id="doc-credits" role="doc-credits">credits</div>
|
||||||
|
<div id="doc-dedication" role="doc-dedication">dedication</div>
|
||||||
|
<div id="doc-endnote" role="doc-endnote">endnote</div>
|
||||||
|
<div id="doc-endnotes" role="doc-endnotes">endnotes</div>
|
||||||
|
<div id="doc-epigraph" role="doc-epigraph">epigraph</div>
|
||||||
|
<div id="doc-epilogue" role="doc-epilogue">epilogue</div>
|
||||||
|
<div id="doc-errata" role="doc-errata">errata</div>
|
||||||
|
<div id="doc-example" role="doc-example">example</div>
|
||||||
|
<div id="doc-footnote" role="doc-footnote">footnote</div>
|
||||||
|
<div id="doc-foreword" role="doc-foreword">foreword</div>
|
||||||
|
<div id="doc-glossary" role="doc-glossary">glossary</div>
|
||||||
|
<div id="doc-glossref" role="doc-glossref">glossref</div>
|
||||||
|
<div id="doc-index" role="doc-index">index</div>
|
||||||
|
<div id="doc-introduction" role="doc-introduction">introduction</div>
|
||||||
|
<div id="doc-noteref" role="doc-noteref">noteref</div>
|
||||||
|
<div id="doc-notice" role="doc-notice">notice</div>
|
||||||
|
<div id="doc-pagebreak" role="doc-pagebreak">pagebreak</div>
|
||||||
|
<div id="doc-pagelist" role="doc-pagelist">pagelist</div>
|
||||||
|
<div id="doc-part" role="doc-part">part</div>
|
||||||
|
<div id="doc-preface" role="doc-preface">preface</div>
|
||||||
|
<div id="doc-prologue" role="doc-prologue">prologue</div>
|
||||||
|
<div id="doc-pullquote" role="doc-pullquote">pullquote</div>
|
||||||
|
<div id="doc-qna" role="doc-qna">qna</div>
|
||||||
|
<div id="doc-subtitle" role="doc-subtitle">subtitle</div>
|
||||||
|
<div id="doc-tip" role="doc-tip">tip</div>
|
||||||
|
<div id="doc-toc" role="doc-toc">toc</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -23,6 +23,8 @@ const {
|
||||||
const SHOW_GRID_AREAS = "devtools.gridinspector.showGridAreas";
|
const SHOW_GRID_AREAS = "devtools.gridinspector.showGridAreas";
|
||||||
const SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
|
const SHOW_GRID_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
|
||||||
const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
|
const SHOW_INFINITE_LINES_PREF = "devtools.gridinspector.showInfiniteLines";
|
||||||
|
// @remove after release 56 (See Bug 1355747)
|
||||||
|
const PROMOTE_COUNT_PREF = "devtools.promote.layoutview";
|
||||||
|
|
||||||
// Default grid colors.
|
// Default grid colors.
|
||||||
const GRID_COLORS = [
|
const GRID_COLORS = [
|
||||||
|
@ -480,6 +482,9 @@ GridInspector.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @remove after release 56 (See Bug 1355747)
|
||||||
|
Services.prefs.setIntPref(PROMOTE_COUNT_PREF, 0);
|
||||||
|
|
||||||
this.inspector.reflowTracker.trackReflows(this, this.onReflow);
|
this.inspector.reflowTracker.trackReflows(this, this.onReflow);
|
||||||
this.layoutInspector.on("grid-layout-changed", this.onGridLayoutChange);
|
this.layoutInspector.on("grid-layout-changed", this.onGridLayoutChange);
|
||||||
this.updateGridPanel();
|
this.updateGridPanel();
|
||||||
|
|
|
@ -18,6 +18,7 @@ const BoxModelTypes = require("devtools/client/inspector/boxmodel/types");
|
||||||
const GridTypes = require("devtools/client/inspector/grids/types");
|
const GridTypes = require("devtools/client/inspector/grids/types");
|
||||||
|
|
||||||
const Accordion = createFactory(require("./Accordion"));
|
const Accordion = createFactory(require("./Accordion"));
|
||||||
|
const LayoutPromoteBar = createFactory(require("./LayoutPromoteBar"));
|
||||||
|
|
||||||
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
|
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
|
||||||
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
|
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
|
||||||
|
@ -41,6 +42,7 @@ const App = createClass({
|
||||||
showBoxModelProperties: PropTypes.bool.isRequired,
|
showBoxModelProperties: PropTypes.bool.isRequired,
|
||||||
showGridOutline: PropTypes.bool.isRequired,
|
showGridOutline: PropTypes.bool.isRequired,
|
||||||
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
||||||
|
onPromoteLearnMoreClick: PropTypes.func.isRequired,
|
||||||
onSetGridOverlayColor: PropTypes.func.isRequired,
|
onSetGridOverlayColor: PropTypes.func.isRequired,
|
||||||
onShowBoxModelEditor: PropTypes.func.isRequired,
|
onShowBoxModelEditor: PropTypes.func.isRequired,
|
||||||
onShowBoxModelHighlighter: PropTypes.func.isRequired,
|
onShowBoxModelHighlighter: PropTypes.func.isRequired,
|
||||||
|
@ -53,11 +55,16 @@ const App = createClass({
|
||||||
mixins: [ addons.PureRenderMixin ],
|
mixins: [ addons.PureRenderMixin ],
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let { onPromoteLearnMoreClick } = this.props;
|
||||||
|
|
||||||
return dom.div(
|
return dom.div(
|
||||||
{
|
{
|
||||||
id: "layout-container",
|
id: "layout-container",
|
||||||
className: "devtools-monospace",
|
className: "devtools-monospace",
|
||||||
},
|
},
|
||||||
|
LayoutPromoteBar({
|
||||||
|
onPromoteLearnMoreClick,
|
||||||
|
}),
|
||||||
Accordion({
|
Accordion({
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* !!!! TO BE REMOVED AFTER RELEASE 56 !!!!
|
||||||
|
* !!!! !!!!
|
||||||
|
* !!!! This file is a temporary panel that should only be used for release 56 to !!!!
|
||||||
|
* !!!! promote the new layout panel. After release 56, it should be removed. !!!!
|
||||||
|
* !!!! See bug 1355747. !!!!
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Services = require("Services");
|
||||||
|
const { addons, createClass, DOM: dom, PropTypes } =
|
||||||
|
require("devtools/client/shared/vendor/react");
|
||||||
|
|
||||||
|
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||||
|
|
||||||
|
const LAYOUT_STRINGS_URI = "devtools/client/locales/layout.properties";
|
||||||
|
const LAYOUT_L10N = new LocalizationHelper(LAYOUT_STRINGS_URI);
|
||||||
|
|
||||||
|
const SHOW_PROMOTE_BAR_PREF = "devtools.promote.layoutview.showPromoteBar";
|
||||||
|
|
||||||
|
module.exports = createClass({
|
||||||
|
|
||||||
|
displayName: "LayoutPromoteBar",
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
onPromoteLearnMoreClick: PropTypes.func.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [ addons.PureRenderMixin ],
|
||||||
|
|
||||||
|
getInitialState() {
|
||||||
|
return {
|
||||||
|
showPromoteBar: Services.prefs.getBoolPref(SHOW_PROMOTE_BAR_PREF)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
onPromoteCloseButtonClick() {
|
||||||
|
Services.prefs.setBoolPref(SHOW_PROMOTE_BAR_PREF, false);
|
||||||
|
this.setState({ showPromoteBar: false });
|
||||||
|
},
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let { onPromoteLearnMoreClick } = this.props;
|
||||||
|
let { showPromoteBar } = this.state;
|
||||||
|
|
||||||
|
return showPromoteBar ?
|
||||||
|
dom.div({ className: "layout-promote-bar" },
|
||||||
|
dom.span({ className: "layout-promote-info-icon" }),
|
||||||
|
dom.div({ className: "layout-promote-message" },
|
||||||
|
LAYOUT_L10N.getStr("layout.promoteMessage"),
|
||||||
|
dom.a(
|
||||||
|
{
|
||||||
|
className: "layout-promote-learn-more-link theme-link",
|
||||||
|
href: "#",
|
||||||
|
onClick: onPromoteLearnMoreClick,
|
||||||
|
},
|
||||||
|
LAYOUT_L10N.getStr("layout.learnMore")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
dom.button(
|
||||||
|
{
|
||||||
|
className: "layout-promote-close-button devtools-button",
|
||||||
|
onClick: this.onPromoteCloseButtonClick,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
:
|
||||||
|
null;
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
|
@ -8,4 +8,5 @@ DevToolsModules(
|
||||||
'Accordion.css',
|
'Accordion.css',
|
||||||
'Accordion.js',
|
'Accordion.js',
|
||||||
'App.js',
|
'App.js',
|
||||||
|
'LayoutPromoteBar.js',
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,12 +16,19 @@ const INSPECTOR_L10N =
|
||||||
new LocalizationHelper("devtools/client/locales/inspector.properties");
|
new LocalizationHelper("devtools/client/locales/inspector.properties");
|
||||||
|
|
||||||
const SHOW_GRID_OUTLINE_PREF = "devtools.gridinspector.showGridOutline";
|
const SHOW_GRID_OUTLINE_PREF = "devtools.gridinspector.showGridOutline";
|
||||||
|
// @remove after release 56 (See Bug 1355747)
|
||||||
|
const PROMOTE_COUNT_PREF = "devtools.promote.layoutview";
|
||||||
|
|
||||||
|
// @remove after release 56 (See Bug 1355747)
|
||||||
|
const GRID_LINK = "https://www.mozilla.org/en-US/developer/css-grid/?utm_source=gridtooltip&utm_medium=devtools&utm_campaign=cssgrid_layout";
|
||||||
|
|
||||||
function LayoutView(inspector, window) {
|
function LayoutView(inspector, window) {
|
||||||
this.document = window.document;
|
this.document = window.document;
|
||||||
this.inspector = inspector;
|
this.inspector = inspector;
|
||||||
this.store = inspector.store;
|
this.store = inspector.store;
|
||||||
|
|
||||||
|
this.onPromoteLearnMoreClick = this.onPromoteLearnMoreClick.bind(this);
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +63,10 @@ LayoutView.prototype = {
|
||||||
onToggleShowInfiniteLines,
|
onToggleShowInfiniteLines,
|
||||||
} = this.inspector.gridInspector.getComponentProps();
|
} = this.inspector.gridInspector.getComponentProps();
|
||||||
|
|
||||||
|
let {
|
||||||
|
onPromoteLearnMoreClick,
|
||||||
|
} = this;
|
||||||
|
|
||||||
let app = App({
|
let app = App({
|
||||||
getSwatchColorPickerTooltip,
|
getSwatchColorPickerTooltip,
|
||||||
setSelectedNode,
|
setSelectedNode,
|
||||||
|
@ -72,6 +83,7 @@ LayoutView.prototype = {
|
||||||
showGridOutline: Services.prefs.getBoolPref(SHOW_GRID_OUTLINE_PREF),
|
showGridOutline: Services.prefs.getBoolPref(SHOW_GRID_OUTLINE_PREF),
|
||||||
|
|
||||||
onHideBoxModelHighlighter,
|
onHideBoxModelHighlighter,
|
||||||
|
onPromoteLearnMoreClick,
|
||||||
onSetGridOverlayColor,
|
onSetGridOverlayColor,
|
||||||
onShowBoxModelEditor,
|
onShowBoxModelEditor,
|
||||||
onShowBoxModelHighlighter,
|
onShowBoxModelHighlighter,
|
||||||
|
@ -87,10 +99,14 @@ LayoutView.prototype = {
|
||||||
});
|
});
|
||||||
|
|
||||||
let provider = createElement(Provider, {
|
let provider = createElement(Provider, {
|
||||||
store: this.store,
|
|
||||||
id: "layoutview",
|
id: "layoutview",
|
||||||
title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
|
|
||||||
key: "layoutview",
|
key: "layoutview",
|
||||||
|
store: this.store,
|
||||||
|
title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
|
||||||
|
// @remove after release 56 (See Bug 1355747)
|
||||||
|
badge: Services.prefs.getIntPref(PROMOTE_COUNT_PREF) > 0 ?
|
||||||
|
INSPECTOR_L10N.getStr("inspector.sidebar.newBadge") : null,
|
||||||
|
showBadge: () => Services.prefs.getIntPref(PROMOTE_COUNT_PREF) > 0,
|
||||||
}, app);
|
}, app);
|
||||||
|
|
||||||
let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
|
let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
|
||||||
|
@ -112,6 +128,11 @@ LayoutView.prototype = {
|
||||||
this.store = null;
|
this.store = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onPromoteLearnMoreClick() {
|
||||||
|
let browserWin = this.inspector.target.tab.ownerDocument.defaultView;
|
||||||
|
browserWin.openUILinkIn(GRID_LINK, "current");
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = LayoutView;
|
module.exports = LayoutView;
|
||||||
|
|
|
@ -351,6 +351,11 @@ inspector.sidebar.computedViewTitle=Computed
|
||||||
# that corresponds to the tool displaying layout information defined in the page.
|
# that corresponds to the tool displaying layout information defined in the page.
|
||||||
inspector.sidebar.layoutViewTitle2=Layout
|
inspector.sidebar.layoutViewTitle2=Layout
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (inspector.sidebar.newBadge):
|
||||||
|
# This is the text of a promotion badge showed in the inspector sidebar, next to a panel
|
||||||
|
# name. Used to promote new/recent panels such as the layout panel.
|
||||||
|
inspector.sidebar.newBadge=new!
|
||||||
|
|
||||||
# LOCALIZATION NOTE (inspector.sidebar.animationInspectorTitle):
|
# LOCALIZATION NOTE (inspector.sidebar.animationInspectorTitle):
|
||||||
# This is the title shown in a tab in the side panel of the Inspector panel
|
# This is the title shown in a tab in the side panel of the Inspector panel
|
||||||
# that corresponds to the tool displaying animations defined in the page.
|
# that corresponds to the tool displaying animations defined in the page.
|
||||||
|
|
|
@ -46,3 +46,11 @@ layout.overlayGrid=Overlay Grid
|
||||||
# LOCALIZATION NOTE (layout.rowColumnPositions): The row and column position of a grid
|
# LOCALIZATION NOTE (layout.rowColumnPositions): The row and column position of a grid
|
||||||
# cell shown in the grid cell infobar when hovering over the CSS grid outline.
|
# cell shown in the grid cell infobar when hovering over the CSS grid outline.
|
||||||
layout.rowColumnPositions=Row %S / Column %S
|
layout.rowColumnPositions=Row %S / Column %S
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (layout.promoteMessage): Text displayed in the promote bar for the
|
||||||
|
# layout panel.
|
||||||
|
layout.promoteMessage=Explore CSS Grids with the latest CSS Grid Inspector.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (layout.learnMore): Text for the link displayed in the promote bar
|
||||||
|
# for the layout panel.
|
||||||
|
layout.learnMore=Learn more…
|
||||||
|
|
|
@ -71,6 +71,13 @@ pref("devtools.fontinspector.enabled", true);
|
||||||
// Enable the Layout View
|
// Enable the Layout View
|
||||||
pref("devtools.layoutview.enabled", false);
|
pref("devtools.layoutview.enabled", false);
|
||||||
|
|
||||||
|
// Counter to promote the inspector layout view.
|
||||||
|
// @remove after release 56 (See Bug 1355747)
|
||||||
|
pref("devtools.promote.layoutview", 1);
|
||||||
|
// Whether or not to show the promote bar in the layout view
|
||||||
|
// @remove after release 56 (See Bug 1355747)
|
||||||
|
pref("devtools.promote.layoutview.showPromoteBar", true);
|
||||||
|
|
||||||
// Grid highlighter preferences
|
// Grid highlighter preferences
|
||||||
pref("devtools.gridinspector.showGridAreas", false);
|
pref("devtools.gridinspector.showGridAreas", false);
|
||||||
pref("devtools.gridinspector.showGridLineNumbers", false);
|
pref("devtools.gridinspector.showGridLineNumbers", false);
|
||||||
|
|
|
@ -20,16 +20,33 @@
|
||||||
|
|
||||||
.tabs .tabs-menu-item {
|
.tabs .tabs-menu-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs .tabs-menu-item a {
|
.tabs .tabs-menu-item a {
|
||||||
display: block;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabs .tabs-menu-item .tab-badge {
|
||||||
|
color: var(--theme-highlight-blue);
|
||||||
|
font-size: 80%;
|
||||||
|
font-style: italic;
|
||||||
|
/* Tabs have a 15px padding start/end, so we set the margins here in order to center the
|
||||||
|
badge after the tab title, with a 5px effective margin. */
|
||||||
|
margin-inline-start: 5px;
|
||||||
|
margin-inline-end: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs .tabs-menu-item.is-active .tab-badge {
|
||||||
|
/* Use the same color as the tab-item when active */
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
/* To avoid "select all" commands from selecting content in hidden tabs */
|
/* To avoid "select all" commands from selecting content in hidden tabs */
|
||||||
.tabs .hidden,
|
.tabs .hidden,
|
||||||
.tabs .hidden * {
|
.tabs .hidden * {
|
||||||
|
|
|
@ -234,16 +234,21 @@ define(function (require, exports, module) {
|
||||||
.map((tab) => typeof tab === "function" ? tab() : tab)
|
.map((tab) => typeof tab === "function" ? tab() : tab)
|
||||||
.filter((tab) => tab)
|
.filter((tab) => tab)
|
||||||
.map((tab, index) => {
|
.map((tab, index) => {
|
||||||
let id = tab.props.id;
|
let {
|
||||||
|
id,
|
||||||
|
className: tabClassName,
|
||||||
|
title,
|
||||||
|
badge,
|
||||||
|
showBadge,
|
||||||
|
} = tab.props;
|
||||||
|
|
||||||
let ref = "tab-menu-" + index;
|
let ref = "tab-menu-" + index;
|
||||||
let title = tab.props.title;
|
|
||||||
let tabClassName = tab.props.className;
|
|
||||||
let isTabSelected = this.state.tabActive === index;
|
let isTabSelected = this.state.tabActive === index;
|
||||||
|
|
||||||
let className = [
|
let className = [
|
||||||
"tabs-menu-item",
|
"tabs-menu-item",
|
||||||
tabClassName,
|
tabClassName,
|
||||||
isTabSelected ? "is-active" : ""
|
isTabSelected ? "is-active" : "",
|
||||||
].join(" ");
|
].join(" ");
|
||||||
|
|
||||||
// Set tabindex to -1 (except the selected tab) so, it's focusable,
|
// Set tabindex to -1 (except the selected tab) so, it's focusable,
|
||||||
|
@ -266,7 +271,11 @@ define(function (require, exports, module) {
|
||||||
role: "tab",
|
role: "tab",
|
||||||
onClick: this.onClickTab.bind(this, index),
|
onClick: this.onClickTab.bind(this, index),
|
||||||
},
|
},
|
||||||
title
|
title,
|
||||||
|
badge && !isTabSelected && showBadge() ?
|
||||||
|
DOM.span({ className: "tab-badge" }, badge)
|
||||||
|
:
|
||||||
|
null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -48,6 +48,56 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout Promote Bar
|
||||||
|
*/
|
||||||
|
|
||||||
|
.layout-promote-bar {
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--theme-toolbar-background);
|
||||||
|
border-bottom: 1px solid var(--theme-splitter-color);
|
||||||
|
display: flex;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 5px;
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
width: 100%;
|
||||||
|
-moz-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-promote-bar:hover {
|
||||||
|
background-color: var(--theme-toolbar-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-promote-info-icon {
|
||||||
|
display: inline-block;
|
||||||
|
background-size: 16px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin: 6px;
|
||||||
|
background-image: url("chrome://browser/skin/info.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-promote-message {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-promote-learn-more-link {
|
||||||
|
margin-inline-start: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-promote-learn-more-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-promote-close-button {
|
||||||
|
margin: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-promote-close-button::before {
|
||||||
|
background-image: url("chrome://devtools/skin/images/close.svg");
|
||||||
|
margin: -6px 0 0 -6px;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grid Container
|
* Grid Container
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4084,42 +4084,33 @@ enum nsPreviousIntersectionThreshold {
|
||||||
void
|
void
|
||||||
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
|
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
|
||||||
{
|
{
|
||||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
|
RegisteredIntersectionObservers()->LookupForAdd(aObserver).OrInsert([]() {
|
||||||
RegisteredIntersectionObservers();
|
// Value can be:
|
||||||
if (observers->Contains(aObserver)) {
|
// -2: Makes sure next calculated threshold always differs, leading to a
|
||||||
return;
|
// notification task being scheduled.
|
||||||
}
|
// -1: Non-intersecting.
|
||||||
|
// >= 0: Intersecting, valid index of aObserver->mThresholds.
|
||||||
// Value can be:
|
return eUninitialized;
|
||||||
// -2: Makes sure next calculated threshold always differs, leading to a
|
});
|
||||||
// notification task being scheduled.
|
|
||||||
// -1: Non-intersecting.
|
|
||||||
// >= 0: Intersecting, valid index of aObserver->mThresholds.
|
|
||||||
RegisteredIntersectionObservers()->Put(aObserver, eUninitialized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
|
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
|
||||||
{
|
{
|
||||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
|
RegisteredIntersectionObservers()->Remove(aObserver);
|
||||||
RegisteredIntersectionObservers();
|
|
||||||
observers->Remove(aObserver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
|
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
|
||||||
{
|
{
|
||||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
|
bool updated = false;
|
||||||
RegisteredIntersectionObservers();
|
RegisteredIntersectionObservers()->LookupRemoveIf(aObserver,
|
||||||
if (!observers->Contains(aObserver)) {
|
[&updated, aThreshold] (int32_t& aValue) {
|
||||||
return false;
|
updated = aValue != aThreshold;
|
||||||
}
|
aValue = aThreshold;
|
||||||
int32_t previousThreshold = observers->Get(aObserver);
|
return false; // don't remove the entry
|
||||||
if (previousThreshold != aThreshold) {
|
});
|
||||||
observers->Put(aObserver, aThreshold);
|
return updated;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -28,26 +28,27 @@ ImageTracker::Add(imgIRequest* aImage)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aImage);
|
MOZ_ASSERT(aImage);
|
||||||
|
|
||||||
// See if the image is already in the hashtable. If it is, get the old count.
|
|
||||||
uint32_t oldCount = 0;
|
|
||||||
mImages.Get(aImage, &oldCount);
|
|
||||||
|
|
||||||
// Put the image in the hashtable, with the proper count.
|
|
||||||
mImages.Put(aImage, oldCount + 1);
|
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
auto entry = mImages.LookupForAdd(aImage);
|
||||||
|
if (entry) {
|
||||||
|
// The image is already in the hashtable. Increment its count.
|
||||||
|
uint32_t oldCount = entry.Data();
|
||||||
|
MOZ_ASSERT(oldCount > 0, "Entry in the image tracker with count 0!");
|
||||||
|
entry.Data() = oldCount + 1;
|
||||||
|
} else {
|
||||||
|
// A new entry was inserted - set the count to 1.
|
||||||
|
entry.OrInsert([]() { return 1; });
|
||||||
|
|
||||||
// If this is the first insertion and we're locking images, lock this image
|
// If we're locking images, lock this image too.
|
||||||
// too.
|
if (mLocking) {
|
||||||
if (oldCount == 0 && mLocking) {
|
rv = aImage->LockImage();
|
||||||
rv = aImage->LockImage();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the first insertion and we're animating images, request
|
// If we're animating images, request that this image be animated too.
|
||||||
// that this image be animated too.
|
if (mAnimating) {
|
||||||
if (oldCount == 0 && mAnimating) {
|
nsresult rv2 = aImage->IncrementAnimationConsumers();
|
||||||
nsresult rv2 = aImage->IncrementAnimationConsumers();
|
rv = NS_SUCCEEDED(rv) ? rv2 : rv;
|
||||||
rv = NS_SUCCEEDED(rv) ? rv2 : rv;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -59,23 +60,23 @@ ImageTracker::Remove(imgIRequest* aImage, uint32_t aFlags)
|
||||||
NS_ENSURE_ARG_POINTER(aImage);
|
NS_ENSURE_ARG_POINTER(aImage);
|
||||||
|
|
||||||
// Get the old count. It should exist and be > 0.
|
// Get the old count. It should exist and be > 0.
|
||||||
uint32_t count = 0;
|
DebugOnly<bool> found = false;
|
||||||
DebugOnly<bool> found = mImages.Get(aImage, &count);
|
bool remove = false;
|
||||||
|
mImages.LookupRemoveIf(aImage,
|
||||||
|
[&found, &remove] (uint32_t& aCount) {
|
||||||
|
found = true;
|
||||||
|
MOZ_ASSERT(aCount > 0, "Entry in the image tracker with count 0!");
|
||||||
|
--aCount;
|
||||||
|
// If the count is now zero, remove it from the tracker.
|
||||||
|
remove = aCount == 0;
|
||||||
|
return remove;
|
||||||
|
});
|
||||||
|
|
||||||
MOZ_ASSERT(found, "Removing image that wasn't in the tracker!");
|
MOZ_ASSERT(found, "Removing image that wasn't in the tracker!");
|
||||||
MOZ_ASSERT(count > 0, "Entry in the cache tracker with count 0!");
|
if (!remove) {
|
||||||
|
|
||||||
// We're removing, so decrement the count.
|
|
||||||
count--;
|
|
||||||
|
|
||||||
// If the count is now zero, remove from the tracker.
|
|
||||||
// Otherwise, set the new value.
|
|
||||||
if (count != 0) {
|
|
||||||
mImages.Put(aImage, count);
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
mImages.Remove(aImage);
|
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
// Now that we're no longer tracking this image, unlock it if we'd
|
// Now that we're no longer tracking this image, unlock it if we'd
|
||||||
|
|
|
@ -99,13 +99,14 @@ StructuredCloneBlob::Deserialize(JSContext* aCx, JS::HandleObject aTargetScope,
|
||||||
|
|
||||||
|
|
||||||
/* static */ JSObject*
|
/* static */ JSObject*
|
||||||
StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader)
|
StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||||
|
StructuredCloneHolder* aHolder)
|
||||||
{
|
{
|
||||||
JS::RootedObject obj(aCx);
|
JS::RootedObject obj(aCx);
|
||||||
{
|
{
|
||||||
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
|
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
|
||||||
|
|
||||||
if (!holder->ReadStructuredCloneInternal(aCx, aReader) ||
|
if (!holder->ReadStructuredCloneInternal(aCx, aReader, aHolder) ||
|
||||||
!holder->WrapObject(aCx, nullptr, &obj)) {
|
!holder->WrapObject(aCx, nullptr, &obj)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +115,8 @@ StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader)
|
StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||||
|
StructuredCloneHolder* aHolder)
|
||||||
{
|
{
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
|
@ -122,6 +124,15 @@ StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredClo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t blobOffset;
|
||||||
|
uint32_t blobCount;
|
||||||
|
if (!JS_ReadUint32Pair(aReader, &blobOffset, &blobCount)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (blobCount) {
|
||||||
|
BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
|
||||||
|
}
|
||||||
|
|
||||||
JSStructuredCloneData data(length, length, 4096);
|
JSStructuredCloneData data(length, length, 4096);
|
||||||
if (!JS_ReadBytes(aReader, data.Start(), length)) {
|
if (!JS_ReadBytes(aReader, data.Start(), length)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -136,14 +147,18 @@ StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredClo
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter)
|
StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||||
|
StructuredCloneHolder* aHolder)
|
||||||
{
|
{
|
||||||
auto& data = mBuffer->data();
|
auto& data = mBuffer->data();
|
||||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_HOLDER, 0) ||
|
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_HOLDER, 0) ||
|
||||||
!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION)) {
|
!JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION) ||
|
||||||
|
!JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(), BlobImpls().Length())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aHolder->BlobImpls().AppendElements(BlobImpls());
|
||||||
|
|
||||||
auto iter = data.Iter();
|
auto iter = data.Iter();
|
||||||
while (!iter.Done()) {
|
while (!iter.Done()) {
|
||||||
if (!JS_WriteBytes(aWriter, iter.Data(), iter.RemainingInSegment())) {
|
if (!JS_WriteBytes(aWriter, iter.Data(), iter.RemainingInSegment())) {
|
||||||
|
|
|
@ -26,8 +26,10 @@ public:
|
||||||
|
|
||||||
explicit StructuredCloneBlob();
|
explicit StructuredCloneBlob();
|
||||||
|
|
||||||
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader);
|
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||||
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter);
|
StructuredCloneHolder* aHolder);
|
||||||
|
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||||
|
StructuredCloneHolder* aHolder);
|
||||||
|
|
||||||
static already_AddRefed<StructuredCloneBlob>
|
static already_AddRefed<StructuredCloneBlob>
|
||||||
Constructor(GlobalObject& aGlobal, JS::HandleValue aValue, JS::HandleObject aTargetGlobal, ErrorResult& aRv);
|
Constructor(GlobalObject& aGlobal, JS::HandleValue aValue, JS::HandleObject aTargetGlobal, ErrorResult& aRv);
|
||||||
|
@ -47,7 +49,8 @@ protected:
|
||||||
~StructuredCloneBlob() = default;
|
~StructuredCloneBlob() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader);
|
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||||
|
StructuredCloneHolder* aHolder);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
|
|
|
@ -358,10 +358,6 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
|
||||||
return ReadStructuredCloneImageData(aCx, aReader);
|
return ReadStructuredCloneImageData(aCx, aReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
|
|
||||||
return StructuredCloneBlob::ReadStructuredClone(aCx, aReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
|
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
|
||||||
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||||
if (!global) {
|
if (!global) {
|
||||||
|
@ -458,14 +454,6 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if this is a StructuredCloneBlob object.
|
|
||||||
{
|
|
||||||
StructuredCloneBlob* holder = nullptr;
|
|
||||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, aObj, holder))) {
|
|
||||||
return holder->WriteStructuredClone(aCx, aWriter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle URLSearchParams cloning
|
// Handle URLSearchParams cloning
|
||||||
{
|
{
|
||||||
URLSearchParams* usp = nullptr;
|
URLSearchParams* usp = nullptr;
|
||||||
|
@ -999,6 +987,10 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
|
||||||
parent, GetSurfaces(), aIndex);
|
parent, GetSurfaces(), aIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
|
||||||
|
return StructuredCloneBlob::ReadStructuredClone(aCx, aReader, this);
|
||||||
|
}
|
||||||
|
|
||||||
if (aTag == SCTAG_DOM_WASM) {
|
if (aTag == SCTAG_DOM_WASM) {
|
||||||
return ReadWasmModule(aCx, aIndex, this);
|
return ReadWasmModule(aCx, aIndex, this);
|
||||||
}
|
}
|
||||||
|
@ -1062,6 +1054,14 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See if this is a StructuredCloneBlob object.
|
||||||
|
{
|
||||||
|
StructuredCloneBlob* holder = nullptr;
|
||||||
|
if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, aObj, holder))) {
|
||||||
|
return holder->WriteStructuredClone(aCx, aWriter, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// See if this is a WasmModule.
|
// See if this is a WasmModule.
|
||||||
if ((mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
|
if ((mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
|
||||||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) &&
|
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) &&
|
||||||
|
|
|
@ -54,7 +54,6 @@ Timeout::SetWhenOrTimeRemaining(const TimeStamp& aBaseTime,
|
||||||
if (mWindow->IsFrozen()) {
|
if (mWindow->IsFrozen()) {
|
||||||
mWhen = TimeStamp();
|
mWhen = TimeStamp();
|
||||||
mTimeRemaining = aDelay;
|
mTimeRemaining = aDelay;
|
||||||
mScheduledDelay = TimeDuration(0);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +62,6 @@ Timeout::SetWhenOrTimeRemaining(const TimeStamp& aBaseTime,
|
||||||
// that it appears time passes while suspended.
|
// that it appears time passes while suspended.
|
||||||
mWhen = aBaseTime + aDelay;
|
mWhen = aBaseTime + aDelay;
|
||||||
mTimeRemaining = TimeDuration(0);
|
mTimeRemaining = TimeDuration(0);
|
||||||
mScheduledDelay = aDelay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimeStamp&
|
const TimeStamp&
|
||||||
|
@ -84,12 +82,5 @@ Timeout::TimeRemaining() const
|
||||||
return mTimeRemaining;
|
return mTimeRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimeDuration&
|
|
||||||
Timeout::ScheduledDelay() const
|
|
||||||
{
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!mWhen.IsNull());
|
|
||||||
return mScheduledDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -50,9 +50,6 @@ public:
|
||||||
// Can only be called when frozen.
|
// Can only be called when frozen.
|
||||||
const TimeDuration& TimeRemaining() const;
|
const TimeDuration& TimeRemaining() const;
|
||||||
|
|
||||||
// Can only be called when not frozen.
|
|
||||||
const TimeDuration& ScheduledDelay() const;
|
|
||||||
|
|
||||||
// Window for which this timeout fires
|
// Window for which this timeout fires
|
||||||
RefPtr<nsGlobalWindow> mWindow;
|
RefPtr<nsGlobalWindow> mWindow;
|
||||||
|
|
||||||
|
@ -101,10 +98,6 @@ private:
|
||||||
// Remaining time to wait. Used only when timeouts are frozen.
|
// Remaining time to wait. Used only when timeouts are frozen.
|
||||||
TimeDuration mTimeRemaining;
|
TimeDuration mTimeRemaining;
|
||||||
|
|
||||||
// The actual interval in milliseconds. This may be throttled to
|
|
||||||
// a longer delay than mInterval for a number of reasons.
|
|
||||||
TimeDuration mScheduledDelay;
|
|
||||||
|
|
||||||
~Timeout() = default;
|
~Timeout() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,13 @@ TimeoutExecutor::ScheduleImmediate(const TimeStamp& aDeadline,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
||||||
const TimeStamp& aNow)
|
const TimeStamp& aNow,
|
||||||
|
const TimeDuration& aMinDelay)
|
||||||
{
|
{
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mDeadline.IsNull());
|
MOZ_DIAGNOSTIC_ASSERT(mDeadline.IsNull());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mMode == Mode::None);
|
MOZ_DIAGNOSTIC_ASSERT(mMode == Mode::None);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aDeadline > (aNow + mAllowedEarlyFiringTime));
|
MOZ_DIAGNOSTIC_ASSERT(!aMinDelay.IsZero() ||
|
||||||
|
aDeadline > (aNow + mAllowedEarlyFiringTime));
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
@ -65,6 +67,15 @@ TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
||||||
rv = mTimer->SetTarget(mOwner->EventTarget());
|
rv = mTimer->SetTarget(mOwner->EventTarget());
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Calculate the delay based on the deadline and current time. If we have
|
||||||
|
// a minimum delay set then clamp to that value.
|
||||||
|
//
|
||||||
|
// Note, we don't actually adjust our mDeadline for the minimum delay, just
|
||||||
|
// the nsITimer value. This is necessary to avoid lots of needless
|
||||||
|
// rescheduling if more deadlines come in between now and the minimum delay
|
||||||
|
// firing time.
|
||||||
|
TimeDuration delay = TimeDuration::Max(aMinDelay, aDeadline - aNow);
|
||||||
|
|
||||||
// Note, we cannot use the normal nsITimer init methods that take
|
// Note, we cannot use the normal nsITimer init methods that take
|
||||||
// integer milliseconds. We need higher precision. Consider this
|
// integer milliseconds. We need higher precision. Consider this
|
||||||
// situation:
|
// situation:
|
||||||
|
@ -83,7 +94,7 @@ TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
||||||
// schedule a new nsITimer for g(). Its only 500us in the future, though. We
|
// schedule a new nsITimer for g(). Its only 500us in the future, though. We
|
||||||
// must be able to pass this fractional value to nsITimer in order to get an
|
// must be able to pass this fractional value to nsITimer in order to get an
|
||||||
// accurate wakeup time.
|
// accurate wakeup time.
|
||||||
rv = mTimer->InitHighResolutionWithCallback(this, aDeadline - aNow,
|
rv = mTimer->InitHighResolutionWithCallback(this, delay,
|
||||||
nsITimer::TYPE_ONE_SHOT);
|
nsITimer::TYPE_ONE_SHOT);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
@ -94,22 +105,24 @@ TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
TimeoutExecutor::Schedule(const TimeStamp& aDeadline)
|
TimeoutExecutor::Schedule(const TimeStamp& aDeadline,
|
||||||
|
const TimeDuration& aMinDelay)
|
||||||
{
|
{
|
||||||
TimeStamp now(TimeStamp::Now());
|
TimeStamp now(TimeStamp::Now());
|
||||||
|
|
||||||
// Schedule an immediate runnable if the desired deadline has passed
|
// Schedule an immediate runnable if the desired deadline has passed
|
||||||
// or is slightly in the future. This is similar to how nsITimer will
|
// or is slightly in the future. This is similar to how nsITimer will
|
||||||
// fire timers early based on the interval resolution.
|
// fire timers early based on the interval resolution.
|
||||||
if (aDeadline <= (now + mAllowedEarlyFiringTime)) {
|
if (aMinDelay.IsZero() && aDeadline <= (now + mAllowedEarlyFiringTime)) {
|
||||||
return ScheduleImmediate(aDeadline, now);
|
return ScheduleImmediate(aDeadline, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScheduleDelayed(aDeadline, now);
|
return ScheduleDelayed(aDeadline, now, aMinDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
TimeoutExecutor::MaybeReschedule(const TimeStamp& aDeadline)
|
TimeoutExecutor::MaybeReschedule(const TimeStamp& aDeadline,
|
||||||
|
const TimeDuration& aMinDelay)
|
||||||
{
|
{
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!mDeadline.IsNull());
|
MOZ_DIAGNOSTIC_ASSERT(!mDeadline.IsNull());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mMode == Mode::Immediate ||
|
MOZ_DIAGNOSTIC_ASSERT(mMode == Mode::Immediate ||
|
||||||
|
@ -127,7 +140,7 @@ TimeoutExecutor::MaybeReschedule(const TimeStamp& aDeadline)
|
||||||
}
|
}
|
||||||
|
|
||||||
Cancel();
|
Cancel();
|
||||||
return Schedule(aDeadline);
|
return Schedule(aDeadline, aMinDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -176,7 +189,8 @@ TimeoutExecutor::Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
TimeoutExecutor::MaybeSchedule(const TimeStamp& aDeadline)
|
TimeoutExecutor::MaybeSchedule(const TimeStamp& aDeadline,
|
||||||
|
const TimeDuration& aMinDelay)
|
||||||
{
|
{
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!aDeadline.IsNull());
|
MOZ_DIAGNOSTIC_ASSERT(!aDeadline.IsNull());
|
||||||
|
|
||||||
|
@ -185,10 +199,10 @@ TimeoutExecutor::MaybeSchedule(const TimeStamp& aDeadline)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMode == Mode::Immediate || mMode == Mode::Delayed) {
|
if (mMode == Mode::Immediate || mMode == Mode::Delayed) {
|
||||||
return MaybeReschedule(aDeadline);
|
return MaybeReschedule(aDeadline, aMinDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Schedule(aDeadline);
|
return Schedule(aDeadline, aMinDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -56,13 +56,14 @@ class TimeoutExecutor final : public nsIRunnable
|
||||||
ScheduleImmediate(const TimeStamp& aDeadline, const TimeStamp& aNow);
|
ScheduleImmediate(const TimeStamp& aDeadline, const TimeStamp& aNow);
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ScheduleDelayed(const TimeStamp& aDeadline, const TimeStamp& aNow);
|
ScheduleDelayed(const TimeStamp& aDeadline, const TimeStamp& aNow,
|
||||||
|
const TimeDuration& aMinDelay);
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
Schedule(const TimeStamp& aDeadline);
|
Schedule(const TimeStamp& aDeadline, const TimeDuration& aMinDelay);
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
MaybeReschedule(const TimeStamp& aDeadline);
|
MaybeReschedule(const TimeStamp& aDeadline, const TimeDuration& aMinDelay);
|
||||||
|
|
||||||
void
|
void
|
||||||
MaybeExecute();
|
MaybeExecute();
|
||||||
|
@ -74,7 +75,7 @@ public:
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
MaybeSchedule(const TimeStamp& aDeadline);
|
MaybeSchedule(const TimeStamp& aDeadline, const TimeDuration& aMinDelay);
|
||||||
|
|
||||||
void
|
void
|
||||||
Cancel();
|
Cancel();
|
||||||
|
|
|
@ -146,6 +146,9 @@ const uint32_t TimeoutManager::InvalidFiringId = 0;
|
||||||
bool
|
bool
|
||||||
TimeoutManager::IsBackground() const
|
TimeoutManager::IsBackground() const
|
||||||
{
|
{
|
||||||
|
// Don't use the background timeout value when the tab is playing audio.
|
||||||
|
// Until bug 1336484 we only used to do this for pages that use Web Audio.
|
||||||
|
// The original behavior was implemented in bug 11811073.
|
||||||
return !mWindow.AsInner()->IsPlayingAudio() && mWindow.IsBackgroundInternal();
|
return !mWindow.AsInner()->IsPlayingAudio() && mWindow.IsBackgroundInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +180,15 @@ TimeoutManager::IsValidFiringId(uint32_t aFiringId) const
|
||||||
return !IsInvalidFiringId(aFiringId);
|
return !IsInvalidFiringId(aFiringId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TimeDuration
|
||||||
|
TimeoutManager::MinSchedulingDelay() const
|
||||||
|
{
|
||||||
|
if (IsBackground()) {
|
||||||
|
return TimeDuration::FromMilliseconds(gMinBackgroundTimeoutValue);
|
||||||
|
}
|
||||||
|
return TimeDuration();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TimeoutManager::IsInvalidFiringId(uint32_t aFiringId) const
|
TimeoutManager::IsInvalidFiringId(uint32_t aFiringId) const
|
||||||
{
|
{
|
||||||
|
@ -218,15 +230,9 @@ TimeoutManager::IsInvalidFiringId(uint32_t aFiringId) const
|
||||||
|
|
||||||
int32_t
|
int32_t
|
||||||
TimeoutManager::DOMMinTimeoutValue(bool aIsTracking) const {
|
TimeoutManager::DOMMinTimeoutValue(bool aIsTracking) const {
|
||||||
// Don't use the background timeout value when the tab is playing audio.
|
|
||||||
// Until bug 1336484 we only used to do this for pages that use Web Audio.
|
|
||||||
// The original behavior was implemented in bug 11811073.
|
|
||||||
bool isBackground = IsBackground();
|
|
||||||
bool throttleTracking = aIsTracking && mThrottleTrackingTimeouts;
|
bool throttleTracking = aIsTracking && mThrottleTrackingTimeouts;
|
||||||
auto minValue = throttleTracking ? (isBackground ? gMinTrackingBackgroundTimeoutValue
|
auto minValue = throttleTracking ? gMinTrackingTimeoutValue
|
||||||
: gMinTrackingTimeoutValue)
|
: gMinTimeoutValue;
|
||||||
: (isBackground ? gMinBackgroundTimeoutValue
|
|
||||||
: gMinTimeoutValue);
|
|
||||||
return minValue;
|
return minValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,7 +415,6 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
||||||
uint32_t nestingLevel = sNestingLevel + 1;
|
uint32_t nestingLevel = sNestingLevel + 1;
|
||||||
uint32_t realInterval = interval;
|
uint32_t realInterval = interval;
|
||||||
if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL ||
|
if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL ||
|
||||||
mWindow.IsBackgroundInternal() ||
|
|
||||||
timeout->mIsTracking) {
|
timeout->mIsTracking) {
|
||||||
// Don't allow timeouts less than DOMMinTimeoutValue() from
|
// Don't allow timeouts less than DOMMinTimeoutValue() from
|
||||||
// now...
|
// now...
|
||||||
|
@ -424,7 +429,8 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
||||||
|
|
||||||
// If we're not suspended, then set the timer.
|
// If we're not suspended, then set the timer.
|
||||||
if (!mWindow.IsSuspended()) {
|
if (!mWindow.IsSuspended()) {
|
||||||
nsresult rv = mExecutor->MaybeSchedule(timeout->When());
|
nsresult rv = mExecutor->MaybeSchedule(timeout->When(),
|
||||||
|
MinSchedulingDelay());
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -476,7 +482,7 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
||||||
mThrottleTrackingTimeouts ? "yes"
|
mThrottleTrackingTimeouts ? "yes"
|
||||||
: (mThrottleTrackingTimeoutsTimer ?
|
: (mThrottleTrackingTimeoutsTimer ?
|
||||||
"pending" : "no"),
|
"pending" : "no"),
|
||||||
int(mWindow.IsBackgroundInternal()), realInterval,
|
int(IsBackground()), realInterval,
|
||||||
timeout->mIsTracking ? "" : "non-",
|
timeout->mIsTracking ? "" : "non-",
|
||||||
timeout->mTimeoutId));
|
timeout->mTimeoutId));
|
||||||
|
|
||||||
|
@ -535,7 +541,8 @@ TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason)
|
||||||
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
|
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
|
||||||
Timeout* nextTimeout = iter.Next();
|
Timeout* nextTimeout = iter.Next();
|
||||||
if (nextTimeout) {
|
if (nextTimeout) {
|
||||||
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextTimeout->When()));
|
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextTimeout->When(),
|
||||||
|
MinSchedulingDelay()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,7 +660,8 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
|
||||||
// method and the window should not have been suspended while
|
// method and the window should not have been suspended while
|
||||||
// executing the loop above since it doesn't call out to js.
|
// executing the loop above since it doesn't call out to js.
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!mWindow.IsSuspended());
|
MOZ_DIAGNOSTIC_ASSERT(!mWindow.IsSuspended());
|
||||||
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextDeadline));
|
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextDeadline,
|
||||||
|
MinSchedulingDelay()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maybe the timeout that the event was fired for has been deleted
|
// Maybe the timeout that the event was fired for has been deleted
|
||||||
|
@ -777,7 +785,8 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
|
||||||
if (!mWindow.IsSuspended()) {
|
if (!mWindow.IsSuspended()) {
|
||||||
RefPtr<Timeout> timeout = runIter.Next();
|
RefPtr<Timeout> timeout = runIter.Next();
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(timeout->When()));
|
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(timeout->When(),
|
||||||
|
MinSchedulingDelay()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -818,132 +827,13 @@ TimeoutManager::RescheduleTimeout(Timeout* aTimeout, const TimeStamp& now)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = mExecutor->MaybeSchedule(aTimeout->When());
|
nsresult rv = mExecutor->MaybeSchedule(aTimeout->When(),
|
||||||
|
MinSchedulingDelay());
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
TimeoutManager::ResetTimersForThrottleReduction()
|
|
||||||
{
|
|
||||||
return ResetTimersForThrottleReduction(gMinBackgroundTimeoutValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
TimeoutManager::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aPreviousThrottleDelayMS > 0);
|
|
||||||
|
|
||||||
MOZ_ASSERT_IF(mWindow.IsFrozen(), mWindow.IsSuspended());
|
|
||||||
if (mWindow.IsSuspended()) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = mNormalTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
|
||||||
*this,
|
|
||||||
Timeouts::SortBy::TimeWhen);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rv = mTrackingTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
|
||||||
*this,
|
|
||||||
Timeouts::SortBy::TimeWhen);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
|
|
||||||
Timeout* firstTimeout = iter.Next();
|
|
||||||
if (firstTimeout) {
|
|
||||||
rv = mExecutor->MaybeSchedule(firstTimeout->When());
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
|
||||||
const TimeoutManager& aTimeoutManager,
|
|
||||||
SortBy aSortBy)
|
|
||||||
{
|
|
||||||
TimeStamp now = TimeStamp::Now();
|
|
||||||
|
|
||||||
for (RefPtr<Timeout> timeout = GetFirst(); timeout; ) {
|
|
||||||
// Skip over any Timeout values with a valid FiringId. These are in the
|
|
||||||
// middle of a RunTimeout and should not be modified. Also, skip any
|
|
||||||
// timeouts in the past. It's important that this check be <= so that we
|
|
||||||
// guarantee that taking std::max with |now| won't make a quantity equal to
|
|
||||||
// timeout->When() below.
|
|
||||||
if (mManager.IsValidFiringId(timeout->mFiringId) ||
|
|
||||||
timeout->When() <= now) {
|
|
||||||
timeout = timeout->getNext();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout->When() - now >
|
|
||||||
TimeDuration::FromMilliseconds(aPreviousThrottleDelayMS)) {
|
|
||||||
// No need to loop further. Timeouts are sorted in When() order
|
|
||||||
// and the ones after this point were all set up for at least
|
|
||||||
// gMinBackgroundTimeoutValue ms and hence were not clamped.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We reduced our throttled delay. Re-init the timer appropriately.
|
|
||||||
// Compute the interval the timer should have had if it had not been set in a
|
|
||||||
// background window
|
|
||||||
TimeDuration interval =
|
|
||||||
TimeDuration::FromMilliseconds(
|
|
||||||
std::max(timeout->mInterval,
|
|
||||||
uint32_t(aTimeoutManager.
|
|
||||||
DOMMinTimeoutValue(timeout->mIsTracking))));
|
|
||||||
const TimeDuration& oldInterval = timeout->ScheduledDelay();
|
|
||||||
if (oldInterval > interval) {
|
|
||||||
// unclamp
|
|
||||||
TimeStamp firingTime =
|
|
||||||
std::max(timeout->When() - oldInterval + interval, now);
|
|
||||||
|
|
||||||
NS_ASSERTION(firingTime < timeout->When(),
|
|
||||||
"Our firing time should strictly decrease!");
|
|
||||||
|
|
||||||
TimeDuration delay = firingTime - now;
|
|
||||||
timeout->SetWhenOrTimeRemaining(now, delay);
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(timeout->When() == firingTime);
|
|
||||||
|
|
||||||
// Since we reset When() we need to move |timeout| to the right
|
|
||||||
// place in the list so that it remains sorted by When().
|
|
||||||
|
|
||||||
// Get the pointer to the next timeout now, before we move the
|
|
||||||
// current timeout in the list.
|
|
||||||
Timeout* nextTimeout = timeout->getNext();
|
|
||||||
|
|
||||||
// Since we are only reducing intervals in this method we can
|
|
||||||
// make an optimization here. If the reduction does not cause us
|
|
||||||
// to fall before our previous timeout then we do not have to
|
|
||||||
// remove and re-insert the current timeout. This is important
|
|
||||||
// because re-insertion makes this algorithm O(n^2). Since we
|
|
||||||
// will typically be shifting a lot of timers at once this
|
|
||||||
// optimization saves us a lot of work.
|
|
||||||
Timeout* prevTimeout = timeout->getPrevious();
|
|
||||||
if (prevTimeout && prevTimeout->When() > timeout->When()) {
|
|
||||||
// It is safe to remove and re-insert because When() is now
|
|
||||||
// strictly smaller than it used to be, so we know we'll insert
|
|
||||||
// |timeout| before nextTimeout.
|
|
||||||
NS_ASSERTION(!nextTimeout ||
|
|
||||||
timeout->When() < nextTimeout->When(), "How did that happen?");
|
|
||||||
timeout->remove();
|
|
||||||
// Insert() will reset mFiringId. Make sure to undo that.
|
|
||||||
uint32_t firingId = timeout->mFiringId;
|
|
||||||
Insert(timeout, aSortBy);
|
|
||||||
timeout->mFiringId = firingId;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout = nextTimeout;
|
|
||||||
} else {
|
|
||||||
timeout = timeout->getNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimeoutManager::ClearAllTimeouts()
|
TimeoutManager::ClearAllTimeouts()
|
||||||
{
|
{
|
||||||
|
@ -1112,7 +1002,8 @@ TimeoutManager::Resume()
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!nextWakeUp.IsNull()) {
|
if (!nextWakeUp.IsNull()) {
|
||||||
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextWakeUp));
|
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextWakeUp,
|
||||||
|
MinSchedulingDelay()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1152,6 +1043,24 @@ TimeoutManager::Thaw()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimeoutManager::UpdateBackgroundState()
|
||||||
|
{
|
||||||
|
// When the window moves to the background or foreground we should
|
||||||
|
// reschedule the TimeoutExecutor in case the MinSchedulingDelay()
|
||||||
|
// changed. Only do this if the window is not suspended and we
|
||||||
|
// actually have a timeout.
|
||||||
|
if (!mWindow.IsSuspended()) {
|
||||||
|
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
|
||||||
|
Timeout* nextTimeout = iter.Next();
|
||||||
|
if (nextTimeout) {
|
||||||
|
mExecutor->Cancel();
|
||||||
|
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(nextTimeout->When(),
|
||||||
|
MinSchedulingDelay()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TimeoutManager::IsTimeoutTracking(uint32_t aTimeoutId)
|
TimeoutManager::IsTimeoutTracking(uint32_t aTimeoutId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,11 +55,6 @@ public:
|
||||||
void ClearAllTimeouts();
|
void ClearAllTimeouts();
|
||||||
uint32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);
|
uint32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);
|
||||||
|
|
||||||
// When timers are being throttled and we reduce the thottle delay we must
|
|
||||||
// reschedule. The amount of the old throttle delay must be provided in
|
|
||||||
// order to bound how many timers must be examined.
|
|
||||||
nsresult ResetTimersForThrottleReduction();
|
|
||||||
|
|
||||||
int32_t DOMMinTimeoutValue(bool aIsTracking) const;
|
int32_t DOMMinTimeoutValue(bool aIsTracking) const;
|
||||||
|
|
||||||
// aTimeout is the timeout that we're about to start running. This function
|
// aTimeout is the timeout that we're about to start running. This function
|
||||||
|
@ -77,6 +72,10 @@ public:
|
||||||
void Freeze();
|
void Freeze();
|
||||||
void Thaw();
|
void Thaw();
|
||||||
|
|
||||||
|
// This should be called by nsGlobalWindow when the window might have moved
|
||||||
|
// to the background or foreground.
|
||||||
|
void UpdateBackgroundState();
|
||||||
|
|
||||||
// Initialize TimeoutManager before the first time it is accessed.
|
// Initialize TimeoutManager before the first time it is accessed.
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
|
|
||||||
|
@ -116,7 +115,6 @@ public:
|
||||||
static const uint32_t InvalidFiringId;
|
static const uint32_t InvalidFiringId;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS);
|
|
||||||
void MaybeStartThrottleTrackingTimout();
|
void MaybeStartThrottleTrackingTimout();
|
||||||
|
|
||||||
bool IsBackground() const;
|
bool IsBackground() const;
|
||||||
|
@ -133,6 +131,9 @@ private:
|
||||||
bool
|
bool
|
||||||
IsInvalidFiringId(uint32_t aFiringId) const;
|
IsInvalidFiringId(uint32_t aFiringId) const;
|
||||||
|
|
||||||
|
TimeDuration
|
||||||
|
MinSchedulingDelay() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Timeouts {
|
struct Timeouts {
|
||||||
explicit Timeouts(const TimeoutManager& aManager)
|
explicit Timeouts(const TimeoutManager& aManager)
|
||||||
|
@ -149,9 +150,6 @@ private:
|
||||||
TimeWhen
|
TimeWhen
|
||||||
};
|
};
|
||||||
void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
|
void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
|
||||||
nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
|
||||||
const TimeoutManager& aTimeoutManager,
|
|
||||||
SortBy aSortBy);
|
|
||||||
|
|
||||||
const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
|
const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
|
||||||
Timeout* GetFirst() { return mTimeoutList.getFirst(); }
|
Timeout* GetFirst() { return mTimeoutList.getFirst(); }
|
||||||
|
|
|
@ -9640,10 +9640,11 @@ nsDocument::MaybePreconnect(nsIURI* aOrigURI, mozilla::CORSMode aCORSMode)
|
||||||
uri->SetPath(NS_LITERAL_CSTRING("/"));
|
uri->SetPath(NS_LITERAL_CSTRING("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPreloadedPreconnects.Contains(uri)) {
|
auto entry = mPreloadedPreconnects.LookupForAdd(uri);
|
||||||
return;
|
if (entry) {
|
||||||
|
return; // we found an existing entry
|
||||||
}
|
}
|
||||||
mPreloadedPreconnects.Put(uri, true);
|
entry.OrInsert([] () { return true; });
|
||||||
|
|
||||||
nsCOMPtr<nsISpeculativeConnect>
|
nsCOMPtr<nsISpeculativeConnect>
|
||||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||||
|
|
|
@ -350,6 +350,45 @@ GK_ATOM(displayMode, "display-mode")
|
||||||
GK_ATOM(distinct, "distinct")
|
GK_ATOM(distinct, "distinct")
|
||||||
GK_ATOM(div, "div")
|
GK_ATOM(div, "div")
|
||||||
GK_ATOM(dl, "dl")
|
GK_ATOM(dl, "dl")
|
||||||
|
GK_ATOM(docAbstract, "doc-abstract")
|
||||||
|
GK_ATOM(docAcknowledgments, "doc-acknowledgments")
|
||||||
|
GK_ATOM(docAfterword, "doc-afterword")
|
||||||
|
GK_ATOM(docAppendix, "doc-appendix")
|
||||||
|
GK_ATOM(docBacklink, "doc-backlink")
|
||||||
|
GK_ATOM(docBiblioentry, "doc-biblioentry")
|
||||||
|
GK_ATOM(docBibliography, "doc-bibliography")
|
||||||
|
GK_ATOM(docBiblioref, "doc-biblioref")
|
||||||
|
GK_ATOM(docChapter, "doc-chapter")
|
||||||
|
GK_ATOM(docColophon, "doc-colophon")
|
||||||
|
GK_ATOM(docConclusion, "doc-conclusion")
|
||||||
|
GK_ATOM(docCover, "doc-cover")
|
||||||
|
GK_ATOM(docCredit, "doc-credit")
|
||||||
|
GK_ATOM(docCredits, "doc-credits")
|
||||||
|
GK_ATOM(docDedication, "doc-dedication")
|
||||||
|
GK_ATOM(docEndnote, "doc-endnote")
|
||||||
|
GK_ATOM(docEndnotes, "doc-endnotes")
|
||||||
|
GK_ATOM(docEpigraph, "doc-epigraph")
|
||||||
|
GK_ATOM(docEpilogue, "doc-epilogue")
|
||||||
|
GK_ATOM(docErrata, "doc-errata")
|
||||||
|
GK_ATOM(docExample, "doc-example")
|
||||||
|
GK_ATOM(docFootnote, "doc-footnote")
|
||||||
|
GK_ATOM(docForeword, "doc-foreword")
|
||||||
|
GK_ATOM(docGlossary, "doc-glossary")
|
||||||
|
GK_ATOM(docGlossref, "doc-glossref")
|
||||||
|
GK_ATOM(docIndex, "doc-index")
|
||||||
|
GK_ATOM(docIntroduction, "doc-introduction")
|
||||||
|
GK_ATOM(docNoteref, "doc-noteref")
|
||||||
|
GK_ATOM(docNotice, "doc-notice")
|
||||||
|
GK_ATOM(docPagebreak, "doc-pagebreak")
|
||||||
|
GK_ATOM(docPagelist, "doc-pagelist")
|
||||||
|
GK_ATOM(docPart, "doc-part")
|
||||||
|
GK_ATOM(docPreface, "doc-preface")
|
||||||
|
GK_ATOM(docPrologue, "doc-prologue")
|
||||||
|
GK_ATOM(docPullquote, "doc-pullquote")
|
||||||
|
GK_ATOM(docQna, "doc-qna")
|
||||||
|
GK_ATOM(docSubtitle, "doc-subtitle")
|
||||||
|
GK_ATOM(docTip, "doc-tip")
|
||||||
|
GK_ATOM(docToc, "doc-toc")
|
||||||
GK_ATOM(doctypePublic, "doctype-public")
|
GK_ATOM(doctypePublic, "doctype-public")
|
||||||
GK_ATOM(doctypeSystem, "doctype-system")
|
GK_ATOM(doctypeSystem, "doctype-system")
|
||||||
GK_ATOM(document, "document")
|
GK_ATOM(document, "document")
|
||||||
|
|
|
@ -10671,13 +10671,16 @@ void nsGlobalWindow::SetIsBackground(bool aIsBackground)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsOuterWindow());
|
MOZ_ASSERT(IsOuterWindow());
|
||||||
|
|
||||||
bool resetTimers = (!aIsBackground && AsOuter()->IsBackground());
|
bool changed = aIsBackground != AsOuter()->IsBackground();
|
||||||
SetIsBackgroundInternal(aIsBackground);
|
SetIsBackgroundInternal(aIsBackground);
|
||||||
|
|
||||||
nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
|
nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
|
||||||
|
|
||||||
|
if (inner && changed) {
|
||||||
|
inner->mTimeoutManager->UpdateBackgroundState();
|
||||||
|
}
|
||||||
|
|
||||||
if (aIsBackground) {
|
if (aIsBackground) {
|
||||||
MOZ_ASSERT(!resetTimers);
|
|
||||||
// Notify gamepadManager we are at the background window,
|
// Notify gamepadManager we are at the background window,
|
||||||
// we need to stop vibrate.
|
// we need to stop vibrate.
|
||||||
if (inner) {
|
if (inner) {
|
||||||
|
@ -10685,9 +10688,6 @@ void nsGlobalWindow::SetIsBackground(bool aIsBackground)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (inner) {
|
} else if (inner) {
|
||||||
if (resetTimers) {
|
|
||||||
inner->mTimeoutManager->ResetTimersForThrottleReduction();
|
|
||||||
}
|
|
||||||
inner->SyncGamepadState();
|
inner->SyncGamepadState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,19 @@ var testURLs = [
|
||||||
|
|
||||||
// We want to ensure that while audio is being played back, a background tab is
|
// We want to ensure that while audio is being played back, a background tab is
|
||||||
// treated the same as a foreground tab as far as timeout throttling is concerned.
|
// treated the same as a foreground tab as far as timeout throttling is concerned.
|
||||||
// So we use a 10ms minimum timeout value for foreground tabs and a 100,000 second
|
// So we use a 100,000 second minimum timeout value for background tabs. This
|
||||||
// minimum timeout value for background tabs. This means that in case the test
|
// means that in case the test fails, it will time out in practice, but just for
|
||||||
// fails, it will time out in practice, but just for sanity the test condition
|
// sanity the test condition ensures that the observed timeout delay falls in
|
||||||
// ensures that the observed timeout delay falls in this range.
|
// this range.
|
||||||
const kMinTimeoutForeground = 10;
|
|
||||||
const kMinTimeoutBackground = 100 * 1000 * 1000;
|
const kMinTimeoutBackground = 100 * 1000 * 1000;
|
||||||
|
|
||||||
|
const kDelay = 10;
|
||||||
|
|
||||||
|
// Allow a very generous error range due to debug automation tests running
|
||||||
|
// very slowly. This is still far below the configured background throttle
|
||||||
|
// amount.
|
||||||
|
const kAllowedError = 1000;
|
||||||
|
|
||||||
Services.scriptloader.loadSubScript(kPluginJS, this);
|
Services.scriptloader.loadSubScript(kPluginJS, this);
|
||||||
|
|
||||||
function* runTest(url) {
|
function* runTest(url) {
|
||||||
|
@ -31,19 +37,16 @@ function* runTest(url) {
|
||||||
// Put the tab in the background.
|
// Put the tab in the background.
|
||||||
yield BrowserTestUtils.switchTab(gBrowser, currentTab);
|
yield BrowserTestUtils.switchTab(gBrowser, currentTab);
|
||||||
|
|
||||||
let timeout = yield ContentTask.spawn(newBrowser, {}, function() {
|
let timeout = yield ContentTask.spawn(newBrowser, kDelay, function(delay) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
let before = new Date();
|
let before = new Date();
|
||||||
content.window.setTimeout(function() {
|
content.window.setTimeout(function() {
|
||||||
let after = new Date();
|
let after = new Date();
|
||||||
// Sometimes due to rounding errors, we may get a result of 9ms here, so
|
resolve(after - before);
|
||||||
// let's round up by 1 to protect against such intermittent failures.
|
}, delay);
|
||||||
resolve(after - before + 1);
|
|
||||||
}, 0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ok(timeout >= kMinTimeoutForeground &&
|
ok(timeout <= kDelay + kAllowedError, `Got the correct timeout (${timeout}`);
|
||||||
timeout < kMinTimeoutBackground, `Got the correct timeout (${timeout})`);
|
|
||||||
|
|
||||||
// All done.
|
// All done.
|
||||||
yield BrowserTestUtils.removeTab(newTab);
|
yield BrowserTestUtils.removeTab(newTab);
|
||||||
|
@ -51,7 +54,6 @@ function* runTest(url) {
|
||||||
|
|
||||||
add_task(function* setup() {
|
add_task(function* setup() {
|
||||||
yield SpecialPowers.pushPrefEnv({"set": [
|
yield SpecialPowers.pushPrefEnv({"set": [
|
||||||
["dom.min_timeout_value", kMinTimeoutForeground],
|
|
||||||
["dom.min_background_timeout_value", kMinTimeoutBackground],
|
["dom.min_background_timeout_value", kMinTimeoutBackground],
|
||||||
]});
|
]});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1593,6 +1593,8 @@ EventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
|
||||||
nsAutoString eventType;
|
nsAutoString eventType;
|
||||||
if (listener.mAllEvents) {
|
if (listener.mAllEvents) {
|
||||||
eventType.SetIsVoid(true);
|
eventType.SetIsVoid(true);
|
||||||
|
} else if (listener.mListenerType == Listener::eNoListener) {
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
eventType.Assign(Substring(nsDependentAtomString(listener.mTypeAtom), 2));
|
eventType.Assign(Substring(nsDependentAtomString(listener.mTypeAtom), 2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,14 +453,16 @@ already_AddRefed<ParticularProcessPriorityManager>
|
||||||
ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
|
ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
|
||||||
ContentParent* aContentParent)
|
ContentParent* aContentParent)
|
||||||
{
|
{
|
||||||
RefPtr<ParticularProcessPriorityManager> pppm;
|
|
||||||
uint64_t cpId = aContentParent->ChildID();
|
uint64_t cpId = aContentParent->ChildID();
|
||||||
mParticularManagers.Get(cpId, &pppm);
|
auto entry = mParticularManagers.LookupForAdd(cpId);
|
||||||
if (!pppm) {
|
RefPtr<ParticularProcessPriorityManager> pppm = entry.OrInsert(
|
||||||
pppm = new ParticularProcessPriorityManager(aContentParent);
|
[aContentParent]() {
|
||||||
pppm->Init();
|
return new ParticularProcessPriorityManager(aContentParent);
|
||||||
mParticularManagers.Put(cpId, pppm);
|
});
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
// We created a new entry.
|
||||||
|
pppm->Init();
|
||||||
FireTestOnlyObserverNotification("process-created",
|
FireTestOnlyObserverNotification("process-created",
|
||||||
nsPrintfCString("%" PRIu64, cpId));
|
nsPrintfCString("%" PRIu64, cpId));
|
||||||
}
|
}
|
||||||
|
@ -501,15 +503,12 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
|
||||||
props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
|
props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
|
||||||
NS_ENSURE_TRUE_VOID(childID != CONTENT_PROCESS_ID_UNKNOWN);
|
NS_ENSURE_TRUE_VOID(childID != CONTENT_PROCESS_ID_UNKNOWN);
|
||||||
|
|
||||||
RefPtr<ParticularProcessPriorityManager> pppm;
|
mParticularManagers.LookupRemoveIf(childID,
|
||||||
mParticularManagers.Get(childID, &pppm);
|
[this, childID] (RefPtr<ParticularProcessPriorityManager>& aValue) {
|
||||||
if (pppm) {
|
aValue->ShutDown();
|
||||||
pppm->ShutDown();
|
mHighPriorityChildIDs.RemoveEntry(childID);
|
||||||
|
return true; // remove it
|
||||||
mParticularManagers.Remove(childID);
|
});
|
||||||
|
|
||||||
mHighPriorityChildIDs.RemoveEntry(childID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -574,14 +574,14 @@ MediaCacheStream::BlockList::NotifyBlockSwapped(int32_t aBlockIndex1,
|
||||||
if (e1) {
|
if (e1) {
|
||||||
e1Prev = e1->mPrevBlock;
|
e1Prev = e1->mPrevBlock;
|
||||||
e1Next = e1->mNextBlock;
|
e1Next = e1->mNextBlock;
|
||||||
mEntries.RemoveEntry(aBlockIndex1);
|
mEntries.RemoveEntry(e1);
|
||||||
// Refresh pointer after hashtable mutation.
|
// Refresh pointer after hashtable mutation.
|
||||||
e2 = mEntries.GetEntry(aBlockIndex2);
|
e2 = mEntries.GetEntry(aBlockIndex2);
|
||||||
}
|
}
|
||||||
if (e2) {
|
if (e2) {
|
||||||
e2Prev = e2->mPrevBlock;
|
e2Prev = e2->mPrevBlock;
|
||||||
e2Next = e2->mNextBlock;
|
e2Next = e2->mNextBlock;
|
||||||
mEntries.RemoveEntry(aBlockIndex2);
|
mEntries.RemoveEntry(e2);
|
||||||
}
|
}
|
||||||
// Put new entries back.
|
// Put new entries back.
|
||||||
if (e1) {
|
if (e1) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define VideoUtils_h
|
#define VideoUtils_h
|
||||||
|
|
||||||
#include "MediaInfo.h"
|
#include "MediaInfo.h"
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "mozilla/MozPromise.h"
|
#include "mozilla/MozPromise.h"
|
||||||
|
|
|
@ -19,7 +19,6 @@ UNIFIED_SOURCES += [
|
||||||
'TestMediaDataDecoder.cpp',
|
'TestMediaDataDecoder.cpp',
|
||||||
'TestMediaEventSource.cpp',
|
'TestMediaEventSource.cpp',
|
||||||
'TestMediaMIMETypes.cpp',
|
'TestMediaMIMETypes.cpp',
|
||||||
'TestMozPromise.cpp',
|
|
||||||
'TestMP3Demuxer.cpp',
|
'TestMP3Demuxer.cpp',
|
||||||
'TestMP4Demuxer.cpp',
|
'TestMP4Demuxer.cpp',
|
||||||
'TestRust.cpp',
|
'TestRust.cpp',
|
||||||
|
|
|
@ -42,6 +42,9 @@ public:
|
||||||
mTaskQueue->Dispatch(Move(aRunnable), aFailureHandling, aReason);
|
mTaskQueue->Dispatch(Move(aRunnable), aFailureHandling, aReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent a GCC warning about the other overload of Dispatch being hidden.
|
||||||
|
using AbstractThread::Dispatch;
|
||||||
|
|
||||||
// Blocks until all tasks finish executing.
|
// Blocks until all tasks finish executing.
|
||||||
void AwaitIdle() { mTaskQueue->AwaitIdle(); }
|
void AwaitIdle() { mTaskQueue->AwaitIdle(); }
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include "mozilla/dom/EncodingUtils.h"
|
#include "mozilla/dom/EncodingUtils.h"
|
||||||
#include "mozilla/ConsoleReportCollector.h"
|
#include "mozilla/ConsoleReportCollector.h"
|
||||||
|
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/AsyncEventDispatcher.h"
|
#include "mozilla/AsyncEventDispatcher.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
|
|
|
@ -228,6 +228,11 @@
|
||||||
stroke="black" stroke-width="8" stroke-linejoin="round" fill="lightcyan"
|
stroke="black" stroke-width="8" stroke-linejoin="round" fill="lightcyan"
|
||||||
clip-path="url('#circle7')" marker-mid="url(#m_atr)"/>
|
clip-path="url('#circle7')" marker-mid="url(#m_atr)"/>
|
||||||
|
|
||||||
|
<path id="path13" d="M50,0 C 130,0 50,0 100,50
|
||||||
|
C 100,130 100,50 50,100
|
||||||
|
C -30,100 50,100 0,50
|
||||||
|
C 0,-30 0,50 50,0Z" />
|
||||||
|
|
||||||
<!-- use -->
|
<!-- use -->
|
||||||
<use id="use1" xlink:href="#rect-10" x="50" y="50" clip-path="url('#circle8')"/>
|
<use id="use1" xlink:href="#rect-10" x="50" y="50" clip-path="url('#circle8')"/>
|
||||||
<use id="use2" xlink:href="#rect-11" x="50" y="50" clip-path="url('#circle9')"/>
|
<use id="use2" xlink:href="#rect-11" x="50" y="50" clip-path="url('#circle9')"/>
|
||||||
|
|
До Ширина: | Высота: | Размер: 20 KiB После Ширина: | Высота: | Размер: 20 KiB |
|
@ -162,6 +162,7 @@ function run()
|
||||||
checkBBox("path10", opt, 10,25,100,75, 0);
|
checkBBox("path10", opt, 10,25,100,75, 0);
|
||||||
checkBBox("path11", opt, 160,25,100,75, 0);
|
checkBBox("path11", opt, 160,25,100,75, 0);
|
||||||
checkBBox("path12", opt, 10,125,100,75, 0);
|
checkBBox("path12", opt, 10,125,100,75, 0);
|
||||||
|
checkBBox("path13", opt, 0,0,100,100, 0);
|
||||||
|
|
||||||
opt = { fill: false, stroke: true, markers: false, clipped: false };
|
opt = { fill: false, stroke: true, markers: false, clipped: false };
|
||||||
checkBBox("path1", opt, 2,17,116,91, 0);
|
checkBBox("path1", opt, 2,17,116,91, 0);
|
||||||
|
|
|
@ -51,8 +51,8 @@ SimpleTest.waitForFocus(runTest);
|
||||||
<div id="closure">
|
<div id="closure">
|
||||||
<div style="transform-style: preserve-3d;">
|
<div style="transform-style: preserve-3d;">
|
||||||
<div style="transform-style: preserve-3d; background-color: blue;">
|
<div style="transform-style: preserve-3d; background-color: blue;">
|
||||||
<ul>
|
<ul style="transform-style: preserve-3d;">
|
||||||
<li><div id="target" class="panel"></div>
|
<li style="transform-style:preserve-3d;"><div id="target" class="panel"></div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "hasht.h"
|
#include "hasht.h"
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/dom/CallbackFunction.h"
|
#include "mozilla/dom/CallbackFunction.h"
|
||||||
#include "mozilla/dom/ContentChild.h"
|
#include "mozilla/dom/ContentChild.h"
|
||||||
#include "mozilla/dom/CryptoBuffer.h"
|
#include "mozilla/dom/CryptoBuffer.h"
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "mozilla/dom/U2FSoftTokenManager.h"
|
#include "mozilla/dom/U2FSoftTokenManager.h"
|
||||||
#include "CryptoBuffer.h"
|
#include "CryptoBuffer.h"
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/Base64.h"
|
#include "mozilla/Base64.h"
|
||||||
#include "mozilla/Casting.h"
|
#include "mozilla/Casting.h"
|
||||||
#include "nsNSSComponent.h"
|
#include "nsNSSComponent.h"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "hasht.h"
|
#include "hasht.h"
|
||||||
#include "nsNetCID.h"
|
#include "nsNetCID.h"
|
||||||
#include "nsICryptoHash.h"
|
#include "nsICryptoHash.h"
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/dom/AuthenticatorAttestationResponse.h"
|
#include "mozilla/dom/AuthenticatorAttestationResponse.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
|
|
|
@ -2727,9 +2727,8 @@ nsWebBrowserPersist::MakeAndStoreLocalFilenameInURIMap(
|
||||||
|
|
||||||
// Create a sensibly named filename for the URI and store in the URI map
|
// Create a sensibly named filename for the URI and store in the URI map
|
||||||
URIData *data;
|
URIData *data;
|
||||||
if (mURIMap.Contains(spec))
|
if (mURIMap.Get(spec, &data))
|
||||||
{
|
{
|
||||||
data = mURIMap.Get(spec);
|
|
||||||
if (aNeedsPersisting)
|
if (aNeedsPersisting)
|
||||||
{
|
{
|
||||||
data->mNeedsPersisting = true;
|
data->mNeedsPersisting = true;
|
||||||
|
|
|
@ -1641,17 +1641,16 @@ ServiceWorkerManager::GetOrCreateJobQueue(const nsACString& aKey,
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!aKey.IsEmpty());
|
MOZ_ASSERT(!aKey.IsEmpty());
|
||||||
ServiceWorkerManager::RegistrationDataPerPrincipal* data;
|
ServiceWorkerManager::RegistrationDataPerPrincipal* data;
|
||||||
|
// XXX we could use LookupForAdd here to avoid a hashtable lookup, except that
|
||||||
|
// leads to a false positive assertion, see bug 1370674 comment 7.
|
||||||
if (!mRegistrationInfos.Get(aKey, &data)) {
|
if (!mRegistrationInfos.Get(aKey, &data)) {
|
||||||
data = new RegistrationDataPerPrincipal();
|
data = new RegistrationDataPerPrincipal();
|
||||||
mRegistrationInfos.Put(aKey, data);
|
mRegistrationInfos.Put(aKey, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ServiceWorkerJobQueue> queue;
|
RefPtr<ServiceWorkerJobQueue> queue =
|
||||||
if (!data->mJobQueues.Get(aScope, getter_AddRefs(queue))) {
|
data->mJobQueues.LookupForAdd(aScope).OrInsert(
|
||||||
RefPtr<ServiceWorkerJobQueue> newQueue = new ServiceWorkerJobQueue();
|
[]() { return new ServiceWorkerJobQueue(); });
|
||||||
queue = newQueue;
|
|
||||||
data->mJobQueues.Put(aScope, newQueue.forget());
|
|
||||||
}
|
|
||||||
|
|
||||||
return queue.forget();
|
return queue.forget();
|
||||||
}
|
}
|
||||||
|
@ -2245,11 +2244,9 @@ ServiceWorkerManager::AddScopeAndRegistration(const nsACString& aScope,
|
||||||
|
|
||||||
MOZ_ASSERT(!scopeKey.IsEmpty());
|
MOZ_ASSERT(!scopeKey.IsEmpty());
|
||||||
|
|
||||||
RegistrationDataPerPrincipal* data;
|
RegistrationDataPerPrincipal* data =
|
||||||
if (!swm->mRegistrationInfos.Get(scopeKey, &data)) {
|
swm->mRegistrationInfos.LookupForAdd(scopeKey).OrInsert(
|
||||||
data = new RegistrationDataPerPrincipal();
|
[]() { return new RegistrationDataPerPrincipal(); });
|
||||||
swm->mRegistrationInfos.Put(scopeKey, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < data->mOrderedScopes.Length(); ++i) {
|
for (uint32_t i = 0; i < data->mOrderedScopes.Length(); ++i) {
|
||||||
const nsCString& current = data->mOrderedScopes[i];
|
const nsCString& current = data->mOrderedScopes[i];
|
||||||
|
@ -2344,11 +2341,11 @@ ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo*
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aRegistration->mScope);
|
data->mUpdateTimers.LookupRemoveIf(aRegistration->mScope,
|
||||||
if (timer) {
|
[] (nsCOMPtr<nsITimer>& aTimer) {
|
||||||
timer->Cancel();
|
aTimer->Cancel();
|
||||||
data->mUpdateTimers.Remove(aRegistration->mScope);
|
return true; // remove it
|
||||||
}
|
});
|
||||||
|
|
||||||
// The registration should generally only be removed if there are no controlled
|
// The registration should generally only be removed if there are no controlled
|
||||||
// documents, but mControlledDocuments can contain references to potentially
|
// documents, but mControlledDocuments can contain references to potentially
|
||||||
|
@ -2363,9 +2360,7 @@ ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo*
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ServiceWorkerRegistrationInfo> info;
|
RefPtr<ServiceWorkerRegistrationInfo> info;
|
||||||
data->mInfos.Get(aRegistration->mScope, getter_AddRefs(info));
|
data->mInfos.Remove(aRegistration->mScope, getter_AddRefs(info));
|
||||||
|
|
||||||
data->mInfos.Remove(aRegistration->mScope);
|
|
||||||
data->mOrderedScopes.RemoveElement(aRegistration->mScope);
|
data->mOrderedScopes.RemoveElement(aRegistration->mScope);
|
||||||
swm->NotifyListenersOnUnregister(info);
|
swm->NotifyListenersOnUnregister(info);
|
||||||
|
|
||||||
|
@ -2376,14 +2371,12 @@ ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo*
|
||||||
void
|
void
|
||||||
ServiceWorkerManager::MaybeRemoveRegistrationInfo(const nsACString& aScopeKey)
|
ServiceWorkerManager::MaybeRemoveRegistrationInfo(const nsACString& aScopeKey)
|
||||||
{
|
{
|
||||||
RegistrationDataPerPrincipal* data;
|
mRegistrationInfos.LookupRemoveIf(aScopeKey,
|
||||||
if (!mRegistrationInfos.Get(aScopeKey, &data)) {
|
[] (RegistrationDataPerPrincipal* aData) {
|
||||||
return;
|
bool remove = aData->mOrderedScopes.IsEmpty() &&
|
||||||
}
|
aData->mJobQueues.Count() == 0;
|
||||||
|
return remove;
|
||||||
if (data->mOrderedScopes.IsEmpty() && data->mJobQueues.Count() == 0) {
|
});
|
||||||
mRegistrationInfos.Remove(aScopeKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -3679,12 +3672,11 @@ ServiceWorkerManager::ForceUnregister(RegistrationDataPerPrincipal* aRegistratio
|
||||||
queue->CancelAll();
|
queue->CancelAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsITimer> timer =
|
aRegistrationData->mUpdateTimers.LookupRemoveIf(aRegistration->mScope,
|
||||||
aRegistrationData->mUpdateTimers.Get(aRegistration->mScope);
|
[] (nsCOMPtr<nsITimer>& aTimer) {
|
||||||
if (timer) {
|
aTimer->Cancel();
|
||||||
timer->Cancel();
|
return true; // remove it
|
||||||
aRegistrationData->mUpdateTimers.Remove(aRegistration->mScope);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Since Unregister is async, it is ok to call it in an enumeration.
|
// Since Unregister is async, it is ok to call it in an enumeration.
|
||||||
Unregister(aRegistration->mPrincipal, nullptr, NS_ConvertUTF8toUTF16(aRegistration->mScope));
|
Unregister(aRegistration->mPrincipal, nullptr, NS_ConvertUTF8toUTF16(aRegistration->mScope));
|
||||||
|
@ -4250,7 +4242,7 @@ ServiceWorkerManager::ScheduleUpdateTimer(nsIPrincipal* aPrincipal,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aScope);
|
nsCOMPtr<nsITimer>& timer = data->mUpdateTimers.GetOrInsert(aScope);
|
||||||
if (timer) {
|
if (timer) {
|
||||||
// There is already a timer scheduled. In this case just use the original
|
// There is already a timer scheduled. In this case just use the original
|
||||||
// schedule time. We don't want to push it out to a later time since that
|
// schedule time. We don't want to push it out to a later time since that
|
||||||
|
@ -4261,6 +4253,7 @@ ServiceWorkerManager::ScheduleUpdateTimer(nsIPrincipal* aPrincipal,
|
||||||
|
|
||||||
timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
data->mUpdateTimers.Remove(aScope); // another lookup, but very rare
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4272,10 +4265,9 @@ ServiceWorkerManager::ScheduleUpdateTimer(nsIPrincipal* aPrincipal,
|
||||||
rv = timer->InitWithCallback(callback, UPDATE_DELAY_MS,
|
rv = timer->InitWithCallback(callback, UPDATE_DELAY_MS,
|
||||||
nsITimer::TYPE_ONE_SHOT);
|
nsITimer::TYPE_ONE_SHOT);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
data->mUpdateTimers.Remove(aScope); // another lookup, but very rare
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->mUpdateTimers.Put(aScope, timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -4302,11 +4294,11 @@ ServiceWorkerManager::UpdateTimerFired(nsIPrincipal* aPrincipal,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aScope);
|
data->mUpdateTimers.LookupRemoveIf(aScope,
|
||||||
if (timer) {
|
[] (nsCOMPtr<nsITimer>& aTimer) {
|
||||||
timer->Cancel();
|
aTimer->Cancel();
|
||||||
data->mUpdateTimers.Remove(aScope);
|
return true; // remove it
|
||||||
}
|
});
|
||||||
|
|
||||||
RefPtr<ServiceWorkerRegistrationInfo> registration;
|
RefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||||
data->mInfos.Get(aScope, getter_AddRefs(registration));
|
data->mInfos.Get(aScope, getter_AddRefs(registration));
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "ServiceWorkerUpdaterChild.h"
|
#include "ServiceWorkerUpdaterChild.h"
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <stdlib.h> // for getenv
|
#include <stdlib.h> // for getenv
|
||||||
|
|
||||||
|
#include "mozilla/AbstractThread.h" // for AbstractThread
|
||||||
#include "mozilla/Attributes.h" // for final
|
#include "mozilla/Attributes.h" // for final
|
||||||
#include "mozilla/Preferences.h" // for Preferences
|
#include "mozilla/Preferences.h" // for Preferences
|
||||||
#include "mozilla/dom/Element.h" // for Element
|
#include "mozilla/dom/Element.h" // for Element
|
||||||
|
|
|
@ -175,7 +175,7 @@ PathSkia::GetBounds(const Matrix &aTransform) const
|
||||||
return Rect();
|
return Rect();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect bounds = SkRectToRect(mPath.getBounds());
|
Rect bounds = SkRectToRect(mPath.computeTightBounds());
|
||||||
return aTransform.TransformBounds(bounds);
|
return aTransform.TransformBounds(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
|
||||||
SkPath result;
|
SkPath result;
|
||||||
paint.getFillPath(mPath, &result);
|
paint.getFillPath(mPath, &result);
|
||||||
|
|
||||||
Rect bounds = SkRectToRect(result.getBounds());
|
Rect bounds = SkRectToRect(result.computeTightBounds());
|
||||||
return aTransform.TransformBounds(bounds);
|
return aTransform.TransformBounds(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -237,6 +237,27 @@ LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget, const
|
||||||
mTargetBounds = aRect;
|
mTargetBounds = aRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerManagerComposite::PostProcessLayers(nsIntRegion& aOpaqueRegion)
|
||||||
|
{
|
||||||
|
LayerIntRegion visible;
|
||||||
|
PostProcessLayers(mRoot, aOpaqueRegion, visible, Nothing());
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to skip directly through ContainerLayers that don't have an intermediate
|
||||||
|
// surface. We compute occlusions for leaves and intermediate surfaces against
|
||||||
|
// the layer that they actually composite into so that we can use the final (snapped)
|
||||||
|
// effective transform.
|
||||||
|
bool ShouldProcessLayer(Layer* aLayer)
|
||||||
|
{
|
||||||
|
if (!aLayer->GetParent() ||
|
||||||
|
!aLayer->AsContainerLayer()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return aLayer->AsContainerLayer()->UseIntermediateSurface();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get accumulated transform of from the context creating layer to the
|
* Get accumulated transform of from the context creating layer to the
|
||||||
* given layer.
|
* given layer.
|
||||||
|
@ -258,20 +279,52 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
||||||
LayerIntRegion& aVisibleRegion,
|
LayerIntRegion& aVisibleRegion,
|
||||||
const Maybe<ParentLayerIntRect>& aClipFromAncestors)
|
const Maybe<ParentLayerIntRect>& aClipFromAncestors)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Compute a clip that's the combination of our layer clip with the clip
|
||||||
|
// from our ancestors.
|
||||||
|
LayerComposite* composite = static_cast<LayerComposite*>(aLayer->AsHostLayer());
|
||||||
|
Maybe<ParentLayerIntRect> layerClip = composite->GetShadowClipRect();
|
||||||
|
MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(),
|
||||||
|
"The layer with a clip should not participate "
|
||||||
|
"a 3D rendering context");
|
||||||
|
Maybe<ParentLayerIntRect> outsideClip =
|
||||||
|
IntersectMaybeRects(layerClip, aClipFromAncestors);
|
||||||
|
|
||||||
|
Maybe<LayerIntRect> insideClip;
|
||||||
if (aLayer->Extend3DContext()) {
|
if (aLayer->Extend3DContext()) {
|
||||||
|
// If we're preserve-3d just pass the clip rect down directly, and we'll do the
|
||||||
|
// conversion at the preserve-3d leaf Layer.
|
||||||
|
insideClip = Some(ViewAs<LayerPixel>(*outsideClip, PixelCastJustification::MovingDownToChildren));
|
||||||
|
} else if (outsideClip) {
|
||||||
|
// Convert the combined clip into our pre-transform coordinate space, so
|
||||||
|
// that it can later be intersected with our visible region.
|
||||||
|
// If our transform is a perspective, there's no meaningful insideClip rect
|
||||||
|
// we can compute (it would need to be a cone).
|
||||||
|
Matrix4x4 localTransform = GetAccTransformIn3DContext(aLayer);
|
||||||
|
if (!localTransform.HasPerspectiveComponent() && localTransform.Invert()) {
|
||||||
|
LayerRect insideClipFloat =
|
||||||
|
UntransformBy(ViewAs<ParentLayerToLayerMatrix4x4>(localTransform),
|
||||||
|
ParentLayerRect(*outsideClip),
|
||||||
|
LayerRect::MaxIntRect()).valueOr(LayerRect());
|
||||||
|
insideClipFloat.RoundOut();
|
||||||
|
LayerIntRect insideClipInt;
|
||||||
|
if (insideClipFloat.ToIntRect(&insideClipInt)) {
|
||||||
|
insideClip = Some(insideClipInt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe<ParentLayerIntRect> ancestorClipForChildren;
|
||||||
|
if (insideClip) {
|
||||||
|
ancestorClipForChildren =
|
||||||
|
Some(ViewAs<ParentLayerPixel>(*insideClip, PixelCastJustification::MovingDownToChildren));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ShouldProcessLayer(aLayer)) {
|
||||||
|
MOZ_ASSERT(!aLayer->AsContainerLayer() || !aLayer->AsContainerLayer()->UseIntermediateSurface());
|
||||||
// For layers participating 3D rendering context, their visible
|
// For layers participating 3D rendering context, their visible
|
||||||
// region should be empty (invisible), so we pass through them
|
// region should be empty (invisible), so we pass through them
|
||||||
// without doing anything.
|
// without doing anything.
|
||||||
|
|
||||||
// Direct children of the establisher may have a clip, becaue the
|
|
||||||
// item containing it; ex. of nsHTMLScrollFrame, may give it one.
|
|
||||||
Maybe<ParentLayerIntRect> layerClip =
|
|
||||||
aLayer->AsHostLayer()->GetShadowClipRect();
|
|
||||||
Maybe<ParentLayerIntRect> ancestorClipForChildren =
|
|
||||||
IntersectMaybeRects(layerClip, aClipFromAncestors);
|
|
||||||
MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(),
|
|
||||||
"Only direct children of the establisher could have a clip");
|
|
||||||
|
|
||||||
for (Layer* child = aLayer->GetLastChild();
|
for (Layer* child = aLayer->GetLastChild();
|
||||||
child;
|
child;
|
||||||
child = child->GetPrevSibling()) {
|
child = child->GetPrevSibling()) {
|
||||||
|
@ -284,7 +337,7 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
||||||
nsIntRegion localOpaque;
|
nsIntRegion localOpaque;
|
||||||
// Treat layers on the path to the root of the 3D rendering context as
|
// Treat layers on the path to the root of the 3D rendering context as
|
||||||
// a giant layer if it is a leaf.
|
// a giant layer if it is a leaf.
|
||||||
Matrix4x4 transform = GetAccTransformIn3DContext(aLayer);
|
Matrix4x4 transform = aLayer->GetEffectiveTransform();
|
||||||
Matrix transform2d;
|
Matrix transform2d;
|
||||||
Maybe<IntPoint> integerTranslation;
|
Maybe<IntPoint> integerTranslation;
|
||||||
// If aLayer has a simple transform (only an integer translation) then we
|
// If aLayer has a simple transform (only an integer translation) then we
|
||||||
|
@ -298,44 +351,6 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute a clip that's the combination of our layer clip with the clip
|
|
||||||
// from our ancestors.
|
|
||||||
LayerComposite* composite = static_cast<LayerComposite*>(aLayer->AsHostLayer());
|
|
||||||
Maybe<ParentLayerIntRect> layerClip = composite->GetShadowClipRect();
|
|
||||||
MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(),
|
|
||||||
"The layer with a clip should not participate "
|
|
||||||
"a 3D rendering context");
|
|
||||||
Maybe<ParentLayerIntRect> outsideClip =
|
|
||||||
IntersectMaybeRects(layerClip, aClipFromAncestors);
|
|
||||||
|
|
||||||
// Convert the combined clip into our pre-transform coordinate space, so
|
|
||||||
// that it can later be intersected with our visible region.
|
|
||||||
// If our transform is a perspective, there's no meaningful insideClip rect
|
|
||||||
// we can compute (it would need to be a cone).
|
|
||||||
Maybe<LayerIntRect> insideClip;
|
|
||||||
if (outsideClip && !transform.HasPerspectiveComponent()) {
|
|
||||||
Matrix4x4 inverse = transform;
|
|
||||||
if (inverse.Invert()) {
|
|
||||||
Maybe<LayerRect> insideClipFloat =
|
|
||||||
UntransformBy(ViewAs<ParentLayerToLayerMatrix4x4>(inverse),
|
|
||||||
ParentLayerRect(*outsideClip),
|
|
||||||
LayerRect::MaxIntRect());
|
|
||||||
if (insideClipFloat) {
|
|
||||||
insideClipFloat->RoundOut();
|
|
||||||
LayerIntRect insideClipInt;
|
|
||||||
if (insideClipFloat->ToIntRect(&insideClipInt)) {
|
|
||||||
insideClip = Some(insideClipInt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Maybe<ParentLayerIntRect> ancestorClipForChildren;
|
|
||||||
if (insideClip) {
|
|
||||||
ancestorClipForChildren =
|
|
||||||
Some(ViewAs<ParentLayerPixel>(*insideClip, PixelCastJustification::MovingDownToChildren));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the value of localOpaque, which currently stores the region obscured
|
// Save the value of localOpaque, which currently stores the region obscured
|
||||||
// by siblings (and uncles and such), before our descendants contribute to it.
|
// by siblings (and uncles and such), before our descendants contribute to it.
|
||||||
nsIntRegion obscured = localOpaque;
|
nsIntRegion obscured = localOpaque;
|
||||||
|
@ -345,6 +360,7 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
||||||
// - They recalculate their visible regions, taking ancestorClipForChildren
|
// - They recalculate their visible regions, taking ancestorClipForChildren
|
||||||
// into account, and accumulate them into descendantsVisibleRegion.
|
// into account, and accumulate them into descendantsVisibleRegion.
|
||||||
LayerIntRegion descendantsVisibleRegion;
|
LayerIntRegion descendantsVisibleRegion;
|
||||||
|
|
||||||
bool hasPreserve3DChild = false;
|
bool hasPreserve3DChild = false;
|
||||||
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
|
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||||
PostProcessLayers(child, localOpaque, descendantsVisibleRegion, ancestorClipForChildren);
|
PostProcessLayers(child, localOpaque, descendantsVisibleRegion, ancestorClipForChildren);
|
||||||
|
@ -378,9 +394,6 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
||||||
// for the caller to use.
|
// for the caller to use.
|
||||||
ParentLayerIntRegion visibleParentSpace = TransformBy(
|
ParentLayerIntRegion visibleParentSpace = TransformBy(
|
||||||
ViewAs<LayerToParentLayerMatrix4x4>(transform), visible);
|
ViewAs<LayerToParentLayerMatrix4x4>(transform), visible);
|
||||||
if (const Maybe<ParentLayerIntRect>& clipRect = composite->GetShadowClipRect()) {
|
|
||||||
visibleParentSpace.AndWith(*clipRect);
|
|
||||||
}
|
|
||||||
aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace,
|
aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace,
|
||||||
PixelCastJustification::MovingDownToChildren));
|
PixelCastJustification::MovingDownToChildren));
|
||||||
|
|
||||||
|
@ -392,10 +405,10 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
||||||
if (aLayer->IsOpaque()) {
|
if (aLayer->IsOpaque()) {
|
||||||
localOpaque.OrWith(composite->GetFullyRenderedRegion());
|
localOpaque.OrWith(composite->GetFullyRenderedRegion());
|
||||||
}
|
}
|
||||||
localOpaque.MoveBy(*integerTranslation);
|
if (insideClip) {
|
||||||
if (layerClip) {
|
localOpaque.AndWith(insideClip->ToUnknownRect());
|
||||||
localOpaque.AndWith(layerClip->ToUnknownRect());
|
|
||||||
}
|
}
|
||||||
|
localOpaque.MoveBy(*integerTranslation);
|
||||||
aOpaqueRegion.OrWith(localOpaque);
|
aOpaqueRegion.OrWith(localOpaque);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,17 +462,14 @@ void
|
||||||
LayerManagerComposite::UpdateAndRender()
|
LayerManagerComposite::UpdateAndRender()
|
||||||
{
|
{
|
||||||
nsIntRegion invalid;
|
nsIntRegion invalid;
|
||||||
bool didEffectiveTransforms = false;
|
// The results of our drawing always go directly into a pixel buffer,
|
||||||
|
// so we don't need to pass any global transform here.
|
||||||
|
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
||||||
|
|
||||||
nsIntRegion opaque;
|
nsIntRegion opaque;
|
||||||
LayerIntRegion visible;
|
PostProcessLayers(opaque);
|
||||||
PostProcessLayers(mRoot, opaque, visible, Nothing());
|
|
||||||
|
|
||||||
if (mClonedLayerTreeProperties) {
|
if (mClonedLayerTreeProperties) {
|
||||||
// Effective transforms are needed by ComputeDifferences().
|
|
||||||
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
|
||||||
didEffectiveTransforms = true;
|
|
||||||
|
|
||||||
// We need to compute layer tree differences even if we're not going to
|
// We need to compute layer tree differences even if we're not going to
|
||||||
// immediately use the resulting damage area, since ComputeDifferences
|
// immediately use the resulting damage area, since ComputeDifferences
|
||||||
// is also responsible for invalidates intermediate surfaces in
|
// is also responsible for invalidates intermediate surfaces in
|
||||||
|
@ -502,12 +512,6 @@ LayerManagerComposite::UpdateAndRender()
|
||||||
// so we will invalidate after we've decided if something changed.
|
// so we will invalidate after we've decided if something changed.
|
||||||
InvalidateDebugOverlay(invalid, mRenderBounds);
|
InvalidateDebugOverlay(invalid, mRenderBounds);
|
||||||
|
|
||||||
if (!didEffectiveTransforms) {
|
|
||||||
// The results of our drawing always go directly into a pixel buffer,
|
|
||||||
// so we don't need to pass any global transform here.
|
|
||||||
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
|
||||||
}
|
|
||||||
|
|
||||||
Render(invalid, opaque);
|
Render(invalid, opaque);
|
||||||
#if defined(MOZ_WIDGET_ANDROID)
|
#if defined(MOZ_WIDGET_ANDROID)
|
||||||
RenderToPresentationSurface();
|
RenderToPresentationSurface();
|
||||||
|
@ -1109,8 +1113,7 @@ LayerManagerComposite::RenderToPresentationSurface()
|
||||||
|
|
||||||
mRoot->ComputeEffectiveTransforms(matrix);
|
mRoot->ComputeEffectiveTransforms(matrix);
|
||||||
nsIntRegion opaque;
|
nsIntRegion opaque;
|
||||||
LayerIntRegion visible;
|
PostProcessLayers(opaque);
|
||||||
PostProcessLayers(mRoot, opaque, visible, Nothing());
|
|
||||||
|
|
||||||
nsIntRegion invalid;
|
nsIntRegion invalid;
|
||||||
IntRect bounds = IntRect::Truncate(0, 0, scale * pageWidth, actualHeight);
|
IntRect bounds = IntRect::Truncate(0, 0, scale * pageWidth, actualHeight);
|
||||||
|
|
|
@ -305,6 +305,7 @@ public:
|
||||||
* Each layer accumulates into |aVisibleRegion| its post-transform
|
* Each layer accumulates into |aVisibleRegion| its post-transform
|
||||||
* (including async transforms) visible region.
|
* (including async transforms) visible region.
|
||||||
*/
|
*/
|
||||||
|
void PostProcessLayers(nsIntRegion& aOpaqueRegion);
|
||||||
void PostProcessLayers(Layer* aLayer,
|
void PostProcessLayers(Layer* aLayer,
|
||||||
nsIntRegion& aOpaqueRegion,
|
nsIntRegion& aOpaqueRegion,
|
||||||
LayerIntRegion& aVisibleRegion,
|
LayerIntRegion& aVisibleRegion,
|
||||||
|
|
|
@ -159,7 +159,8 @@ D3D11Checks::DoesDeviceWork()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (displayLinkModuleVersion <= V(8,6,1,36484)) {
|
if (displayLinkModuleVersion <= V(8,6,1,36484)) {
|
||||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DisplayLink: too old version " << displayLinkModuleVersionString.get();
|
NS_ConvertUTF16toUTF8 version(displayLinkModuleVersionString);
|
||||||
|
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "DisplayLink: too old version " << version.get();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1904,9 +1904,8 @@ imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
|
||||||
imgCacheQueue& queue = GetCacheQueue(aKey);
|
imgCacheQueue& queue = GetCacheQueue(aKey);
|
||||||
|
|
||||||
RefPtr<imgCacheEntry> entry;
|
RefPtr<imgCacheEntry> entry;
|
||||||
if (cache.Get(aKey, getter_AddRefs(entry)) && entry) {
|
cache.Remove(aKey, getter_AddRefs(entry));
|
||||||
cache.Remove(aKey);
|
if (entry) {
|
||||||
|
|
||||||
MOZ_ASSERT(!entry->Evicted(), "Evicting an already-evicted cache entry!");
|
MOZ_ASSERT(!entry->Evicted(), "Evicting an already-evicted cache entry!");
|
||||||
|
|
||||||
// Entries with no proxies are in the tracker.
|
// Entries with no proxies are in the tracker.
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
#include "base/message_pump_android.h"
|
#include "base/message_pump_android.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "nsISerialEventTarget.h"
|
||||||
#ifdef MOZ_TASK_TRACER
|
#ifdef MOZ_TASK_TRACER
|
||||||
#include "GeckoTaskTracer.h"
|
#include "GeckoTaskTracer.h"
|
||||||
#include "TracedTaskCommon.h"
|
#include "TracedTaskCommon.h"
|
||||||
|
@ -84,6 +85,84 @@ static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class MessageLoop::EventTarget
|
||||||
|
: public nsISerialEventTarget
|
||||||
|
, public MessageLoop::DestructionObserver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
NS_DECL_NSIEVENTTARGET_FULL
|
||||||
|
|
||||||
|
explicit EventTarget(MessageLoop* aLoop) : mLoop(aLoop) {
|
||||||
|
aLoop->AddDestructionObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~EventTarget() {
|
||||||
|
if (mLoop) {
|
||||||
|
mLoop->RemoveDestructionObserver(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WillDestroyCurrentMessageLoop() override {
|
||||||
|
mLoop->RemoveDestructionObserver(this);
|
||||||
|
mLoop = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageLoop* mLoop;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS(MessageLoop::EventTarget, nsIEventTarget, nsISerialEventTarget)
|
||||||
|
|
||||||
|
NS_IMETHODIMP_(bool)
|
||||||
|
MessageLoop::EventTarget::IsOnCurrentThreadInfallible()
|
||||||
|
{
|
||||||
|
return mLoop == MessageLoop::current();
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
MessageLoop::EventTarget::IsOnCurrentThread(bool* aResult)
|
||||||
|
{
|
||||||
|
*aResult = IsOnCurrentThreadInfallible();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
MessageLoop::EventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIRunnable> event(aEvent);
|
||||||
|
return Dispatch(event.forget(), aFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
MessageLoop::EventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags)
|
||||||
|
{
|
||||||
|
if (!mLoop) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aFlags != NS_DISPATCH_NORMAL) {
|
||||||
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLoop->PostTask(Move(aEvent));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
MessageLoop::EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
|
||||||
|
uint32_t aDelayMs)
|
||||||
|
{
|
||||||
|
if (!mLoop) {
|
||||||
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLoop->PostDelayedTask(Move(aEvent), aDelayMs);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// static
|
// static
|
||||||
MessageLoop* MessageLoop::current() {
|
MessageLoop* MessageLoop::current() {
|
||||||
return get_tls_ptr().Get();
|
return get_tls_ptr().Get();
|
||||||
|
@ -103,7 +182,8 @@ MessageLoop::MessageLoop(Type type, nsIThread* aThread)
|
||||||
#endif // OS_WIN
|
#endif // OS_WIN
|
||||||
transient_hang_timeout_(0),
|
transient_hang_timeout_(0),
|
||||||
permanent_hang_timeout_(0),
|
permanent_hang_timeout_(0),
|
||||||
next_sequence_num_(0) {
|
next_sequence_num_(0),
|
||||||
|
mEventTarget(new EventTarget(this)) {
|
||||||
DCHECK(!current()) << "should only have one message loop per thread";
|
DCHECK(!current()) << "should only have one message loop per thread";
|
||||||
get_tls_ptr().Set(this);
|
get_tls_ptr().Set(this);
|
||||||
|
|
||||||
|
@ -248,7 +328,7 @@ bool MessageLoop::ProcessNextDelayedNonNestableTask() {
|
||||||
if (deferred_non_nestable_work_queue_.empty())
|
if (deferred_non_nestable_work_queue_.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RefPtr<Runnable> task = deferred_non_nestable_work_queue_.front().task.forget();
|
nsCOMPtr<nsIRunnable> task = deferred_non_nestable_work_queue_.front().task.forget();
|
||||||
deferred_non_nestable_work_queue_.pop();
|
deferred_non_nestable_work_queue_.pop();
|
||||||
|
|
||||||
RunTask(task.forget());
|
RunTask(task.forget());
|
||||||
|
@ -266,15 +346,15 @@ void MessageLoop::Quit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageLoop::PostTask(already_AddRefed<Runnable> task) {
|
void MessageLoop::PostTask(already_AddRefed<nsIRunnable> task) {
|
||||||
PostTask_Helper(Move(task), 0);
|
PostTask_Helper(Move(task), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageLoop::PostDelayedTask(already_AddRefed<Runnable> task, int delay_ms) {
|
void MessageLoop::PostDelayedTask(already_AddRefed<nsIRunnable> task, int delay_ms) {
|
||||||
PostTask_Helper(Move(task), delay_ms);
|
PostTask_Helper(Move(task), delay_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageLoop::PostIdleTask(already_AddRefed<Runnable> task) {
|
void MessageLoop::PostIdleTask(already_AddRefed<nsIRunnable> task) {
|
||||||
DCHECK(current() == this);
|
DCHECK(current() == this);
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
@ -283,7 +363,7 @@ void MessageLoop::PostIdleTask(already_AddRefed<Runnable> task) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Possibly called on a background thread!
|
// Possibly called on a background thread!
|
||||||
void MessageLoop::PostTask_Helper(already_AddRefed<Runnable> task, int delay_ms) {
|
void MessageLoop::PostTask_Helper(already_AddRefed<nsIRunnable> task, int delay_ms) {
|
||||||
if (nsIEventTarget* target = pump_->GetXPCOMThread()) {
|
if (nsIEventTarget* target = pump_->GetXPCOMThread()) {
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
if (delay_ms) {
|
if (delay_ms) {
|
||||||
|
@ -296,7 +376,7 @@ void MessageLoop::PostTask_Helper(already_AddRefed<Runnable> task, int delay_ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_TASK_TRACER
|
#ifdef MOZ_TASK_TRACER
|
||||||
RefPtr<Runnable> tracedTask = task;
|
nsCOMPtr<nsIRunnable> tracedTask = task;
|
||||||
if (mozilla::tasktracer::IsStartLogging()) {
|
if (mozilla::tasktracer::IsStartLogging()) {
|
||||||
tracedTask = mozilla::tasktracer::CreateTracedRunnable(Move(task));
|
tracedTask = mozilla::tasktracer::CreateTracedRunnable(Move(task));
|
||||||
(static_cast<mozilla::tasktracer::TracedRunnable*>(tracedTask.get()))->DispatchTask();
|
(static_cast<mozilla::tasktracer::TracedRunnable*>(tracedTask.get()))->DispatchTask();
|
||||||
|
@ -352,12 +432,12 @@ bool MessageLoop::NestableTasksAllowed() const {
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
void MessageLoop::RunTask(already_AddRefed<Runnable> aTask) {
|
void MessageLoop::RunTask(already_AddRefed<nsIRunnable> aTask) {
|
||||||
DCHECK(nestable_tasks_allowed_);
|
DCHECK(nestable_tasks_allowed_);
|
||||||
// Execute the task and assume the worst: It is probably not reentrant.
|
// Execute the task and assume the worst: It is probably not reentrant.
|
||||||
nestable_tasks_allowed_ = false;
|
nestable_tasks_allowed_ = false;
|
||||||
|
|
||||||
RefPtr<Runnable> task = aTask;
|
nsCOMPtr<nsIRunnable> task = aTask;
|
||||||
task->Run();
|
task->Run();
|
||||||
task = nullptr;
|
task = nullptr;
|
||||||
|
|
||||||
|
@ -524,6 +604,13 @@ bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
|
||||||
return (sequence_num - other.sequence_num) > 0;
|
return (sequence_num - other.sequence_num) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// MessageLoop::SerialEventTarget
|
||||||
|
|
||||||
|
nsISerialEventTarget* MessageLoop::SerialEventTarget() {
|
||||||
|
return mEventTarget;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// MessageLoopForUI
|
// MessageLoopForUI
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsIRunnable.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
|
||||||
|
class nsISerialEventTarget;
|
||||||
class nsIThread;
|
class nsIThread;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -112,12 +115,12 @@ public:
|
||||||
// NOTE: These methods may be called on any thread. The Task will be invoked
|
// NOTE: These methods may be called on any thread. The Task will be invoked
|
||||||
// on the thread that executes MessageLoop::Run().
|
// on the thread that executes MessageLoop::Run().
|
||||||
|
|
||||||
void PostTask(already_AddRefed<mozilla::Runnable> task);
|
void PostTask(already_AddRefed<nsIRunnable> task);
|
||||||
|
|
||||||
void PostDelayedTask(already_AddRefed<mozilla::Runnable> task, int delay_ms);
|
void PostDelayedTask(already_AddRefed<nsIRunnable> task, int delay_ms);
|
||||||
|
|
||||||
// PostIdleTask is not thread safe and should be called on this thread
|
// PostIdleTask is not thread safe and should be called on this thread
|
||||||
void PostIdleTask(already_AddRefed<mozilla::Runnable> task);
|
void PostIdleTask(already_AddRefed<nsIRunnable> task);
|
||||||
|
|
||||||
// Run the message loop.
|
// Run the message loop.
|
||||||
void Run();
|
void Run();
|
||||||
|
@ -143,6 +146,9 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Return an XPCOM-compatible event target for this thread.
|
||||||
|
nsISerialEventTarget* SerialEventTarget();
|
||||||
|
|
||||||
// A MessageLoop has a particular type, which indicates the set of
|
// A MessageLoop has a particular type, which indicates the set of
|
||||||
// asynchronous events it may process in addition to tasks and timers.
|
// asynchronous events it may process in addition to tasks and timers.
|
||||||
//
|
//
|
||||||
|
@ -282,12 +288,12 @@ public:
|
||||||
|
|
||||||
// This structure is copied around by value.
|
// This structure is copied around by value.
|
||||||
struct PendingTask {
|
struct PendingTask {
|
||||||
RefPtr<mozilla::Runnable> task; // The task to run.
|
nsCOMPtr<nsIRunnable> task; // The task to run.
|
||||||
base::TimeTicks delayed_run_time; // The time when the task should be run.
|
base::TimeTicks delayed_run_time; // The time when the task should be run.
|
||||||
int sequence_num; // Secondary sort key for run time.
|
int sequence_num; // Secondary sort key for run time.
|
||||||
bool nestable; // OK to dispatch from a nested loop.
|
bool nestable; // OK to dispatch from a nested loop.
|
||||||
|
|
||||||
PendingTask(already_AddRefed<mozilla::Runnable> aTask, bool aNestable)
|
PendingTask(already_AddRefed<nsIRunnable> aTask, bool aNestable)
|
||||||
: task(aTask), sequence_num(0), nestable(aNestable) {
|
: task(aTask), sequence_num(0), nestable(aNestable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,10 +361,10 @@ public:
|
||||||
// appended to the list work_queue_. Such re-entrancy generally happens when
|
// appended to the list work_queue_. Such re-entrancy generally happens when
|
||||||
// an unrequested message pump (typical of a native dialog) is executing in
|
// an unrequested message pump (typical of a native dialog) is executing in
|
||||||
// the context of a task.
|
// the context of a task.
|
||||||
bool QueueOrRunTask(already_AddRefed<mozilla::Runnable> new_task);
|
bool QueueOrRunTask(already_AddRefed<nsIRunnable> new_task);
|
||||||
|
|
||||||
// Runs the specified task and deletes it.
|
// Runs the specified task and deletes it.
|
||||||
void RunTask(already_AddRefed<mozilla::Runnable> task);
|
void RunTask(already_AddRefed<nsIRunnable> task);
|
||||||
|
|
||||||
// Calls RunTask or queues the pending_task on the deferred task list if it
|
// Calls RunTask or queues the pending_task on the deferred task list if it
|
||||||
// cannot be run right now. Returns true if the task was run.
|
// cannot be run right now. Returns true if the task was run.
|
||||||
|
@ -378,7 +384,7 @@ public:
|
||||||
bool DeletePendingTasks();
|
bool DeletePendingTasks();
|
||||||
|
|
||||||
// Post a task to our incomming queue.
|
// Post a task to our incomming queue.
|
||||||
void PostTask_Helper(already_AddRefed<mozilla::Runnable> task, int delay_ms);
|
void PostTask_Helper(already_AddRefed<nsIRunnable> task, int delay_ms);
|
||||||
|
|
||||||
// base::MessagePump::Delegate methods:
|
// base::MessagePump::Delegate methods:
|
||||||
virtual bool DoWork() override;
|
virtual bool DoWork() override;
|
||||||
|
@ -436,6 +442,9 @@ public:
|
||||||
// The next sequence number to use for delayed tasks.
|
// The next sequence number to use for delayed tasks.
|
||||||
int next_sequence_num_;
|
int next_sequence_num_;
|
||||||
|
|
||||||
|
class EventTarget;
|
||||||
|
RefPtr<EventTarget> mEventTarget;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(MessageLoop);
|
DISALLOW_COPY_AND_ASSIGN(MessageLoop);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
#include "mozilla/ipc/MessageChannel.h"
|
#include "mozilla/ipc/MessageChannel.h"
|
||||||
|
|
||||||
#include "MessageLoopAbstractThreadWrapper.h"
|
|
||||||
#include "mozilla/AbstractThread.h"
|
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/dom/ScriptSettings.h"
|
#include "mozilla/dom/ScriptSettings.h"
|
||||||
|
@ -750,23 +748,6 @@ MessageChannel::Clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AbstractThreadWrapperCleanup : public MessageLoop::DestructionObserver
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit AbstractThreadWrapperCleanup(already_AddRefed<AbstractThread> aWrapper)
|
|
||||||
: mWrapper(aWrapper)
|
|
||||||
{}
|
|
||||||
virtual ~AbstractThreadWrapperCleanup() override {}
|
|
||||||
virtual void WillDestroyCurrentMessageLoop() override
|
|
||||||
{
|
|
||||||
mWrapper = nullptr;
|
|
||||||
MessageLoop::current()->RemoveDestructionObserver(this);
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
RefPtr<AbstractThread> mWrapper;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
|
MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
|
||||||
{
|
{
|
||||||
|
@ -778,13 +759,6 @@ MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
|
||||||
mWorkerLoop->AddDestructionObserver(this);
|
mWorkerLoop->AddDestructionObserver(this);
|
||||||
mListener->SetIsMainThreadProtocol();
|
mListener->SetIsMainThreadProtocol();
|
||||||
|
|
||||||
if (!AbstractThread::GetCurrent()) {
|
|
||||||
mWorkerLoop->AddDestructionObserver(
|
|
||||||
new AbstractThreadWrapperCleanup(
|
|
||||||
MessageLoopAbstractThreadWrapper::Create(mWorkerLoop)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ProcessLink *link = new ProcessLink(this);
|
ProcessLink *link = new ProcessLink(this);
|
||||||
link->Open(aTransport, aIOLoop, aSide); // :TODO: n.b.: sets mChild
|
link->Open(aTransport, aIOLoop, aSide); // :TODO: n.b.: sets mChild
|
||||||
mLink = link;
|
mLink = link;
|
||||||
|
@ -864,12 +838,6 @@ MessageChannel::CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide)
|
||||||
mWorkerLoop->AddDestructionObserver(this);
|
mWorkerLoop->AddDestructionObserver(this);
|
||||||
mListener->SetIsMainThreadProtocol();
|
mListener->SetIsMainThreadProtocol();
|
||||||
|
|
||||||
if (!AbstractThread::GetCurrent()) {
|
|
||||||
mWorkerLoop->AddDestructionObserver(
|
|
||||||
new AbstractThreadWrapperCleanup(
|
|
||||||
MessageLoopAbstractThreadWrapper::Create(mWorkerLoop)));
|
|
||||||
}
|
|
||||||
|
|
||||||
mLink = new ThreadLink(this, aTargetChan);
|
mLink = new ThreadLink(this, aTargetChan);
|
||||||
mSide = aSide;
|
mSide = aSide;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,159 +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/. */
|
|
||||||
|
|
||||||
#ifndef mozilla_ipc_glue_MessageLoopAbstractThreadWrapper_h
|
|
||||||
#define mozilla_ipc_glue_MessageLoopAbstractThreadWrapper_h
|
|
||||||
|
|
||||||
#include "mozilla/AbstractThread.h"
|
|
||||||
|
|
||||||
#include "base/message_loop.h"
|
|
||||||
|
|
||||||
#include "nsThreadUtils.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace ipc {
|
|
||||||
|
|
||||||
class MessageLoopAbstractThreadWrapper : public AbstractThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static already_AddRefed<AbstractThread>
|
|
||||||
Create(MessageLoop* aMessageLoop)
|
|
||||||
{
|
|
||||||
RefPtr<MessageLoopAbstractThreadWrapper> wrapper =
|
|
||||||
new MessageLoopAbstractThreadWrapper(aMessageLoop);
|
|
||||||
|
|
||||||
bool onCurrentThread = (aMessageLoop == MessageLoop::current());
|
|
||||||
|
|
||||||
if (onCurrentThread) {
|
|
||||||
sCurrentThreadTLS.set(wrapper);
|
|
||||||
return wrapper.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the thread-local sCurrentThreadTLS to point to the wrapper on the
|
|
||||||
// target thread. This ensures that sCurrentThreadTLS is as expected by
|
|
||||||
// AbstractThread::GetCurrent() on the target thread.
|
|
||||||
RefPtr<Runnable> r =
|
|
||||||
NS_NewRunnableFunction([wrapper]() { sCurrentThreadTLS.set(wrapper); });
|
|
||||||
aMessageLoop->PostTask(r.forget());
|
|
||||||
return wrapper.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Dispatch(already_AddRefed<nsIRunnable> aRunnable,
|
|
||||||
DispatchFailureHandling aFailureHandling = AssertDispatchSuccess,
|
|
||||||
DispatchReason aReason = NormalDispatch) override
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(aReason == NormalDispatch, "Only supports NormalDispatch");
|
|
||||||
|
|
||||||
RefPtr<Runnable> runner(new Runner(this, Move(aRunnable)));
|
|
||||||
mMessageLoop->PostTask(runner.forget());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool IsCurrentThreadIn() override
|
|
||||||
{
|
|
||||||
MessageLoop* messageLoop = MessageLoop::current();
|
|
||||||
bool in = (mMessageLoop == messageLoop);
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual TaskDispatcher& TailDispatcher() override
|
|
||||||
{
|
|
||||||
MOZ_CRASH("Not supported!");
|
|
||||||
TaskDispatcher* dispatcher = nullptr;
|
|
||||||
return *dispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool MightHaveTailTasks() override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
explicit MessageLoopAbstractThreadWrapper(MessageLoop* aMessageLoop)
|
|
||||||
: AbstractThread(false)
|
|
||||||
, mMessageLoop(aMessageLoop)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageLoop* mMessageLoop;
|
|
||||||
|
|
||||||
class Runner : public CancelableRunnable {
|
|
||||||
class MOZ_STACK_CLASS AutoTaskGuard final {
|
|
||||||
public:
|
|
||||||
explicit AutoTaskGuard(MessageLoopAbstractThreadWrapper* aThread)
|
|
||||||
: mLastCurrentThread(nullptr)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aThread);
|
|
||||||
mLastCurrentThread = sCurrentThreadTLS.get();
|
|
||||||
sCurrentThreadTLS.set(aThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
~AutoTaskGuard()
|
|
||||||
{
|
|
||||||
sCurrentThreadTLS.set(mLastCurrentThread);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
AbstractThread* mLastCurrentThread;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Runner(MessageLoopAbstractThreadWrapper* aThread,
|
|
||||||
already_AddRefed<nsIRunnable> aRunnable)
|
|
||||||
: mThread(aThread)
|
|
||||||
, mRunnable(aRunnable)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
|
||||||
{
|
|
||||||
AutoTaskGuard taskGuard(mThread);
|
|
||||||
|
|
||||||
MOZ_ASSERT(mThread == AbstractThread::GetCurrent());
|
|
||||||
MOZ_ASSERT(mThread->IsCurrentThreadIn());
|
|
||||||
nsresult rv = mRunnable->Run();
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Cancel() override
|
|
||||||
{
|
|
||||||
// Set the TLS during Cancel() just in case it calls Run().
|
|
||||||
AutoTaskGuard taskGuard(mThread);
|
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
|
||||||
|
|
||||||
// Try to cancel the runnable if it implements the right interface.
|
|
||||||
// Otherwise just skip the runnable.
|
|
||||||
nsCOMPtr<nsICancelableRunnable> cr = do_QueryInterface(mRunnable);
|
|
||||||
if (cr) {
|
|
||||||
rv = cr->Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD GetName(nsACString& aName) override
|
|
||||||
{
|
|
||||||
aName.AssignLiteral("AbstractThread::Runner");
|
|
||||||
if (nsCOMPtr<nsINamed> named = do_QueryInterface(mRunnable)) {
|
|
||||||
nsAutoCString name;
|
|
||||||
named->GetName(name);
|
|
||||||
if (!name.IsEmpty()) {
|
|
||||||
aName.AppendLiteral(" for ");
|
|
||||||
aName.Append(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RefPtr<MessageLoopAbstractThreadWrapper> mThread;
|
|
||||||
RefPtr<nsIRunnable> mRunnable;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ipc
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_ipc_glue_MessageLoopAbstractThreadWrapper_h
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "IPDLUnitTests.h" // fail etc.
|
#include "IPDLUnitTests.h" // fail etc.
|
||||||
|
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -26,10 +27,7 @@ TestAsyncReturnsParent::~TestAsyncReturnsParent()
|
||||||
void
|
void
|
||||||
TestAsyncReturnsParent::Main()
|
TestAsyncReturnsParent::Main()
|
||||||
{
|
{
|
||||||
if (!AbstractThread::MainThread()) {
|
SendNoReturn()->Then(MessageLoop::current()->SerialEventTarget(), __func__,
|
||||||
fail("AbstractThread not initalized");
|
|
||||||
}
|
|
||||||
SendNoReturn()->Then(AbstractThread::MainThread(), __func__,
|
|
||||||
[](bool unused) {
|
[](bool unused) {
|
||||||
fail("resolve handler should not be called");
|
fail("resolve handler should not be called");
|
||||||
},
|
},
|
||||||
|
@ -41,7 +39,7 @@ TestAsyncReturnsParent::Main()
|
||||||
}
|
}
|
||||||
passed("reject handler called on channel close");
|
passed("reject handler called on channel close");
|
||||||
});
|
});
|
||||||
SendPing()->Then(AbstractThread::MainThread(), __func__,
|
SendPing()->Then(MessageLoop::current()->SerialEventTarget(), __func__,
|
||||||
[this](bool one) {
|
[this](bool one) {
|
||||||
if (one) {
|
if (one) {
|
||||||
passed("take one argument");
|
passed("take one argument");
|
||||||
|
@ -87,10 +85,7 @@ TestAsyncReturnsChild::RecvNoReturn(NoReturnResolver&& aResolve)
|
||||||
mozilla::ipc::IPCResult
|
mozilla::ipc::IPCResult
|
||||||
TestAsyncReturnsChild::RecvPing(PingResolver&& aResolve)
|
TestAsyncReturnsChild::RecvPing(PingResolver&& aResolve)
|
||||||
{
|
{
|
||||||
if (!AbstractThread::MainThread()) {
|
SendPong()->Then(MessageLoop::current()->SerialEventTarget(), __func__,
|
||||||
fail("AbstractThread not initalized");
|
|
||||||
}
|
|
||||||
SendPong()->Then(AbstractThread::MainThread(), __func__,
|
|
||||||
[aResolve](const Tuple<uint32_t, uint32_t>& aParam) {
|
[aResolve](const Tuple<uint32_t, uint32_t>& aParam) {
|
||||||
if (Get<0>(aParam) == sMagic1 && Get<1>(aParam) == sMagic2) {
|
if (Get<0>(aParam) == sMagic1 && Get<1>(aParam) == sMagic2) {
|
||||||
passed("take two arguments");
|
passed("take two arguments");
|
||||||
|
|
|
@ -85,7 +85,7 @@ GUIDToString(REFGUID aGuid, nsAString& aOutString)
|
||||||
// to include curly braces and dashes.
|
// to include curly braces and dashes.
|
||||||
const int kBufLenWithNul = 39;
|
const int kBufLenWithNul = 39;
|
||||||
aOutString.SetLength(kBufLenWithNul);
|
aOutString.SetLength(kBufLenWithNul);
|
||||||
int result = StringFromGUID2(aGuid, wwc(aOutString.BeginWriting()), kBufLenWithNul);
|
int result = StringFromGUID2(aGuid, char16ptr_t(aOutString.BeginWriting()), kBufLenWithNul);
|
||||||
MOZ_ASSERT(result);
|
MOZ_ASSERT(result);
|
||||||
if (result) {
|
if (result) {
|
||||||
// Truncate the terminator
|
// Truncate the terminator
|
||||||
|
|
|
@ -2006,9 +2006,7 @@ nsPresContext::ForceCacheLang(nsIAtom *aLanguage)
|
||||||
{
|
{
|
||||||
// force it to be cached
|
// force it to be cached
|
||||||
GetDefaultFont(kPresContext_DefaultVariableFont_ID, aLanguage);
|
GetDefaultFont(kPresContext_DefaultVariableFont_ID, aLanguage);
|
||||||
if (!mLanguagesUsed.Contains(aLanguage)) {
|
mLanguagesUsed.PutEntry(aLanguage);
|
||||||
mLanguagesUsed.PutEntry(aLanguage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1392,7 +1392,8 @@ nsIFrame::Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay,
|
||||||
EffectSet* aEffectSet) const
|
EffectSet* aEffectSet) const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||||
if (!GetParent() || !GetParent()->Extend3DContext(aEffectSet)) {
|
nsIFrame* parent = GetFlattenedTreeParentPrimaryFrame();
|
||||||
|
if (!parent || !parent->Extend3DContext()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return IsTransformed(aStyleDisplay,aEffectSet) ||
|
return IsTransformed(aStyleDisplay,aEffectSet) ||
|
||||||
|
@ -2320,9 +2321,9 @@ FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
|
||||||
MOZ_ASSERT(aAncestor != aDescendant);
|
MOZ_ASSERT(aAncestor != aDescendant);
|
||||||
MOZ_ASSERT(aAncestor->Extend3DContext());
|
MOZ_ASSERT(aAncestor->Extend3DContext());
|
||||||
nsIFrame* frame;
|
nsIFrame* frame;
|
||||||
for (frame = nsLayoutUtils::GetCrossDocParentFrame(aDescendant);
|
for (frame = aDescendant->GetFlattenedTreeParentPrimaryFrame();
|
||||||
frame && aAncestor != frame;
|
frame && aAncestor != frame;
|
||||||
frame = nsLayoutUtils::GetCrossDocParentFrame(frame)) {
|
frame = frame->GetFlattenedTreeParentPrimaryFrame()) {
|
||||||
if (!frame->Extend3DContext()) {
|
if (!frame->Extend3DContext()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -6277,6 +6278,16 @@ nsIFrame::GetNearestWidget(nsPoint& aOffset) const
|
||||||
return widget;
|
return widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIFrame*
|
||||||
|
nsIFrame::GetFlattenedTreeParentPrimaryFrame() const
|
||||||
|
{
|
||||||
|
if (!GetContent()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
nsIContent* parent = GetContent()->GetFlattenedTreeParent();
|
||||||
|
return parent ? parent->GetPrimaryFrame() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Matrix4x4
|
Matrix4x4
|
||||||
nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||||
nsIFrame** aOutAncestor,
|
nsIFrame** aOutAncestor,
|
||||||
|
|
|
@ -836,6 +836,12 @@ public:
|
||||||
*/
|
*/
|
||||||
inline nsContainerFrame* GetInFlowParent();
|
inline nsContainerFrame* GetInFlowParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the primary frame of the Content's flattened tree
|
||||||
|
* parent, if one exists.
|
||||||
|
*/
|
||||||
|
inline nsIFrame* GetFlattenedTreeParentPrimaryFrame() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the placeholder for this frame (which must be out-of-flow).
|
* Return the placeholder for this frame (which must be out-of-flow).
|
||||||
* @note this will only return non-null if |this| is the first-in-flow
|
* @note this will only return non-null if |this| is the first-in-flow
|
||||||
|
|
|
@ -4383,6 +4383,13 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||||
layerState == LAYER_ACTIVE_FORCE) {
|
layerState == LAYER_ACTIVE_FORCE) {
|
||||||
newLayerEntry->mPropagateComponentAlphaFlattening = false;
|
newLayerEntry->mPropagateComponentAlphaFlattening = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float contentXScale = 1.0f;
|
||||||
|
float contentYScale = 1.0f;
|
||||||
|
if (ContainerLayer* ownContainer = ownLayer->AsContainerLayer()) {
|
||||||
|
contentXScale = 1 / ownContainer->GetPreXScale();
|
||||||
|
contentYScale = 1 / ownContainer->GetPreYScale();
|
||||||
|
}
|
||||||
// nsDisplayTransform::BuildLayer must set layerContentsVisibleRect.
|
// nsDisplayTransform::BuildLayer must set layerContentsVisibleRect.
|
||||||
// We rely on this to ensure 3D transforms compute a reasonable
|
// We rely on this to ensure 3D transforms compute a reasonable
|
||||||
// layer visible region.
|
// layer visible region.
|
||||||
|
@ -4400,7 +4407,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||||
// to avoid failure caused by singular transforms.
|
// to avoid failure caused by singular transforms.
|
||||||
newLayerEntry->mUntransformedVisibleRegion = true;
|
newLayerEntry->mUntransformedVisibleRegion = true;
|
||||||
newLayerEntry->mVisibleRegion =
|
newLayerEntry->mVisibleRegion =
|
||||||
item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel);
|
item->GetVisibleRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel);
|
||||||
} else {
|
} else {
|
||||||
newLayerEntry->mVisibleRegion = itemVisibleRegion;
|
newLayerEntry->mVisibleRegion = itemVisibleRegion;
|
||||||
}
|
}
|
||||||
|
@ -4414,7 +4421,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||||
(item->Frame()->IsPreserve3DLeaf() ||
|
(item->Frame()->IsPreserve3DLeaf() ||
|
||||||
item->Frame()->HasPerspective());
|
item->Frame()->HasPerspective());
|
||||||
const nsIntRegion &visible = useChildrenVisible ?
|
const nsIntRegion &visible = useChildrenVisible ?
|
||||||
item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel):
|
item->GetVisibleRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel):
|
||||||
itemVisibleRegion;
|
itemVisibleRegion;
|
||||||
|
|
||||||
SetOuterVisibleRegionForLayer(ownLayer, visible,
|
SetOuterVisibleRegionForLayer(ownLayer, visible,
|
||||||
|
|
|
@ -1719,12 +1719,15 @@ nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsPresContext* key = aFrame->PresContext();
|
nsPresContext* key = aFrame->PresContext();
|
||||||
if (!mWillChangeBudget.Contains(key)) {
|
|
||||||
mWillChangeBudget.Put(key, DocumentWillChangeBudget());
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentWillChangeBudget budget;
|
DocumentWillChangeBudget budget;
|
||||||
mWillChangeBudget.Get(key, &budget);
|
auto willChangeBudgetEntry = mWillChangeBudget.LookupForAdd(key);
|
||||||
|
if (willChangeBudgetEntry) {
|
||||||
|
// We have an existing entry.
|
||||||
|
budget = willChangeBudgetEntry.Data();
|
||||||
|
} else {
|
||||||
|
budget = DocumentWillChangeBudget();
|
||||||
|
willChangeBudgetEntry.OrInsert([&budget] () { return budget; });
|
||||||
|
}
|
||||||
|
|
||||||
nsRect area = aFrame->PresContext()->GetVisibleArea();
|
nsRect area = aFrame->PresContext()->GetVisibleArea();
|
||||||
uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
|
uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
|
||||||
|
@ -1736,7 +1739,7 @@ nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
|
||||||
|
|
||||||
if (onBudget) {
|
if (onBudget) {
|
||||||
budget.mBudget += cost;
|
budget.mBudget += cost;
|
||||||
mWillChangeBudget.Put(key, budget);
|
willChangeBudgetEntry.Data() = budget;
|
||||||
mWillChangeBudgetSet.PutEntry(aFrame);
|
mWillChangeBudgetSet.PutEntry(aFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-parent.html animate-preserve3d
|
||||||
fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
|
fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
|
||||||
== animate-backface-hidden.html about:blank
|
== animate-backface-hidden.html about:blank
|
||||||
fails-if(webrender) == 1245450-1.html green-rect.html
|
fails-if(webrender) == 1245450-1.html green-rect.html
|
||||||
fuzzy(1,2000) fails-if(webrender) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
|
fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
|
||||||
fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
|
fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
|
||||||
fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
|
fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
|
||||||
fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
|
fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
|
||||||
|
|
|
@ -139,9 +139,8 @@ CSSVariableDeclarations::MapRuleInfoInto(nsRuleData* aRuleData)
|
||||||
nsDataHashtable<nsStringHashKey, nsString>& variables =
|
nsDataHashtable<nsStringHashKey, nsString>& variables =
|
||||||
aRuleData->mVariables->mVariables;
|
aRuleData->mVariables->mVariables;
|
||||||
const nsAString& aName = iter.Key();
|
const nsAString& aName = iter.Key();
|
||||||
if (!variables.Contains(aName)) {
|
variables.LookupForAdd(aName).OrInsert(
|
||||||
variables.Put(aName, iter.UserData());
|
[&iter] () { return iter.UserData(); });
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,13 +98,6 @@ if CONFIG['CLANG_CL'] or not CONFIG['_MSC_VER']:
|
||||||
elif f.endswith('avx2.c'):
|
elif f.endswith('avx2.c'):
|
||||||
SOURCES[f].flags += ['-mavx2']
|
SOURCES[f].flags += ['-mavx2']
|
||||||
|
|
||||||
if CONFIG['_MSC_VER'] and not config['CLANG_CL']:
|
|
||||||
for f in SOURCES:
|
|
||||||
if f.endswith('avx.c'):
|
|
||||||
SOURCES[f].flags += ['-arch:AVX']
|
|
||||||
if f.endswith('avx2.c'):
|
|
||||||
SOURCES[f].flags += ['-arch:AVX2']
|
|
||||||
|
|
||||||
# Suppress warnings in third-party code.
|
# Suppress warnings in third-party code.
|
||||||
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
|
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
|
||||||
CFLAGS += [
|
CFLAGS += [
|
||||||
|
|
|
@ -56,6 +56,12 @@ public:
|
||||||
{
|
{
|
||||||
return reinterpret_cast<const wchar_t*>(mPtr);
|
return reinterpret_cast<const wchar_t*>(mPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator wchar_t*()
|
||||||
|
{
|
||||||
|
return const_cast<wchar_t*>(reinterpret_cast<const wchar_t*>(mPtr));
|
||||||
|
}
|
||||||
|
|
||||||
operator const void*() const
|
operator const void*() const
|
||||||
{
|
{
|
||||||
return mPtr;
|
return mPtr;
|
||||||
|
|
|
@ -781,6 +781,37 @@ continue_loading:
|
||||||
return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
|
return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _M_AMD64
|
||||||
|
typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module);
|
||||||
|
static LdrUnloadDll_func stub_LdrUnloadDll;
|
||||||
|
|
||||||
|
static NTSTATUS NTAPI
|
||||||
|
patched_LdrUnloadDll(HMODULE module)
|
||||||
|
{
|
||||||
|
// Prevent the stack walker from suspending this thread when LdrUnloadDll
|
||||||
|
// holds the RtlLookupFunctionEntry lock.
|
||||||
|
AutoSuppressStackWalking suppress;
|
||||||
|
return stub_LdrUnloadDll(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These pointers are disguised as PVOID to avoid pulling in obscure headers
|
||||||
|
typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase,
|
||||||
|
PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook,
|
||||||
|
PVOID ThunkAddress, ULONG Flags);
|
||||||
|
static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI;
|
||||||
|
|
||||||
|
static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase,
|
||||||
|
PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook,
|
||||||
|
PVOID ThunkAddress, ULONG Flags)
|
||||||
|
{
|
||||||
|
// Prevent the stack walker from suspending this thread when
|
||||||
|
// LdrResolveDelayLoadAPI holds the RtlLookupFunctionEntry lock.
|
||||||
|
AutoSuppressStackWalking suppress;
|
||||||
|
return stub_LdrResolveDelayLoadedAPI(ParentModuleBase, DelayloadDescriptor,
|
||||||
|
FailureDllHook, FailureSystemHook,
|
||||||
|
ThunkAddress, Flags);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
static bool
|
static bool
|
||||||
|
@ -861,6 +892,14 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
||||||
Kernel32Intercept.Init("kernel32.dll");
|
Kernel32Intercept.Init("kernel32.dll");
|
||||||
|
|
||||||
#ifdef _M_AMD64
|
#ifdef _M_AMD64
|
||||||
|
NtDllIntercept.AddHook("LdrUnloadDll",
|
||||||
|
reinterpret_cast<intptr_t>(patched_LdrUnloadDll),
|
||||||
|
(void**)&stub_LdrUnloadDll);
|
||||||
|
if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8
|
||||||
|
NtDllIntercept.AddHook("LdrResolveDelayLoadedAPI",
|
||||||
|
reinterpret_cast<intptr_t>(patched_LdrResolveDelayLoadedAPI),
|
||||||
|
(void**)&stub_LdrResolveDelayLoadedAPI);
|
||||||
|
}
|
||||||
if (!IsWin8OrLater()) {
|
if (!IsWin8OrLater()) {
|
||||||
// The crash that this hook works around is only seen on Win7.
|
// The crash that this hook works around is only seen on Win7.
|
||||||
Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback",
|
Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback",
|
||||||
|
|
|
@ -192,11 +192,6 @@ StackWalkInitCriticalAddress()
|
||||||
#include "mozilla/StackWalk_windows.h"
|
#include "mozilla/StackWalk_windows.h"
|
||||||
#include "mozilla/WindowsVersion.h"
|
#include "mozilla/WindowsVersion.h"
|
||||||
|
|
||||||
#ifdef MOZ_STATIC_JS // The standalone SM build lacks the interceptor headers.
|
|
||||||
#include "nsWindowsDllInterceptor.h"
|
|
||||||
#define STACKWALK_HAS_DLL_INTERCEPTOR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <imagehlp.h>
|
#include <imagehlp.h>
|
||||||
// We need a way to know if we are building for WXP (or later), as if we are, we
|
// We need a way to know if we are building for WXP (or later), as if we are, we
|
||||||
// need to use the newer 64-bit APIs. API_VERSION_NUMBER seems to fit the bill.
|
// need to use the newer 64-bit APIs. API_VERSION_NUMBER seems to fit the bill.
|
||||||
|
@ -285,39 +280,6 @@ UnregisterJitCodeRegion(uint8_t* aStart, size_t aSize)
|
||||||
sJitCodeRegionSize = 0;
|
sJitCodeRegionSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STACKWALK_HAS_DLL_INTERCEPTOR
|
|
||||||
static WindowsDllInterceptor NtDllInterceptor;
|
|
||||||
|
|
||||||
typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module);
|
|
||||||
static LdrUnloadDll_func stub_LdrUnloadDll;
|
|
||||||
|
|
||||||
static NTSTATUS NTAPI
|
|
||||||
patched_LdrUnloadDll(HMODULE module)
|
|
||||||
{
|
|
||||||
// Prevent the stack walker from suspending this thread when LdrUnloadDll
|
|
||||||
// holds the RtlLookupFunctionEntry lock.
|
|
||||||
AutoSuppressStackWalking suppress;
|
|
||||||
return stub_LdrUnloadDll(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
// These pointers are disguised as PVOID to avoid pulling in obscure headers
|
|
||||||
typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase,
|
|
||||||
PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook,
|
|
||||||
PVOID ThunkAddress, ULONG Flags);
|
|
||||||
static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI;
|
|
||||||
|
|
||||||
static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase,
|
|
||||||
PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook,
|
|
||||||
PVOID ThunkAddress, ULONG Flags)
|
|
||||||
{
|
|
||||||
// Prevent the stack walker from suspending this thread when
|
|
||||||
// LdrResolveDelayLoadAPI holds the RtlLookupFunctionEntry lock.
|
|
||||||
AutoSuppressStackWalking suppress;
|
|
||||||
return stub_LdrResolveDelayLoadedAPI(ParentModuleBase, DelayloadDescriptor,
|
|
||||||
FailureDllHook, FailureSystemHook,
|
|
||||||
ThunkAddress, Flags);
|
|
||||||
}
|
|
||||||
#endif // STACKWALK_HAS_DLL_INTERCEPTOR
|
|
||||||
#endif // _M_AMD64
|
#endif // _M_AMD64
|
||||||
|
|
||||||
// Routine to print an error message to standard error.
|
// Routine to print an error message to standard error.
|
||||||
|
@ -404,20 +366,6 @@ EnsureWalkThreadReady()
|
||||||
stackWalkThread = nullptr;
|
stackWalkThread = nullptr;
|
||||||
readyEvent = nullptr;
|
readyEvent = nullptr;
|
||||||
|
|
||||||
#if defined(_M_AMD64) && defined(STACKWALK_HAS_DLL_INTERCEPTOR)
|
|
||||||
NtDllInterceptor.Init("ntdll.dll");
|
|
||||||
NtDllInterceptor.AddHook("LdrUnloadDll",
|
|
||||||
reinterpret_cast<intptr_t>(patched_LdrUnloadDll),
|
|
||||||
(void**)&stub_LdrUnloadDll);
|
|
||||||
if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8
|
|
||||||
NtDllInterceptor.AddHook("LdrResolveDelayLoadedAPI",
|
|
||||||
reinterpret_cast<intptr_t>(patched_LdrResolveDelayLoadedAPI),
|
|
||||||
(void**)&stub_LdrResolveDelayLoadedAPI);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
InitializeDbgHelpCriticalSection();
|
|
||||||
|
|
||||||
return walkThreadReady = true;
|
return walkThreadReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,7 +623,11 @@ MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
||||||
DWORD walkerReturn;
|
DWORD walkerReturn;
|
||||||
struct WalkStackData data;
|
struct WalkStackData data;
|
||||||
|
|
||||||
if (!EnsureWalkThreadReady()) {
|
InitializeDbgHelpCriticalSection();
|
||||||
|
|
||||||
|
// EnsureWalkThreadReady's _beginthreadex takes a heap lock and must be
|
||||||
|
// avoided if we're walking another (i.e. suspended) thread.
|
||||||
|
if (!aThread && !EnsureWalkThreadReady()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
// HttpLog.h should generally be included first
|
// HttpLog.h should generally be included first
|
||||||
#include "HttpLog.h"
|
#include "HttpLog.h"
|
||||||
|
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||||
#include "mozilla/net/HttpChannelParent.h"
|
#include "mozilla/net/HttpChannelParent.h"
|
||||||
|
|
|
@ -223,6 +223,11 @@ extern "C" {
|
||||||
* @Since: ATK-2.16.
|
* @Since: ATK-2.16.
|
||||||
*@ATK_ROLE_MATH_ROOT: An object that represents a mathematical expression
|
*@ATK_ROLE_MATH_ROOT: An object that represents a mathematical expression
|
||||||
* displayed with a radical. @Since: ATK-2.16.
|
* displayed with a radical. @Since: ATK-2.16.
|
||||||
|
*@ATK_ROLE_SUBSCRIPT: An object that contains text that is displayed as a
|
||||||
|
* subscript. @Since: ATK-2.16.
|
||||||
|
*@ATK_ROLE_SUPERSCRIPT: An object that contains text that is displayed as a
|
||||||
|
* superscript. @Since: ATK-2.16.
|
||||||
|
*@ATK_ROLE_FOOTNOTE: An object that contains the text of a footnote. @Since: ATK-2.26.
|
||||||
*@ATK_ROLE_LAST_DEFINED: not a valid role, used for finding end of the enumeration
|
*@ATK_ROLE_LAST_DEFINED: not a valid role, used for finding end of the enumeration
|
||||||
*
|
*
|
||||||
* Describes the role of an object
|
* Describes the role of an object
|
||||||
|
@ -353,6 +358,9 @@ typedef enum
|
||||||
ATK_ROLE_STATIC,
|
ATK_ROLE_STATIC,
|
||||||
ATK_ROLE_MATH_FRACTION,
|
ATK_ROLE_MATH_FRACTION,
|
||||||
ATK_ROLE_MATH_ROOT,
|
ATK_ROLE_MATH_ROOT,
|
||||||
|
ATK_ROLE_SUBSCRIPT,
|
||||||
|
ATK_ROLE_SUPERSCRIPT,
|
||||||
|
ATK_ROLE_FOOTNOTE,
|
||||||
ATK_ROLE_LAST_DEFINED
|
ATK_ROLE_LAST_DEFINED
|
||||||
} AtkRole;
|
} AtkRole;
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,12 @@ enum IA2Role {
|
||||||
to the main content. If the complementary content is completely separable main
|
to the main content. If the complementary content is completely separable main
|
||||||
content, it may be appropriate to use a more general role.
|
content, it may be appropriate to use a more general role.
|
||||||
*/
|
*/
|
||||||
IA2_ROLE_COMPLEMENTARY_CONTENT
|
IA2_ROLE_COMPLEMENTARY_CONTENT,
|
||||||
|
|
||||||
|
/** An object representing a navigational landmark, a region on a page to
|
||||||
|
which the user may want quick access, such as navigating, searching,
|
||||||
|
perusing the primary content.
|
||||||
|
*/
|
||||||
|
IA2_ROLE_LANDMARK
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,8 +46,13 @@ class SigningMixin(BaseSigningMixin):
|
||||||
token = os.path.join(dirs['base_work_dir'], 'token')
|
token = os.path.join(dirs['base_work_dir'], 'token')
|
||||||
nonce = os.path.join(dirs['base_work_dir'], 'nonce')
|
nonce = os.path.join(dirs['base_work_dir'], 'nonce')
|
||||||
host_cert = os.path.join(signing_dir, 'host.cert')
|
host_cert = os.path.join(signing_dir, 'host.cert')
|
||||||
|
python = sys.executable
|
||||||
|
# A mock environment is a special case, the system python isn't
|
||||||
|
# available there
|
||||||
|
if 'mock_target' in self.config:
|
||||||
|
python = 'python2.7'
|
||||||
cmd = [
|
cmd = [
|
||||||
sys.executable,
|
python,
|
||||||
os.path.join(signing_dir, 'signtool.py'),
|
os.path.join(signing_dir, 'signtool.py'),
|
||||||
'--cachedir', cache_dir,
|
'--cachedir', cache_dir,
|
||||||
'-t', token,
|
'-t', token,
|
||||||
|
|
|
@ -7,6 +7,7 @@ from mozharness.base.log import INFO
|
||||||
|
|
||||||
# BalrogMixin {{{1
|
# BalrogMixin {{{1
|
||||||
class BalrogMixin(object):
|
class BalrogMixin(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _query_balrog_username(server_config, product=None):
|
def _query_balrog_username(server_config, product=None):
|
||||||
username = server_config["balrog_usernames"].get(product)
|
username = server_config["balrog_usernames"].get(product)
|
||||||
|
@ -15,6 +16,15 @@ class BalrogMixin(object):
|
||||||
else:
|
else:
|
||||||
raise KeyError("Couldn't find balrog username.")
|
raise KeyError("Couldn't find balrog username.")
|
||||||
|
|
||||||
|
def query_python(self):
|
||||||
|
python = sys.executable
|
||||||
|
# A mock environment is a special case, the system python isn't
|
||||||
|
# available there
|
||||||
|
if 'mock_target' in self.config:
|
||||||
|
python = 'python2.7'
|
||||||
|
return python
|
||||||
|
|
||||||
|
|
||||||
def generate_balrog_props(self, props_path):
|
def generate_balrog_props(self, props_path):
|
||||||
self.set_buildbot_property(
|
self.set_buildbot_property(
|
||||||
"hashType", self.config.get("hash_type", "sha512"), write_to_file=True
|
"hashType", self.config.get("hash_type", "sha512"), write_to_file=True
|
||||||
|
@ -57,7 +67,7 @@ class BalrogMixin(object):
|
||||||
self.generate_balrog_props(props_path)
|
self.generate_balrog_props(props_path)
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
sys.executable,
|
self.query_python(),
|
||||||
submitter_script,
|
submitter_script,
|
||||||
"--build-properties", props_path,
|
"--build-properties", props_path,
|
||||||
"-t", release_type,
|
"-t", release_type,
|
||||||
|
@ -91,7 +101,10 @@ class BalrogMixin(object):
|
||||||
|
|
||||||
def submit_balrog_release_pusher(self, dirs):
|
def submit_balrog_release_pusher(self, dirs):
|
||||||
product = self.buildbot_config["properties"]["product"]
|
product = self.buildbot_config["properties"]["product"]
|
||||||
cmd = [sys.executable, os.path.join(os.path.join(dirs['abs_tools_dir'], "scripts/updates/balrog-release-pusher.py"))]
|
cmd = [
|
||||||
|
self.query_python(),
|
||||||
|
os.path.join(os.path.join(dirs['abs_tools_dir'], "scripts/updates/balrog-release-pusher.py"))
|
||||||
|
]
|
||||||
cmd.extend(["--build-properties", os.path.join(dirs["base_work_dir"], "balrog_props.json")])
|
cmd.extend(["--build-properties", os.path.join(dirs["base_work_dir"], "balrog_props.json")])
|
||||||
cmd.extend(["--buildbot-configs", "https://hg.mozilla.org/build/buildbot-configs"])
|
cmd.extend(["--buildbot-configs", "https://hg.mozilla.org/build/buildbot-configs"])
|
||||||
cmd.extend(["--release-config", os.path.join(dirs['build_dir'], self.config.get("release_config_file"))])
|
cmd.extend(["--release-config", os.path.join(dirs['build_dir'], self.config.get("release_config_file"))])
|
||||||
|
@ -131,7 +144,7 @@ class BalrogMixin(object):
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
sys.executable,
|
self.query_python(),
|
||||||
submitter_script,
|
submitter_script,
|
||||||
"--credentials-file", credentials_file,
|
"--credentials-file", credentials_file,
|
||||||
"--api-root", c["balrog_api_root"],
|
"--api-root", c["balrog_api_root"],
|
||||||
|
|
|
@ -698,7 +698,12 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
||||||
return self._mach(target=target, env=env)
|
return self._mach(target=target, env=env)
|
||||||
|
|
||||||
def _get_mach_executable(self):
|
def _get_mach_executable(self):
|
||||||
return [sys.executable, 'mach']
|
python = sys.executable
|
||||||
|
# A mock environment is a special case, the system python isn't
|
||||||
|
# available there
|
||||||
|
if 'mock_target' in self.config:
|
||||||
|
python = 'python2.7'
|
||||||
|
return [python, 'mach']
|
||||||
|
|
||||||
def _get_make_executable(self):
|
def _get_make_executable(self):
|
||||||
config = self.config
|
config = self.config
|
||||||
|
@ -1042,8 +1047,14 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
||||||
return self.warning(ERROR_MSGS['tooltool_manifest_undetermined'])
|
return self.warning(ERROR_MSGS['tooltool_manifest_undetermined'])
|
||||||
tooltool_manifest_path = os.path.join(dirs['abs_mozilla_dir'],
|
tooltool_manifest_path = os.path.join(dirs['abs_mozilla_dir'],
|
||||||
manifest_src)
|
manifest_src)
|
||||||
|
python = sys.executable
|
||||||
|
# A mock environment is a special case, the system python isn't
|
||||||
|
# available there
|
||||||
|
if 'mock_target' in self.config:
|
||||||
|
python = 'python2.7'
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
sys.executable, '-u',
|
python, '-u',
|
||||||
os.path.join(dirs['abs_mozilla_dir'], 'mach'),
|
os.path.join(dirs['abs_mozilla_dir'], 'mach'),
|
||||||
'artifact',
|
'artifact',
|
||||||
'toolchain',
|
'toolchain',
|
||||||
|
|
|
@ -77,3 +77,35 @@ add_task(async function tabsSendMessageReply() {
|
||||||
await extension.awaitFinish("sendMessage");
|
await extension.awaitFinish("sendMessage");
|
||||||
await extension.unload();
|
await extension.unload();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_task(async function tabsSendMessageBlob() {
|
||||||
|
function background() {
|
||||||
|
browser.runtime.onMessage.addListener(msg => {
|
||||||
|
browser.test.assertTrue(msg.blob instanceof Blob, "Message is a blob");
|
||||||
|
return Promise.resolve(msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
let childFrame = document.createElement("iframe");
|
||||||
|
childFrame.src = "extensionpage.html";
|
||||||
|
document.body.appendChild(childFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
function senderScript() {
|
||||||
|
browser.runtime.sendMessage({blob: new Blob(["hello"])}).then(response => {
|
||||||
|
browser.test.assertTrue(response.blob instanceof Blob, "Response is a blob");
|
||||||
|
browser.test.notifyPass("sendBlob");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background,
|
||||||
|
files: {
|
||||||
|
"senderScript.js": senderScript,
|
||||||
|
"extensionpage.html": `<!DOCTYPE html><meta charset="utf-8"><script src="senderScript.js"></script>`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.startup();
|
||||||
|
await extension.awaitFinish("sendBlob");
|
||||||
|
await extension.unload();
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/* eslint-env mozilla/chrome-worker */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
importScripts("resource://gre/modules/osfile.jsm");
|
||||||
|
|
||||||
|
const FILE_ENTRY = "201: ";
|
||||||
|
|
||||||
|
onmessage = async function(msg) {
|
||||||
|
try {
|
||||||
|
let extractedPaths = [];
|
||||||
|
let jarPath = "jar:file://" + msg.data.zipPath + "!/";
|
||||||
|
let jarResponse = await fetch(jarPath);
|
||||||
|
let dirListing = await jarResponse.text();
|
||||||
|
let lines = dirListing.split("\n");
|
||||||
|
let reader = new FileReader();
|
||||||
|
for (let line of lines) {
|
||||||
|
if (!line.startsWith(FILE_ENTRY)) {
|
||||||
|
// Not a file entry, skip.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let lineSplits = line.split(" ");
|
||||||
|
let fileName = lineSplits[1];
|
||||||
|
// We don't need these types of files.
|
||||||
|
if (fileName == "verified_contents.json" ||
|
||||||
|
fileName == "icon-128x128.png") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let filePath = jarPath + fileName;
|
||||||
|
let filePathResponse = await fetch(filePath);
|
||||||
|
let fileContents = await filePathResponse.blob();
|
||||||
|
let fileData = await new Promise(resolve => {
|
||||||
|
reader.onloadend = function() { resolve(reader.result) };
|
||||||
|
reader.readAsArrayBuffer(fileContents);
|
||||||
|
});
|
||||||
|
let profileDirPath = OS.Constants.Path.profileDir;
|
||||||
|
let installToDirPath = OS.Path.join(profileDirPath,
|
||||||
|
msg.data.relativeInstallPath);
|
||||||
|
await OS.File.makeDir(installToDirPath, {ignoreExisting: true,
|
||||||
|
unixMode: 0o755,
|
||||||
|
from: profileDirPath});
|
||||||
|
// Do not extract into directories. Extract all files to the same
|
||||||
|
// directory.
|
||||||
|
let destPath = OS.Path.join(installToDirPath, fileName);
|
||||||
|
await OS.File.writeAtomic(destPath, new Uint8Array(fileData),
|
||||||
|
{tmpPath: destPath + ".tmp"});
|
||||||
|
// Ensure files are writable and executable. Otherwise, we may be
|
||||||
|
// unable to execute or uninstall them.
|
||||||
|
await OS.File.setPermissions(destPath, {unixMode: 0o700});
|
||||||
|
extractedPaths.push(destPath);
|
||||||
|
}
|
||||||
|
postMessage({
|
||||||
|
"result": "success",
|
||||||
|
extractedPaths
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
postMessage({
|
||||||
|
"result": "fail",
|
||||||
|
"exception": e.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -369,27 +369,11 @@ GMPAddon.prototype = {
|
||||||
* into the specified location. (Which typically leties per platform)
|
* into the specified location. (Which typically leties per platform)
|
||||||
* @param zipPath The path on disk of the zip file to extract
|
* @param zipPath The path on disk of the zip file to extract
|
||||||
*/
|
*/
|
||||||
function GMPExtractor(zipPath, installToDirPath) {
|
function GMPExtractor(zipPath, relativeInstallPath) {
|
||||||
this.zipPath = zipPath;
|
this.zipPath = zipPath;
|
||||||
this.installToDirPath = installToDirPath;
|
this.relativeInstallPath = relativeInstallPath;
|
||||||
}
|
}
|
||||||
GMPExtractor.prototype = {
|
GMPExtractor.prototype = {
|
||||||
/**
|
|
||||||
* Obtains a list of all the entries in a zipfile in the format of *.*.
|
|
||||||
* This also includes files inside directories.
|
|
||||||
*
|
|
||||||
* @param zipReader the nsIZipReader to check
|
|
||||||
* @return An array of string name entries which can be used
|
|
||||||
* in nsIZipReader.extract
|
|
||||||
*/
|
|
||||||
_getZipEntries(zipReader) {
|
|
||||||
let entries = [];
|
|
||||||
let enumerator = zipReader.findEntries("*.*");
|
|
||||||
while (enumerator.hasMore()) {
|
|
||||||
entries.push(enumerator.getNext());
|
|
||||||
}
|
|
||||||
return entries;
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* Installs the this.zipPath contents into the directory used to store GMP
|
* Installs the this.zipPath contents into the directory used to store GMP
|
||||||
* addons for the current platform.
|
* addons for the current platform.
|
||||||
|
@ -398,70 +382,26 @@ GMPExtractor.prototype = {
|
||||||
* See GMPInstallManager.installAddon for resolve/rejected info
|
* See GMPInstallManager.installAddon for resolve/rejected info
|
||||||
*/
|
*/
|
||||||
install() {
|
install() {
|
||||||
try {
|
this._deferred = Promise.defer();
|
||||||
let log = getScopedLogger("GMPExtractor.install");
|
let deferredPromise = this._deferred;
|
||||||
this._deferred = Promise.defer();
|
let {zipPath, relativeInstallPath} = this;
|
||||||
log.info("Installing " + this.zipPath + "...");
|
let worker =
|
||||||
// Get the input zip file
|
new ChromeWorker("resource://gre/modules/GMPExtractorWorker.js");
|
||||||
let zipFile = Cc["@mozilla.org/file/local;1"].
|
worker.onmessage = function(msg) {
|
||||||
createInstance(Ci.nsIFile);
|
let log = getScopedLogger("GMPExtractor");
|
||||||
zipFile.initWithPath(this.zipPath);
|
worker.terminate();
|
||||||
|
if (msg.data.result != "success") {
|
||||||
// Initialize a zipReader and obtain the entries
|
log.error("Failed to extract zip file: " + zipPath);
|
||||||
var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
return deferredPromise.reject({
|
||||||
createInstance(Ci.nsIZipReader);
|
target: this,
|
||||||
zipReader.open(zipFile)
|
status: msg.data.exception,
|
||||||
let entries = this._getZipEntries(zipReader);
|
type: "exception"
|
||||||
let extractedPaths = [];
|
});
|
||||||
|
|
||||||
let destDir = Cc["@mozilla.org/file/local;1"].
|
|
||||||
createInstance(Ci.nsILocalFile);
|
|
||||||
destDir.initWithPath(this.installToDirPath);
|
|
||||||
// Make sure the destination exists
|
|
||||||
if (!destDir.exists()) {
|
|
||||||
destDir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
|
|
||||||
}
|
}
|
||||||
|
log.info("Successfully extracted zip file: " + zipPath);
|
||||||
// Extract each of the entries
|
return deferredPromise.resolve(msg.data.extractedPaths);
|
||||||
entries.forEach(entry => {
|
|
||||||
// We don't need these types of files
|
|
||||||
if (entry.includes("__MACOSX") ||
|
|
||||||
entry == "_metadata/verified_contents.json" ||
|
|
||||||
entry == "imgs/icon-128x128.png") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let outFile = destDir.clone();
|
|
||||||
// Do not extract into directories. Extract all files to the same
|
|
||||||
// directory. DO NOT use |OS.Path.basename()| here, as in Windows it
|
|
||||||
// does not work properly with forward slashes (which we must use here).
|
|
||||||
let outBaseName = entry.slice(entry.lastIndexOf("/") + 1);
|
|
||||||
outFile.appendRelativePath(outBaseName);
|
|
||||||
|
|
||||||
zipReader.extract(entry, outFile);
|
|
||||||
extractedPaths.push(outFile.path);
|
|
||||||
// Ensure files are writable and executable. Otherwise we may be unable to
|
|
||||||
// execute or uninstall them.
|
|
||||||
outFile.permissions |= parseInt("0700", 8);
|
|
||||||
log.info(entry + " was successfully extracted to: " +
|
|
||||||
outFile.path);
|
|
||||||
});
|
|
||||||
zipReader.close();
|
|
||||||
if (!GMPInstallManager.overrideLeaveDownloadedZip) {
|
|
||||||
zipFile.remove(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(this.zipPath + " was installed successfully");
|
|
||||||
this._deferred.resolve(extractedPaths);
|
|
||||||
} catch (e) {
|
|
||||||
if (zipReader) {
|
|
||||||
zipReader.close();
|
|
||||||
}
|
|
||||||
this._deferred.reject({
|
|
||||||
target: this,
|
|
||||||
status: e,
|
|
||||||
type: "exception"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
worker.postMessage({zipPath, relativeInstallPath});
|
||||||
return this._deferred.promise;
|
return this._deferred.promise;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -496,11 +436,10 @@ GMPDownloader.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProductAddonChecker.downloadAddon(gmpAddon).then((zipPath) => {
|
return ProductAddonChecker.downloadAddon(gmpAddon).then((zipPath) => {
|
||||||
let path = OS.Path.join(OS.Constants.Path.profileDir,
|
let relativePath = OS.Path.join(gmpAddon.id,
|
||||||
gmpAddon.id,
|
gmpAddon.version);
|
||||||
gmpAddon.version);
|
log.info("install to directory path: " + relativePath);
|
||||||
log.info("install to directory path: " + path);
|
let gmpInstaller = new GMPExtractor(zipPath, relativePath);
|
||||||
let gmpInstaller = new GMPExtractor(zipPath, path);
|
|
||||||
let installPromise = gmpInstaller.install();
|
let installPromise = gmpInstaller.install();
|
||||||
return installPromise.then(extractedPaths => {
|
return installPromise.then(extractedPaths => {
|
||||||
// Success, set the prefs
|
// Success, set the prefs
|
||||||
|
|
|
@ -196,6 +196,7 @@ EXTRA_JS_MODULES += [
|
||||||
'FinderIterator.jsm',
|
'FinderIterator.jsm',
|
||||||
'FormLikeFactory.jsm',
|
'FormLikeFactory.jsm',
|
||||||
'Geometry.jsm',
|
'Geometry.jsm',
|
||||||
|
'GMPExtractorWorker.js',
|
||||||
'GMPInstallManager.jsm',
|
'GMPInstallManager.jsm',
|
||||||
'GMPUtils.jsm',
|
'GMPUtils.jsm',
|
||||||
'HiddenFrame.jsm',
|
'HiddenFrame.jsm',
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "shared-libraries.h"
|
#include "shared-libraries.h"
|
||||||
#include "js/Value.h"
|
#include "js/Value.h"
|
||||||
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/TypedArray.h"
|
#include "mozilla/dom/TypedArray.h"
|
||||||
|
|
|
@ -344,7 +344,7 @@ IMMHandler::InitKeyboardLayout(nsWindow* aWindow,
|
||||||
// Add room for the terminating null character
|
// Add room for the terminating null character
|
||||||
sIMEName.SetLength(++IMENameLength);
|
sIMEName.SetLength(++IMENameLength);
|
||||||
IMENameLength =
|
IMENameLength =
|
||||||
::ImmGetDescriptionW(aKeyboardLayout, wwc(sIMEName.BeginWriting()),
|
::ImmGetDescriptionW(aKeyboardLayout, sIMEName.get(),
|
||||||
IMENameLength);
|
IMENameLength);
|
||||||
// Adjust the length to ignore the terminating null character
|
// Adjust the length to ignore the terminating null character
|
||||||
sIMEName.SetLength(IMENameLength);
|
sIMEName.SetLength(IMENameLength);
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "nsISupportsImpl.h"
|
#include "nsISupportsImpl.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
|
||||||
nsresult NS_FASTCALL
|
nsresult NS_FASTCALL
|
||||||
NS_TableDrivenQI(void* aThis, REFNSIID aIID, void** aInstancePtr,
|
NS_TableDrivenQI(void* aThis, REFNSIID aIID, void** aInstancePtr,
|
||||||
const QITableEntry* aEntries)
|
const QITableEntry* aEntries)
|
||||||
|
@ -28,10 +30,15 @@ NS_TableDrivenQI(void* aThis, REFNSIID aIID, void** aInstancePtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
|
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
|
||||||
|
nsAutoOwningThread::nsAutoOwningThread()
|
||||||
|
: mThread(GetCurrentVirtualThread())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsAutoOwningThread::AssertCurrentThreadOwnsMe(const char* msg) const
|
nsAutoOwningThread::AssertCurrentThreadOwnsMe(const char* msg) const
|
||||||
{
|
{
|
||||||
if (MOZ_UNLIKELY(mThread != PR_GetCurrentThread())) {
|
if (MOZ_UNLIKELY(mThread != GetCurrentVirtualThread())) {
|
||||||
// `msg` is a string literal by construction.
|
// `msg` is a string literal by construction.
|
||||||
MOZ_CRASH_UNSAFE_OOL(msg);
|
MOZ_CRASH_UNSAFE_OOL(msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ ToCanonicalSupports(nsISupports* aSupports)
|
||||||
class nsAutoOwningThread
|
class nsAutoOwningThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsAutoOwningThread() { mThread = PR_GetCurrentThread(); }
|
nsAutoOwningThread();
|
||||||
|
|
||||||
// We move the actual assertion checks out-of-line to minimize code bloat,
|
// We move the actual assertion checks out-of-line to minimize code bloat,
|
||||||
// but that means we have to pass a non-literal string to
|
// but that means we have to pass a non-literal string to
|
||||||
|
|
|
@ -229,7 +229,7 @@ nsresult GetCountryCode(nsAString& aCountryCode)
|
||||||
}
|
}
|
||||||
// Now get the string for real
|
// Now get the string for real
|
||||||
aCountryCode.SetLength(numChars);
|
aCountryCode.SetLength(numChars);
|
||||||
numChars = GetGeoInfoW(geoid, GEO_ISO2, wwc(aCountryCode.BeginWriting()),
|
numChars = GetGeoInfoW(geoid, GEO_ISO2, char16ptr_t(aCountryCode.BeginWriting()),
|
||||||
aCountryCode.Length(), 0);
|
aCountryCode.Length(), 0);
|
||||||
if (!numChars) {
|
if (!numChars) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
|
@ -194,6 +194,92 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EntryPtr {
|
||||||
|
private:
|
||||||
|
EntryType& mEntry;
|
||||||
|
bool mExistingEntry;
|
||||||
|
// For debugging purposes
|
||||||
|
#ifdef DEBUG
|
||||||
|
nsBaseHashtable& mTable;
|
||||||
|
uint32_t mTableGeneration;
|
||||||
|
bool mDidInitNewEntry;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
EntryPtr(nsBaseHashtable& aTable, EntryType* aEntry, bool aExistingEntry)
|
||||||
|
: mEntry(*aEntry)
|
||||||
|
, mExistingEntry(aExistingEntry)
|
||||||
|
#ifdef DEBUG
|
||||||
|
, mTable(aTable)
|
||||||
|
, mTableGeneration(aTable.GetGeneration())
|
||||||
|
, mDidInitNewEntry(false)
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
|
~EntryPtr()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mExistingEntry || mDidInitNewEntry,
|
||||||
|
"Forgot to call OrInsert() on a new entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is there something stored in the table already?
|
||||||
|
explicit operator bool() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
|
||||||
|
return mExistingEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
UserDataType OrInsert(F func)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
|
||||||
|
if (!mExistingEntry) {
|
||||||
|
mEntry.mData = func();
|
||||||
|
#ifdef DEBUG
|
||||||
|
mDidInitNewEntry = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return mEntry.mData;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_MUST_USE DataType& Data()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
|
||||||
|
return mEntry.mData;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up aKey in the hashtable and returns an object that allows you to
|
||||||
|
* insert a new entry into the hashtable for that key if an existing entry
|
||||||
|
* isn't found for it.
|
||||||
|
*
|
||||||
|
* A typical usage of this API looks like this:
|
||||||
|
*
|
||||||
|
* auto insertedValue = table.LookupForAdd(key).OrInsert([]() {
|
||||||
|
* return newValue;
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* auto p = table.LookupForAdd(key);
|
||||||
|
* if (p) {
|
||||||
|
* // The entry already existed in the table.
|
||||||
|
* DoSomething(p.Data());
|
||||||
|
* } else {
|
||||||
|
* // An existing entry wasn't found, store a new entry in the hashtable.
|
||||||
|
* p.OrInsert([]() { return newValue; });
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* We ensure that the hashtable isn't modified before EntryPtr method calls.
|
||||||
|
* This is useful for cases where you want to insert a new entry into the
|
||||||
|
* hashtable if one doesn't exist before but would like to avoid two hashtable
|
||||||
|
* lookups.
|
||||||
|
*/
|
||||||
|
MOZ_MUST_USE EntryPtr LookupForAdd(KeyType aKey)
|
||||||
|
{
|
||||||
|
auto count = Count();
|
||||||
|
EntryType* ent = this->PutEntry(aKey);
|
||||||
|
return EntryPtr(*this, ent, count == Count());
|
||||||
|
}
|
||||||
|
|
||||||
// This is an iterator that also allows entry removal. Example usage:
|
// This is an iterator that also allows entry removal. Example usage:
|
||||||
//
|
//
|
||||||
// for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
|
// for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
|
||||||
|
|
|
@ -68,74 +68,6 @@ public:
|
||||||
* @param aKey the key to get and remove from the hashtable
|
* @param aKey the key to get and remove from the hashtable
|
||||||
*/
|
*/
|
||||||
void RemoveAndForget(KeyType aKey, nsAutoPtr<T>& aOut);
|
void RemoveAndForget(KeyType aKey, nsAutoPtr<T>& aOut);
|
||||||
|
|
||||||
struct EntryPtr {
|
|
||||||
private:
|
|
||||||
typename base_type::EntryType& mEntry;
|
|
||||||
// For debugging purposes
|
|
||||||
#ifdef DEBUG
|
|
||||||
base_type& mTable;
|
|
||||||
uint32_t mTableGeneration;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
EntryPtr(base_type& aTable, typename base_type::EntryType* aEntry)
|
|
||||||
: mEntry(*aEntry)
|
|
||||||
#ifdef DEBUG
|
|
||||||
, mTable(aTable)
|
|
||||||
, mTableGeneration(aTable.GetGeneration())
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~EntryPtr()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mEntry.mData, "Entry should have been added by now");
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const
|
|
||||||
{
|
|
||||||
// Is there something stored in the table already?
|
|
||||||
MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
|
|
||||||
return !!mEntry.mData;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
T* OrInsert(F func)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
|
|
||||||
if (!mEntry.mData) {
|
|
||||||
mEntry.mData = func();
|
|
||||||
}
|
|
||||||
return mEntry.mData;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looks up aKey in the hashtable and returns an object that allows you to
|
|
||||||
* insert a new entry into the hashtable for that key if an existing entry
|
|
||||||
* isn't found for it.
|
|
||||||
*
|
|
||||||
* A typical usage of this API looks like this:
|
|
||||||
*
|
|
||||||
* auto insertedValue = table.LookupForAdd(key).OrInsert([]() {
|
|
||||||
* return newValue;
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* auto p = table.LookupForAdd(key);
|
|
||||||
* if (p) {
|
|
||||||
* // The entry already existed in the table.
|
|
||||||
* DoSomething();
|
|
||||||
* } else {
|
|
||||||
* // An existing entry wasn't found, store a new entry in the hashtable.
|
|
||||||
* p.OrInsert([]() { return newValue; });
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* We ensure that the hashtable isn't modified before OrInsert() is called.
|
|
||||||
* This is useful for cases where you want to insert a new entry into the
|
|
||||||
* hashtable if one doesn't exist before but would like to avoid two hashtable
|
|
||||||
* lookups.
|
|
||||||
*/
|
|
||||||
MOZ_MUST_USE EntryPtr LookupForAdd(KeyType aKey);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -148,21 +80,14 @@ T*
|
||||||
nsClassHashtable<KeyClass, T>::LookupOrAdd(KeyType aKey,
|
nsClassHashtable<KeyClass, T>::LookupOrAdd(KeyType aKey,
|
||||||
Args&&... aConstructionArgs)
|
Args&&... aConstructionArgs)
|
||||||
{
|
{
|
||||||
|
auto count = this->Count();
|
||||||
typename base_type::EntryType* ent = this->PutEntry(aKey);
|
typename base_type::EntryType* ent = this->PutEntry(aKey);
|
||||||
if (!ent->mData) {
|
if (count != this->Count()) {
|
||||||
ent->mData = new T(mozilla::Forward<Args>(aConstructionArgs)...);
|
ent->mData = new T(mozilla::Forward<Args>(aConstructionArgs)...);
|
||||||
}
|
}
|
||||||
return ent->mData;
|
return ent->mData;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class KeyClass, class T>
|
|
||||||
typename nsClassHashtable<KeyClass, T>::EntryPtr
|
|
||||||
nsClassHashtable<KeyClass, T>::LookupForAdd(KeyType aKey)
|
|
||||||
{
|
|
||||||
typename base_type::EntryType* ent = this->PutEntry(aKey);
|
|
||||||
return EntryPtr(*this, ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class KeyClass, class T>
|
template<class KeyClass, class T>
|
||||||
bool
|
bool
|
||||||
nsClassHashtable<KeyClass, T>::Get(KeyType aKey, T** aRetVal) const
|
nsClassHashtable<KeyClass, T>::Get(KeyType aKey, T** aRetVal) const
|
||||||
|
|
|
@ -354,11 +354,8 @@ nsWindowsRegKey::ReadStringValue(const nsAString& aName, nsAString& aResult)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAString::iterator begin;
|
|
||||||
expandedResult.BeginWriting(begin);
|
|
||||||
|
|
||||||
resultLen = ExpandEnvironmentStringsW(flatSource.get(),
|
resultLen = ExpandEnvironmentStringsW(flatSource.get(),
|
||||||
wwc(begin.get()),
|
expandedResult.get(),
|
||||||
resultLen + 1);
|
resultLen + 1);
|
||||||
if (resultLen <= 0) {
|
if (resultLen <= 0) {
|
||||||
rv = ERROR_UNKNOWN_FEATURE;
|
rv = ERROR_UNKNOWN_FEATURE;
|
||||||
|
|
|
@ -61,7 +61,7 @@ HandleToFilename(HANDLE aHandle, const LARGE_INTEGER& aOffset,
|
||||||
do {
|
do {
|
||||||
mappedFilename.SetLength(mappedFilename.Length() + MAX_PATH);
|
mappedFilename.SetLength(mappedFilename.Length() + MAX_PATH);
|
||||||
len = GetMappedFileNameW(GetCurrentProcess(), view,
|
len = GetMappedFileNameW(GetCurrentProcess(), view,
|
||||||
wwc(mappedFilename.BeginWriting()),
|
mappedFilename.get(),
|
||||||
mappedFilename.Length());
|
mappedFilename.Length());
|
||||||
} while (!len && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
} while (!len && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
||||||
if (!len) {
|
if (!len) {
|
||||||
|
|
|
@ -995,7 +995,7 @@ nsLocalFile::ResolveShortcut()
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t* resolvedPath = wwc(mResolvedPath.BeginWriting());
|
wchar_t* resolvedPath = mResolvedPath.get();
|
||||||
|
|
||||||
// resolve this shortcut
|
// resolve this shortcut
|
||||||
nsresult rv = gResolver->Resolve(mWorkingPath.get(), resolvedPath);
|
nsresult rv = gResolver->Resolve(mWorkingPath.get(), resolvedPath);
|
||||||
|
@ -1365,7 +1365,7 @@ nsLocalFile::Create(uint32_t aType, uint32_t aAttributes)
|
||||||
// Skip the first 'X:\' for the first form, and skip the first full
|
// Skip the first 'X:\' for the first form, and skip the first full
|
||||||
// '\\machine\volume\' segment for the second form.
|
// '\\machine\volume\' segment for the second form.
|
||||||
|
|
||||||
wchar_t* path = wwc(mResolvedPath.BeginWriting());
|
wchar_t* path = char16ptr_t(mResolvedPath.BeginWriting());
|
||||||
|
|
||||||
if (path[0] == L'\\' && path[1] == L'\\') {
|
if (path[0] == L'\\' && path[1] == L'\\') {
|
||||||
// dealing with a UNC path here; skip past '\\machine\'
|
// dealing with a UNC path here; skip past '\\machine\'
|
||||||
|
@ -3743,7 +3743,7 @@ nsDriveEnumerator::Init()
|
||||||
if (!mDrives.SetLength(length + 1, fallible)) {
|
if (!mDrives.SetLength(length + 1, fallible)) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
if (!GetLogicalDriveStringsW(length, wwc(mDrives.BeginWriting()))) {
|
if (!GetLogicalDriveStringsW(length, mDrives.get())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
mDrives.BeginReading(mStartOfCurrentDrive);
|
mDrives.BeginReading(mStartOfCurrentDrive);
|
||||||
|
|
|
@ -929,12 +929,8 @@ NS_CopyNativeToUnicode(const nsACString& aInput, nsAString& aOutput)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
if (resultLen > 0) {
|
if (resultLen > 0) {
|
||||||
nsAString::iterator out_iter;
|
char16ptr_t result = aOutput.BeginWriting();
|
||||||
aOutput.BeginWriting(out_iter);
|
::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, result, resultLen);
|
||||||
|
|
||||||
char16_t* result = out_iter.get();
|
|
||||||
|
|
||||||
::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, wwc(result), resultLen);
|
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -978,41 +974,6 @@ NS_CopyUnicodeToNative(const nsAString& aInput, nsACString& aOutput)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// moved from widget/windows/nsToolkit.cpp
|
|
||||||
int32_t
|
|
||||||
NS_ConvertAtoW(const char* aStrInA, int aBufferSize, char16_t* aStrOutW)
|
|
||||||
{
|
|
||||||
return MultiByteToWideChar(CP_ACP, 0, aStrInA, -1, wwc(aStrOutW), aBufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t
|
|
||||||
NS_ConvertWtoA(const char16_t* aStrInW, int aBufferSizeOut,
|
|
||||||
char* aStrOutA, const char* aDefault)
|
|
||||||
{
|
|
||||||
if ((!aStrInW) || (!aStrOutA) || (aBufferSizeOut <= 0)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numCharsConverted = WideCharToMultiByte(CP_ACP, 0, char16ptr_t(aStrInW), -1,
|
|
||||||
aStrOutA, aBufferSizeOut,
|
|
||||||
aDefault, nullptr);
|
|
||||||
|
|
||||||
if (!numCharsConverted) {
|
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
||||||
// Overflow, add missing null termination but return 0
|
|
||||||
aStrOutA[aBufferSizeOut - 1] = '\0';
|
|
||||||
} else {
|
|
||||||
// Other error, clear string and return 0
|
|
||||||
aStrOutA[0] = '\0';
|
|
||||||
}
|
|
||||||
} else if (numCharsConverted < aBufferSizeOut) {
|
|
||||||
// Add 2nd null (really necessary?)
|
|
||||||
aStrOutA[numCharsConverted] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return numCharsConverted;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
|
|
|
@ -148,49 +148,6 @@ private:
|
||||||
NS_ConvertUTF8toUTF16(char16_t) = delete;
|
NS_ConvertUTF8toUTF16(char16_t) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef MOZ_USE_CHAR16_WRAPPER
|
|
||||||
|
|
||||||
inline char16_t*
|
|
||||||
wwc(wchar_t* aStr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<char16_t*>(aStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline wchar_t*
|
|
||||||
wwc(char16_t* aStr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<wchar_t*>(aStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char16_t*
|
|
||||||
wwc(const wchar_t* aStr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<const char16_t*>(aStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const wchar_t*
|
|
||||||
wwc(const char16_t* aStr)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<const wchar_t*>(aStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
inline char16_t*
|
|
||||||
wwc(char16_t* aStr)
|
|
||||||
{
|
|
||||||
return aStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char16_t*
|
|
||||||
wwc(const char16_t* aStr)
|
|
||||||
{
|
|
||||||
return aStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// the following are included/declared for backwards compatibility
|
// the following are included/declared for backwards compatibility
|
||||||
typedef nsAutoString nsVoidableString;
|
typedef nsAutoString nsVoidableString;
|
||||||
|
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче