зеркало из 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;
|
||||
else if (aAtkObj->role == ATK_ROLE_MATH && !IsAtkVersionAtLeast(2, 12))
|
||||
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))
|
||||
aAtkObj->role = ATK_ROLE_TEXT;
|
||||
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::a11y;
|
||||
|
||||
int atkMajorVersion = 1, atkMinorVersion = 12;
|
||||
int atkMajorVersion = 1, atkMinorVersion = 12, atkMicroVersion = 0;
|
||||
|
||||
GType (*gAtkTableCellGetTypeFunc)();
|
||||
|
||||
|
@ -168,8 +168,11 @@ a11y::PlatformInit()
|
|||
if (version) {
|
||||
char* endPtr = nullptr;
|
||||
atkMajorVersion = strtol(version, &endPtr, 10);
|
||||
if (*endPtr == '.')
|
||||
if (atkMajorVersion != 0L) {
|
||||
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::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
|
||||
* aMajor.aMinor.0.
|
||||
* aMajor.aMinor.aMicro.
|
||||
*/
|
||||
static inline bool
|
||||
IsAtkVersionAtLeast(int aMajor, int aMinor)
|
||||
IsAtkVersionAtLeast(int aMajor, int aMinor, int aMicro=0)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -186,6 +186,396 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
|
|||
eList,
|
||||
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
|
||||
&nsGkAtoms::document,
|
||||
roles::DOCUMENT,
|
||||
|
|
|
@ -982,7 +982,25 @@ enum Role {
|
|||
*/
|
||||
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
|
||||
|
|
|
@ -1002,7 +1002,7 @@ ROLE(EMBEDDED_OBJECT,
|
|||
|
||||
ROLE(NOTE,
|
||||
"note",
|
||||
ATK_ROLE_SECTION,
|
||||
ATK_ROLE_COMMENT,
|
||||
NSAccessibilityGroupRole,
|
||||
USE_ROLE_STRING,
|
||||
IA2_ROLE_NOTE,
|
||||
|
@ -1368,3 +1368,26 @@ ROLE(SUMMARY,
|
|||
ROLE_SYSTEM_PUSHBUTTON,
|
||||
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.
|
||||
*/
|
||||
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)
|
||||
landmark = proxy->LandmarkRole();
|
||||
|
||||
// HTML Elements treated as landmarks
|
||||
// XXX bug 1371712
|
||||
if (landmark) {
|
||||
if (landmark == nsGkAtoms::application)
|
||||
return @"AXLandmarkApplication";
|
||||
|
@ -747,6 +749,13 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
|||
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
|
||||
nsIAtom* roleAtom = nullptr;
|
||||
if (accWrap && accWrap->HasARIARole()) {
|
||||
|
@ -889,6 +898,17 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
|||
case roles::SUMMARY:
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
support-files =
|
||||
!/accessible/tests/mochitest/*.js
|
||||
|
||||
[test_dpub_aria_xml-roles.html]
|
||||
[test_obj.html]
|
||||
[test_obj_css.html]
|
||||
[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_FIGURE = nsIAccessibleRole.ROLE_FIGURE;
|
||||
const ROLE_FOOTER = nsIAccessibleRole.ROLE_FOOTER;
|
||||
const ROLE_FOOTNOTE = nsIAccessibleRole.ROLE_FOOTNOTE;
|
||||
const ROLE_FLAT_EQUATION = nsIAccessibleRole.ROLE_FLAT_EQUATION;
|
||||
const ROLE_FORM = nsIAccessibleRole.ROLE_FORM;
|
||||
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_INTERNAL_FRAME = nsIAccessibleRole.ROLE_INTERNAL_FRAME;
|
||||
const ROLE_LABEL = nsIAccessibleRole.ROLE_LABEL;
|
||||
const ROLE_LANDMARK = nsIAccessibleRole.ROLE_LANDMARK;
|
||||
const ROLE_LINK = nsIAccessibleRole.ROLE_LINK;
|
||||
const ROLE_LIST = nsIAccessibleRole.ROLE_LIST;
|
||||
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_MENUITEM = nsIAccessibleRole.ROLE_MENUITEM;
|
||||
const ROLE_MENUPOPUP = nsIAccessibleRole.ROLE_MENUPOPUP;
|
||||
const ROLE_NAVIGATION = nsIAccessibleRole.ROLE_NAVIGATION;
|
||||
const ROLE_NOTHING = nsIAccessibleRole.ROLE_NOTHING;
|
||||
const ROLE_NOTE = nsIAccessibleRole.ROLE_NOTE;
|
||||
const ROLE_OPTION = nsIAccessibleRole.ROLE_OPTION;
|
||||
|
|
|
@ -5,6 +5,7 @@ support-files =
|
|||
|
||||
[test_aria.html]
|
||||
[test_aria.xul]
|
||||
[test_dpub_aria.html]
|
||||
[test_general.html]
|
||||
[test_general.xul]
|
||||
[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_LINE_NUMBERS = "devtools.gridinspector.showGridLineNumbers";
|
||||
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.
|
||||
const GRID_COLORS = [
|
||||
|
@ -480,6 +482,9 @@ GridInspector.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// @remove after release 56 (See Bug 1355747)
|
||||
Services.prefs.setIntPref(PROMOTE_COUNT_PREF, 0);
|
||||
|
||||
this.inspector.reflowTracker.trackReflows(this, this.onReflow);
|
||||
this.layoutInspector.on("grid-layout-changed", this.onGridLayoutChange);
|
||||
this.updateGridPanel();
|
||||
|
|
|
@ -18,6 +18,7 @@ const BoxModelTypes = require("devtools/client/inspector/boxmodel/types");
|
|||
const GridTypes = require("devtools/client/inspector/grids/types");
|
||||
|
||||
const Accordion = createFactory(require("./Accordion"));
|
||||
const LayoutPromoteBar = createFactory(require("./LayoutPromoteBar"));
|
||||
|
||||
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
|
||||
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
|
||||
|
@ -41,6 +42,7 @@ const App = createClass({
|
|||
showBoxModelProperties: PropTypes.bool.isRequired,
|
||||
showGridOutline: PropTypes.bool.isRequired,
|
||||
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
||||
onPromoteLearnMoreClick: PropTypes.func.isRequired,
|
||||
onSetGridOverlayColor: PropTypes.func.isRequired,
|
||||
onShowBoxModelEditor: PropTypes.func.isRequired,
|
||||
onShowBoxModelHighlighter: PropTypes.func.isRequired,
|
||||
|
@ -53,11 +55,16 @@ const App = createClass({
|
|||
mixins: [ addons.PureRenderMixin ],
|
||||
|
||||
render() {
|
||||
let { onPromoteLearnMoreClick } = this.props;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
id: "layout-container",
|
||||
className: "devtools-monospace",
|
||||
},
|
||||
LayoutPromoteBar({
|
||||
onPromoteLearnMoreClick,
|
||||
}),
|
||||
Accordion({
|
||||
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.js',
|
||||
'App.js',
|
||||
'LayoutPromoteBar.js',
|
||||
)
|
||||
|
|
|
@ -16,12 +16,19 @@ const INSPECTOR_L10N =
|
|||
new LocalizationHelper("devtools/client/locales/inspector.properties");
|
||||
|
||||
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) {
|
||||
this.document = window.document;
|
||||
this.inspector = inspector;
|
||||
this.store = inspector.store;
|
||||
|
||||
this.onPromoteLearnMoreClick = this.onPromoteLearnMoreClick.bind(this);
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -56,6 +63,10 @@ LayoutView.prototype = {
|
|||
onToggleShowInfiniteLines,
|
||||
} = this.inspector.gridInspector.getComponentProps();
|
||||
|
||||
let {
|
||||
onPromoteLearnMoreClick,
|
||||
} = this;
|
||||
|
||||
let app = App({
|
||||
getSwatchColorPickerTooltip,
|
||||
setSelectedNode,
|
||||
|
@ -72,6 +83,7 @@ LayoutView.prototype = {
|
|||
showGridOutline: Services.prefs.getBoolPref(SHOW_GRID_OUTLINE_PREF),
|
||||
|
||||
onHideBoxModelHighlighter,
|
||||
onPromoteLearnMoreClick,
|
||||
onSetGridOverlayColor,
|
||||
onShowBoxModelEditor,
|
||||
onShowBoxModelHighlighter,
|
||||
|
@ -87,10 +99,14 @@ LayoutView.prototype = {
|
|||
});
|
||||
|
||||
let provider = createElement(Provider, {
|
||||
store: this.store,
|
||||
id: "layoutview",
|
||||
title: INSPECTOR_L10N.getStr("inspector.sidebar.layoutViewTitle2"),
|
||||
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);
|
||||
|
||||
let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar");
|
||||
|
@ -112,6 +128,11 @@ LayoutView.prototype = {
|
|||
this.store = null;
|
||||
},
|
||||
|
||||
onPromoteLearnMoreClick() {
|
||||
let browserWin = this.inspector.target.tab.ownerDocument.defaultView;
|
||||
browserWin.openUILinkIn(GRID_LINK, "current");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = LayoutView;
|
||||
|
|
|
@ -351,6 +351,11 @@ inspector.sidebar.computedViewTitle=Computed
|
|||
# that corresponds to the tool displaying layout information defined in the page.
|
||||
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):
|
||||
# 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.
|
||||
|
|
|
@ -46,3 +46,11 @@ layout.overlayGrid=Overlay 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.
|
||||
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
|
||||
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
|
||||
pref("devtools.gridinspector.showGridAreas", false);
|
||||
pref("devtools.gridinspector.showGridLineNumbers", false);
|
||||
|
|
|
@ -20,16 +20,33 @@
|
|||
|
||||
.tabs .tabs-menu-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabs .tabs-menu-item a {
|
||||
display: block;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
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 */
|
||||
.tabs .hidden,
|
||||
.tabs .hidden * {
|
||||
|
|
|
@ -234,16 +234,21 @@ define(function (require, exports, module) {
|
|||
.map((tab) => typeof tab === "function" ? tab() : tab)
|
||||
.filter((tab) => tab)
|
||||
.map((tab, index) => {
|
||||
let id = tab.props.id;
|
||||
let {
|
||||
id,
|
||||
className: tabClassName,
|
||||
title,
|
||||
badge,
|
||||
showBadge,
|
||||
} = tab.props;
|
||||
|
||||
let ref = "tab-menu-" + index;
|
||||
let title = tab.props.title;
|
||||
let tabClassName = tab.props.className;
|
||||
let isTabSelected = this.state.tabActive === index;
|
||||
|
||||
let className = [
|
||||
"tabs-menu-item",
|
||||
tabClassName,
|
||||
isTabSelected ? "is-active" : ""
|
||||
isTabSelected ? "is-active" : "",
|
||||
].join(" ");
|
||||
|
||||
// Set tabindex to -1 (except the selected tab) so, it's focusable,
|
||||
|
@ -266,7 +271,11 @@ define(function (require, exports, module) {
|
|||
role: "tab",
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
|
|
@ -4084,42 +4084,33 @@ enum nsPreviousIntersectionThreshold {
|
|||
void
|
||||
Element::RegisterIntersectionObserver(DOMIntersectionObserver* aObserver)
|
||||
{
|
||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
|
||||
RegisteredIntersectionObservers();
|
||||
if (observers->Contains(aObserver)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Value can be:
|
||||
// -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);
|
||||
RegisteredIntersectionObservers()->LookupForAdd(aObserver).OrInsert([]() {
|
||||
// Value can be:
|
||||
// -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.
|
||||
return eUninitialized;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Element::UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver)
|
||||
{
|
||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
|
||||
RegisteredIntersectionObservers();
|
||||
observers->Remove(aObserver);
|
||||
RegisteredIntersectionObservers()->Remove(aObserver);
|
||||
}
|
||||
|
||||
bool
|
||||
Element::UpdateIntersectionObservation(DOMIntersectionObserver* aObserver, int32_t aThreshold)
|
||||
{
|
||||
nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>* observers =
|
||||
RegisteredIntersectionObservers();
|
||||
if (!observers->Contains(aObserver)) {
|
||||
return false;
|
||||
}
|
||||
int32_t previousThreshold = observers->Get(aObserver);
|
||||
if (previousThreshold != aThreshold) {
|
||||
observers->Put(aObserver, aThreshold);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
bool updated = false;
|
||||
RegisteredIntersectionObservers()->LookupRemoveIf(aObserver,
|
||||
[&updated, aThreshold] (int32_t& aValue) {
|
||||
updated = aValue != aThreshold;
|
||||
aValue = aThreshold;
|
||||
return false; // don't remove the entry
|
||||
});
|
||||
return updated;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -28,26 +28,27 @@ ImageTracker::Add(imgIRequest* 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;
|
||||
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
|
||||
// too.
|
||||
if (oldCount == 0 && mLocking) {
|
||||
rv = aImage->LockImage();
|
||||
}
|
||||
// If we're locking images, lock this image too.
|
||||
if (mLocking) {
|
||||
rv = aImage->LockImage();
|
||||
}
|
||||
|
||||
// If this is the first insertion and we're animating images, request
|
||||
// that this image be animated too.
|
||||
if (oldCount == 0 && mAnimating) {
|
||||
nsresult rv2 = aImage->IncrementAnimationConsumers();
|
||||
rv = NS_SUCCEEDED(rv) ? rv2 : rv;
|
||||
// If we're animating images, request that this image be animated too.
|
||||
if (mAnimating) {
|
||||
nsresult rv2 = aImage->IncrementAnimationConsumers();
|
||||
rv = NS_SUCCEEDED(rv) ? rv2 : rv;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -59,23 +60,23 @@ ImageTracker::Remove(imgIRequest* aImage, uint32_t aFlags)
|
|||
NS_ENSURE_ARG_POINTER(aImage);
|
||||
|
||||
// Get the old count. It should exist and be > 0.
|
||||
uint32_t count = 0;
|
||||
DebugOnly<bool> found = mImages.Get(aImage, &count);
|
||||
DebugOnly<bool> found = false;
|
||||
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(count > 0, "Entry in the cache tracker with count 0!");
|
||||
|
||||
// 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);
|
||||
if (!remove) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mImages.Remove(aImage);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// 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*
|
||||
StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader)
|
||||
StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
StructuredCloneHolder* aHolder)
|
||||
{
|
||||
JS::RootedObject obj(aCx);
|
||||
{
|
||||
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
|
||||
|
||||
if (!holder->ReadStructuredCloneInternal(aCx, aReader) ||
|
||||
if (!holder->ReadStructuredCloneInternal(aCx, aReader, aHolder) ||
|
||||
!holder->WrapObject(aCx, nullptr, &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -114,7 +115,8 @@ StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader
|
|||
}
|
||||
|
||||
bool
|
||||
StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader)
|
||||
StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
StructuredCloneHolder* aHolder)
|
||||
{
|
||||
uint32_t length;
|
||||
uint32_t version;
|
||||
|
@ -122,6 +124,15 @@ StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredClo
|
|||
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);
|
||||
if (!JS_ReadBytes(aReader, data.Start(), length)) {
|
||||
return false;
|
||||
|
@ -136,14 +147,18 @@ StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredClo
|
|||
}
|
||||
|
||||
bool
|
||||
StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter)
|
||||
StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||
StructuredCloneHolder* aHolder)
|
||||
{
|
||||
auto& data = mBuffer->data();
|
||||
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;
|
||||
}
|
||||
|
||||
aHolder->BlobImpls().AppendElements(BlobImpls());
|
||||
|
||||
auto iter = data.Iter();
|
||||
while (!iter.Done()) {
|
||||
if (!JS_WriteBytes(aWriter, iter.Data(), iter.RemainingInSegment())) {
|
||||
|
|
|
@ -26,8 +26,10 @@ public:
|
|||
|
||||
explicit StructuredCloneBlob();
|
||||
|
||||
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader);
|
||||
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter);
|
||||
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
StructuredCloneHolder* aHolder);
|
||||
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
|
||||
StructuredCloneHolder* aHolder);
|
||||
|
||||
static already_AddRefed<StructuredCloneBlob>
|
||||
Constructor(GlobalObject& aGlobal, JS::HandleValue aValue, JS::HandleObject aTargetGlobal, ErrorResult& aRv);
|
||||
|
@ -47,7 +49,8 @@ protected:
|
|||
~StructuredCloneBlob() = default;
|
||||
|
||||
private:
|
||||
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader);
|
||||
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
StructuredCloneHolder* aHolder);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -358,10 +358,6 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
|
|||
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) {
|
||||
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
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
|
||||
{
|
||||
URLSearchParams* usp = nullptr;
|
||||
|
@ -999,6 +987,10 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
|
|||
parent, GetSurfaces(), aIndex);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
|
||||
return StructuredCloneBlob::ReadStructuredClone(aCx, aReader, this);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_WASM) {
|
||||
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.
|
||||
if ((mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread ||
|
||||
mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread) &&
|
||||
|
|
|
@ -54,7 +54,6 @@ Timeout::SetWhenOrTimeRemaining(const TimeStamp& aBaseTime,
|
|||
if (mWindow->IsFrozen()) {
|
||||
mWhen = TimeStamp();
|
||||
mTimeRemaining = aDelay;
|
||||
mScheduledDelay = TimeDuration(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -63,7 +62,6 @@ Timeout::SetWhenOrTimeRemaining(const TimeStamp& aBaseTime,
|
|||
// that it appears time passes while suspended.
|
||||
mWhen = aBaseTime + aDelay;
|
||||
mTimeRemaining = TimeDuration(0);
|
||||
mScheduledDelay = aDelay;
|
||||
}
|
||||
|
||||
const TimeStamp&
|
||||
|
@ -84,12 +82,5 @@ Timeout::TimeRemaining() const
|
|||
return mTimeRemaining;
|
||||
}
|
||||
|
||||
const TimeDuration&
|
||||
Timeout::ScheduledDelay() const
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mWhen.IsNull());
|
||||
return mScheduledDelay;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -50,9 +50,6 @@ public:
|
|||
// Can only be called when frozen.
|
||||
const TimeDuration& TimeRemaining() const;
|
||||
|
||||
// Can only be called when not frozen.
|
||||
const TimeDuration& ScheduledDelay() const;
|
||||
|
||||
// Window for which this timeout fires
|
||||
RefPtr<nsGlobalWindow> mWindow;
|
||||
|
||||
|
@ -101,10 +98,6 @@ private:
|
|||
// Remaining time to wait. Used only when timeouts are frozen.
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -40,11 +40,13 @@ TimeoutExecutor::ScheduleImmediate(const TimeStamp& aDeadline,
|
|||
|
||||
nsresult
|
||||
TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
||||
const TimeStamp& aNow)
|
||||
const TimeStamp& aNow,
|
||||
const TimeDuration& aMinDelay)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(mDeadline.IsNull());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mMode == Mode::None);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aDeadline > (aNow + mAllowedEarlyFiringTime));
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aMinDelay.IsZero() ||
|
||||
aDeadline > (aNow + mAllowedEarlyFiringTime));
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -65,6 +67,15 @@ TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
|||
rv = mTimer->SetTarget(mOwner->EventTarget());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Calculate the delay based on the deadline and current time. If we have
|
||||
// a minimum delay set then clamp to that value.
|
||||
//
|
||||
// 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
|
||||
// integer milliseconds. We need higher precision. Consider this
|
||||
// situation:
|
||||
|
@ -83,7 +94,7 @@ TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
|||
// 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
|
||||
// accurate wakeup time.
|
||||
rv = mTimer->InitHighResolutionWithCallback(this, aDeadline - aNow,
|
||||
rv = mTimer->InitHighResolutionWithCallback(this, delay,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -94,22 +105,24 @@ TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
|||
}
|
||||
|
||||
nsresult
|
||||
TimeoutExecutor::Schedule(const TimeStamp& aDeadline)
|
||||
TimeoutExecutor::Schedule(const TimeStamp& aDeadline,
|
||||
const TimeDuration& aMinDelay)
|
||||
{
|
||||
TimeStamp now(TimeStamp::Now());
|
||||
|
||||
// Schedule an immediate runnable if the desired deadline has passed
|
||||
// or is slightly in the future. This is similar to how nsITimer will
|
||||
// fire timers early based on the interval resolution.
|
||||
if (aDeadline <= (now + mAllowedEarlyFiringTime)) {
|
||||
if (aMinDelay.IsZero() && aDeadline <= (now + mAllowedEarlyFiringTime)) {
|
||||
return ScheduleImmediate(aDeadline, now);
|
||||
}
|
||||
|
||||
return ScheduleDelayed(aDeadline, now);
|
||||
return ScheduleDelayed(aDeadline, now, aMinDelay);
|
||||
}
|
||||
|
||||
nsresult
|
||||
TimeoutExecutor::MaybeReschedule(const TimeStamp& aDeadline)
|
||||
TimeoutExecutor::MaybeReschedule(const TimeStamp& aDeadline,
|
||||
const TimeDuration& aMinDelay)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mDeadline.IsNull());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mMode == Mode::Immediate ||
|
||||
|
@ -127,7 +140,7 @@ TimeoutExecutor::MaybeReschedule(const TimeStamp& aDeadline)
|
|||
}
|
||||
|
||||
Cancel();
|
||||
return Schedule(aDeadline);
|
||||
return Schedule(aDeadline, aMinDelay);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -176,7 +189,8 @@ TimeoutExecutor::Shutdown()
|
|||
}
|
||||
|
||||
nsresult
|
||||
TimeoutExecutor::MaybeSchedule(const TimeStamp& aDeadline)
|
||||
TimeoutExecutor::MaybeSchedule(const TimeStamp& aDeadline,
|
||||
const TimeDuration& aMinDelay)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aDeadline.IsNull());
|
||||
|
||||
|
@ -185,10 +199,10 @@ TimeoutExecutor::MaybeSchedule(const TimeStamp& aDeadline)
|
|||
}
|
||||
|
||||
if (mMode == Mode::Immediate || mMode == Mode::Delayed) {
|
||||
return MaybeReschedule(aDeadline);
|
||||
return MaybeReschedule(aDeadline, aMinDelay);
|
||||
}
|
||||
|
||||
return Schedule(aDeadline);
|
||||
return Schedule(aDeadline, aMinDelay);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -56,13 +56,14 @@ class TimeoutExecutor final : public nsIRunnable
|
|||
ScheduleImmediate(const TimeStamp& aDeadline, const TimeStamp& aNow);
|
||||
|
||||
nsresult
|
||||
ScheduleDelayed(const TimeStamp& aDeadline, const TimeStamp& aNow);
|
||||
ScheduleDelayed(const TimeStamp& aDeadline, const TimeStamp& aNow,
|
||||
const TimeDuration& aMinDelay);
|
||||
|
||||
nsresult
|
||||
Schedule(const TimeStamp& aDeadline);
|
||||
Schedule(const TimeStamp& aDeadline, const TimeDuration& aMinDelay);
|
||||
|
||||
nsresult
|
||||
MaybeReschedule(const TimeStamp& aDeadline);
|
||||
MaybeReschedule(const TimeStamp& aDeadline, const TimeDuration& aMinDelay);
|
||||
|
||||
void
|
||||
MaybeExecute();
|
||||
|
@ -74,7 +75,7 @@ public:
|
|||
Shutdown();
|
||||
|
||||
nsresult
|
||||
MaybeSchedule(const TimeStamp& aDeadline);
|
||||
MaybeSchedule(const TimeStamp& aDeadline, const TimeDuration& aMinDelay);
|
||||
|
||||
void
|
||||
Cancel();
|
||||
|
|
|
@ -146,6 +146,9 @@ const uint32_t TimeoutManager::InvalidFiringId = 0;
|
|||
bool
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -177,6 +180,15 @@ TimeoutManager::IsValidFiringId(uint32_t aFiringId) const
|
|||
return !IsInvalidFiringId(aFiringId);
|
||||
}
|
||||
|
||||
TimeDuration
|
||||
TimeoutManager::MinSchedulingDelay() const
|
||||
{
|
||||
if (IsBackground()) {
|
||||
return TimeDuration::FromMilliseconds(gMinBackgroundTimeoutValue);
|
||||
}
|
||||
return TimeDuration();
|
||||
}
|
||||
|
||||
bool
|
||||
TimeoutManager::IsInvalidFiringId(uint32_t aFiringId) const
|
||||
{
|
||||
|
@ -218,15 +230,9 @@ TimeoutManager::IsInvalidFiringId(uint32_t aFiringId) const
|
|||
|
||||
int32_t
|
||||
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;
|
||||
auto minValue = throttleTracking ? (isBackground ? gMinTrackingBackgroundTimeoutValue
|
||||
: gMinTrackingTimeoutValue)
|
||||
: (isBackground ? gMinBackgroundTimeoutValue
|
||||
: gMinTimeoutValue);
|
||||
auto minValue = throttleTracking ? gMinTrackingTimeoutValue
|
||||
: gMinTimeoutValue;
|
||||
return minValue;
|
||||
}
|
||||
|
||||
|
@ -409,7 +415,6 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
|||
uint32_t nestingLevel = sNestingLevel + 1;
|
||||
uint32_t realInterval = interval;
|
||||
if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL ||
|
||||
mWindow.IsBackgroundInternal() ||
|
||||
timeout->mIsTracking) {
|
||||
// Don't allow timeouts less than DOMMinTimeoutValue() from
|
||||
// now...
|
||||
|
@ -424,7 +429,8 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
|||
|
||||
// If we're not suspended, then set the timer.
|
||||
if (!mWindow.IsSuspended()) {
|
||||
nsresult rv = mExecutor->MaybeSchedule(timeout->When());
|
||||
nsresult rv = mExecutor->MaybeSchedule(timeout->When(),
|
||||
MinSchedulingDelay());
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -476,7 +482,7 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
|||
mThrottleTrackingTimeouts ? "yes"
|
||||
: (mThrottleTrackingTimeoutsTimer ?
|
||||
"pending" : "no"),
|
||||
int(mWindow.IsBackgroundInternal()), realInterval,
|
||||
int(IsBackground()), realInterval,
|
||||
timeout->mIsTracking ? "" : "non-",
|
||||
timeout->mTimeoutId));
|
||||
|
||||
|
@ -535,7 +541,8 @@ TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason)
|
|||
OrderedTimeoutIterator iter(mNormalTimeouts, mTrackingTimeouts);
|
||||
Timeout* nextTimeout = iter.Next();
|
||||
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
|
||||
// executing the loop above since it doesn't call out to js.
|
||||
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
|
||||
|
@ -777,7 +785,8 @@ TimeoutManager::RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadli
|
|||
if (!mWindow.IsSuspended()) {
|
||||
RefPtr<Timeout> timeout = runIter.Next();
|
||||
if (timeout) {
|
||||
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(timeout->When()));
|
||||
MOZ_ALWAYS_SUCCEEDS(mExecutor->MaybeSchedule(timeout->When(),
|
||||
MinSchedulingDelay()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -818,132 +827,13 @@ TimeoutManager::RescheduleTimeout(Timeout* aTimeout, const TimeStamp& now)
|
|||
return true;
|
||||
}
|
||||
|
||||
nsresult rv = mExecutor->MaybeSchedule(aTimeout->When());
|
||||
nsresult rv = mExecutor->MaybeSchedule(aTimeout->When(),
|
||||
MinSchedulingDelay());
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
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
|
||||
TimeoutManager::ClearAllTimeouts()
|
||||
{
|
||||
|
@ -1112,7 +1002,8 @@ TimeoutManager::Resume()
|
|||
});
|
||||
|
||||
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
|
||||
TimeoutManager::IsTimeoutTracking(uint32_t aTimeoutId)
|
||||
{
|
||||
|
|
|
@ -55,11 +55,6 @@ public:
|
|||
void ClearAllTimeouts();
|
||||
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;
|
||||
|
||||
// aTimeout is the timeout that we're about to start running. This function
|
||||
|
@ -77,6 +72,10 @@ public:
|
|||
void Freeze();
|
||||
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.
|
||||
static void Initialize();
|
||||
|
||||
|
@ -116,7 +115,6 @@ public:
|
|||
static const uint32_t InvalidFiringId;
|
||||
|
||||
private:
|
||||
nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS);
|
||||
void MaybeStartThrottleTrackingTimout();
|
||||
|
||||
bool IsBackground() const;
|
||||
|
@ -133,6 +131,9 @@ private:
|
|||
bool
|
||||
IsInvalidFiringId(uint32_t aFiringId) const;
|
||||
|
||||
TimeDuration
|
||||
MinSchedulingDelay() const;
|
||||
|
||||
private:
|
||||
struct Timeouts {
|
||||
explicit Timeouts(const TimeoutManager& aManager)
|
||||
|
@ -149,9 +150,6 @@ private:
|
|||
TimeWhen
|
||||
};
|
||||
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(); }
|
||||
Timeout* GetFirst() { return mTimeoutList.getFirst(); }
|
||||
|
|
|
@ -9640,10 +9640,11 @@ nsDocument::MaybePreconnect(nsIURI* aOrigURI, mozilla::CORSMode aCORSMode)
|
|||
uri->SetPath(NS_LITERAL_CSTRING("/"));
|
||||
}
|
||||
|
||||
if (mPreloadedPreconnects.Contains(uri)) {
|
||||
return;
|
||||
auto entry = mPreloadedPreconnects.LookupForAdd(uri);
|
||||
if (entry) {
|
||||
return; // we found an existing entry
|
||||
}
|
||||
mPreloadedPreconnects.Put(uri, true);
|
||||
entry.OrInsert([] () { return true; });
|
||||
|
||||
nsCOMPtr<nsISpeculativeConnect>
|
||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||
|
|
|
@ -350,6 +350,45 @@ GK_ATOM(displayMode, "display-mode")
|
|||
GK_ATOM(distinct, "distinct")
|
||||
GK_ATOM(div, "div")
|
||||
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(doctypeSystem, "doctype-system")
|
||||
GK_ATOM(document, "document")
|
||||
|
|
|
@ -10671,13 +10671,16 @@ void nsGlobalWindow::SetIsBackground(bool aIsBackground)
|
|||
{
|
||||
MOZ_ASSERT(IsOuterWindow());
|
||||
|
||||
bool resetTimers = (!aIsBackground && AsOuter()->IsBackground());
|
||||
bool changed = aIsBackground != AsOuter()->IsBackground();
|
||||
SetIsBackgroundInternal(aIsBackground);
|
||||
|
||||
nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
|
||||
|
||||
if (inner && changed) {
|
||||
inner->mTimeoutManager->UpdateBackgroundState();
|
||||
}
|
||||
|
||||
if (aIsBackground) {
|
||||
MOZ_ASSERT(!resetTimers);
|
||||
// Notify gamepadManager we are at the background window,
|
||||
// we need to stop vibrate.
|
||||
if (inner) {
|
||||
|
@ -10685,9 +10688,6 @@ void nsGlobalWindow::SetIsBackground(bool aIsBackground)
|
|||
}
|
||||
return;
|
||||
} else if (inner) {
|
||||
if (resetTimers) {
|
||||
inner->mTimeoutManager->ResetTimersForThrottleReduction();
|
||||
}
|
||||
inner->SyncGamepadState();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,19 @@ var testURLs = [
|
|||
|
||||
// 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.
|
||||
// So we use a 10ms minimum timeout value for foreground tabs and a 100,000 second
|
||||
// minimum timeout value for background tabs. This means that in case the test
|
||||
// fails, it will time out in practice, but just for sanity the test condition
|
||||
// ensures that the observed timeout delay falls in this range.
|
||||
const kMinTimeoutForeground = 10;
|
||||
// So we use a 100,000 second minimum timeout value for background tabs. This
|
||||
// means that in case the test fails, it will time out in practice, but just for
|
||||
// sanity the test condition ensures that the observed timeout delay falls in
|
||||
// this range.
|
||||
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);
|
||||
|
||||
function* runTest(url) {
|
||||
|
@ -31,19 +37,16 @@ function* runTest(url) {
|
|||
// Put the tab in the background.
|
||||
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 => {
|
||||
let before = new Date();
|
||||
content.window.setTimeout(function() {
|
||||
let after = new Date();
|
||||
// Sometimes due to rounding errors, we may get a result of 9ms here, so
|
||||
// let's round up by 1 to protect against such intermittent failures.
|
||||
resolve(after - before + 1);
|
||||
}, 0);
|
||||
resolve(after - before);
|
||||
}, delay);
|
||||
});
|
||||
});
|
||||
ok(timeout >= kMinTimeoutForeground &&
|
||||
timeout < kMinTimeoutBackground, `Got the correct timeout (${timeout})`);
|
||||
ok(timeout <= kDelay + kAllowedError, `Got the correct timeout (${timeout}`);
|
||||
|
||||
// All done.
|
||||
yield BrowserTestUtils.removeTab(newTab);
|
||||
|
@ -51,7 +54,6 @@ function* runTest(url) {
|
|||
|
||||
add_task(function* setup() {
|
||||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.min_timeout_value", kMinTimeoutForeground],
|
||||
["dom.min_background_timeout_value", kMinTimeoutBackground],
|
||||
]});
|
||||
});
|
||||
|
|
|
@ -1593,6 +1593,8 @@ EventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
|
|||
nsAutoString eventType;
|
||||
if (listener.mAllEvents) {
|
||||
eventType.SetIsVoid(true);
|
||||
} else if (listener.mListenerType == Listener::eNoListener) {
|
||||
continue;
|
||||
} else {
|
||||
eventType.Assign(Substring(nsDependentAtomString(listener.mTypeAtom), 2));
|
||||
}
|
||||
|
|
|
@ -453,14 +453,16 @@ already_AddRefed<ParticularProcessPriorityManager>
|
|||
ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
|
||||
ContentParent* aContentParent)
|
||||
{
|
||||
RefPtr<ParticularProcessPriorityManager> pppm;
|
||||
uint64_t cpId = aContentParent->ChildID();
|
||||
mParticularManagers.Get(cpId, &pppm);
|
||||
if (!pppm) {
|
||||
pppm = new ParticularProcessPriorityManager(aContentParent);
|
||||
pppm->Init();
|
||||
mParticularManagers.Put(cpId, pppm);
|
||||
auto entry = mParticularManagers.LookupForAdd(cpId);
|
||||
RefPtr<ParticularProcessPriorityManager> pppm = entry.OrInsert(
|
||||
[aContentParent]() {
|
||||
return new ParticularProcessPriorityManager(aContentParent);
|
||||
});
|
||||
|
||||
if (!entry) {
|
||||
// We created a new entry.
|
||||
pppm->Init();
|
||||
FireTestOnlyObserverNotification("process-created",
|
||||
nsPrintfCString("%" PRIu64, cpId));
|
||||
}
|
||||
|
@ -501,15 +503,12 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
|
|||
props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
|
||||
NS_ENSURE_TRUE_VOID(childID != CONTENT_PROCESS_ID_UNKNOWN);
|
||||
|
||||
RefPtr<ParticularProcessPriorityManager> pppm;
|
||||
mParticularManagers.Get(childID, &pppm);
|
||||
if (pppm) {
|
||||
pppm->ShutDown();
|
||||
|
||||
mParticularManagers.Remove(childID);
|
||||
|
||||
mHighPriorityChildIDs.RemoveEntry(childID);
|
||||
}
|
||||
mParticularManagers.LookupRemoveIf(childID,
|
||||
[this, childID] (RefPtr<ParticularProcessPriorityManager>& aValue) {
|
||||
aValue->ShutDown();
|
||||
mHighPriorityChildIDs.RemoveEntry(childID);
|
||||
return true; // remove it
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -574,14 +574,14 @@ MediaCacheStream::BlockList::NotifyBlockSwapped(int32_t aBlockIndex1,
|
|||
if (e1) {
|
||||
e1Prev = e1->mPrevBlock;
|
||||
e1Next = e1->mNextBlock;
|
||||
mEntries.RemoveEntry(aBlockIndex1);
|
||||
mEntries.RemoveEntry(e1);
|
||||
// Refresh pointer after hashtable mutation.
|
||||
e2 = mEntries.GetEntry(aBlockIndex2);
|
||||
}
|
||||
if (e2) {
|
||||
e2Prev = e2->mPrevBlock;
|
||||
e2Next = e2->mNextBlock;
|
||||
mEntries.RemoveEntry(aBlockIndex2);
|
||||
mEntries.RemoveEntry(e2);
|
||||
}
|
||||
// Put new entries back.
|
||||
if (e1) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define VideoUtils_h
|
||||
|
||||
#include "MediaInfo.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
|
|
|
@ -19,7 +19,6 @@ UNIFIED_SOURCES += [
|
|||
'TestMediaDataDecoder.cpp',
|
||||
'TestMediaEventSource.cpp',
|
||||
'TestMediaMIMETypes.cpp',
|
||||
'TestMozPromise.cpp',
|
||||
'TestMP3Demuxer.cpp',
|
||||
'TestMP4Demuxer.cpp',
|
||||
'TestRust.cpp',
|
||||
|
|
|
@ -42,6 +42,9 @@ public:
|
|||
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.
|
||||
void AwaitIdle() { mTaskQueue->AwaitIdle(); }
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "mozilla/dom/EncodingUtils.h"
|
||||
#include "mozilla/ConsoleReportCollector.h"
|
||||
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
|
|
@ -228,6 +228,11 @@
|
|||
stroke="black" stroke-width="8" stroke-linejoin="round" fill="lightcyan"
|
||||
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 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')"/>
|
||||
|
|
До Ширина: | Высота: | Размер: 20 KiB После Ширина: | Высота: | Размер: 20 KiB |
|
@ -162,6 +162,7 @@ function run()
|
|||
checkBBox("path10", opt, 10,25,100,75, 0);
|
||||
checkBBox("path11", opt, 160,25,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 };
|
||||
checkBBox("path1", opt, 2,17,116,91, 0);
|
||||
|
|
|
@ -51,8 +51,8 @@ SimpleTest.waitForFocus(runTest);
|
|||
<div id="closure">
|
||||
<div style="transform-style: preserve-3d;">
|
||||
<div style="transform-style: preserve-3d; background-color: blue;">
|
||||
<ul>
|
||||
<li><div id="target" class="panel"></div>
|
||||
<ul style="transform-style: preserve-3d;">
|
||||
<li style="transform-style:preserve-3d;"><div id="target" class="panel"></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "hasht.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/dom/CallbackFunction.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/CryptoBuffer.h"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "mozilla/dom/U2FSoftTokenManager.h"
|
||||
#include "CryptoBuffer.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "nsNSSComponent.h"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "hasht.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/dom/AuthenticatorAttestationResponse.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
|
||||
URIData *data;
|
||||
if (mURIMap.Contains(spec))
|
||||
if (mURIMap.Get(spec, &data))
|
||||
{
|
||||
data = mURIMap.Get(spec);
|
||||
if (aNeedsPersisting)
|
||||
{
|
||||
data->mNeedsPersisting = true;
|
||||
|
|
|
@ -1641,17 +1641,16 @@ ServiceWorkerManager::GetOrCreateJobQueue(const nsACString& aKey,
|
|||
{
|
||||
MOZ_ASSERT(!aKey.IsEmpty());
|
||||
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)) {
|
||||
data = new RegistrationDataPerPrincipal();
|
||||
mRegistrationInfos.Put(aKey, data);
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerJobQueue> queue;
|
||||
if (!data->mJobQueues.Get(aScope, getter_AddRefs(queue))) {
|
||||
RefPtr<ServiceWorkerJobQueue> newQueue = new ServiceWorkerJobQueue();
|
||||
queue = newQueue;
|
||||
data->mJobQueues.Put(aScope, newQueue.forget());
|
||||
}
|
||||
RefPtr<ServiceWorkerJobQueue> queue =
|
||||
data->mJobQueues.LookupForAdd(aScope).OrInsert(
|
||||
[]() { return new ServiceWorkerJobQueue(); });
|
||||
|
||||
return queue.forget();
|
||||
}
|
||||
|
@ -2245,11 +2244,9 @@ ServiceWorkerManager::AddScopeAndRegistration(const nsACString& aScope,
|
|||
|
||||
MOZ_ASSERT(!scopeKey.IsEmpty());
|
||||
|
||||
RegistrationDataPerPrincipal* data;
|
||||
if (!swm->mRegistrationInfos.Get(scopeKey, &data)) {
|
||||
data = new RegistrationDataPerPrincipal();
|
||||
swm->mRegistrationInfos.Put(scopeKey, data);
|
||||
}
|
||||
RegistrationDataPerPrincipal* data =
|
||||
swm->mRegistrationInfos.LookupForAdd(scopeKey).OrInsert(
|
||||
[]() { return new RegistrationDataPerPrincipal(); });
|
||||
|
||||
for (uint32_t i = 0; i < data->mOrderedScopes.Length(); ++i) {
|
||||
const nsCString& current = data->mOrderedScopes[i];
|
||||
|
@ -2344,11 +2341,11 @@ ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo*
|
|||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aRegistration->mScope);
|
||||
if (timer) {
|
||||
timer->Cancel();
|
||||
data->mUpdateTimers.Remove(aRegistration->mScope);
|
||||
}
|
||||
data->mUpdateTimers.LookupRemoveIf(aRegistration->mScope,
|
||||
[] (nsCOMPtr<nsITimer>& aTimer) {
|
||||
aTimer->Cancel();
|
||||
return true; // remove it
|
||||
});
|
||||
|
||||
// The registration should generally only be removed if there are no controlled
|
||||
// documents, but mControlledDocuments can contain references to potentially
|
||||
|
@ -2363,9 +2360,7 @@ ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo*
|
|||
}
|
||||
|
||||
RefPtr<ServiceWorkerRegistrationInfo> info;
|
||||
data->mInfos.Get(aRegistration->mScope, getter_AddRefs(info));
|
||||
|
||||
data->mInfos.Remove(aRegistration->mScope);
|
||||
data->mInfos.Remove(aRegistration->mScope, getter_AddRefs(info));
|
||||
data->mOrderedScopes.RemoveElement(aRegistration->mScope);
|
||||
swm->NotifyListenersOnUnregister(info);
|
||||
|
||||
|
@ -2376,14 +2371,12 @@ ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo*
|
|||
void
|
||||
ServiceWorkerManager::MaybeRemoveRegistrationInfo(const nsACString& aScopeKey)
|
||||
{
|
||||
RegistrationDataPerPrincipal* data;
|
||||
if (!mRegistrationInfos.Get(aScopeKey, &data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->mOrderedScopes.IsEmpty() && data->mJobQueues.Count() == 0) {
|
||||
mRegistrationInfos.Remove(aScopeKey);
|
||||
}
|
||||
mRegistrationInfos.LookupRemoveIf(aScopeKey,
|
||||
[] (RegistrationDataPerPrincipal* aData) {
|
||||
bool remove = aData->mOrderedScopes.IsEmpty() &&
|
||||
aData->mJobQueues.Count() == 0;
|
||||
return remove;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3679,12 +3672,11 @@ ServiceWorkerManager::ForceUnregister(RegistrationDataPerPrincipal* aRegistratio
|
|||
queue->CancelAll();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimer> timer =
|
||||
aRegistrationData->mUpdateTimers.Get(aRegistration->mScope);
|
||||
if (timer) {
|
||||
timer->Cancel();
|
||||
aRegistrationData->mUpdateTimers.Remove(aRegistration->mScope);
|
||||
}
|
||||
aRegistrationData->mUpdateTimers.LookupRemoveIf(aRegistration->mScope,
|
||||
[] (nsCOMPtr<nsITimer>& aTimer) {
|
||||
aTimer->Cancel();
|
||||
return true; // remove it
|
||||
});
|
||||
|
||||
// Since Unregister is async, it is ok to call it in an enumeration.
|
||||
Unregister(aRegistration->mPrincipal, nullptr, NS_ConvertUTF8toUTF16(aRegistration->mScope));
|
||||
|
@ -4250,7 +4242,7 @@ ServiceWorkerManager::ScheduleUpdateTimer(nsIPrincipal* aPrincipal,
|
|||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aScope);
|
||||
nsCOMPtr<nsITimer>& timer = data->mUpdateTimers.GetOrInsert(aScope);
|
||||
if (timer) {
|
||||
// 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
|
||||
|
@ -4261,6 +4253,7 @@ ServiceWorkerManager::ScheduleUpdateTimer(nsIPrincipal* aPrincipal,
|
|||
|
||||
timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
data->mUpdateTimers.Remove(aScope); // another lookup, but very rare
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4272,10 +4265,9 @@ ServiceWorkerManager::ScheduleUpdateTimer(nsIPrincipal* aPrincipal,
|
|||
rv = timer->InitWithCallback(callback, UPDATE_DELAY_MS,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
data->mUpdateTimers.Remove(aScope); // another lookup, but very rare
|
||||
return;
|
||||
}
|
||||
|
||||
data->mUpdateTimers.Put(aScope, timer);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4302,11 +4294,11 @@ ServiceWorkerManager::UpdateTimerFired(nsIPrincipal* aPrincipal,
|
|||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimer> timer = data->mUpdateTimers.Get(aScope);
|
||||
if (timer) {
|
||||
timer->Cancel();
|
||||
data->mUpdateTimers.Remove(aScope);
|
||||
}
|
||||
data->mUpdateTimers.LookupRemoveIf(aScope,
|
||||
[] (nsCOMPtr<nsITimer>& aTimer) {
|
||||
aTimer->Cancel();
|
||||
return true; // remove it
|
||||
});
|
||||
|
||||
RefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
data->mInfos.Get(aScope, getter_AddRefs(registration));
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ServiceWorkerUpdaterChild.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <stdlib.h> // for getenv
|
||||
|
||||
#include "mozilla/AbstractThread.h" // for AbstractThread
|
||||
#include "mozilla/Attributes.h" // for final
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "mozilla/dom/Element.h" // for Element
|
||||
|
|
|
@ -175,7 +175,7 @@ PathSkia::GetBounds(const Matrix &aTransform) const
|
|||
return Rect();
|
||||
}
|
||||
|
||||
Rect bounds = SkRectToRect(mPath.getBounds());
|
||||
Rect bounds = SkRectToRect(mPath.computeTightBounds());
|
||||
return aTransform.TransformBounds(bounds);
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
|
|||
SkPath result;
|
||||
paint.getFillPath(mPath, &result);
|
||||
|
||||
Rect bounds = SkRectToRect(result.getBounds());
|
||||
Rect bounds = SkRectToRect(result.computeTightBounds());
|
||||
return aTransform.TransformBounds(bounds);
|
||||
}
|
||||
|
||||
|
|
|
@ -237,6 +237,27 @@ LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget, const
|
|||
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
|
||||
* given layer.
|
||||
|
@ -258,20 +279,52 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
|||
LayerIntRegion& aVisibleRegion,
|
||||
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 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
|
||||
// region should be empty (invisible), so we pass through them
|
||||
// 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();
|
||||
child;
|
||||
child = child->GetPrevSibling()) {
|
||||
|
@ -284,7 +337,7 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
|||
nsIntRegion localOpaque;
|
||||
// Treat layers on the path to the root of the 3D rendering context as
|
||||
// a giant layer if it is a leaf.
|
||||
Matrix4x4 transform = GetAccTransformIn3DContext(aLayer);
|
||||
Matrix4x4 transform = aLayer->GetEffectiveTransform();
|
||||
Matrix transform2d;
|
||||
Maybe<IntPoint> integerTranslation;
|
||||
// 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
|
||||
// by siblings (and uncles and such), before our descendants contribute to it.
|
||||
nsIntRegion obscured = localOpaque;
|
||||
|
@ -345,6 +360,7 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
|||
// - They recalculate their visible regions, taking ancestorClipForChildren
|
||||
// into account, and accumulate them into descendantsVisibleRegion.
|
||||
LayerIntRegion descendantsVisibleRegion;
|
||||
|
||||
bool hasPreserve3DChild = false;
|
||||
for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
|
||||
PostProcessLayers(child, localOpaque, descendantsVisibleRegion, ancestorClipForChildren);
|
||||
|
@ -378,9 +394,6 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
|||
// for the caller to use.
|
||||
ParentLayerIntRegion visibleParentSpace = TransformBy(
|
||||
ViewAs<LayerToParentLayerMatrix4x4>(transform), visible);
|
||||
if (const Maybe<ParentLayerIntRect>& clipRect = composite->GetShadowClipRect()) {
|
||||
visibleParentSpace.AndWith(*clipRect);
|
||||
}
|
||||
aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace,
|
||||
PixelCastJustification::MovingDownToChildren));
|
||||
|
||||
|
@ -392,10 +405,10 @@ LayerManagerComposite::PostProcessLayers(Layer* aLayer,
|
|||
if (aLayer->IsOpaque()) {
|
||||
localOpaque.OrWith(composite->GetFullyRenderedRegion());
|
||||
}
|
||||
localOpaque.MoveBy(*integerTranslation);
|
||||
if (layerClip) {
|
||||
localOpaque.AndWith(layerClip->ToUnknownRect());
|
||||
if (insideClip) {
|
||||
localOpaque.AndWith(insideClip->ToUnknownRect());
|
||||
}
|
||||
localOpaque.MoveBy(*integerTranslation);
|
||||
aOpaqueRegion.OrWith(localOpaque);
|
||||
}
|
||||
}
|
||||
|
@ -449,17 +462,14 @@ void
|
|||
LayerManagerComposite::UpdateAndRender()
|
||||
{
|
||||
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;
|
||||
LayerIntRegion visible;
|
||||
PostProcessLayers(mRoot, opaque, visible, Nothing());
|
||||
PostProcessLayers(opaque);
|
||||
|
||||
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
|
||||
// immediately use the resulting damage area, since ComputeDifferences
|
||||
// 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.
|
||||
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);
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
RenderToPresentationSurface();
|
||||
|
@ -1109,8 +1113,7 @@ LayerManagerComposite::RenderToPresentationSurface()
|
|||
|
||||
mRoot->ComputeEffectiveTransforms(matrix);
|
||||
nsIntRegion opaque;
|
||||
LayerIntRegion visible;
|
||||
PostProcessLayers(mRoot, opaque, visible, Nothing());
|
||||
PostProcessLayers(opaque);
|
||||
|
||||
nsIntRegion invalid;
|
||||
IntRect bounds = IntRect::Truncate(0, 0, scale * pageWidth, actualHeight);
|
||||
|
|
|
@ -305,6 +305,7 @@ public:
|
|||
* Each layer accumulates into |aVisibleRegion| its post-transform
|
||||
* (including async transforms) visible region.
|
||||
*/
|
||||
void PostProcessLayers(nsIntRegion& aOpaqueRegion);
|
||||
void PostProcessLayers(Layer* aLayer,
|
||||
nsIntRegion& aOpaqueRegion,
|
||||
LayerIntRegion& aVisibleRegion,
|
||||
|
|
|
@ -159,7 +159,8 @@ D3D11Checks::DoesDeviceWork()
|
|||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1904,9 +1904,8 @@ imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
|
|||
imgCacheQueue& queue = GetCacheQueue(aKey);
|
||||
|
||||
RefPtr<imgCacheEntry> entry;
|
||||
if (cache.Get(aKey, getter_AddRefs(entry)) && entry) {
|
||||
cache.Remove(aKey);
|
||||
|
||||
cache.Remove(aKey, getter_AddRefs(entry));
|
||||
if (entry) {
|
||||
MOZ_ASSERT(!entry->Evicted(), "Evicting an already-evicted cache entry!");
|
||||
|
||||
// Entries with no proxies are in the tracker.
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#ifdef ANDROID
|
||||
#include "base/message_pump_android.h"
|
||||
#endif
|
||||
#include "nsISerialEventTarget.h"
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
#include "GeckoTaskTracer.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
|
||||
MessageLoop* MessageLoop::current() {
|
||||
return get_tls_ptr().Get();
|
||||
|
@ -103,7 +182,8 @@ MessageLoop::MessageLoop(Type type, nsIThread* aThread)
|
|||
#endif // OS_WIN
|
||||
transient_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";
|
||||
get_tls_ptr().Set(this);
|
||||
|
||||
|
@ -248,7 +328,7 @@ bool MessageLoop::ProcessNextDelayedNonNestableTask() {
|
|||
if (deferred_non_nestable_work_queue_.empty())
|
||||
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();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void MessageLoop::PostIdleTask(already_AddRefed<Runnable> task) {
|
||||
void MessageLoop::PostIdleTask(already_AddRefed<nsIRunnable> task) {
|
||||
DCHECK(current() == this);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -283,7 +363,7 @@ void MessageLoop::PostIdleTask(already_AddRefed<Runnable> task) {
|
|||
}
|
||||
|
||||
// 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()) {
|
||||
nsresult rv;
|
||||
if (delay_ms) {
|
||||
|
@ -296,7 +376,7 @@ void MessageLoop::PostTask_Helper(already_AddRefed<Runnable> task, int delay_ms)
|
|||
}
|
||||
|
||||
#ifdef MOZ_TASK_TRACER
|
||||
RefPtr<Runnable> tracedTask = task;
|
||||
nsCOMPtr<nsIRunnable> tracedTask = task;
|
||||
if (mozilla::tasktracer::IsStartLogging()) {
|
||||
tracedTask = mozilla::tasktracer::CreateTracedRunnable(Move(task));
|
||||
(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_);
|
||||
// Execute the task and assume the worst: It is probably not reentrant.
|
||||
nestable_tasks_allowed_ = false;
|
||||
|
||||
RefPtr<Runnable> task = aTask;
|
||||
nsCOMPtr<nsIRunnable> task = aTask;
|
||||
task->Run();
|
||||
task = nullptr;
|
||||
|
||||
|
@ -524,6 +604,13 @@ bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
|
|||
return (sequence_num - other.sequence_num) > 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MessageLoop::SerialEventTarget
|
||||
|
||||
nsISerialEventTarget* MessageLoop::SerialEventTarget() {
|
||||
return mEventTarget;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MessageLoopForUI
|
||||
|
||||
|
|
|
@ -26,8 +26,11 @@
|
|||
#endif
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsISerialEventTarget;
|
||||
class nsIThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -112,12 +115,12 @@ public:
|
|||
// NOTE: These methods may be called on any thread. The Task will be invoked
|
||||
// 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
|
||||
void PostIdleTask(already_AddRefed<mozilla::Runnable> task);
|
||||
void PostIdleTask(already_AddRefed<nsIRunnable> task);
|
||||
|
||||
// Run the message loop.
|
||||
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
|
||||
// asynchronous events it may process in addition to tasks and timers.
|
||||
//
|
||||
|
@ -282,12 +288,12 @@ public:
|
|||
|
||||
// This structure is copied around by value.
|
||||
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.
|
||||
int sequence_num; // Secondary sort key for run time.
|
||||
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) {
|
||||
}
|
||||
|
||||
|
@ -355,10 +361,10 @@ public:
|
|||
// appended to the list work_queue_. Such re-entrancy generally happens when
|
||||
// an unrequested message pump (typical of a native dialog) is executing in
|
||||
// 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.
|
||||
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
|
||||
// cannot be run right now. Returns true if the task was run.
|
||||
|
@ -378,7 +384,7 @@ public:
|
|||
bool DeletePendingTasks();
|
||||
|
||||
// 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:
|
||||
virtual bool DoWork() override;
|
||||
|
@ -436,6 +442,9 @@ public:
|
|||
// The next sequence number to use for delayed tasks.
|
||||
int next_sequence_num_;
|
||||
|
||||
class EventTarget;
|
||||
RefPtr<EventTarget> mEventTarget;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageLoop);
|
||||
};
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
#include "mozilla/ipc/MessageChannel.h"
|
||||
|
||||
#include "MessageLoopAbstractThreadWrapper.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DebugOnly.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
|
||||
MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
|
||||
{
|
||||
|
@ -778,13 +759,6 @@ MessageChannel::Open(Transport* aTransport, MessageLoop* aIOLoop, Side aSide)
|
|||
mWorkerLoop->AddDestructionObserver(this);
|
||||
mListener->SetIsMainThreadProtocol();
|
||||
|
||||
if (!AbstractThread::GetCurrent()) {
|
||||
mWorkerLoop->AddDestructionObserver(
|
||||
new AbstractThreadWrapperCleanup(
|
||||
MessageLoopAbstractThreadWrapper::Create(mWorkerLoop)));
|
||||
}
|
||||
|
||||
|
||||
ProcessLink *link = new ProcessLink(this);
|
||||
link->Open(aTransport, aIOLoop, aSide); // :TODO: n.b.: sets mChild
|
||||
mLink = link;
|
||||
|
@ -864,12 +838,6 @@ MessageChannel::CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide)
|
|||
mWorkerLoop->AddDestructionObserver(this);
|
||||
mListener->SetIsMainThreadProtocol();
|
||||
|
||||
if (!AbstractThread::GetCurrent()) {
|
||||
mWorkerLoop->AddDestructionObserver(
|
||||
new AbstractThreadWrapperCleanup(
|
||||
MessageLoopAbstractThreadWrapper::Create(mWorkerLoop)));
|
||||
}
|
||||
|
||||
mLink = new ThreadLink(this, aTargetChan);
|
||||
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 "mozilla/AbstractThread.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -26,10 +27,7 @@ TestAsyncReturnsParent::~TestAsyncReturnsParent()
|
|||
void
|
||||
TestAsyncReturnsParent::Main()
|
||||
{
|
||||
if (!AbstractThread::MainThread()) {
|
||||
fail("AbstractThread not initalized");
|
||||
}
|
||||
SendNoReturn()->Then(AbstractThread::MainThread(), __func__,
|
||||
SendNoReturn()->Then(MessageLoop::current()->SerialEventTarget(), __func__,
|
||||
[](bool unused) {
|
||||
fail("resolve handler should not be called");
|
||||
},
|
||||
|
@ -41,7 +39,7 @@ TestAsyncReturnsParent::Main()
|
|||
}
|
||||
passed("reject handler called on channel close");
|
||||
});
|
||||
SendPing()->Then(AbstractThread::MainThread(), __func__,
|
||||
SendPing()->Then(MessageLoop::current()->SerialEventTarget(), __func__,
|
||||
[this](bool one) {
|
||||
if (one) {
|
||||
passed("take one argument");
|
||||
|
@ -87,10 +85,7 @@ TestAsyncReturnsChild::RecvNoReturn(NoReturnResolver&& aResolve)
|
|||
mozilla::ipc::IPCResult
|
||||
TestAsyncReturnsChild::RecvPing(PingResolver&& aResolve)
|
||||
{
|
||||
if (!AbstractThread::MainThread()) {
|
||||
fail("AbstractThread not initalized");
|
||||
}
|
||||
SendPong()->Then(AbstractThread::MainThread(), __func__,
|
||||
SendPong()->Then(MessageLoop::current()->SerialEventTarget(), __func__,
|
||||
[aResolve](const Tuple<uint32_t, uint32_t>& aParam) {
|
||||
if (Get<0>(aParam) == sMagic1 && Get<1>(aParam) == sMagic2) {
|
||||
passed("take two arguments");
|
||||
|
|
|
@ -85,7 +85,7 @@ GUIDToString(REFGUID aGuid, nsAString& aOutString)
|
|||
// to include curly braces and dashes.
|
||||
const int kBufLenWithNul = 39;
|
||||
aOutString.SetLength(kBufLenWithNul);
|
||||
int result = StringFromGUID2(aGuid, wwc(aOutString.BeginWriting()), kBufLenWithNul);
|
||||
int result = StringFromGUID2(aGuid, char16ptr_t(aOutString.BeginWriting()), kBufLenWithNul);
|
||||
MOZ_ASSERT(result);
|
||||
if (result) {
|
||||
// Truncate the terminator
|
||||
|
|
|
@ -2006,9 +2006,7 @@ nsPresContext::ForceCacheLang(nsIAtom *aLanguage)
|
|||
{
|
||||
// force it to be cached
|
||||
GetDefaultFont(kPresContext_DefaultVariableFont_ID, aLanguage);
|
||||
if (!mLanguagesUsed.Contains(aLanguage)) {
|
||||
mLanguagesUsed.PutEntry(aLanguage);
|
||||
}
|
||||
mLanguagesUsed.PutEntry(aLanguage);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1392,7 +1392,8 @@ nsIFrame::Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay,
|
|||
EffectSet* aEffectSet) const
|
||||
{
|
||||
MOZ_ASSERT(aStyleDisplay == StyleDisplay());
|
||||
if (!GetParent() || !GetParent()->Extend3DContext(aEffectSet)) {
|
||||
nsIFrame* parent = GetFlattenedTreeParentPrimaryFrame();
|
||||
if (!parent || !parent->Extend3DContext()) {
|
||||
return false;
|
||||
}
|
||||
return IsTransformed(aStyleDisplay,aEffectSet) ||
|
||||
|
@ -2320,9 +2321,9 @@ FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
|
|||
MOZ_ASSERT(aAncestor != aDescendant);
|
||||
MOZ_ASSERT(aAncestor->Extend3DContext());
|
||||
nsIFrame* frame;
|
||||
for (frame = nsLayoutUtils::GetCrossDocParentFrame(aDescendant);
|
||||
for (frame = aDescendant->GetFlattenedTreeParentPrimaryFrame();
|
||||
frame && aAncestor != frame;
|
||||
frame = nsLayoutUtils::GetCrossDocParentFrame(frame)) {
|
||||
frame = frame->GetFlattenedTreeParentPrimaryFrame()) {
|
||||
if (!frame->Extend3DContext()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6277,6 +6278,16 @@ nsIFrame::GetNearestWidget(nsPoint& aOffset) const
|
|||
return widget;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsIFrame::GetFlattenedTreeParentPrimaryFrame() const
|
||||
{
|
||||
if (!GetContent()) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent* parent = GetContent()->GetFlattenedTreeParent();
|
||||
return parent ? parent->GetPrimaryFrame() : nullptr;
|
||||
}
|
||||
|
||||
Matrix4x4
|
||||
nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
|
||||
nsIFrame** aOutAncestor,
|
||||
|
|
|
@ -836,6 +836,12 @@ public:
|
|||
*/
|
||||
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).
|
||||
* @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) {
|
||||
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.
|
||||
// We rely on this to ensure 3D transforms compute a reasonable
|
||||
// layer visible region.
|
||||
|
@ -4400,7 +4407,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
// to avoid failure caused by singular transforms.
|
||||
newLayerEntry->mUntransformedVisibleRegion = true;
|
||||
newLayerEntry->mVisibleRegion =
|
||||
item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel);
|
||||
item->GetVisibleRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel);
|
||||
} else {
|
||||
newLayerEntry->mVisibleRegion = itemVisibleRegion;
|
||||
}
|
||||
|
@ -4414,7 +4421,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
|||
(item->Frame()->IsPreserve3DLeaf() ||
|
||||
item->Frame()->HasPerspective());
|
||||
const nsIntRegion &visible = useChildrenVisible ?
|
||||
item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel):
|
||||
item->GetVisibleRectForChildren().ScaleToOutsidePixels(contentXScale, contentYScale, mAppUnitsPerDevPixel):
|
||||
itemVisibleRegion;
|
||||
|
||||
SetOuterVisibleRegionForLayer(ownLayer, visible,
|
||||
|
|
|
@ -1719,12 +1719,15 @@ nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
|
|||
}
|
||||
|
||||
nsPresContext* key = aFrame->PresContext();
|
||||
if (!mWillChangeBudget.Contains(key)) {
|
||||
mWillChangeBudget.Put(key, DocumentWillChangeBudget());
|
||||
}
|
||||
|
||||
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();
|
||||
uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
|
||||
|
@ -1736,7 +1739,7 @@ nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
|
|||
|
||||
if (onBudget) {
|
||||
budget.mBudget += cost;
|
||||
mWillChangeBudget.Put(key, budget);
|
||||
willChangeBudgetEntry.Data() = budget;
|
||||
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
|
||||
== animate-backface-hidden.html about:blank
|
||||
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,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-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 =
|
||||
aRuleData->mVariables->mVariables;
|
||||
const nsAString& aName = iter.Key();
|
||||
if (!variables.Contains(aName)) {
|
||||
variables.Put(aName, iter.UserData());
|
||||
}
|
||||
variables.LookupForAdd(aName).OrInsert(
|
||||
[&iter] () { return iter.UserData(); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,13 +98,6 @@ if CONFIG['CLANG_CL'] or not CONFIG['_MSC_VER']:
|
|||
elif f.endswith('avx2.c'):
|
||||
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.
|
||||
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
|
||||
CFLAGS += [
|
||||
|
|
|
@ -56,6 +56,12 @@ public:
|
|||
{
|
||||
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
|
||||
{
|
||||
return mPtr;
|
||||
|
|
|
@ -781,6 +781,37 @@ continue_loading:
|
|||
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
|
||||
static bool
|
||||
|
@ -861,6 +892,14 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
|||
Kernel32Intercept.Init("kernel32.dll");
|
||||
|
||||
#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()) {
|
||||
// The crash that this hook works around is only seen on Win7.
|
||||
Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback",
|
||||
|
|
|
@ -192,11 +192,6 @@ StackWalkInitCriticalAddress()
|
|||
#include "mozilla/StackWalk_windows.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>
|
||||
// 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.
|
||||
|
@ -285,39 +280,6 @@ UnregisterJitCodeRegion(uint8_t* aStart, size_t aSize)
|
|||
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
|
||||
|
||||
// Routine to print an error message to standard error.
|
||||
|
@ -404,20 +366,6 @@ EnsureWalkThreadReady()
|
|||
stackWalkThread = 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;
|
||||
}
|
||||
|
||||
|
@ -675,7 +623,11 @@ MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
|||
DWORD walkerReturn;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
// HttpLog.h should generally be included first
|
||||
#include "HttpLog.h"
|
||||
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/net/HttpChannelParent.h"
|
||||
|
|
|
@ -223,6 +223,11 @@ extern "C" {
|
|||
* @Since: ATK-2.16.
|
||||
*@ATK_ROLE_MATH_ROOT: An object that represents a mathematical expression
|
||||
* 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
|
||||
*
|
||||
* Describes the role of an object
|
||||
|
@ -353,6 +358,9 @@ typedef enum
|
|||
ATK_ROLE_STATIC,
|
||||
ATK_ROLE_MATH_FRACTION,
|
||||
ATK_ROLE_MATH_ROOT,
|
||||
ATK_ROLE_SUBSCRIPT,
|
||||
ATK_ROLE_SUPERSCRIPT,
|
||||
ATK_ROLE_FOOTNOTE,
|
||||
ATK_ROLE_LAST_DEFINED
|
||||
} AtkRole;
|
||||
|
||||
|
|
|
@ -290,6 +290,12 @@ enum IA2Role {
|
|||
to the main content. If the complementary content is completely separable main
|
||||
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')
|
||||
nonce = os.path.join(dirs['base_work_dir'], 'nonce')
|
||||
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 = [
|
||||
sys.executable,
|
||||
python,
|
||||
os.path.join(signing_dir, 'signtool.py'),
|
||||
'--cachedir', cache_dir,
|
||||
'-t', token,
|
||||
|
|
|
@ -7,6 +7,7 @@ from mozharness.base.log import INFO
|
|||
|
||||
# BalrogMixin {{{1
|
||||
class BalrogMixin(object):
|
||||
|
||||
@staticmethod
|
||||
def _query_balrog_username(server_config, product=None):
|
||||
username = server_config["balrog_usernames"].get(product)
|
||||
|
@ -15,6 +16,15 @@ class BalrogMixin(object):
|
|||
else:
|
||||
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):
|
||||
self.set_buildbot_property(
|
||||
"hashType", self.config.get("hash_type", "sha512"), write_to_file=True
|
||||
|
@ -57,7 +67,7 @@ class BalrogMixin(object):
|
|||
self.generate_balrog_props(props_path)
|
||||
|
||||
cmd = [
|
||||
sys.executable,
|
||||
self.query_python(),
|
||||
submitter_script,
|
||||
"--build-properties", props_path,
|
||||
"-t", release_type,
|
||||
|
@ -91,7 +101,10 @@ class BalrogMixin(object):
|
|||
|
||||
def submit_balrog_release_pusher(self, dirs):
|
||||
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(["--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"))])
|
||||
|
@ -131,7 +144,7 @@ class BalrogMixin(object):
|
|||
)
|
||||
|
||||
cmd = [
|
||||
sys.executable,
|
||||
self.query_python(),
|
||||
submitter_script,
|
||||
"--credentials-file", credentials_file,
|
||||
"--api-root", c["balrog_api_root"],
|
||||
|
|
|
@ -698,7 +698,12 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
|||
return self._mach(target=target, env=env)
|
||||
|
||||
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):
|
||||
config = self.config
|
||||
|
@ -1042,8 +1047,14 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
|
|||
return self.warning(ERROR_MSGS['tooltool_manifest_undetermined'])
|
||||
tooltool_manifest_path = os.path.join(dirs['abs_mozilla_dir'],
|
||||
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 = [
|
||||
sys.executable, '-u',
|
||||
python, '-u',
|
||||
os.path.join(dirs['abs_mozilla_dir'], 'mach'),
|
||||
'artifact',
|
||||
'toolchain',
|
||||
|
|
|
@ -77,3 +77,35 @@ add_task(async function tabsSendMessageReply() {
|
|||
await extension.awaitFinish("sendMessage");
|
||||
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)
|
||||
* @param zipPath The path on disk of the zip file to extract
|
||||
*/
|
||||
function GMPExtractor(zipPath, installToDirPath) {
|
||||
function GMPExtractor(zipPath, relativeInstallPath) {
|
||||
this.zipPath = zipPath;
|
||||
this.installToDirPath = installToDirPath;
|
||||
this.relativeInstallPath = relativeInstallPath;
|
||||
}
|
||||
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
|
||||
* addons for the current platform.
|
||||
|
@ -398,70 +382,26 @@ GMPExtractor.prototype = {
|
|||
* See GMPInstallManager.installAddon for resolve/rejected info
|
||||
*/
|
||||
install() {
|
||||
try {
|
||||
let log = getScopedLogger("GMPExtractor.install");
|
||||
this._deferred = Promise.defer();
|
||||
log.info("Installing " + this.zipPath + "...");
|
||||
// Get the input zip file
|
||||
let zipFile = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsIFile);
|
||||
zipFile.initWithPath(this.zipPath);
|
||||
|
||||
// Initialize a zipReader and obtain the entries
|
||||
var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
zipReader.open(zipFile)
|
||||
let entries = this._getZipEntries(zipReader);
|
||||
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));
|
||||
this._deferred = Promise.defer();
|
||||
let deferredPromise = this._deferred;
|
||||
let {zipPath, relativeInstallPath} = this;
|
||||
let worker =
|
||||
new ChromeWorker("resource://gre/modules/GMPExtractorWorker.js");
|
||||
worker.onmessage = function(msg) {
|
||||
let log = getScopedLogger("GMPExtractor");
|
||||
worker.terminate();
|
||||
if (msg.data.result != "success") {
|
||||
log.error("Failed to extract zip file: " + zipPath);
|
||||
return deferredPromise.reject({
|
||||
target: this,
|
||||
status: msg.data.exception,
|
||||
type: "exception"
|
||||
});
|
||||
}
|
||||
|
||||
// Extract each of the entries
|
||||
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"
|
||||
});
|
||||
log.info("Successfully extracted zip file: " + zipPath);
|
||||
return deferredPromise.resolve(msg.data.extractedPaths);
|
||||
}
|
||||
worker.postMessage({zipPath, relativeInstallPath});
|
||||
return this._deferred.promise;
|
||||
}
|
||||
};
|
||||
|
@ -496,11 +436,10 @@ GMPDownloader.prototype = {
|
|||
}
|
||||
|
||||
return ProductAddonChecker.downloadAddon(gmpAddon).then((zipPath) => {
|
||||
let path = OS.Path.join(OS.Constants.Path.profileDir,
|
||||
gmpAddon.id,
|
||||
gmpAddon.version);
|
||||
log.info("install to directory path: " + path);
|
||||
let gmpInstaller = new GMPExtractor(zipPath, path);
|
||||
let relativePath = OS.Path.join(gmpAddon.id,
|
||||
gmpAddon.version);
|
||||
log.info("install to directory path: " + relativePath);
|
||||
let gmpInstaller = new GMPExtractor(zipPath, relativePath);
|
||||
let installPromise = gmpInstaller.install();
|
||||
return installPromise.then(extractedPaths => {
|
||||
// Success, set the prefs
|
||||
|
|
|
@ -196,6 +196,7 @@ EXTRA_JS_MODULES += [
|
|||
'FinderIterator.jsm',
|
||||
'FormLikeFactory.jsm',
|
||||
'Geometry.jsm',
|
||||
'GMPExtractorWorker.js',
|
||||
'GMPInstallManager.jsm',
|
||||
'GMPUtils.jsm',
|
||||
'HiddenFrame.jsm',
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "shared-libraries.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
|
|
@ -344,7 +344,7 @@ IMMHandler::InitKeyboardLayout(nsWindow* aWindow,
|
|||
// Add room for the terminating null character
|
||||
sIMEName.SetLength(++IMENameLength);
|
||||
IMENameLength =
|
||||
::ImmGetDescriptionW(aKeyboardLayout, wwc(sIMEName.BeginWriting()),
|
||||
::ImmGetDescriptionW(aKeyboardLayout, sIMEName.get(),
|
||||
IMENameLength);
|
||||
// Adjust the length to ignore the terminating null character
|
||||
sIMEName.SetLength(IMENameLength);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
nsresult NS_FASTCALL
|
||||
NS_TableDrivenQI(void* aThis, REFNSIID aIID, void** aInstancePtr,
|
||||
const QITableEntry* aEntries)
|
||||
|
@ -28,10 +30,15 @@ NS_TableDrivenQI(void* aThis, REFNSIID aIID, void** aInstancePtr,
|
|||
}
|
||||
|
||||
#ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
|
||||
nsAutoOwningThread::nsAutoOwningThread()
|
||||
: mThread(GetCurrentVirtualThread())
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsAutoOwningThread::AssertCurrentThreadOwnsMe(const char* msg) const
|
||||
{
|
||||
if (MOZ_UNLIKELY(mThread != PR_GetCurrentThread())) {
|
||||
if (MOZ_UNLIKELY(mThread != GetCurrentVirtualThread())) {
|
||||
// `msg` is a string literal by construction.
|
||||
MOZ_CRASH_UNSAFE_OOL(msg);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ ToCanonicalSupports(nsISupports* aSupports)
|
|||
class nsAutoOwningThread
|
||||
{
|
||||
public:
|
||||
nsAutoOwningThread() { mThread = PR_GetCurrentThread(); }
|
||||
nsAutoOwningThread();
|
||||
|
||||
// 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
|
||||
|
|
|
@ -229,7 +229,7 @@ nsresult GetCountryCode(nsAString& aCountryCode)
|
|||
}
|
||||
// Now get the string for real
|
||||
aCountryCode.SetLength(numChars);
|
||||
numChars = GetGeoInfoW(geoid, GEO_ISO2, wwc(aCountryCode.BeginWriting()),
|
||||
numChars = GetGeoInfoW(geoid, GEO_ISO2, char16ptr_t(aCountryCode.BeginWriting()),
|
||||
aCountryCode.Length(), 0);
|
||||
if (!numChars) {
|
||||
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:
|
||||
//
|
||||
// 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
|
||||
*/
|
||||
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,
|
||||
Args&&... aConstructionArgs)
|
||||
{
|
||||
auto count = this->Count();
|
||||
typename base_type::EntryType* ent = this->PutEntry(aKey);
|
||||
if (!ent->mData) {
|
||||
if (count != this->Count()) {
|
||||
ent->mData = new T(mozilla::Forward<Args>(aConstructionArgs)...);
|
||||
}
|
||||
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>
|
||||
bool
|
||||
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;
|
||||
}
|
||||
|
||||
nsAString::iterator begin;
|
||||
expandedResult.BeginWriting(begin);
|
||||
|
||||
resultLen = ExpandEnvironmentStringsW(flatSource.get(),
|
||||
wwc(begin.get()),
|
||||
expandedResult.get(),
|
||||
resultLen + 1);
|
||||
if (resultLen <= 0) {
|
||||
rv = ERROR_UNKNOWN_FEATURE;
|
||||
|
|
|
@ -61,7 +61,7 @@ HandleToFilename(HANDLE aHandle, const LARGE_INTEGER& aOffset,
|
|||
do {
|
||||
mappedFilename.SetLength(mappedFilename.Length() + MAX_PATH);
|
||||
len = GetMappedFileNameW(GetCurrentProcess(), view,
|
||||
wwc(mappedFilename.BeginWriting()),
|
||||
mappedFilename.get(),
|
||||
mappedFilename.Length());
|
||||
} while (!len && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
||||
if (!len) {
|
||||
|
|
|
@ -995,7 +995,7 @@ nsLocalFile::ResolveShortcut()
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
wchar_t* resolvedPath = wwc(mResolvedPath.BeginWriting());
|
||||
wchar_t* resolvedPath = mResolvedPath.get();
|
||||
|
||||
// resolve this shortcut
|
||||
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
|
||||
// '\\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'\\') {
|
||||
// dealing with a UNC path here; skip past '\\machine\'
|
||||
|
@ -3743,7 +3743,7 @@ nsDriveEnumerator::Init()
|
|||
if (!mDrives.SetLength(length + 1, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (!GetLogicalDriveStringsW(length, wwc(mDrives.BeginWriting()))) {
|
||||
if (!GetLogicalDriveStringsW(length, mDrives.get())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mDrives.BeginReading(mStartOfCurrentDrive);
|
||||
|
|
|
@ -929,12 +929,8 @@ NS_CopyNativeToUnicode(const nsACString& aInput, nsAString& aOutput)
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (resultLen > 0) {
|
||||
nsAString::iterator out_iter;
|
||||
aOutput.BeginWriting(out_iter);
|
||||
|
||||
char16_t* result = out_iter.get();
|
||||
|
||||
::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, wwc(result), resultLen);
|
||||
char16ptr_t result = aOutput.BeginWriting();
|
||||
::MultiByteToWideChar(CP_ACP, 0, buf, inputLen, result, resultLen);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -978,41 +974,6 @@ NS_CopyUnicodeToNative(const nsAString& aInput, nsACString& aOutput)
|
|||
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
|
||||
|
||||
#include "nsReadableUtils.h"
|
||||
|
|
|
@ -148,49 +148,6 @@ private:
|
|||
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
|
||||
typedef nsAutoString nsVoidableString;
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче