зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c. a=merge
This commit is contained in:
Коммит
5f9582530e
|
@ -67,6 +67,11 @@ DocAccessibleParent::AddSubtree(ProxyAccessible* aParent,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (mAccessibles.Contains(newChild.ID())) {
|
||||
NS_ERROR("ID already in use");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto role = static_cast<a11y::role>(newChild.Role());
|
||||
ProxyAccessible* newProxy =
|
||||
new ProxyAccessible(newChild.ID(), aParent, this, role);
|
||||
|
@ -95,6 +100,8 @@ DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
|
|||
if (mShutdown)
|
||||
return true;
|
||||
|
||||
CheckDocTree();
|
||||
|
||||
ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
|
||||
if (!rootEntry) {
|
||||
NS_ERROR("invalid root being removed!");
|
||||
|
@ -236,5 +243,17 @@ DocAccessibleParent::Destroy()
|
|||
GetAccService()->RemoteDocShutdown(this);
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleParent::CheckDocTree() const
|
||||
{
|
||||
size_t childDocs = mChildDocs.Length();
|
||||
for (size_t i = 0; i < childDocs; i++) {
|
||||
if (!mChildDocs[i] || mChildDocs[i]->mParentDoc != this)
|
||||
MOZ_CRASH("document tree is broken!");
|
||||
|
||||
mChildDocs[i]->CheckDocTree();
|
||||
}
|
||||
}
|
||||
|
||||
} // a11y
|
||||
} // mozilla
|
||||
|
|
|
@ -150,6 +150,8 @@ private:
|
|||
uint32_t AddSubtree(ProxyAccessible* aParent,
|
||||
const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
|
||||
uint32_t aIdxInParent);
|
||||
void CheckDocTree() const;
|
||||
|
||||
static PLDHashOperator ShutdownAccessibles(ProxyEntry* entry, void* unused);
|
||||
|
||||
nsTArray<DocAccessibleParent*> mChildDocs;
|
||||
|
|
|
@ -1456,7 +1456,6 @@ pref("devtools.debugger.source-maps-enabled", true);
|
|||
pref("devtools.debugger.pretty-print-enabled", true);
|
||||
pref("devtools.debugger.auto-pretty-print", false);
|
||||
pref("devtools.debugger.auto-black-box", true);
|
||||
pref("devtools.debugger.tracer", false);
|
||||
pref("devtools.debugger.workers", false);
|
||||
pref("devtools.debugger.promise", false);
|
||||
|
||||
|
|
|
@ -183,9 +183,7 @@ let PanelFrame = {
|
|||
}
|
||||
});
|
||||
|
||||
// in overflow, the anchor is a normal toolbarbutton, in toolbar it is a badge button
|
||||
let anchor = aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-badge-container") ||
|
||||
aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-icon");
|
||||
let anchor = aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-icon");
|
||||
// Bug 849216 - open the popup asynchronously so we avoid the auto-rollup
|
||||
// handling from preventing it being opened in some cases.
|
||||
Services.tm.mainThread.dispatch(function() {
|
||||
|
|
|
@ -584,7 +584,7 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
|||
.findbar-button > .toolbarbutton-text,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-icon {
|
||||
-moz-margin-end: 0;
|
||||
padding: 2px 6px;
|
||||
|
@ -595,14 +595,14 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
|
|||
}
|
||||
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
padding: 3px 7px;
|
||||
}
|
||||
|
||||
/* Help SDK icons fit: */
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
|
@ -620,7 +620,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
|||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open]:not([disabled=true]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):not([open]):hover > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):not([open]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-icon {
|
||||
background: var(--toolbarbutton-hover-background);
|
||||
border-width: 1px;
|
||||
|
@ -638,7 +638,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
|||
.findbar-button:not([disabled=true]):-moz-any([checked="true"],:hover:active) > .toolbarbutton-text,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open="true"]) > .toolbarbutton-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack,
|
||||
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
|
||||
background: var(--toolbarbutton-active-background);
|
||||
box-shadow: var(--toolbarbutton-active-boxshadow);
|
||||
|
|
|
@ -1067,7 +1067,7 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
|||
}
|
||||
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
width: 18px;
|
||||
}
|
||||
|
@ -1090,25 +1090,25 @@ toolbar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutto
|
|||
|
||||
/* Help SDK icons fit: */
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
@media (-moz-mac-lion-theme) {
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker,
|
||||
#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-text,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
.toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
|
@ -1116,7 +1116,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
|||
}
|
||||
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
#main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon {
|
||||
opacity: .25;
|
||||
}
|
||||
|
|
|
@ -233,14 +233,14 @@ toolbarpaletteitem[notransition][place="panel"] {
|
|||
}
|
||||
|
||||
toolbarpaletteitem > toolbarbutton > .toolbarbutton-icon,
|
||||
toolbarpaletteitem > toolbarbutton > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarpaletteitem > toolbarbutton > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
toolbarpaletteitem > toolbaritem.panel-wide-item,
|
||||
toolbarpaletteitem > toolbarbutton[type="menu-button"] {
|
||||
transition: transform .3s cubic-bezier(.6, 2, .75, 1.5) !important;
|
||||
}
|
||||
|
||||
toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-icon,
|
||||
toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
|
|
|
@ -312,9 +312,9 @@ toolbarpaletteitem[place="panel"]:not([haswideitem=true]) > .toolbarbutton-1 {
|
|||
|
||||
/* Help SDK buttons fit in. */
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-icon,
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
@ -432,10 +432,10 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
|
|||
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
.panelUI-grid #bookmarks-toolbar-placeholder > .toolbarbutton-icon,
|
||||
.customization-palette #bookmarks-toolbar-placeholder > .toolbarbutton-icon,
|
||||
.panel-customization-placeholder-child > .toolbarbutton-icon {
|
||||
|
@ -461,8 +461,8 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
|
|||
/* above we treat the container as the icon for the margins, that is so the
|
||||
/* badge itself is positioned correctly. Here we make sure that the icon itself
|
||||
/* has the minimum size we want, but no padding/margin. */
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
min-width: 32px;
|
||||
|
|
|
@ -191,39 +191,39 @@
|
|||
-moz-image-region: rect(0, 832px, 32px, 800px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"] > .toolbarbutton-badge-container,
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/menuPanel.png);
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
/* Make sure that the state icons are not shown in the customization palette. */
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0) !important;
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"],
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] {
|
||||
-moz-image-region: rect(0, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 128px, 32px, 96px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 160px, 32px, 128px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 192px, 32px, 160px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 224px, 32px, 192px);
|
||||
}
|
||||
|
||||
|
@ -375,39 +375,39 @@
|
|||
-moz-image-region: rect(64px, 1984px, 128px, 1920px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"] > .toolbarbutton-badge-container,
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/menuPanel@2x.png);
|
||||
-moz-image-region: rect(0, 64px, 64px, 0);
|
||||
}
|
||||
|
||||
/* Make sure that the state icons are not shown in the customization palette. */
|
||||
toolbarpaletteitem[place="palette"] > #loop-button > .toolbarbutton-badge-container {
|
||||
toolbarpaletteitem[place="palette"] > #loop-button {
|
||||
-moz-image-region: rect(0, 64px, 64px, 0) !important;
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"][state="disabled"],
|
||||
#loop-button[cui-areatype="menu-panel"][disabled="true"] {
|
||||
-moz-image-region: rect(0, 128px, 64px, 64px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 192px, 64px, 128px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 256px, 64px, 192px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 320px, 64px, 256px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 384px, 64px, 320px);
|
||||
}
|
||||
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button[cui-areatype="menu-panel"]:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 448px, 64px, 384px);
|
||||
}
|
||||
|
||||
|
|
|
@ -184,37 +184,37 @@ toolbar[brighttext] #sync-button[status="active"] {
|
|||
-moz-image-region: rect(0, 720px, 18px, 702px);
|
||||
}
|
||||
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar.png);
|
||||
-moz-image-region: rect(0, 18px, 18px, 0);
|
||||
}
|
||||
|
||||
toolbar[brighttext] #loop-button > .toolbarbutton-badge-container {
|
||||
toolbar[brighttext] #loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar-inverted.png);
|
||||
}
|
||||
|
||||
#loop-button[state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[state="disabled"],
|
||||
#loop-button[disabled="true"] {
|
||||
-moz-image-region: rect(0, 36px, 18px, 18px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 54px, 18px, 36px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 72px, 18px, 54px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 90px, 18px, 72px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 108px, 18px, 90px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 126px, 18px, 108px);
|
||||
}
|
||||
|
||||
|
@ -430,37 +430,37 @@ toolbar[brighttext] #loop-button > .toolbarbutton-badge-container {
|
|||
%endif
|
||||
}
|
||||
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
|
||||
-moz-image-region: rect(0, 36px, 36px, 0);
|
||||
}
|
||||
|
||||
toolbar[brighttext] #loop-button > .toolbarbutton-badge-container {
|
||||
toolbar[brighttext] #loop-button {
|
||||
list-style-image: url("chrome://browser/skin/loop/toolbar-inverted@2x.png");
|
||||
}
|
||||
|
||||
#loop-button[state="disabled"] > .toolbarbutton-badge-container,
|
||||
#loop-button[disabled="true"] > .toolbarbutton-badge-container {
|
||||
#loop-button[state="disabled"],
|
||||
#loop-button[disabled="true"] {
|
||||
-moz-image-region: rect(0, 72px, 36px, 36px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="error"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="error"] {
|
||||
-moz-image-region: rect(0, 108px, 36px, 72px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"] {
|
||||
-moz-image-region: rect(0, 144px, 36px, 108px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="action"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 180px, 36px, 144px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"] > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"] {
|
||||
-moz-image-region: rect(0, 216px, 36px, 180px);
|
||||
}
|
||||
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) > .toolbarbutton-badge-container {
|
||||
#loop-button:not([disabled="true"])[state="active"]:-moz-any(:hover,:hover:active,[open]) {
|
||||
-moz-image-region: rect(0, 252px, 36px, 216px);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -593,13 +593,13 @@ menuitem.bookmark-item {
|
|||
list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
|
||||
}
|
||||
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver.png)
|
||||
}
|
||||
}
|
||||
|
||||
@media (-moz-windows-theme: luna-silver) and (min-resolution: 1.1dppx) {
|
||||
#loop-button > .toolbarbutton-badge-container {
|
||||
#loop-button {
|
||||
list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver@2x.png)
|
||||
}
|
||||
}
|
||||
|
@ -674,7 +674,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
|||
.findbar-button > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
|
||||
|
@ -687,7 +687,7 @@ toolbar[brighttext] .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
|
|||
|
||||
toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])):not(:-moz-any(@nestedButtons@)) > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-badge-stack > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@):-moz-any([cui-areatype="toolbar"],:not([cui-areatype])) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
width: 18px;
|
||||
|
@ -728,7 +728,7 @@ toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbut
|
|||
.findbar-button > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
background-color: hsla(210,32%,93%,0);
|
||||
|
@ -744,14 +744,14 @@ toolbarbutton[cui-areatype="toolbar"] > :-moz-any(@nestedButtons@) > .toolbarbut
|
|||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-stack,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
padding: calc(var(--toolbarbutton-vertical-inner-padding) + 1px) 7px;
|
||||
}
|
||||
|
||||
/* Help SDK icons fit: */
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-icon,
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-badge-stack > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
|
@ -821,7 +821,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
|||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-stack,
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
|
||||
background: var(--toolbarbutton-hover-background);
|
||||
|
@ -866,7 +866,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
|||
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack {
|
||||
background: var(--toolbarbutton-active-background);
|
||||
border-color: var(--toolbarbutton-active-bordercolor);
|
||||
box-shadow: var(--toolbarbutton-active-boxshadow);
|
||||
|
@ -882,7 +882,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
|||
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-stack {
|
||||
text-shadow: none;
|
||||
transition: none;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class DomainPolicyClone;
|
|||
[ptr] native JSObjectPtr(JSObject);
|
||||
[ptr] native DomainPolicyClonePtr(mozilla::dom::DomainPolicyClone);
|
||||
|
||||
[scriptable, uuid(f4c578b8-5bac-4ba1-9582-f1140e09a3b4)]
|
||||
[scriptable, uuid(50418f5c-b0d8-42c3-ba5d-efffb6927e1c)]
|
||||
interface nsIScriptSecurityManager : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -201,6 +201,20 @@ interface nsIScriptSecurityManager : nsISupports
|
|||
[implicit_jscontext]
|
||||
nsIPrincipal createNullPrincipal(in jsval originAttributes);
|
||||
|
||||
/**
|
||||
* Creates an expanded principal whose capabilities are the union of the
|
||||
* given principals. An expanded principal has an asymmetric privilege
|
||||
* relationship with its sub-principals (that is to say, it subsumes the
|
||||
* sub-principals, but the sub-principals do not subsume it), even if
|
||||
* there's only one. This presents a legitimate use-case for making an
|
||||
* expanded principal around a single sub-principal, which we do frequently.
|
||||
*
|
||||
* Expanded principals cannot have origin attributes themselves, but rather
|
||||
* have them through their sub-principals - so we don't accept them here.
|
||||
*/
|
||||
nsIPrincipal createExpandedPrincipal([array, size_is(aLength)] in nsIPrincipal aPrincipalArray,
|
||||
[optional] in unsigned long aLength);
|
||||
|
||||
/**
|
||||
* Returns OK if aSourceURI and target have the same "origin"
|
||||
* (scheme, host, and port).
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=4 et sw=4 tw=80: */
|
||||
/* 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/. */
|
||||
|
@ -1027,6 +1027,21 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle<JS::Value> aOriginAttrib
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::CreateExpandedPrincipal(nsIPrincipal** aPrincipalArray, uint32_t aLength,
|
||||
nsIPrincipal** aResult)
|
||||
{
|
||||
nsTArray<nsCOMPtr<nsIPrincipal>> principals;
|
||||
principals.SetCapacity(aLength);
|
||||
for (uint32_t i = 0; i < aLength; ++i) {
|
||||
principals.AppendElement(aPrincipalArray[i]);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> p = new nsExpandedPrincipal(principals);
|
||||
p.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsScriptSecurityManager::GetAppCodebasePrincipal(nsIURI* aURI,
|
||||
uint32_t aAppId,
|
||||
|
|
|
@ -47,7 +47,7 @@ function run_test() {
|
|||
var nullPrin = Cu.getObjectPrincipal(new Cu.Sandbox(null));
|
||||
do_check_true(/^moz-nullprincipal:\{([0-9]|[a-z]|\-){36}\}$/.test(nullPrin.origin));
|
||||
checkOriginAttributes(nullPrin);
|
||||
var ep = Cu.getObjectPrincipal(new Cu.Sandbox([exampleCom, nullPrin, exampleOrg]));
|
||||
var ep = ssm.createExpandedPrincipal([exampleCom, nullPrin, exampleOrg]);
|
||||
checkOriginAttributes(ep);
|
||||
checkCrossOrigin(exampleCom, exampleOrg);
|
||||
checkCrossOrigin(exampleOrg, nullPrin);
|
||||
|
|
30
configure.in
30
configure.in
|
@ -476,17 +476,37 @@ dnl Special MacOS X checks
|
|||
dnl ========================================================
|
||||
|
||||
if test -n "$MACOSX_DEPLOYMENT_TARGET" -a -n "$MOZ_RUST"; then
|
||||
AC_MSG_CHECKING([MacOS X compatibility with rust])
|
||||
# rustc doesn't support MacOS X 10.6 or earlier.
|
||||
AC_MSG_CHECKING([rustc compatibility with MacOS X])
|
||||
# Stock rustc doesn't support MacOS X 10.6 or earlier.
|
||||
# https://github.com/rust-lang/rust/issues/25342
|
||||
_MACOSX_TARGET_MINOR=`echo "$MACOSX_DEPLOYMENT_TARGET" | cut -d. -f2`
|
||||
if test "$_MACOSX_TARGET_MINOR" -lt 7; then
|
||||
AC_MSG_ERROR([rustc does not support MacOS X $MACOSX_DEPLOYMENT_TARGET
|
||||
Add 'ac_add_options --enable-macos-target=10.7' (or later)
|
||||
to mozconfig, or disable rust support.])
|
||||
dnl Test C linkage against rust code to see if the rust
|
||||
dnl toolchain output is compatible.
|
||||
cat > conftest.rs <<EOF
|
||||
[#[no_mangle]]
|
||||
pub extern fn rusty_answer() -> u8 { 42 }
|
||||
EOF
|
||||
ac_try="$RUSTC --crate-type staticlib -o conftest.a conftest.rs >/dev/null"
|
||||
AC_TRY_EVAL(ac_try)
|
||||
save_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS conftest.a -lpthread -lm"
|
||||
AC_TRY_LINK_FUNC([rusty_answer], [
|
||||
AC_MSG_RESULT([$MACOSX_DEPLOYMENT_TARGET is ok with this rustc])
|
||||
], [
|
||||
AC_MSG_RESULT([cannot link on $MACOSX_DEPLOYMENT_TARGET])
|
||||
MOZ_RUST=
|
||||
])
|
||||
LDFLAGS=$save_LDFLAGS
|
||||
rm -rf conftest*
|
||||
else
|
||||
AC_MSG_RESULT([$MACOSX_DEPLOYMENT_TARGET is ok])
|
||||
fi
|
||||
if test -z "$MOZ_RUST"; then
|
||||
AC_MSG_ERROR([rustc does not support MacOS X $MACOSX_DEPLOYMENT_TARGET
|
||||
Add 'ac_add_options --enable-macos-target=10.7' (or later)
|
||||
to mozconfig, disable rust support, or use an alternate toolchain.])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
|
|
|
@ -1315,7 +1315,9 @@ nsSHistory::RemoveDuplicate(int32_t aIndex, bool aKeepNext)
|
|||
nsCOMPtr<nsISHTransaction> txToRemove, txToKeep, txNext, txPrev;
|
||||
GetTransactionAtIndex(aIndex, getter_AddRefs(txToRemove));
|
||||
GetTransactionAtIndex(compareIndex, getter_AddRefs(txToKeep));
|
||||
NS_ENSURE_TRUE(txToRemove, false);
|
||||
if (!txToRemove) {
|
||||
return false;
|
||||
}
|
||||
NS_ENSURE_TRUE(txToKeep, false);
|
||||
txToRemove->GetNext(getter_AddRefs(txNext));
|
||||
txToRemove->GetPrev(getter_AddRefs(txPrev));
|
||||
|
|
|
@ -207,8 +207,7 @@ NS_IMPL_ADDREF(AudioChannelService)
|
|||
NS_IMPL_RELEASE(AudioChannelService)
|
||||
|
||||
AudioChannelService::AudioChannelService()
|
||||
: mDisabled(false)
|
||||
, mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
|
||||
: mDefChannelChildID(CONTENT_PROCESS_ID_UNKNOWN)
|
||||
, mTelephonyChannel(false)
|
||||
, mContentOrNormalChannel(false)
|
||||
, mAnyChannel(false)
|
||||
|
@ -238,10 +237,6 @@ void
|
|||
AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
||||
AudioChannel aChannel)
|
||||
{
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t windowID = aAgent->WindowID();
|
||||
AudioChannelWindow* winData = GetWindowData(windowID);
|
||||
if (!winData) {
|
||||
|
@ -272,10 +267,6 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
|
|||
void
|
||||
AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
|
||||
{
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
AudioChannelWindow* winData = GetWindowData(aAgent->WindowID());
|
||||
if (!winData) {
|
||||
return;
|
||||
|
@ -466,8 +457,8 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "xpcom-shutdown")) {
|
||||
mDisabled = true;
|
||||
mWindows.Clear();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
|
|
|
@ -43,11 +43,6 @@ public:
|
|||
*/
|
||||
static already_AddRefed<AudioChannelService> GetOrCreate();
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
static bool IsAudioChannelMutedByDefault();
|
||||
|
||||
/**
|
||||
|
@ -136,6 +131,11 @@ private:
|
|||
AudioChannelService();
|
||||
~AudioChannelService();
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
void MaybeSendStatusUpdate();
|
||||
|
||||
bool ContentOrNormalChannelIsActive();
|
||||
|
@ -204,8 +204,6 @@ private:
|
|||
nsTArray<SpeakerManagerService*> mSpeakerManager;
|
||||
#endif
|
||||
|
||||
bool mDisabled;
|
||||
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
|
||||
uint64_t mDefChannelChildID;
|
||||
|
|
|
@ -717,16 +717,6 @@ nsFocusManager::WindowRaised(nsIDOMWindow* aWindow)
|
|||
if (!currentWindow)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDocShell> currentDocShell = currentWindow->GetDocShell();
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = currentDocShell->GetPresShell();
|
||||
if (presShell) {
|
||||
// disable selection mousedown state on activation
|
||||
// XXXndeakin P3 not sure if this is necessary, but it doesn't hurt
|
||||
nsRefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
|
||||
frameSelection->SetDragState(false);
|
||||
}
|
||||
|
||||
// If there is no nsIXULWindow, then this is an embedded or child process window.
|
||||
// Pass false for aWindowRaised so that commands get updated.
|
||||
nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(baseWindow));
|
||||
|
@ -764,6 +754,19 @@ nsFocusManager::WindowLowered(nsIDOMWindow* aWindow)
|
|||
// clear the mouse capture as the active window has changed
|
||||
nsIPresShell::SetCapturingContent(nullptr, 0);
|
||||
|
||||
// In addition, reset the drag state to ensure that we are no longer in
|
||||
// drag-select mode.
|
||||
if (mFocusedWindow) {
|
||||
nsCOMPtr<nsIDocShell> docShell = mFocusedWindow->GetDocShell();
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
|
||||
if (presShell) {
|
||||
nsRefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
|
||||
frameSelection->SetDragState(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a parent or single process window, send the deactivate event.
|
||||
// Events for child process windows will be sent when ParentActivated
|
||||
// is called.
|
||||
|
|
|
@ -17,7 +17,9 @@ const Cu = Components.utils;
|
|||
sync_test,
|
||||
async_test,
|
||||
rpc_test,
|
||||
lifetime_test
|
||||
lifetime_test,
|
||||
cancel_test,
|
||||
cancel_test2,
|
||||
];
|
||||
|
||||
function go() {
|
||||
|
@ -266,3 +268,72 @@ function lifetime_test(finish)
|
|||
sendRpcMessage("cpows:lifetime_test_2");
|
||||
});
|
||||
}
|
||||
|
||||
function cancel_test(finish)
|
||||
{
|
||||
if (!is_remote) {
|
||||
// No point in doing this in single-process mode.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
let fin1 = false, fin2 = false;
|
||||
|
||||
// CPOW from the parent runs f. When it sends a sync message, the
|
||||
// CPOW is canceled. The parent starts running again immediately
|
||||
// after the CPOW is canceled; f also continues running.
|
||||
function f() {
|
||||
let res = sendSyncMessage("cpows:cancel_sync_message");
|
||||
ok(res[0] == 12, "cancel_sync_message result correct");
|
||||
fin1 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
}
|
||||
|
||||
sendAsyncMessage("cpows:cancel_test", null, {f: f});
|
||||
addMessageListener("cpows:cancel_test_done", msg => {
|
||||
fin2 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
});
|
||||
}
|
||||
|
||||
function cancel_test2(finish)
|
||||
{
|
||||
if (!is_remote) {
|
||||
// No point in doing this in single-process mode.
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
let fin1 = false, fin2 = false;
|
||||
|
||||
// CPOW from the parent runs f. When it does a sync XHR, the
|
||||
// CPOW is canceled. The parent starts running again immediately
|
||||
// after the CPOW is canceled; f also continues running.
|
||||
function f() {
|
||||
let req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
let fin = false;
|
||||
let reqListener = () => {
|
||||
if (req.readyState != req.DONE) {
|
||||
return;
|
||||
}
|
||||
ok(req.status == 200, "XHR succeeded");
|
||||
fin = true;
|
||||
};
|
||||
|
||||
req.onload = reqListener;
|
||||
req.open("get", "http://example.com", false);
|
||||
req.send(null);
|
||||
|
||||
ok(fin == true, "XHR happened");
|
||||
|
||||
fin1 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
}
|
||||
|
||||
sendAsyncMessage("cpows:cancel_test2", null, {f: f});
|
||||
addMessageListener("cpows:cancel_test2_done", msg => {
|
||||
fin2 = true;
|
||||
if (fin1 && fin2) finish();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -364,6 +364,32 @@
|
|||
});
|
||||
}
|
||||
|
||||
function recvCancelTest(msg) {
|
||||
let failed = false;
|
||||
try {
|
||||
msg.objects.f();
|
||||
} catch (e if /cross-process JS call failed/.test(String(e))) {
|
||||
failed = true;
|
||||
}
|
||||
ok(failed, "CPOW should fail due to cancelation");
|
||||
msg.target.messageManager.sendAsyncMessage("cpows:cancel_test_done");
|
||||
}
|
||||
|
||||
function recvCancelSyncMessage() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
function recvCancelTest2(msg) {
|
||||
let failed = false;
|
||||
try {
|
||||
msg.objects.f();
|
||||
} catch (e if /cross-process JS call failed/.test(String(e))) {
|
||||
failed = true;
|
||||
}
|
||||
ok(failed, "CPOW should fail due to cancelation");
|
||||
msg.target.messageManager.sendAsyncMessage("cpows:cancel_test2_done");
|
||||
}
|
||||
|
||||
function run_tests(type) {
|
||||
info("Running tests: " + type);
|
||||
var node = document.getElementById('cpowbrowser_' + type);
|
||||
|
@ -400,6 +426,9 @@
|
|||
mm.addMessageListener("cpows:postmessage_test", recvPostMessageTest);
|
||||
mm.addMessageListener("cpows:lifetime_test_1", recvLifetimeTest1);
|
||||
mm.addMessageListener("cpows:lifetime_test_2", recvLifetimeTest2);
|
||||
mm.addMessageListener("cpows:cancel_test", recvCancelTest);
|
||||
mm.addMessageListener("cpows:cancel_sync_message", recvCancelSyncMessage);
|
||||
mm.addMessageListener("cpows:cancel_test2", recvCancelTest2);
|
||||
mm.loadFrameScript("chrome://mochitests/content/chrome/dom/base/test/chrome/cpows_child.js", true);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.rect(2, 6, 9, 8);
|
||||
ctx.setTransform(1, 2, 3, 0, 4, 1);
|
||||
setTimeout(function() {
|
||||
ctx.moveTo(0, 1);
|
||||
ctx.isPointInPath(0, 0, 'evenodd');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();">
|
||||
<canvas id="canvas"></canvas>
|
||||
</body>
|
||||
</html>
|
|
@ -22,3 +22,4 @@ load 896047-2.html
|
|||
load 916128-1.html
|
||||
load 934939-1.html
|
||||
load 1099143-1.html
|
||||
load 1183363.html
|
||||
|
|
|
@ -945,7 +945,7 @@ IMEStateManager::SetInputContextForChildProcess(
|
|||
GetActionFocusChangeName(aAction.mFocusChange),
|
||||
sPresContext, sActiveTabParent.get()));
|
||||
|
||||
if (NS_WARN_IF(aTabParent != sActiveTabParent)) {
|
||||
if (aTabParent != sActiveTabParent) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||
"because non-focused tab parent tries to set input context"));
|
||||
|
|
|
@ -9,6 +9,7 @@ interface nsIArray;
|
|||
interface nsIDocument;
|
||||
interface nsIInterceptedChannel;
|
||||
interface nsIPrincipal;
|
||||
interface nsIRunnable;
|
||||
interface nsIURI;
|
||||
|
||||
[scriptable, uuid(52ee2c9d-ee87-4caf-9588-23ae77ff8798)]
|
||||
|
@ -33,7 +34,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
|||
readonly attribute DOMString waitingCacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(ed1cbbf2-0400-4caa-8eb2-b09d21a94e20)]
|
||||
[scriptable, builtinclass, uuid(8d80dd18-597b-4378-b41e-768bfe48dd4f)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -93,8 +94,11 @@ interface nsIServiceWorkerManager : nsISupports
|
|||
|
||||
/*
|
||||
* Returns a ServiceWorker.
|
||||
* - aLoadFailedRunnable is an optional callback that will fire on main thread if
|
||||
* a ServiceWorker object is returned, but later fails to load for some reason.
|
||||
*/
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow);
|
||||
[noscript] nsISupports GetDocumentController(in nsIDOMWindow aWindow,
|
||||
in nsIRunnable aLoadFailedRunnable);
|
||||
|
||||
/*
|
||||
* Clears ServiceWorker registrations from memory and disk for the specified
|
||||
|
|
|
@ -16,39 +16,6 @@ extern PRLogModuleInfo* gMediaDecoderLog;
|
|||
#define SINK_LOG_V(msg, ...) \
|
||||
MOZ_LOG(gMediaDecoderLog, LogLevel::Verbose, ("AudioSink=%p " msg, this, ##__VA_ARGS__))
|
||||
|
||||
AudioSink::OnAudioEndTimeUpdateTask::OnAudioEndTimeUpdateTask(
|
||||
MediaDecoderStateMachine* aStateMachine)
|
||||
: mMutex("OnAudioEndTimeUpdateTask")
|
||||
, mEndTime(0)
|
||||
, mStateMachine(aStateMachine)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioSink::OnAudioEndTimeUpdateTask::Run() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mStateMachine) {
|
||||
mStateMachine->OnAudioEndTimeUpdate(mEndTime);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::OnAudioEndTimeUpdateTask::Dispatch(int64_t aEndTime) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mStateMachine) {
|
||||
mEndTime = aEndTime;
|
||||
nsRefPtr<AudioSink::OnAudioEndTimeUpdateTask> runnable(this);
|
||||
mStateMachine->TaskQueue()->Dispatch(runnable.forget());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AudioSink::OnAudioEndTimeUpdateTask::Cancel() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
mStateMachine = nullptr;
|
||||
}
|
||||
|
||||
// The amount of audio frames that is used to fuzz rounding errors.
|
||||
static const int64_t AUDIO_FUZZ_FRAMES = 1;
|
||||
|
||||
|
@ -68,7 +35,6 @@ AudioSink::AudioSink(MediaDecoderStateMachine* aStateMachine,
|
|||
, mSetPlaybackRate(false)
|
||||
, mSetPreservesPitch(false)
|
||||
, mPlaying(true)
|
||||
, mOnAudioEndTimeUpdateTask(new OnAudioEndTimeUpdateTask(aStateMachine))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -132,7 +98,6 @@ AudioSink::PrepareToShutdown()
|
|||
void
|
||||
AudioSink::Shutdown()
|
||||
{
|
||||
mOnAudioEndTimeUpdateTask->Cancel();
|
||||
mThread->Shutdown();
|
||||
mThread = nullptr;
|
||||
MOZ_ASSERT(!mAudioStream);
|
||||
|
@ -218,10 +183,6 @@ AudioSink::AudioLoop()
|
|||
} else {
|
||||
mWritten += PlayFromAudioQueue();
|
||||
}
|
||||
int64_t endTime = GetEndTime();
|
||||
if (endTime != -1) {
|
||||
mOnAudioEndTimeUpdateTask->Dispatch(endTime);
|
||||
}
|
||||
}
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
MOZ_ASSERT(mStopAudioThread || AudioQueue().AtEndOfStream());
|
||||
|
@ -427,7 +388,7 @@ AudioSink::WriteSilence(uint32_t aFrames)
|
|||
}
|
||||
|
||||
int64_t
|
||||
AudioSink::GetEndTime()
|
||||
AudioSink::GetEndTime() const
|
||||
{
|
||||
CheckedInt64 playedUsecs = FramesToUsecs(mWritten, mInfo.mRate) + mStartTime;
|
||||
if (!playedUsecs.isValid()) {
|
||||
|
|
|
@ -27,6 +27,9 @@ public:
|
|||
|
||||
int64_t GetPosition();
|
||||
|
||||
// Thread-safe. Can be called on any thread.
|
||||
int64_t GetEndTime() const;
|
||||
|
||||
// Check whether we've pushed more frames to the audio hardware than it has
|
||||
// played.
|
||||
bool HasUnplayedFrames();
|
||||
|
@ -90,8 +93,6 @@ private:
|
|||
void StartAudioStreamPlaybackIfNeeded();
|
||||
void WriteSilence(uint32_t aFrames);
|
||||
|
||||
int64_t GetEndTime();
|
||||
|
||||
MediaQueue<AudioData>& AudioQueue();
|
||||
|
||||
ReentrantMonitor& GetReentrantMonitor();
|
||||
|
@ -124,7 +125,7 @@ private:
|
|||
// stream error.
|
||||
int64_t mLastGoodPosition;
|
||||
|
||||
AudioInfo mInfo;
|
||||
const AudioInfo mInfo;
|
||||
|
||||
dom::AudioChannel mChannel;
|
||||
|
||||
|
@ -139,23 +140,6 @@ private:
|
|||
bool mSetPreservesPitch;
|
||||
|
||||
bool mPlaying;
|
||||
|
||||
class OnAudioEndTimeUpdateTask : public nsRunnable {
|
||||
public:
|
||||
explicit OnAudioEndTimeUpdateTask(MediaDecoderStateMachine* aStateMachine);
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
void Dispatch(int64_t aEndTime);
|
||||
void Cancel();
|
||||
|
||||
private:
|
||||
Mutex mMutex;
|
||||
int64_t mEndTime;
|
||||
nsRefPtr<MediaDecoderStateMachine> mStateMachine;
|
||||
};
|
||||
|
||||
nsRefPtr<OnAudioEndTimeUpdateTask> mOnAudioEndTimeUpdateTask;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -157,6 +157,11 @@ public:
|
|||
(aOther.mStart - aOther.mFuzz < mEnd + mFuzz);
|
||||
}
|
||||
|
||||
bool IntersectsStrict(const SelfType& aOther) const
|
||||
{
|
||||
return mStart < aOther.mEnd && aOther.mStart < mEnd;
|
||||
}
|
||||
|
||||
// Same as Intersects, but including the boundaries.
|
||||
bool Touches(const SelfType& aOther) const
|
||||
{
|
||||
|
@ -308,14 +313,18 @@ public:
|
|||
SelfType& operator= (const ElemType& aInterval)
|
||||
{
|
||||
mIntervals.Clear();
|
||||
mIntervals.AppendElement(aInterval);
|
||||
if (!aInterval.IsEmpty()) {
|
||||
mIntervals.AppendElement(aInterval);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelfType& operator= (ElemType&& aInterval)
|
||||
{
|
||||
mIntervals.Clear();
|
||||
mIntervals.AppendElement(Move(aInterval));
|
||||
if (!aInterval.IsEmpty()) {
|
||||
mIntervals.AppendElement(Move(aInterval));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -463,7 +472,7 @@ public:
|
|||
const ContainerType& other = aOther.mIntervals;
|
||||
IndexType i = 0, j = 0;
|
||||
for (; i < mIntervals.Length() && j < other.Length();) {
|
||||
if (mIntervals[i].Intersects(other[j])) {
|
||||
if (mIntervals[i].IntersectsStrict(other[j])) {
|
||||
intersection.AppendElement(mIntervals[i].Intersection(other[j]));
|
||||
}
|
||||
if (mIntervals[i].mEnd < other[j].mEnd) {
|
||||
|
|
|
@ -358,8 +358,8 @@ int64_t MediaDecoderStateMachine::GetDecodedAudioDuration()
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
int64_t audioDecoded = AudioQueue().Duration();
|
||||
if (mAudioEndTime != -1) {
|
||||
audioDecoded += mAudioEndTime - GetMediaTime();
|
||||
if (AudioEndTime() != -1) {
|
||||
audioDecoded += AudioEndTime() - GetMediaTime();
|
||||
}
|
||||
return audioDecoded;
|
||||
}
|
||||
|
@ -1776,7 +1776,7 @@ int64_t MediaDecoderStateMachine::AudioDecodedUsecs()
|
|||
// The amount of audio we have decoded is the amount of audio data we've
|
||||
// already decoded and pushed to the hardware, plus the amount of audio
|
||||
// data waiting to be pushed to the hardware.
|
||||
int64_t pushed = (mAudioEndTime != -1) ? (mAudioEndTime - GetMediaTime()) : 0;
|
||||
int64_t pushed = (AudioEndTime() != -1) ? (AudioEndTime() - GetMediaTime()) : 0;
|
||||
|
||||
// Currently for real time streams, AudioQueue().Duration() produce
|
||||
// wrong values (Bug 1114434), so we use frame counts to calculate duration.
|
||||
|
@ -2422,13 +2422,10 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
|
||||
if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
!mSentPlaybackEndedEvent)
|
||||
{
|
||||
int64_t clockTime = std::max(mAudioEndTime, mVideoFrameEndTime);
|
||||
int64_t clockTime = std::max(AudioEndTime(), mVideoFrameEndTime);
|
||||
clockTime = std::max(int64_t(0), std::max(clockTime, Duration().ToMicroseconds()));
|
||||
UpdatePlaybackPosition(clockTime);
|
||||
|
||||
|
@ -2438,6 +2435,12 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
|||
|
||||
mSentPlaybackEndedEvent = true;
|
||||
}
|
||||
|
||||
// Stop audio sink after call to AudioEndTime() above, otherwise it will
|
||||
// return an incorrect value due to a null mAudioSink.
|
||||
StopAudioThread();
|
||||
mDecodedStream->StopPlayback();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -2733,9 +2736,9 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
|
|||
// Cap the current time to the larger of the audio and video end time.
|
||||
// This ensures that if we're running off the system clock, we don't
|
||||
// advance the clock to after the media end time.
|
||||
if (mVideoFrameEndTime != -1 || mAudioEndTime != -1) {
|
||||
if (mVideoFrameEndTime != -1 || AudioEndTime() != -1) {
|
||||
// These will be non -1 if we've displayed a video frame, or played an audio frame.
|
||||
int64_t t = std::min(clockTime, std::max(mVideoFrameEndTime, mAudioEndTime));
|
||||
int64_t t = std::min(clockTime, std::max(mVideoFrameEndTime, AudioEndTime()));
|
||||
// FIXME: Bug 1091422 - chained ogg files hit this assertion.
|
||||
//MOZ_ASSERT(t >= GetMediaTime());
|
||||
if (t > GetMediaTime()) {
|
||||
|
@ -3070,11 +3073,25 @@ void MediaDecoderStateMachine::QueueMetadata(int64_t aPublishTime,
|
|||
mMetadataManager.QueueMetadata(metadata);
|
||||
}
|
||||
|
||||
int64_t
|
||||
MediaDecoderStateMachine::AudioEndTime() const
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (mAudioSink) {
|
||||
return mAudioSink->GetEndTime();
|
||||
}
|
||||
// Don't call this after mAudioSink becomes null since we can't distinguish
|
||||
// "before StartAudioThread" and "after StopAudioThread".
|
||||
MOZ_ASSERT(mAudioCaptured || !mAudioCompleted);
|
||||
return mAudioEndTime;
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::OnAudioEndTimeUpdate(int64_t aAudioEndTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
MOZ_ASSERT(aAudioEndTime >= mAudioEndTime);
|
||||
MOZ_ASSERT(aAudioEndTime >= AudioEndTime());
|
||||
mAudioEndTime = aAudioEndTime;
|
||||
}
|
||||
|
||||
|
|
|
@ -1070,6 +1070,7 @@ protected:
|
|||
// hardware in microseconds. This will approximately be the end time of the
|
||||
// audio stream, unless another frame is pushed to the hardware.
|
||||
int64_t mAudioEndTime;
|
||||
int64_t AudioEndTime() const;
|
||||
|
||||
// The end time of the last decoded audio frame. This signifies the end of
|
||||
// decoded audio data. Used to check if we are low in decoded data.
|
||||
|
|
|
@ -81,16 +81,6 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
|
|||
MediaFormatReader::~MediaFormatReader()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MediaFormatReader);
|
||||
// shutdown main thread demuxer and track demuxers.
|
||||
if (mAudioTrackDemuxer) {
|
||||
mAudioTrackDemuxer->BreakCycles();
|
||||
mAudioTrackDemuxer = nullptr;
|
||||
}
|
||||
if (mVideoTrackDemuxer) {
|
||||
mVideoTrackDemuxer->BreakCycles();
|
||||
mVideoTrackDemuxer = nullptr;
|
||||
}
|
||||
mMainThreadDemuxer = nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<ShutdownPromise>
|
||||
|
@ -99,6 +89,7 @@ MediaFormatReader::Shutdown()
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
mDemuxerInitRequest.DisconnectIfExists();
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
||||
mSkipRequest.DisconnectIfExists();
|
||||
|
||||
|
@ -144,6 +135,17 @@ MediaFormatReader::Shutdown()
|
|||
|
||||
mDemuxer = nullptr;
|
||||
|
||||
// shutdown main thread demuxer and track demuxers.
|
||||
if (mAudioTrackDemuxer) {
|
||||
mAudioTrackDemuxer->BreakCycles();
|
||||
mAudioTrackDemuxer = nullptr;
|
||||
}
|
||||
if (mVideoTrackDemuxer) {
|
||||
mVideoTrackDemuxer->BreakCycles();
|
||||
mVideoTrackDemuxer = nullptr;
|
||||
}
|
||||
mMainThreadDemuxer = nullptr;
|
||||
|
||||
mPlatform = nullptr;
|
||||
|
||||
return MediaDecoderReader::Shutdown();
|
||||
|
@ -356,6 +358,11 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
|||
NS_WARNING("Unable to clone current MediaDataDemuxer");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!videoActive && !audioActive) {
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
if (videoActive) {
|
||||
mVideoTrackDemuxer =
|
||||
mMainThreadDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
|
||||
|
@ -525,7 +532,8 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists() ||
|
||||
mVideo.mTimeThreshold.isSome());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mSkipRequest.Exists(), "called mid-skipping");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
|
||||
LOGV("RequestVideoData(%d, %lld)", aSkipToNextKeyframe, aTimeThreshold);
|
||||
|
@ -622,7 +630,8 @@ MediaFormatReader::RequestAudioData()
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(), "No sample requests allowed while seeking");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudio.mSeekRequest.Exists());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudio.mSeekRequest.Exists() ||
|
||||
mAudio.mTimeThreshold.isSome());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
|
||||
LOGV("");
|
||||
|
@ -719,6 +728,7 @@ MediaFormatReader::NotifyError(TrackType aTrack)
|
|||
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mError = true;
|
||||
decoder.mNeedDraining = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
|
@ -728,6 +738,7 @@ MediaFormatReader::NotifyWaitingForData(TrackType aTrack)
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mWaitingForData = true;
|
||||
decoder.mNeedDraining = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
|
@ -737,6 +748,7 @@ MediaFormatReader::NotifyEndOfStream(TrackType aTrack)
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
decoder.mDemuxEOS = true;
|
||||
decoder.mNeedDraining = true;
|
||||
ScheduleUpdate(aTrack);
|
||||
}
|
||||
|
||||
|
@ -750,6 +762,7 @@ MediaFormatReader::NeedInput(DecoderData& aDecoder)
|
|||
// run of input than we input, decoders fire an "input exhausted" callback,
|
||||
// which overrides our "few more samples" threshold.
|
||||
return
|
||||
!aDecoder.mDraining &&
|
||||
!aDecoder.mError &&
|
||||
(aDecoder.HasPromise() || aDecoder.mForceDecodeAhead) &&
|
||||
!aDecoder.mDemuxRequest.Exists() &&
|
||||
|
@ -797,7 +810,6 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack)
|
|||
(!hasLastEnd || decoder.mTimeRanges.GetEnd() > lastEnd)) {
|
||||
// New data was added after our previous end, we can clear the EOS flag.
|
||||
decoder.mDemuxEOS = false;
|
||||
decoder.mDemuxEOSServiced = false;
|
||||
}
|
||||
|
||||
if (decoder.mError) {
|
||||
|
@ -872,6 +884,17 @@ MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
|
|||
return;
|
||||
}
|
||||
|
||||
if (decoder.mNextStreamSourceID.isNothing() ||
|
||||
decoder.mNextStreamSourceID.ref() != info->GetID()) {
|
||||
LOG("%s stream id has changed from:%d to:%d, draining decoder.",
|
||||
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
|
||||
info->GetID());
|
||||
decoder.mNeedDraining = true;
|
||||
decoder.mNextStreamSourceID = Some(info->GetID());
|
||||
DrainDecoder(aTrack);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("%s stream id has changed from:%d to:%d, recreating decoder.",
|
||||
TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
|
||||
info->GetID());
|
||||
|
@ -944,6 +967,25 @@ MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
|
|||
decoder.mInputExhausted = false;
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::DrainDecoder(TrackType aTrack)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
auto& decoder = GetDecoderData(aTrack);
|
||||
if (!decoder.mNeedDraining || decoder.mDraining) {
|
||||
return;
|
||||
}
|
||||
decoder.mNeedDraining = false;
|
||||
if (!decoder.mDecoder) {
|
||||
return;
|
||||
}
|
||||
decoder.mOutputRequested = true;
|
||||
decoder.mDecoder->Drain();
|
||||
decoder.mDraining = true;
|
||||
LOG("Requesting %s decoder to drain", TrackTypeToStr(aTrack));
|
||||
}
|
||||
|
||||
void
|
||||
MediaFormatReader::Update(TrackType aTrack)
|
||||
{
|
||||
|
@ -965,23 +1007,6 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
return;
|
||||
}
|
||||
|
||||
if (decoder.HasPromise()) {
|
||||
// Handle pending requests from the MediaDecoderStateMachine.
|
||||
if (decoder.mError) {
|
||||
LOG("Decoding Error");
|
||||
decoder.RejectPromise(DECODE_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
if (decoder.mWaitingForData) {
|
||||
LOG("Waiting For Data");
|
||||
decoder.RejectPromise(WAITING_FOR_DATA, __func__);
|
||||
}
|
||||
} else if (decoder.mWaitingForData) {
|
||||
// Nothing more we can do at present.
|
||||
LOGV("Still waiting for data.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Record number of frames decoded and parsed. Automatically update the
|
||||
// stats counters using the AutoNotifyDecoded stack-based class.
|
||||
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
|
||||
|
@ -992,6 +1017,7 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
a.mDecoded = static_cast<uint32_t>(delta);
|
||||
mLastReportedNumDecodedFrames = decoder.mNumSamplesOutput;
|
||||
}
|
||||
|
||||
if (decoder.HasPromise()) {
|
||||
needOutput = true;
|
||||
if (!decoder.mOutput.IsEmpty()) {
|
||||
|
@ -1010,16 +1036,26 @@ MediaFormatReader::Update(TrackType aTrack)
|
|||
output->mKeyframe);
|
||||
}
|
||||
} else if (decoder.mDrainComplete) {
|
||||
decoder.RejectPromise(END_OF_STREAM, __func__);
|
||||
decoder.mDrainComplete = false;
|
||||
decoder.mDraining = false;
|
||||
if (decoder.mError) {
|
||||
LOG("Decoding Error");
|
||||
decoder.RejectPromise(DECODE_ERROR, __func__);
|
||||
return;
|
||||
} else if (decoder.mDemuxEOS) {
|
||||
decoder.RejectPromise(END_OF_STREAM, __func__);
|
||||
} else if (decoder.mWaitingForData) {
|
||||
LOG("Waiting For Data");
|
||||
decoder.RejectPromise(WAITING_FOR_DATA, __func__);
|
||||
}
|
||||
} else if (decoder.mError && !decoder.mDecoder) {
|
||||
decoder.RejectPromise(DECODE_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (decoder.mDemuxEOS && !decoder.mDemuxEOSServiced) {
|
||||
decoder.mOutputRequested = true;
|
||||
decoder.mDecoder->Drain();
|
||||
decoder.mDemuxEOSServiced = true;
|
||||
LOGV("Requesting decoder to drain");
|
||||
if (decoder.mError || decoder.mDemuxEOS || decoder.mWaitingForData) {
|
||||
DrainDecoder(aTrack);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1500,10 +1536,12 @@ MediaFormatReader::NotifyDataArrivedInternal(uint32_t aLength, int64_t aOffset)
|
|||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aLength);
|
||||
|
||||
if (!mInitDone) {
|
||||
if (!mInitDone || mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mMainThreadDemuxer);
|
||||
|
||||
// Queue a task to notify our main thread demuxer.
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethodWithArgs<uint32_t, int64_t>(
|
||||
|
@ -1519,7 +1557,7 @@ MediaFormatReader::NotifyDataRemoved()
|
|||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (!mInitDone) {
|
||||
if (!mInitDone || mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,8 @@ private:
|
|||
// Decode any pending already demuxed samples.
|
||||
void DecodeDemuxedSamples(TrackType aTrack,
|
||||
AbstractMediaDecoder::AutoNotifyDecoded& aA);
|
||||
// Drain the current decoder.
|
||||
void DrainDecoder(TrackType aTrack);
|
||||
void NotifyNewOutput(TrackType aTrack, MediaData* aSample);
|
||||
void NotifyInputExhausted(TrackType aTrack);
|
||||
void NotifyDrainComplete(TrackType aTrack);
|
||||
|
@ -188,13 +190,14 @@ private:
|
|||
, mForceDecodeAhead(false)
|
||||
, mUpdateScheduled(false)
|
||||
, mDemuxEOS(false)
|
||||
, mDemuxEOSServiced(false)
|
||||
, mWaitingForData(false)
|
||||
, mReceivedNewData(false)
|
||||
, mDiscontinuity(true)
|
||||
, mOutputRequested(false)
|
||||
, mInputExhausted(false)
|
||||
, mError(false)
|
||||
, mNeedDraining(false)
|
||||
, mDraining(false)
|
||||
, mDrainComplete(false)
|
||||
, mNumSamplesInput(0)
|
||||
, mNumSamplesOutput(0)
|
||||
|
@ -219,7 +222,6 @@ private:
|
|||
bool mForceDecodeAhead;
|
||||
bool mUpdateScheduled;
|
||||
bool mDemuxEOS;
|
||||
bool mDemuxEOSServiced;
|
||||
bool mWaitingForData;
|
||||
bool mReceivedNewData;
|
||||
bool mDiscontinuity;
|
||||
|
@ -241,6 +243,8 @@ private:
|
|||
bool mOutputRequested;
|
||||
bool mInputExhausted;
|
||||
bool mError;
|
||||
bool mNeedDraining;
|
||||
bool mDraining;
|
||||
bool mDrainComplete;
|
||||
// If set, all decoded samples prior mTimeThreshold will be dropped.
|
||||
// Used for internal seeking when a change of stream is detected.
|
||||
|
@ -270,25 +274,28 @@ private:
|
|||
MOZ_ASSERT(mOwner->OnTaskQueue());
|
||||
mForceDecodeAhead = false;
|
||||
mDemuxEOS = false;
|
||||
mDemuxEOSServiced = false;
|
||||
mWaitingForData = false;
|
||||
mReceivedNewData = false;
|
||||
mDiscontinuity = true;
|
||||
mQueuedSamples.Clear();
|
||||
mOutputRequested = false;
|
||||
mInputExhausted = false;
|
||||
mNeedDraining = false;
|
||||
mDraining = false;
|
||||
mDrainComplete = false;
|
||||
mTimeThreshold.reset();
|
||||
mOutput.Clear();
|
||||
mNumSamplesInput = 0;
|
||||
mNumSamplesOutput = 0;
|
||||
mSizeOfQueue = 0;
|
||||
mNextStreamSourceID.reset();
|
||||
}
|
||||
|
||||
// Used by the MDSM for logging purposes.
|
||||
Atomic<size_t> mSizeOfQueue;
|
||||
// Sample format monitoring.
|
||||
uint32_t mLastStreamSourceID;
|
||||
Maybe<uint32_t> mNextStreamSourceID;
|
||||
media::TimeIntervals mTimeRanges;
|
||||
nsRefPtr<SharedTrackInfo> mInfo;
|
||||
};
|
||||
|
|
|
@ -15,8 +15,49 @@
|
|||
#include "mp4_demuxer/ResourceStream.h"
|
||||
#include "mp4_demuxer/BufferStream.h"
|
||||
|
||||
// Used for telemetry
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Returns true if no SPS was found and search for it should continue.
|
||||
bool
|
||||
AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
|
||||
uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0) |
|
||||
(spsdata.constraint_set1_flag ? (1 << 1) : 0) |
|
||||
(spsdata.constraint_set2_flag ? (1 << 2) : 0) |
|
||||
(spsdata.constraint_set3_flag ? (1 << 3) : 0) |
|
||||
(spsdata.constraint_set4_flag ? (1 << 4) : 0) |
|
||||
(spsdata.constraint_set5_flag ? (1 << 5) : 0);
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG,
|
||||
constraints);
|
||||
|
||||
// Collect profile_idc values up to 244, otherwise 0 for unknown.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_PROFILE,
|
||||
spsdata.profile_idc <= 244 ? spsdata.profile_idc : 0);
|
||||
|
||||
// Make sure level_idc represents a value between levels 1 and 5.2,
|
||||
// otherwise collect 0 for unknown level.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_LEVEL,
|
||||
(spsdata.level_idc >= 10 && spsdata.level_idc <= 52) ?
|
||||
spsdata.level_idc : 0);
|
||||
|
||||
// max_num_ref_frames should be between 0 and 16, anything larger will
|
||||
// be treated as invalid.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_H264_SPS_MAX_NUM_REF_FRAMES,
|
||||
std::min(spsdata.max_num_ref_frames, 17u));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MP4Demuxer::MP4Demuxer(MediaResource* aResource)
|
||||
: mResource(aResource)
|
||||
, mStream(new mp4_demuxer::ResourceStream(aResource))
|
||||
|
@ -169,6 +210,17 @@ MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent,
|
|||
&mMonitor);
|
||||
mIterator = MakeUnique<mp4_demuxer::SampleIterator>(mIndex);
|
||||
EnsureUpToDateIndex(); // Force update of index
|
||||
|
||||
// Collect telemetry from h264 AVCC SPS.
|
||||
if (mInfo->GetAsVideoInfo() &&
|
||||
(mInfo->mMimeType.EqualsLiteral("video/mp4") ||
|
||||
mInfo->mMimeType.EqualsLiteral("video/avc"))) {
|
||||
mNeedSPSForTelemetry =
|
||||
AccumulateSPSTelemetry(mInfo->GetAsVideoInfo()->mExtraData);
|
||||
} else {
|
||||
// No SPS to be found.
|
||||
mNeedSPSForTelemetry = false;
|
||||
}
|
||||
}
|
||||
|
||||
UniquePtr<TrackInfo>
|
||||
|
@ -268,6 +320,12 @@ MP4TrackDemuxer::UpdateSamples(nsTArray<nsRefPtr<MediaRawData>>& aSamples)
|
|||
{
|
||||
for (size_t i = 0; i < aSamples.Length(); i++) {
|
||||
MediaRawData* sample = aSamples[i];
|
||||
// Collect telemetry from h264 Annex B SPS.
|
||||
if (mNeedSPSForTelemetry && mp4_demuxer::AnnexB::HasSPS(sample)) {
|
||||
nsRefPtr<MediaByteBuffer> extradata =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(sample);
|
||||
mNeedSPSForTelemetry = AccumulateSPSTelemetry(extradata);
|
||||
}
|
||||
if (sample->mCrypto.mValid) {
|
||||
nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
|
||||
writer->mCrypto.mMode = mInfo->mCrypto.mMode;
|
||||
|
|
|
@ -96,6 +96,7 @@ private:
|
|||
// Queued samples extracted by the demuxer, but not yet returned.
|
||||
nsRefPtr<MediaRawData> mQueuedSample;
|
||||
bool mNeedReIndex;
|
||||
bool mNeedSPSForTelemetry;
|
||||
|
||||
// We do not actually need a monitor, however MoofParser will assert
|
||||
// if a monitor isn't held.
|
||||
|
|
|
@ -66,40 +66,7 @@ TrackTypeToStr(TrackInfo::TrackType aTrack)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata)
|
||||
{
|
||||
SPSData spsdata;
|
||||
if (H264::DecodeSPSFromExtraData(aExtradata, spsdata)) {
|
||||
uint8_t constraints = (spsdata.constraint_set0_flag ? (1 << 0) : 0) |
|
||||
(spsdata.constraint_set1_flag ? (1 << 1) : 0) |
|
||||
(spsdata.constraint_set2_flag ? (1 << 2) : 0) |
|
||||
(spsdata.constraint_set3_flag ? (1 << 3) : 0) |
|
||||
(spsdata.constraint_set4_flag ? (1 << 4) : 0) |
|
||||
(spsdata.constraint_set5_flag ? (1 << 5) : 0);
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_CONSTRAINT_SET_FLAG,
|
||||
constraints);
|
||||
|
||||
// Collect profile_idc values up to 244, otherwise 0 for unknown.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_PROFILE,
|
||||
spsdata.profile_idc <= 244 ? spsdata.profile_idc : 0);
|
||||
|
||||
// Make sure level_idc represents a value between levels 1 and 5.2,
|
||||
// otherwise collect 0 for unknown level.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_DECODED_H264_SPS_LEVEL,
|
||||
(spsdata.level_idc >= 10 && spsdata.level_idc <= 52) ?
|
||||
spsdata.level_idc : 0);
|
||||
|
||||
// max_num_ref_frames should be between 0 and 16, anything larger will
|
||||
// be treated as invalid.
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_H264_SPS_MAX_NUM_REF_FRAMES,
|
||||
std::min(spsdata.max_num_ref_frames, 17u));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
extern bool AccumulateSPSTelemetry(const MediaByteBuffer* aExtradata);
|
||||
|
||||
// MP4Demuxer wants to do various blocking reads, which cause deadlocks while
|
||||
// mDemuxerMonitor is held. This stuff should really be redesigned, but we don't
|
||||
|
|
|
@ -40,9 +40,9 @@ GMPSharedMemManager::MgrAllocShmem(GMPSharedMem::GMPMemoryClasses aClass, size_t
|
|||
size_t pagesize = ipc::SharedMemory::SystemPageSize();
|
||||
aSize = (aSize + (pagesize-1)) & ~(pagesize-1); // round up to page size
|
||||
bool retval = Alloc(aSize, aType, aMem);
|
||||
// The allocator (or NeedsShmem call) should never return less than we ask for...
|
||||
MOZ_ASSERT(aMem->Size<uint8_t>() >= aSize);
|
||||
if (retval) {
|
||||
// The allocator (or NeedsShmem call) should never return less than we ask for...
|
||||
MOZ_ASSERT(aMem->Size<uint8_t>() >= aSize);
|
||||
mData->mGmpAllocated[aClass]++;
|
||||
}
|
||||
return retval;
|
||||
|
|
|
@ -146,6 +146,7 @@ MediaSourceDecoder::Shutdown()
|
|||
if (mMediaSource) {
|
||||
mMediaSource->Detach();
|
||||
}
|
||||
mDemuxer = nullptr;
|
||||
|
||||
MediaDecoder::Shutdown();
|
||||
// Kick WaitForData out of its slumber.
|
||||
|
@ -292,6 +293,7 @@ void
|
|||
MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
if (mIsUsingFormatReader) {
|
||||
mDemuxer->GetMozDebugReaderData(aString);
|
||||
return;
|
||||
}
|
||||
GetReader()->GetMozDebugReaderData(aString);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "MediaSourceDemuxer.h"
|
||||
#include "SourceBufferList.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -224,6 +225,41 @@ MediaSourceDemuxer::~MediaSourceDemuxer()
|
|||
mTaskQueue = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDemuxer::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
nsAutoCString result;
|
||||
result += nsPrintfCString("Dumping data for demuxer %p:\n", this);
|
||||
if (mAudioTrack) {
|
||||
result += nsPrintfCString("\tDumping Audio Track Buffer(%s): - mLastAudioTime: %f\n"
|
||||
"\t\tNumSamples:%u Size:%u NextGetSampleIndex:%u NextInsertionIndex:%d\n",
|
||||
mAudioTrack->mAudioTracks.mInfo->mMimeType.get(),
|
||||
mAudioTrack->mAudioTracks.mNextSampleTime.ToSeconds(),
|
||||
mAudioTrack->mAudioTracks.mBuffers[0].Length(),
|
||||
mAudioTrack->mAudioTracks.mSizeBuffer,
|
||||
mAudioTrack->mAudioTracks.mNextGetSampleIndex.valueOr(-1),
|
||||
mAudioTrack->mAudioTracks.mNextInsertionIndex.valueOr(-1));
|
||||
|
||||
result += nsPrintfCString("\t\tBuffered: ranges=%s\n",
|
||||
DumpTimeRanges(mAudioTrack->SafeBuffered(TrackInfo::kAudioTrack)).get());
|
||||
}
|
||||
if (mVideoTrack) {
|
||||
result += nsPrintfCString("\tDumping Video Track Buffer(%s) - mLastVideoTime: %f\n"
|
||||
"\t\tNumSamples:%u Size:%u NextGetSampleIndex:%u NextInsertionIndex:%d\n",
|
||||
mVideoTrack->mVideoTracks.mInfo->mMimeType.get(),
|
||||
mVideoTrack->mVideoTracks.mNextSampleTime.ToSeconds(),
|
||||
mVideoTrack->mVideoTracks.mBuffers[0].Length(),
|
||||
mVideoTrack->mVideoTracks.mSizeBuffer,
|
||||
mVideoTrack->mVideoTracks.mNextGetSampleIndex.valueOr(-1),
|
||||
mVideoTrack->mVideoTracks.mNextInsertionIndex.valueOr(-1));
|
||||
|
||||
result += nsPrintfCString("\t\tBuffered: ranges=%s\n",
|
||||
DumpTimeRanges(mVideoTrack->SafeBuffered(TrackInfo::kVideoTrack)).get());
|
||||
}
|
||||
aString += NS_ConvertUTF8toUTF16(result);
|
||||
}
|
||||
|
||||
MediaSourceTrackDemuxer::MediaSourceTrackDemuxer(MediaSourceDemuxer* aParent,
|
||||
TrackInfo::TrackType aType,
|
||||
TrackBuffersManager* aManager)
|
||||
|
@ -314,7 +350,10 @@ MediaSourceTrackDemuxer::BreakCycles()
|
|||
{
|
||||
nsRefPtr<MediaSourceTrackDemuxer> self = this;
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction([self]() { self->mParent = nullptr; } );
|
||||
NS_NewRunnableFunction([self]() {
|
||||
self->mParent = nullptr;
|
||||
self->mManager = nullptr;
|
||||
} );
|
||||
mParent->GetTaskQueue()->Dispatch(task.forget());
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,10 @@ public:
|
|||
MediaTaskQueue* GetTaskQueue() { return mTaskQueue; }
|
||||
void NotifyTimeRangesChanged();
|
||||
|
||||
// Returns a string describing the state of the MediaSource internal
|
||||
// buffered data. Used for debugging purposes.
|
||||
void GetMozDebugReaderData(nsAString& aString);
|
||||
|
||||
private:
|
||||
~MediaSourceDemuxer();
|
||||
friend class MediaSourceTrackDemuxer;
|
||||
|
|
|
@ -1713,6 +1713,15 @@ TrackBuffersManager::Buffered(TrackInfo::TrackType aTrack)
|
|||
return GetTracksData(aTrack).mBufferedRanges;
|
||||
}
|
||||
|
||||
TimeIntervals
|
||||
TrackBuffersManager::SafeBuffered(TrackInfo::TrackType aTrack) const
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return aTrack == TrackInfo::kVideoTrack
|
||||
? mVideoBufferedRanges
|
||||
: mAudioBufferedRanges;
|
||||
}
|
||||
|
||||
const TrackBuffersManager::TrackBuffer&
|
||||
TrackBuffersManager::GetTrackBuffer(TrackInfo::TrackType aTrack)
|
||||
{
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
MediaInfo GetMetadata();
|
||||
const TrackBuffer& GetTrackBuffer(TrackInfo::TrackType aTrack);
|
||||
const TimeIntervals& Buffered(TrackInfo::TrackType);
|
||||
TimeIntervals SafeBuffered(TrackInfo::TrackType) const;
|
||||
bool IsEnded() const
|
||||
{
|
||||
return mEnded;
|
||||
|
@ -95,6 +96,8 @@ public:
|
|||
#endif
|
||||
|
||||
private:
|
||||
// for MediaSourceDemuxer::GetMozDebugReaderData
|
||||
friend class MediaSourceDemuxer;
|
||||
virtual ~TrackBuffersManager();
|
||||
// All following functions run on the taskqueue.
|
||||
nsRefPtr<AppendPromise> InitSegmentParserLoop();
|
||||
|
|
|
@ -15,6 +15,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=495145
|
|||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=495145">Mozilla Bug 495145</a>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
//longer timeout for slow platforms
|
||||
if (isSlowPlatform()) {
|
||||
SimpleTest.requestLongerTimeout(1.5);
|
||||
}
|
||||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
//longer timeout for slow platforms
|
||||
if (isSlowPlatform()) {
|
||||
SimpleTest.requestLongerTimeout(1.5);
|
||||
}
|
||||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
//longer timeout for slow platforms
|
||||
if (isSlowPlatform()) {
|
||||
SimpleTest.requestLongerTimeout(1.5);
|
||||
}
|
||||
|
||||
var manager = new MediaTestManager;
|
||||
|
||||
function startTest(test, token) {
|
||||
|
|
|
@ -94,8 +94,8 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video suppo
|
|||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_captureStream_canvas_webgl.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
|
||||
[test_peerConnection_certificates.html]
|
||||
skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
# [test_peerConnection_certificates.html] # bug 1180968
|
||||
# skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867)
|
||||
[test_peerConnection_close.html]
|
||||
[test_peerConnection_closeDuringIce.html]
|
||||
[test_peerConnection_errorCallbacks.html]
|
||||
|
|
|
@ -14,33 +14,41 @@
|
|||
* E: element type, must be a POD type.
|
||||
* N: N bytes alignment for the first element, defaults to 32
|
||||
*/
|
||||
template <typename E, int N, typename Alloc>
|
||||
class AlignedTArray_Impl : public nsTArray_Impl<E, Alloc>
|
||||
template <typename E, int N = 32>
|
||||
class AlignedTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
|
||||
{
|
||||
static_assert((N & (N-1)) == 0, "N must be power of 2");
|
||||
typedef nsTArray_Impl<E, Alloc> base_type;
|
||||
typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
|
||||
public:
|
||||
typedef E elem_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
typedef typename base_type::index_type index_type;
|
||||
|
||||
AlignedTArray_Impl() {}
|
||||
explicit AlignedTArray_Impl(size_type capacity) : base_type(capacity+sExtra) {}
|
||||
AlignedTArray() {}
|
||||
explicit AlignedTArray(size_type capacity) : base_type(capacity + sExtra) {}
|
||||
elem_type* Elements() { return getAligned(base_type::Elements()); }
|
||||
const elem_type* Elements() const { return getAligned(base_type::Elements()); }
|
||||
elem_type& operator[](index_type i) { return Elements()[i];}
|
||||
const elem_type& operator[](index_type i) const { return Elements()[i]; }
|
||||
|
||||
typename Alloc::ResultType SetLength(size_type newLen) {
|
||||
return base_type::SetLength(newLen + sExtra);
|
||||
void SetLength(size_type newLen)
|
||||
{
|
||||
base_type::SetLength(newLen + sExtra);
|
||||
}
|
||||
|
||||
MOZ_WARN_UNUSED_RESULT
|
||||
bool SetLength(size_type newLen, const mozilla::fallible_t&)
|
||||
{
|
||||
return base_type::SetLength(newLen + sExtra, mozilla::fallible);
|
||||
}
|
||||
|
||||
size_type Length() const {
|
||||
return base_type::Length() <= sExtra ? 0 : base_type::Length() - sExtra;
|
||||
}
|
||||
|
||||
private:
|
||||
AlignedTArray_Impl(const AlignedTArray_Impl& other) = delete;
|
||||
void operator=(const AlignedTArray_Impl& other) = delete;
|
||||
AlignedTArray(const AlignedTArray& other) = delete;
|
||||
void operator=(const AlignedTArray& other) = delete;
|
||||
|
||||
static const size_type sPadding = N <= MOZ_ALIGNOF(E) ? 0 : N - MOZ_ALIGNOF(E);
|
||||
static const size_type sExtra = (sPadding + sizeof(E) - 1) / sizeof(E);
|
||||
|
@ -52,34 +60,4 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename E, int N=32>
|
||||
class AlignedTArray : public AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator>
|
||||
{
|
||||
public:
|
||||
typedef AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator> base_type;
|
||||
typedef AlignedTArray<E, N> self_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
|
||||
AlignedTArray() {}
|
||||
explicit AlignedTArray(size_type capacity) : base_type(capacity) {}
|
||||
private:
|
||||
AlignedTArray(const AlignedTArray& other) = delete;
|
||||
void operator=(const AlignedTArray& other) = delete;
|
||||
};
|
||||
|
||||
template <typename E, int N=32>
|
||||
class AlignedFallibleTArray : public AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator>
|
||||
{
|
||||
public:
|
||||
typedef AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator> base_type;
|
||||
typedef AlignedFallibleTArray<E, N> self_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
|
||||
AlignedFallibleTArray() {}
|
||||
explicit AlignedFallibleTArray(size_type capacity) : base_type(capacity) {}
|
||||
private:
|
||||
AlignedFallibleTArray(const AlignedFallibleTArray& other) = delete;
|
||||
void operator=(const AlignedFallibleTArray& other) = delete;
|
||||
};
|
||||
|
||||
#endif // AlignedTArray_h__
|
||||
|
|
|
@ -251,11 +251,11 @@ bool
|
|||
AnalyserNode::FFTAnalysis()
|
||||
{
|
||||
float* inputBuffer;
|
||||
AlignedFallibleTArray<float> tmpBuffer;
|
||||
AlignedTArray<float> tmpBuffer;
|
||||
if (mWriteIndex == 0) {
|
||||
inputBuffer = mBuffer.Elements();
|
||||
} else {
|
||||
if (!tmpBuffer.SetLength(FftSize())) {
|
||||
if (!tmpBuffer.SetLength(FftSize(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
inputBuffer = tmpBuffer.Elements();
|
||||
|
@ -301,13 +301,13 @@ AnalyserNode::AllocateBuffer()
|
|||
{
|
||||
bool result = true;
|
||||
if (mBuffer.Length() != FftSize()) {
|
||||
if (!mBuffer.SetLength(FftSize())) {
|
||||
if (!mBuffer.SetLength(FftSize(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
memset(mBuffer.Elements(), 0, sizeof(float) * FftSize());
|
||||
mWriteIndex = 0;
|
||||
|
||||
if (!mOutputBuffer.SetLength(FrequencyBinCount())) {
|
||||
if (!mOutputBuffer.SetLength(FrequencyBinCount(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
memset(mOutputBuffer.Elements(), 0, sizeof(float) * FrequencyBinCount());
|
||||
|
|
|
@ -78,8 +78,8 @@ private:
|
|||
double mMaxDecibels;
|
||||
double mSmoothingTimeConstant;
|
||||
uint32_t mWriteIndex;
|
||||
AlignedFallibleTArray<float> mBuffer;
|
||||
AlignedFallibleTArray<float> mOutputBuffer;
|
||||
AlignedTArray<float> mBuffer;
|
||||
AlignedTArray<float> mOutputBuffer;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -135,7 +135,7 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId,
|
|||
// We are going to abort due to the failure, lets note the cause
|
||||
// in the report for diagnosing.
|
||||
nsAutoCString error;
|
||||
error.AppendPrintf("%X", *rv);
|
||||
error.AppendPrintf("%X %d", *rv, chromeParent->GetIPCChannel()->GetChannelState__TotallyRacy());
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BridgePluginError"), error);
|
||||
#endif
|
||||
return false;
|
||||
|
|
|
@ -179,6 +179,20 @@ SpeakerManagerService::Observe(nsISupports* aSubject,
|
|||
} else {
|
||||
NS_WARNING("ipc:content-shutdown message without childID property");
|
||||
}
|
||||
} else if (!strcmp(aTopic, "xpcom-will-shutdown")) {
|
||||
// Note that we need to do this before xpcom-shutdown, since the
|
||||
// AudioChannelService cannot be used past that point.
|
||||
nsRefPtr<AudioChannelService> audioChannelService =
|
||||
AudioChannelService::GetOrCreate();
|
||||
audioChannelService->UnregisterSpeakerManager(this);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "ipc:content-shutdown");
|
||||
obs->RemoveObserver(this, "xpcom-will-shutdown");
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -192,6 +206,7 @@ SpeakerManagerService::SpeakerManagerService()
|
|||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "ipc:content-shutdown", false);
|
||||
obs->AddObserver(this, "xpcom-will-shutdown", false);
|
||||
}
|
||||
}
|
||||
nsRefPtr<AudioChannelService> audioChannelService =
|
||||
|
@ -202,7 +217,4 @@ SpeakerManagerService::SpeakerManagerService()
|
|||
SpeakerManagerService::~SpeakerManagerService()
|
||||
{
|
||||
MOZ_COUNT_DTOR(SpeakerManagerService);
|
||||
nsRefPtr<AudioChannelService> audioChannelService =
|
||||
AudioChannelService::GetOrCreate();
|
||||
audioChannelService->UnregisterSpeakerManager(this);
|
||||
}
|
||||
|
|
|
@ -46,10 +46,6 @@ public:
|
|||
{
|
||||
mRegisteredSpeakerManagers.RemoveElement(aSpeakerManager);
|
||||
}
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
SpeakerManagerService();
|
||||
|
@ -60,6 +56,11 @@ protected:
|
|||
|
||||
void TurnOnSpeaker(bool aEnable);
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
nsTArray<nsRefPtr<SpeakerManager> > mRegisteredSpeakerManagers;
|
||||
// Set for remember all the child speaker status
|
||||
nsCheapSet<nsUint64HashKey> mSpeakerStatusSet;
|
||||
|
|
|
@ -1729,6 +1729,7 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
if (NS_FAILED(loadInfo.mLoadResult)) {
|
||||
scriptloader::ReportLoadError(aCx, loadInfo.mURL, loadInfo.mLoadResult,
|
||||
false);
|
||||
aWorkerPrivate->MaybeDispatchLoadFailedRunnable();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -164,8 +164,13 @@ ServiceWorkerContainer::GetController()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: What should we do here if the ServiceWorker script fails to load?
|
||||
// In theory the DOM ServiceWorker object can exist without the worker
|
||||
// thread running, but it seems our design does not expect that.
|
||||
nsCOMPtr<nsISupports> serviceWorker;
|
||||
rv = swm->GetDocumentController(GetOwner(), getter_AddRefs(serviceWorker));
|
||||
rv = swm->GetDocumentController(GetOwner(),
|
||||
nullptr, // aLoadFailedRunnable
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -1062,6 +1062,11 @@ public:
|
|||
MOZ_ASSERT(!data->mSetOfScopesBeingUpdated.Contains(mRegistration->mScope));
|
||||
data->mSetOfScopesBeingUpdated.Put(mRegistration->mScope, true);
|
||||
|
||||
// Call FailScopeUpdate on main thread if the SW script load fails below.
|
||||
nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs
|
||||
<StorensRefPtrPassByPtr<ServiceWorkerManager>, nsCString>
|
||||
(this, &ServiceWorkerRegisterJob::FailScopeUpdate, swm, scopeKey);
|
||||
|
||||
MOZ_ASSERT(!mUpdateAndInstallInfo);
|
||||
mUpdateAndInstallInfo =
|
||||
new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec,
|
||||
|
@ -1069,11 +1074,11 @@ public:
|
|||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = swm->CreateServiceWorker(mRegistration->mPrincipal,
|
||||
mUpdateAndInstallInfo,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
return Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return FailScopeUpdate(swm, scopeKey);
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerJob> upcasted = this;
|
||||
|
@ -1088,11 +1093,22 @@ public:
|
|||
jsapi.Init();
|
||||
bool ok = r->Dispatch(jsapi.cx());
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
return Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return FailScopeUpdate(swm, scopeKey);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FailScopeUpdate(ServiceWorkerManager* aSwm, const nsACString& aScopeKey)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aSwm);
|
||||
ServiceWorkerManager::RegistrationDataPerPrincipal* data;
|
||||
if (aSwm->mRegistrationInfos.Get(aScopeKey, &data)) {
|
||||
data->mSetOfScopesBeingUpdated.Remove(aScopeKey);
|
||||
}
|
||||
Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
// Public so our error handling code can use it.
|
||||
// Callers MUST hold a strong ref before calling this!
|
||||
void
|
||||
|
@ -1168,9 +1184,15 @@ public:
|
|||
|
||||
NS_DispatchToMainThread(upr);
|
||||
|
||||
// Call ContinueAfterInstallEvent(false, false) on main thread if the SW
|
||||
// script fails to load.
|
||||
nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs<bool, bool>
|
||||
(this, &ServiceWorkerRegisterJob::ContinueAfterInstallEvent, false, false);
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = swm->CreateServiceWorker(mRegistration->mPrincipal,
|
||||
mRegistration->mInstallingWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -1834,18 +1856,20 @@ ServiceWorkerRegistrationInfo::Activate()
|
|||
this);
|
||||
NS_DispatchToMainThread(controllerChangeRunnable);
|
||||
|
||||
nsCOMPtr<nsIRunnable> failRunnable =
|
||||
NS_NewRunnableMethodWithArg<bool>(this,
|
||||
&ServiceWorkerRegistrationInfo::FinishActivate,
|
||||
false /* success */);
|
||||
|
||||
MOZ_ASSERT(mActiveWorker);
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
nsresult rv =
|
||||
swm->CreateServiceWorker(mPrincipal,
|
||||
mActiveWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArg<bool>(this,
|
||||
&ServiceWorkerRegistrationInfo::FinishActivate,
|
||||
false /* success */);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(failRunnable)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2227,7 +2251,7 @@ ServiceWorkerManager::SendPushEvent(const nsACString& aOriginAttributes,
|
|||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope);
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr /* failure runnable */);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2262,7 +2286,7 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginA
|
|||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope);
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr /* fail runnable */);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2387,7 +2411,8 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix
|
|||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker = CreateServiceWorkerForScope(attrs, aScope);
|
||||
nsRefPtr<ServiceWorker> serviceWorker =
|
||||
CreateServiceWorkerForScope(attrs, aScope, nullptr);
|
||||
if (!serviceWorker) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -2525,7 +2550,8 @@ ServiceWorkerManager::CheckReadyPromise(nsPIDOMWindow* aWindow,
|
|||
|
||||
already_AddRefed<ServiceWorker>
|
||||
ServiceWorkerManager::CreateServiceWorkerForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope)
|
||||
const nsACString& aScope,
|
||||
nsIRunnable* aLoadFailedRunnable)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
|
@ -2547,6 +2573,7 @@ ServiceWorkerManager::CreateServiceWorkerForScope(const OriginAttributes& aOrigi
|
|||
nsRefPtr<ServiceWorker> sw;
|
||||
rv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker,
|
||||
aLoadFailedRunnable,
|
||||
getter_AddRefs(sw));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -2827,6 +2854,7 @@ ServiceWorkerRegistrationInfo::FinishActivate(bool aSuccess)
|
|||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
@ -2851,6 +2879,7 @@ ServiceWorkerManager::CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
|||
MOZ_ASSERT(!aInfo->CacheName().IsEmpty());
|
||||
loadInfo.mServiceWorkerCacheName = aInfo->CacheName();
|
||||
loadInfo.mServiceWorkerID = aInfo->ID();
|
||||
loadInfo.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
|
||||
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
if (!rs) {
|
||||
|
@ -3418,9 +3447,13 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
|
|||
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// TODO: How should we handle async failure of SW load for getters? In
|
||||
// theory getting a handle to the DOM ServiceWorker object should not
|
||||
// require the worker thread to actually be running.
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
info,
|
||||
nullptr, // load failed runnable
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
|
@ -3690,11 +3723,17 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
|
|||
return;
|
||||
}
|
||||
|
||||
// if the ServiceWorker script fails to load for some reason, just resume
|
||||
// the original channel.
|
||||
nsCOMPtr<nsIRunnable> failRunnable =
|
||||
NS_NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
|
||||
|
||||
nsAutoPtr<ServiceWorkerClientInfo> clientInfo;
|
||||
|
||||
if (!isNavigation) {
|
||||
MOZ_ASSERT(aDoc);
|
||||
aRv = GetDocumentController(aDoc->GetInnerWindow(), getter_AddRefs(serviceWorker));
|
||||
aRv = GetDocumentController(aDoc->GetInnerWindow(), failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
clientInfo = new ServiceWorkerClientInfo(aDoc, aDoc->GetWindow());
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> internalChannel;
|
||||
|
@ -3723,6 +3762,7 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
|
|||
nsRefPtr<ServiceWorker> sw;
|
||||
aRv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker,
|
||||
failRunnable,
|
||||
getter_AddRefs(sw));
|
||||
serviceWorker = sw.forget();
|
||||
}
|
||||
|
@ -3806,7 +3846,9 @@ ServiceWorkerManager::GetDocumentRegistration(nsIDocument* aDoc,
|
|||
* the document was loaded.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports** aServiceWorker)
|
||||
ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
nsISupports** aServiceWorker)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
MOZ_ASSERT(window);
|
||||
|
@ -3825,6 +3867,7 @@ ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports**
|
|||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
registration->mActiveWorker,
|
||||
aLoadFailedRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
|
@ -3867,6 +3910,7 @@ ServiceWorkerManager::GetActive(nsIDOMWindow* aWindow,
|
|||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
@ -3921,6 +3965,8 @@ ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
|
|||
// them here.
|
||||
WorkerPrivate::OverrideLoadInfoLoadGroup(info);
|
||||
|
||||
info.mLoadFailedAsyncRunnable = aLoadFailedRunnable;
|
||||
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
if (!rs) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -420,11 +420,13 @@ private:
|
|||
NS_IMETHOD
|
||||
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHOD
|
||||
CreateServiceWorker(nsIPrincipal* aPrincipal,
|
||||
ServiceWorkerInfo* aInfo,
|
||||
nsIRunnable* aLoadFailedRunnable,
|
||||
ServiceWorker** aServiceWorker);
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -435,7 +437,8 @@ private:
|
|||
|
||||
already_AddRefed<ServiceWorker>
|
||||
CreateServiceWorkerForScope(const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aScope);
|
||||
const nsACString& aScope,
|
||||
nsIRunnable* aLoadFailedRunnable);
|
||||
|
||||
void
|
||||
InvalidateServiceWorkerRegistrationWorker(ServiceWorkerRegistrationInfo* aRegistration,
|
||||
|
|
|
@ -2384,6 +2384,9 @@ WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
|
|||
MOZ_ASSERT(!mLoadGroup);
|
||||
aOther.mLoadGroup.swap(mLoadGroup);
|
||||
|
||||
MOZ_ASSERT(!mLoadFailedAsyncRunnable);
|
||||
aOther.mLoadFailedAsyncRunnable.swap(mLoadFailedAsyncRunnable);
|
||||
|
||||
MOZ_ASSERT(!mInterfaceRequestor);
|
||||
aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
|
||||
|
||||
|
@ -3418,7 +3421,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
|||
AssertIsOnParentThread();
|
||||
MOZ_ASSERT(!mMainThreadObjectsForgotten);
|
||||
|
||||
static const uint32_t kDoomedCount = 9;
|
||||
static const uint32_t kDoomedCount = 10;
|
||||
|
||||
aDoomed.SetCapacity(kDoomedCount);
|
||||
|
||||
|
@ -3430,6 +3433,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
|||
SwapToISupportsArray(mLoadInfo.mChannel, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mCSP, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mLoadGroup, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mLoadFailedAsyncRunnable, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mInterfaceRequestor, aDoomed);
|
||||
// Before adding anything here update kDoomedCount above!
|
||||
|
||||
|
@ -5466,6 +5470,19 @@ WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::MaybeDispatchLoadFailedRunnable()
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = StealLoadFailedAsyncRunnable();
|
||||
if (!runnable) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable.forget())));
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::InitializeGCTimers()
|
||||
{
|
||||
|
|
|
@ -798,6 +798,12 @@ public:
|
|||
void
|
||||
UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup);
|
||||
|
||||
already_AddRefed<nsIRunnable>
|
||||
StealLoadFailedAsyncRunnable()
|
||||
{
|
||||
return mLoadInfo.mLoadFailedAsyncRunnable.forget();
|
||||
}
|
||||
|
||||
IMPL_EVENT_HANDLER(message)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
|
||||
|
@ -956,6 +962,9 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
|||
|
||||
nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
|
||||
|
||||
// fired on the main thread if the worker script fails to load
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
|
||||
|
||||
TimeStamp mKillTime;
|
||||
uint32_t mErrorHandlerRecursionCount;
|
||||
uint32_t mNextTimeoutId;
|
||||
|
@ -1367,6 +1376,9 @@ public:
|
|||
bool
|
||||
RunBeforeNextEvent(nsIRunnable* aRunnable);
|
||||
|
||||
void
|
||||
MaybeDispatchLoadFailedRunnable();
|
||||
|
||||
private:
|
||||
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
|
|
|
@ -39,6 +39,7 @@ class nsIPrincipal;
|
|||
class nsILoadGroup;
|
||||
class nsITabChild;
|
||||
class nsIChannel;
|
||||
class nsIRunnable;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -221,6 +222,12 @@ struct WorkerLoadInfo
|
|||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
// mLoadFailedAsyncRunnable will execute on main thread if script loading
|
||||
// fails during script loading. If script loading is never started due to
|
||||
// a synchronous error, then the runnable is never executed. The runnable
|
||||
// is guaranteed to be released on the main thread.
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedAsyncRunnable;
|
||||
|
||||
class InterfaceRequestor final : public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
|
|
@ -206,7 +206,9 @@ nsEditingSession::DisableJSAndPlugins(nsIDOMWindow *aWindow)
|
|||
NS_IMETHODIMP
|
||||
nsEditingSession::RestoreJSAndPlugins(nsIDOMWindow *aWindow)
|
||||
{
|
||||
NS_ENSURE_TRUE(mDisabledJSAndPlugins, NS_OK);
|
||||
if (!mDisabledJSAndPlugins) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDisabledJSAndPlugins = false;
|
||||
|
||||
|
|
|
@ -1455,57 +1455,31 @@ nsPermissionManager::GetPermissionHashKey(const nsACString& aHost,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// helper struct for passing arguments into hash enumeration callback.
|
||||
struct nsGetEnumeratorData
|
||||
{
|
||||
nsGetEnumeratorData(nsCOMArray<nsIPermission> *aArray,
|
||||
const nsTArray<nsCString> *aTypes,
|
||||
int64_t aSince = 0)
|
||||
: array(aArray)
|
||||
, types(aTypes)
|
||||
, since(aSince) {}
|
||||
|
||||
nsCOMArray<nsIPermission> *array;
|
||||
const nsTArray<nsCString> *types;
|
||||
int64_t since;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
AddPermissionsToList(nsPermissionManager::PermissionHashKey* entry, void *arg)
|
||||
{
|
||||
nsGetEnumeratorData *data = static_cast<nsGetEnumeratorData *>(arg);
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
// given how "default" permissions work and the possibility of them being
|
||||
// overridden with UNKNOWN_ACTION, we might see this value here - but we
|
||||
// do *not* want to return them via the enumerator.
|
||||
if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsPermission *perm = new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
data->types->ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime);
|
||||
|
||||
data->array->AppendObject(perm);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPermissionManager::GetEnumerator(nsISimpleEnumerator **aEnum)
|
||||
{
|
||||
// roll an nsCOMArray of all our permissions, then hand out an enumerator
|
||||
nsCOMArray<nsIPermission> array;
|
||||
nsGetEnumeratorData data(&array, &mTypeArray);
|
||||
|
||||
mPermissionTable.EnumerateEntries(AddPermissionsToList, &data);
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
for (const auto& permEntry : entry->GetPermissions()) {
|
||||
// Given how "default" permissions work and the possibility of them being
|
||||
// overridden with UNKNOWN_ACTION, we might see this value here - but we
|
||||
// do *not* want to return them via the enumerator.
|
||||
if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
array.AppendObject(
|
||||
new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
}
|
||||
|
||||
return NS_NewArrayEnumerator(aEnum, array);
|
||||
}
|
||||
|
@ -1529,42 +1503,29 @@ NS_IMETHODIMP nsPermissionManager::Observe(nsISupports *aSubject, const char *aT
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
AddPermissionsModifiedSinceToList(
|
||||
nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
nsGetEnumeratorData* data = static_cast<nsGetEnumeratorData *>(arg);
|
||||
|
||||
for (size_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
const nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
if (data->since > permEntry.mModificationTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsPermission* perm = new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
data->types->ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime);
|
||||
|
||||
data->array->AppendObject(perm);
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime)
|
||||
{
|
||||
ENSURE_NOT_CHILD_PROCESS;
|
||||
|
||||
// roll an nsCOMArray of all our permissions, then hand out an enumerator
|
||||
nsCOMArray<nsIPermission> array;
|
||||
nsGetEnumeratorData data(&array, &mTypeArray, aModificationTime);
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
for (const auto& permEntry : entry->GetPermissions()) {
|
||||
if (aModificationTime > permEntry.mModificationTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mPermissionTable.EnumerateEntries(AddPermissionsModifiedSinceToList, &data);
|
||||
array.AppendObject(
|
||||
new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i<array.Count(); ++i) {
|
||||
nsAutoCString host;
|
||||
|
@ -1599,31 +1560,6 @@ nsPermissionManager::RemoveAllModifiedSince(int64_t aModificationTime)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsPermissionManager::GetPermissionsForApp(nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
GetPermissionsForAppStruct* data = static_cast<GetPermissionsForAppStruct*>(arg);
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
|
||||
if (entry->GetKey()->mAppId != data->appId ||
|
||||
(data->browserOnly && !entry->GetKey()->mIsInBrowserElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data->permissions.AppendObject(new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
||||
{
|
||||
|
@ -1634,9 +1570,9 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
|||
// After clearing the DB, we call AddInternal() to make sure that all
|
||||
// processes are aware of this change and the representation of the DB in
|
||||
// memory is updated.
|
||||
// We have to get all permissions associated with an application and then
|
||||
// remove those because doing so in EnumerateEntries() would fail because
|
||||
// we might happen to actually delete entries from the list.
|
||||
// We have to get all permissions associated with an application first
|
||||
// because removing entries from the permissions table while iterating over
|
||||
// it is dangerous.
|
||||
|
||||
nsAutoCString sql;
|
||||
sql.AppendLiteral("DELETE FROM moz_hosts WHERE appId=");
|
||||
|
@ -1654,17 +1590,34 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
|||
rv = removeStmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
GetPermissionsForAppStruct data(aAppId, aBrowserOnly);
|
||||
mPermissionTable.EnumerateEntries(GetPermissionsForApp, &data);
|
||||
nsCOMArray<nsIPermission> permissions;
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
if (entry->GetKey()->mAppId != aAppId ||
|
||||
(aBrowserOnly && !entry->GetKey()->mIsInBrowserElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int32_t i=0; i<data.permissions.Count(); ++i) {
|
||||
for (const auto& permEntry : entry->GetPermissions()) {
|
||||
permissions.AppendObject(
|
||||
new nsPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime));
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < permissions.Count(); ++i) {
|
||||
nsAutoCString host;
|
||||
bool isInBrowserElement;
|
||||
nsAutoCString type;
|
||||
|
||||
data.permissions[i]->GetHost(host);
|
||||
data.permissions[i]->GetIsInBrowserElement(&isInBrowserElement);
|
||||
data.permissions[i]->GetType(type);
|
||||
permissions[i]->GetHost(host);
|
||||
permissions[i]->GetIsInBrowserElement(&isInBrowserElement);
|
||||
permissions[i]->GetType(type);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (NS_FAILED(GetPrincipal(host, aAppId, isInBrowserElement,
|
||||
|
@ -1687,63 +1640,59 @@ nsPermissionManager::RemovePermissionsForApp(uint32_t aAppId, bool aBrowserOnly)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
nsPermissionManager::RemoveExpiredPermissionsForAppEnumerator(
|
||||
nsPermissionManager::PermissionHashKey* entry, void* arg)
|
||||
{
|
||||
uint32_t* appId = static_cast<uint32_t*>(arg);
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
if (entry->GetKey()->mAppId != *appId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsPermissionManager::PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
if (permEntry.mExpireType != nsIPermissionManager::EXPIRE_SESSION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (permEntry.mNonSessionExpireType == nsIPermissionManager::EXPIRE_SESSION) {
|
||||
PermissionEntry oldPermissionEntry = entry->GetPermissions()[i];
|
||||
|
||||
entry->GetPermissions().RemoveElementAt(i);
|
||||
|
||||
gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
gPermissionManager->mTypeArray.ElementAt(oldPermissionEntry.mType),
|
||||
oldPermissionEntry.mPermission,
|
||||
oldPermissionEntry.mExpireType,
|
||||
oldPermissionEntry.mExpireTime,
|
||||
MOZ_UTF16("deleted"));
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
permEntry.mPermission = permEntry.mNonSessionPermission;
|
||||
permEntry.mExpireType = permEntry.mNonSessionExpireType;
|
||||
permEntry.mExpireTime = permEntry.mNonSessionExpireTime;
|
||||
|
||||
gPermissionManager->NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
gPermissionManager->mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime,
|
||||
MOZ_UTF16("changed"));
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPermissionManager::RemoveExpiredPermissionsForApp(uint32_t aAppId)
|
||||
{
|
||||
ENSURE_NOT_CHILD_PROCESS;
|
||||
|
||||
if (aAppId != nsIScriptSecurityManager::NO_APP_ID) {
|
||||
mPermissionTable.EnumerateEntries(RemoveExpiredPermissionsForAppEnumerator, &aAppId);
|
||||
if (aAppId == nsIScriptSecurityManager::NO_APP_ID) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
PermissionHashKey* entry = iter.Get();
|
||||
if (entry->GetKey()->mAppId != aAppId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < entry->GetPermissions().Length(); ++i) {
|
||||
PermissionEntry& permEntry = entry->GetPermissions()[i];
|
||||
if (permEntry.mExpireType != nsIPermissionManager::EXPIRE_SESSION) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (permEntry.mNonSessionExpireType ==
|
||||
nsIPermissionManager::EXPIRE_SESSION) {
|
||||
PermissionEntry oldPermEntry = entry->GetPermissions()[i];
|
||||
|
||||
entry->GetPermissions().RemoveElementAt(i);
|
||||
|
||||
NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(oldPermEntry.mType),
|
||||
oldPermEntry.mPermission,
|
||||
oldPermEntry.mExpireType,
|
||||
oldPermEntry.mExpireTime,
|
||||
MOZ_UTF16("deleted"));
|
||||
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
permEntry.mPermission = permEntry.mNonSessionPermission;
|
||||
permEntry.mExpireType = permEntry.mNonSessionExpireType;
|
||||
permEntry.mExpireTime = permEntry.mNonSessionExpireTime;
|
||||
|
||||
NotifyObserversWithPermission(entry->GetKey()->mHost,
|
||||
entry->GetKey()->mAppId,
|
||||
entry->GetKey()->mIsInBrowserElement,
|
||||
mTypeArray.ElementAt(permEntry.mType),
|
||||
permEntry.mPermission,
|
||||
permEntry.mExpireType,
|
||||
permEntry.mExpireTime,
|
||||
MOZ_UTF16("changed"));
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -272,41 +272,6 @@ private:
|
|||
|
||||
nsresult RemoveExpiredPermissionsForApp(uint32_t aAppId);
|
||||
|
||||
/**
|
||||
* This struct has to be passed as an argument to GetPermissionsForApp.
|
||||
* |appId| and |browserOnly| have to be defined.
|
||||
* |permissions| will be filed with permissions that are related to the app.
|
||||
* If |browserOnly| is true, only permissions related to a browserElement will
|
||||
* be in |permissions|.
|
||||
*/
|
||||
struct GetPermissionsForAppStruct {
|
||||
uint32_t appId;
|
||||
bool browserOnly;
|
||||
nsCOMArray<nsIPermission> permissions;
|
||||
|
||||
GetPermissionsForAppStruct() = delete;
|
||||
GetPermissionsForAppStruct(uint32_t aAppId, bool aBrowserOnly)
|
||||
: appId(aAppId)
|
||||
, browserOnly(aBrowserOnly)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method will return the list of all permissions that are related to a
|
||||
* specific app.
|
||||
* @param arg has to be an instance of GetPermissionsForAppStruct.
|
||||
*/
|
||||
static PLDHashOperator
|
||||
GetPermissionsForApp(PermissionHashKey* entry, void* arg);
|
||||
|
||||
/**
|
||||
* This method restores an app's permissions when its session ends.
|
||||
*/
|
||||
static PLDHashOperator
|
||||
RemoveExpiredPermissionsForAppEnumerator(PermissionHashKey* entry,
|
||||
void* nonused);
|
||||
|
||||
|
||||
/**
|
||||
* This method removes all permissions modified after the specified time.
|
||||
*/
|
||||
|
|
|
@ -242,16 +242,6 @@ void mozPersonalDictionary::SyncLoadInternal()
|
|||
mDirty = false;
|
||||
}
|
||||
|
||||
// A little helper function to add the key to the list.
|
||||
// This is not threadsafe, and only safe if the consumer does not
|
||||
// modify the list.
|
||||
static PLDHashOperator
|
||||
AddHostToStringArray(nsUnicharPtrHashKey *aEntry, void *aArg)
|
||||
{
|
||||
static_cast<nsTArray<nsString>*>(aArg)->AppendElement(nsDependentString(aEntry->GetKey()));
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/* void Save (); */
|
||||
NS_IMETHODIMP mozPersonalDictionary::Save()
|
||||
{
|
||||
|
@ -277,7 +267,9 @@ NS_IMETHODIMP mozPersonalDictionary::Save()
|
|||
if (NS_FAILED(res)) return res;
|
||||
|
||||
nsTArray<nsString> array(mDictionaryTable.Count());
|
||||
mDictionaryTable.EnumerateEntries(AddHostToStringArray, &array);
|
||||
for (auto iter = mDictionaryTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
array.AppendElement(nsDependentString(iter.Get()->GetKey()));
|
||||
}
|
||||
|
||||
uint32_t bytesWritten;
|
||||
nsAutoCString utf8Key;
|
||||
|
@ -307,10 +299,9 @@ NS_IMETHODIMP mozPersonalDictionary::GetWordList(nsIStringEnumerator **aWords)
|
|||
WaitForLoad();
|
||||
|
||||
nsTArray<nsString> *array = new nsTArray<nsString>(mDictionaryTable.Count());
|
||||
if (!array)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mDictionaryTable.EnumerateEntries(AddHostToStringArray, array);
|
||||
for (auto iter = mDictionaryTable.Iter(); !iter.Done(); iter.Next()) {
|
||||
array->AppendElement(nsDependentString(iter.Get()->GetKey()));
|
||||
}
|
||||
|
||||
array->Sort();
|
||||
|
||||
|
|
|
@ -866,7 +866,7 @@ ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
|||
// Reset the update rect
|
||||
tile.mUpdateRect = IntRect();
|
||||
}
|
||||
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
|
||||
return SurfaceDescriptorTiles(mValidRegion,
|
||||
tiles,
|
||||
mTiles.mFirst.x, mTiles.mFirst.y,
|
||||
mTiles.mSize.width, mTiles.mSize.height,
|
||||
|
|
|
@ -109,28 +109,13 @@ void
|
|||
UseTileTexture(CompositableTextureHostRef& aTexture,
|
||||
CompositableTextureSourceRef& aTextureSource,
|
||||
const IntRect& aUpdateRect,
|
||||
TextureHost* aNewTexture,
|
||||
Compositor* aCompositor)
|
||||
{
|
||||
MOZ_ASSERT(aNewTexture);
|
||||
if (!aNewTexture) {
|
||||
MOZ_ASSERT(aTexture);
|
||||
if (!aTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTexture) {
|
||||
aTexture->SetCompositor(aCompositor);
|
||||
aNewTexture->SetCompositor(aCompositor);
|
||||
|
||||
if (aTexture->GetFormat() != aNewTexture->GetFormat()) {
|
||||
// Only reuse textures if their format match the new texture's.
|
||||
aTextureSource = nullptr;
|
||||
aTexture = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
aTexture = aNewTexture;
|
||||
|
||||
|
||||
if (aCompositor) {
|
||||
aTexture->SetCompositor(aCompositor);
|
||||
}
|
||||
|
@ -175,6 +160,83 @@ GetCopyOnWriteLock(const TileLock& ipcLock, TileHost& aTile, ISurfaceAllocator*
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::MarkTilesForUnlock()
|
||||
{
|
||||
// Tiles without an internal buffer will have internal locks
|
||||
// held by the gpu driver until the previous draw operation has finished.
|
||||
// We don't know when that will be exactly, so wait until we start the
|
||||
// next composite before unlocking.
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
// Tile with an internal buffer get unlocked as soon as we've uploaded,
|
||||
// so won't have a lock at this point.
|
||||
if (tile.mTextureHost && tile.mSharedLock) {
|
||||
mDelayedUnlocks.AppendElement(tile.mSharedLock);
|
||||
tile.mSharedLock = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TextureSourceRecycler
|
||||
{
|
||||
public:
|
||||
explicit TextureSourceRecycler(nsTArray<TileHost>&& aTileSet)
|
||||
: mTiles(Move(aTileSet))
|
||||
, mFirstPossibility(0)
|
||||
{}
|
||||
|
||||
// Attempts to recycle a texture source that is already bound to the
|
||||
// texture host for aTile.
|
||||
void RecycleTextureSourceForTile(TileHost& aTile) {
|
||||
for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
|
||||
// Skip over existing tiles without a retained texture source
|
||||
// and make sure we don't iterate them in the future.
|
||||
if (!mTiles[i].mTextureSource) {
|
||||
if (i == mFirstPossibility) {
|
||||
mFirstPossibility++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this tile matches, then copy across the retained texture source (if
|
||||
// any).
|
||||
if (aTile.mTextureHost == mTiles[i].mTextureHost) {
|
||||
aTile.mTextureSource = Move(mTiles[i].mTextureSource);
|
||||
if (aTile.mTextureHostOnWhite) {
|
||||
aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to recycle any texture source to avoid needing to allocate
|
||||
// a new one.
|
||||
void RecycleTextureSource(TileHost& aTile) {
|
||||
for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
|
||||
if (!mTiles[i].mTextureSource) {
|
||||
if (i == mFirstPossibility) {
|
||||
mFirstPossibility++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mTiles[i].mTextureSource &&
|
||||
mTiles[i].mTextureHost->GetFormat() == aTile.mTextureHost->GetFormat()) {
|
||||
aTile.mTextureSource = Move(mTiles[i].mTextureSource);
|
||||
if (aTile.mTextureHostOnWhite) {
|
||||
aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
nsTArray<TileHost> mTiles;
|
||||
size_t mFirstPossibility;
|
||||
};
|
||||
|
||||
bool
|
||||
TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
||||
Compositor* aCompositor,
|
||||
|
@ -195,146 +257,97 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
|||
return false;
|
||||
}
|
||||
|
||||
TilesPlacement oldTiles = mTiles;
|
||||
TilesPlacement newTiles(aTiles.firstTileX(), aTiles.firstTileY(),
|
||||
aTiles.retainedWidth(), aTiles.retainedHeight());
|
||||
|
||||
const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();
|
||||
|
||||
nsTArray<TileHost> oldRetainedTiles;
|
||||
mRetainedTiles.SwapElements(oldRetainedTiles);
|
||||
// Step 1, unlock all the old tiles that haven't been unlocked yet. Any tiles that
|
||||
// exist in both the old and new sets will have been locked again by content, so this
|
||||
// doesn't result in the surface being writeable again.
|
||||
MarkTilesForUnlock();
|
||||
|
||||
TextureSourceRecycler oldRetainedTiles(Move(mRetainedTiles));
|
||||
mRetainedTiles.SetLength(tileDescriptors.Length());
|
||||
|
||||
// Step 1, we need to unlock tiles that don't have an internal buffer after the
|
||||
// next frame where they are replaced.
|
||||
// Since we are about to replace the tiles' textures, we need to keep their locks
|
||||
// somewhere (in mPreviousSharedLock) until we composite the layer.
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); ++i) {
|
||||
TileHost& tile = oldRetainedTiles[i];
|
||||
// It can happen that we still have a previous lock at this point,
|
||||
// if we changed a tile's front buffer (causing mSharedLock to
|
||||
// go into mPreviousSharedLock, and then did not composite that tile until
|
||||
// the next transaction, either because the tile is offscreen or because the
|
||||
// two transactions happened with no composition in between (over-production).
|
||||
tile.ReadUnlockPrevious();
|
||||
|
||||
if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
|
||||
MOZ_ASSERT(tile.mSharedLock);
|
||||
const TileIntPoint tilePosition = oldTiles.TilePosition(i);
|
||||
if (newTiles.HasTile(tilePosition)) {
|
||||
// This tile still exist in the new buffer
|
||||
tile.mPreviousSharedLock = tile.mSharedLock;
|
||||
tile.mSharedLock = nullptr;
|
||||
} else {
|
||||
// This tile does not exist anymore in the new buffer because the size
|
||||
// changed.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
// By now we should not have anything in mSharedLock.
|
||||
MOZ_ASSERT(!tile.mSharedLock);
|
||||
}
|
||||
|
||||
// Step 2, move the tiles in mRetainedTiles at places that correspond to where
|
||||
// they should be with the new retained with and height rather than the
|
||||
// old one.
|
||||
// Step 2, deserialize the incoming set of tiles into mRetainedTiles, and attempt
|
||||
// to recycle the TextureSource for any repeated tiles.
|
||||
//
|
||||
// Since we don't have any retained 'tile' object, we have to search for instances
|
||||
// of the same TextureHost in the old tile set. The cost of binding a TextureHost
|
||||
// to a TextureSource for gralloc (binding EGLImage to GL texture) can be really
|
||||
// high, so we avoid this whenever possible.
|
||||
for (size_t i = 0; i < tileDescriptors.Length(); i++) {
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
// First, get the already existing tiles to the right place in the array,
|
||||
// and use placeholders where there was no tiles.
|
||||
if (!oldTiles.HasTile(tilePosition)) {
|
||||
mRetainedTiles[i] = GetPlaceholderTile();
|
||||
} else {
|
||||
mRetainedTiles[i] = oldRetainedTiles[oldTiles.TileIndex(tilePosition)];
|
||||
// If we hit this assertion it means we probably mixed something up in the
|
||||
// logic that tries to reuse tiles on the compositor side. It is most likely
|
||||
// benign, but we are missing some fast paths so let's try to make it not happen.
|
||||
MOZ_ASSERT(tilePosition.x == mRetainedTiles[i].x &&
|
||||
tilePosition.y == mRetainedTiles[i].y);
|
||||
}
|
||||
}
|
||||
|
||||
// It is important to remove the duplicated reference to tiles before calling
|
||||
// TextureHost::PrepareTextureSource, etc. because depending on the textures
|
||||
// ref counts we may or may not get some of the fast paths.
|
||||
oldRetainedTiles.Clear();
|
||||
|
||||
// Step 3, handle the texture updates and release the copy-on-write locks.
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
const TileDescriptor& tileDesc = tileDescriptors[i];
|
||||
|
||||
TileHost& tile = mRetainedTiles[i];
|
||||
|
||||
switch (tileDesc.type()) {
|
||||
case TileDescriptor::TTexturedTileDescriptor: {
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
const TileLock& ipcLock = texturedDesc.sharedLock();
|
||||
if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<TextureHost> textureHost = TextureHost::AsTextureHost(
|
||||
texturedDesc.textureParent()
|
||||
);
|
||||
|
||||
RefPtr<TextureHost> textureOnWhite = nullptr;
|
||||
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
|
||||
textureOnWhite = TextureHost::AsTextureHost(
|
||||
texturedDesc.textureOnWhite().get_PTextureParent()
|
||||
);
|
||||
}
|
||||
|
||||
UseTileTexture(tile.mTextureHost,
|
||||
tile.mTextureSource,
|
||||
texturedDesc.updateRect(),
|
||||
textureHost,
|
||||
aCompositor);
|
||||
|
||||
if (textureOnWhite) {
|
||||
UseTileTexture(tile.mTextureHostOnWhite,
|
||||
tile.mTextureSourceOnWhite,
|
||||
texturedDesc.updateRect(),
|
||||
textureOnWhite,
|
||||
aCompositor);
|
||||
} else {
|
||||
// We could still have component alpha textures from a previous frame.
|
||||
tile.mTextureSourceOnWhite = nullptr;
|
||||
tile.mTextureHostOnWhite = nullptr;
|
||||
}
|
||||
|
||||
if (textureHost->HasInternalBuffer()) {
|
||||
// Now that we did the texture upload (in UseTileTexture), we can release
|
||||
// the lock.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NS_WARNING("Unrecognised tile descriptor type");
|
||||
case TileDescriptor::TPlaceholderTileDescriptor: {
|
||||
|
||||
if (tile.mTextureHost) {
|
||||
tile.mTextureHost->UnbindTextureSource();
|
||||
tile.mTextureSource = nullptr;
|
||||
}
|
||||
if (tile.mTextureHostOnWhite) {
|
||||
tile.mTextureHostOnWhite->UnbindTextureSource();
|
||||
tile.mTextureSourceOnWhite = nullptr;
|
||||
}
|
||||
// we may have a previous lock, and are about to loose our reference to it.
|
||||
// It is okay to unlock it because we just destroyed the texture source.
|
||||
tile.ReadUnlockPrevious();
|
||||
tile = GetPlaceholderTile();
|
||||
|
||||
break;
|
||||
}
|
||||
if (tileDesc.type() != TileDescriptor::TTexturedTileDescriptor) {
|
||||
NS_WARN_IF_FALSE(tileDesc.type() == TileDescriptor::TPlaceholderTileDescriptor,
|
||||
"Unrecognised tile descriptor type");
|
||||
continue;
|
||||
}
|
||||
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
const TileLock& ipcLock = texturedDesc.sharedLock();
|
||||
if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
|
||||
|
||||
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
|
||||
tile.mTextureHostOnWhite =
|
||||
TextureHost::AsTextureHost(texturedDesc.textureOnWhite().get_PTextureParent());
|
||||
}
|
||||
|
||||
tile.mTilePosition = newTiles.TilePosition(i);
|
||||
|
||||
// If this same tile texture existed in the old tile set then this will move the texture
|
||||
// source into our new tile.
|
||||
oldRetainedTiles.RecycleTextureSourceForTile(tile);
|
||||
}
|
||||
|
||||
// Step 3, attempt to recycle unused texture sources from the old tile set into new tiles.
|
||||
//
|
||||
// For gralloc, binding a new TextureHost to the existing TextureSource is the fastest way
|
||||
// to ensure that any implicit locking on the old gralloc image is released.
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
if (!tile.mTextureHost || tile.mTextureSource) {
|
||||
continue;
|
||||
}
|
||||
oldRetainedTiles.RecycleTextureSource(tile);
|
||||
}
|
||||
|
||||
// Step 4, handle the texture uploads, texture source binding and release the
|
||||
// copy-on-write locks for textures with an internal buffer.
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
TileHost& tile = mRetainedTiles[i];
|
||||
if (!tile.mTextureHost) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const TileDescriptor& tileDesc = tileDescriptors[i];
|
||||
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
|
||||
|
||||
UseTileTexture(tile.mTextureHost,
|
||||
tile.mTextureSource,
|
||||
texturedDesc.updateRect(),
|
||||
aCompositor);
|
||||
|
||||
if (tile.mTextureHostOnWhite) {
|
||||
UseTileTexture(tile.mTextureHostOnWhite,
|
||||
tile.mTextureSourceOnWhite,
|
||||
texturedDesc.updateRect(),
|
||||
aCompositor);
|
||||
}
|
||||
|
||||
if (tile.mTextureHost->HasInternalBuffer()) {
|
||||
// Now that we did the texture upload (in UseTileTexture), we can release
|
||||
// the lock.
|
||||
tile.ReadUnlock();
|
||||
}
|
||||
TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
tile.x = tilePosition.x;
|
||||
tile.y = tilePosition.y;
|
||||
}
|
||||
|
||||
mTiles = newTiles;
|
||||
|
@ -346,18 +359,26 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::ProcessDelayedUnlocks()
|
||||
{
|
||||
for (gfxSharedReadLock* lock : mDelayedUnlocks) {
|
||||
lock->ReadUnlock();
|
||||
}
|
||||
mDelayedUnlocks.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
TiledLayerBufferComposite::Clear()
|
||||
{
|
||||
for (TileHost& tile : mRetainedTiles) {
|
||||
tile.ReadUnlock();
|
||||
tile.ReadUnlockPrevious();
|
||||
}
|
||||
mRetainedTiles.Clear();
|
||||
ProcessDelayedUnlocks();
|
||||
mTiles.mFirst = TileIntPoint();
|
||||
mTiles.mSize = TileIntSize();
|
||||
mValidRegion = nsIntRegion();
|
||||
mPaintedRegion = nsIntRegion();
|
||||
mResolution = 1.0;
|
||||
}
|
||||
|
||||
|
@ -416,6 +437,8 @@ TiledContentHost::Composite(LayerComposite* aLayer,
|
|||
aFilter, aClipRect, *renderRegion, aTransform);
|
||||
RenderLayerBuffer(mTiledBuffer, nullptr, aEffectChain, aOpacity, aFilter,
|
||||
aClipRect, *renderRegion, aTransform);
|
||||
mLowPrecisionTiledBuffer.ProcessDelayedUnlocks();
|
||||
mTiledBuffer.ProcessDelayedUnlocks();
|
||||
}
|
||||
|
||||
|
||||
|
@ -479,7 +502,6 @@ TiledContentHost::RenderTile(TileHost& aTile,
|
|||
}
|
||||
mCompositor->DrawDiagnostics(flags,
|
||||
aScreenRegion, aClipRect, aTransform, mFlashCounter);
|
||||
aTile.ReadUnlockPrevious();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -558,7 +580,7 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
|||
|
||||
TileIntPoint tilePosition = aLayerBuffer.GetPlacement().TilePosition(i);
|
||||
// A sanity check that catches a lot of mistakes.
|
||||
MOZ_ASSERT(tilePosition.x == tile.x && tilePosition.y == tile.y);
|
||||
MOZ_ASSERT(tilePosition.x == tile.mTilePosition.x && tilePosition.y == tile.mTilePosition.y);
|
||||
|
||||
IntPoint tileOffset = aLayerBuffer.GetTileOffset(tilePosition);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, aLayerBuffer.GetScaledTileSize());
|
||||
|
|
|
@ -52,8 +52,6 @@ public:
|
|||
// essentially, this is a sentinel used to represent an invalid or blank
|
||||
// tile.
|
||||
TileHost()
|
||||
: x(-1)
|
||||
, y(-1)
|
||||
{}
|
||||
|
||||
// Constructs a TileHost from a gfxSharedReadLock and TextureHost.
|
||||
|
@ -67,8 +65,6 @@ public:
|
|||
, mTextureHostOnWhite(aTextureHostOnWhite)
|
||||
, mTextureSource(aSource)
|
||||
, mTextureSourceOnWhite(aSourceOnWhite)
|
||||
, x(-1)
|
||||
, y(-1)
|
||||
{}
|
||||
|
||||
TileHost(const TileHost& o) {
|
||||
|
@ -77,9 +73,7 @@ public:
|
|||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
mPreviousSharedLock = o.mPreviousSharedLock;
|
||||
x = o.x;
|
||||
y = o.y;
|
||||
mTilePosition = o.mTilePosition;
|
||||
}
|
||||
TileHost& operator=(const TileHost& o) {
|
||||
if (this == &o) {
|
||||
|
@ -90,9 +84,7 @@ public:
|
|||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
mPreviousSharedLock = o.mPreviousSharedLock;
|
||||
x = o.x;
|
||||
y = o.y;
|
||||
mTilePosition = o.mTilePosition;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -112,13 +104,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void ReadUnlockPrevious() {
|
||||
if (mPreviousSharedLock) {
|
||||
mPreviousSharedLock->ReadUnlock();
|
||||
mPreviousSharedLock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Dump(std::stringstream& aStream) {
|
||||
aStream << "TileHost(...)"; // fill in as needed
|
||||
}
|
||||
|
@ -129,14 +114,12 @@ public:
|
|||
}
|
||||
|
||||
RefPtr<gfxSharedReadLock> mSharedLock;
|
||||
RefPtr<gfxSharedReadLock> mPreviousSharedLock;
|
||||
CompositableTextureHostRef mTextureHost;
|
||||
CompositableTextureHostRef mTextureHostOnWhite;
|
||||
mutable CompositableTextureSourceRef mTextureSource;
|
||||
mutable CompositableTextureSourceRef mTextureSourceOnWhite;
|
||||
// This is not strictly necessary but makes debugging whole lot easier.
|
||||
int x;
|
||||
int y;
|
||||
TileIntPoint mTilePosition;
|
||||
};
|
||||
|
||||
class TiledLayerBufferComposite
|
||||
|
@ -154,6 +137,9 @@ public:
|
|||
|
||||
void Clear();
|
||||
|
||||
void MarkTilesForUnlock();
|
||||
void ProcessDelayedUnlocks();
|
||||
|
||||
TileHost GetPlaceholderTile() const { return TileHost(); }
|
||||
|
||||
// Stores the absolute resolution of the containing frame, calculated
|
||||
|
@ -167,7 +153,9 @@ public:
|
|||
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
|
||||
|
||||
protected:
|
||||
|
||||
CSSToParentLayerScale2D mFrameResolution;
|
||||
nsTArray<RefPtr<gfxSharedReadLock>> mDelayedUnlocks;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -332,7 +332,6 @@ union TileDescriptor {
|
|||
|
||||
struct SurfaceDescriptorTiles {
|
||||
nsIntRegion validRegion;
|
||||
nsIntRegion paintedRegion;
|
||||
TileDescriptor[] tiles;
|
||||
int firstTileX;
|
||||
int firstTileY;
|
||||
|
|
|
@ -230,6 +230,7 @@ private:
|
|||
// This should be set to values in the DriverInitStatus enumeration found in
|
||||
// DriverInitCrashDetection.h.
|
||||
DECL_GFX_PREF(Live, "gfx.driver-init.status", DriverInitStatus, int32_t, 0);
|
||||
DECL_GFX_PREF(Once, "gfx.font_rendering.directwrite.enabled", DirectWriteFontRenderingEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.gralloc.fence-with-readpixels", GrallocFenceWithReadPixels, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.layerscope.port", LayerScopePort, int32_t, 23456);
|
||||
|
|
|
@ -436,6 +436,95 @@ gfxWindowsPlatform::CanUseHardwareVideoDecoding()
|
|||
return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitD2DSupport()
|
||||
{
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
bool d2dBlocked = false;
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
if (gfxInfo) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If D2D is blocked or D3D9 is prefered, and D2D is not force-enabled, then
|
||||
// we don't attempt to use D2D.
|
||||
if ((d2dBlocked || gfxPrefs::LayersPreferD3D9()) && !gfxPrefs::Direct2DForceEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not ever try to use D2D if it's explicitly disabled or if we're not
|
||||
// using DWrite fonts.
|
||||
if (gfxPrefs::Direct2DDisabled() || mUsingGDIFonts) {
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Device* device = GetD3D11Device();
|
||||
if (IsVistaOrLater() &&
|
||||
!InSafeMode() &&
|
||||
device &&
|
||||
mDoesD3D11TextureSharingWork)
|
||||
{
|
||||
VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled());
|
||||
if (mD3D10Device && GetD3D11Device()) {
|
||||
mRenderMode = RENDER_DIRECT2D;
|
||||
mUseDirectWrite = true;
|
||||
}
|
||||
} else {
|
||||
mD3D10Device = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitDWriteSupport()
|
||||
{
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
// Enable when it's preffed on -and- we're using Vista or higher. Or when
|
||||
// we're going to use D2D.
|
||||
if (mDWriteFactory || (!mUseDirectWrite || !IsVistaOrLater())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::ScopedGfxFeatureReporter reporter("DWrite");
|
||||
decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
|
||||
GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
|
||||
|
||||
if (!createDWriteFactory) {
|
||||
return;
|
||||
}
|
||||
|
||||
// I need a direct pointer to be able to cast to IUnknown**, I also need to
|
||||
// remember to release this because the nsRefPtr will AddRef it.
|
||||
IDWriteFactory *factory;
|
||||
HRESULT hr = createDWriteFactory(
|
||||
DWRITE_FACTORY_TYPE_SHARED,
|
||||
__uuidof(IDWriteFactory),
|
||||
reinterpret_cast<IUnknown**>(&factory));
|
||||
|
||||
if (SUCCEEDED(hr) && factory) {
|
||||
mDWriteFactory = factory;
|
||||
factory->Release();
|
||||
hr = mDWriteFactory->CreateTextAnalyzer(getter_AddRefs(mDWriteAnalyzer));
|
||||
}
|
||||
|
||||
SetupClearTypeParams();
|
||||
|
||||
if (hr == S_OK) {
|
||||
reporter.SetSuccessful();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::UpdateRenderMode()
|
||||
{
|
||||
|
@ -461,92 +550,10 @@ gfxWindowsPlatform::UpdateRenderMode()
|
|||
}
|
||||
|
||||
mRenderMode = RENDER_GDI;
|
||||
mUseDirectWrite = gfxPrefs::DirectWriteFontRenderingEnabled();
|
||||
|
||||
bool isVistaOrHigher = IsVistaOrLater();
|
||||
|
||||
mUseDirectWrite = Preferences::GetBool("gfx.font_rendering.directwrite.enabled", false);
|
||||
|
||||
#ifdef CAIRO_HAS_D2D_SURFACE
|
||||
bool d2dDisabled = false;
|
||||
bool d2dForceEnabled = false;
|
||||
bool d2dBlocked = false;
|
||||
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
if (gfxInfo) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
d2dBlocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These will only be evaluated once, and any subsequent changes to
|
||||
// the preferences will be ignored until restart.
|
||||
d2dDisabled = gfxPrefs::Direct2DDisabled();
|
||||
d2dForceEnabled = gfxPrefs::Direct2DForceEnabled();
|
||||
|
||||
bool tryD2D = d2dForceEnabled || (!d2dBlocked && !gfxPrefs::LayersPreferD3D9());
|
||||
|
||||
// Do not ever try if d2d is explicitly disabled,
|
||||
// or if we're not using DWrite fonts.
|
||||
if (d2dDisabled || mUsingGDIFonts) {
|
||||
tryD2D = false;
|
||||
}
|
||||
|
||||
ID3D11Device *device = GetD3D11Device();
|
||||
if (isVistaOrHigher && !InSafeMode() && tryD2D && device &&
|
||||
mDoesD3D11TextureSharingWork) {
|
||||
|
||||
VerifyD2DDevice(d2dForceEnabled);
|
||||
if (mD3D10Device && GetD3D11Device()) {
|
||||
mRenderMode = RENDER_DIRECT2D;
|
||||
mUseDirectWrite = true;
|
||||
}
|
||||
} else {
|
||||
mD3D10Device = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CAIRO_HAS_DWRITE_FONT
|
||||
// Enable when it's preffed on -and- we're using Vista or higher. Or when
|
||||
// we're going to use D2D.
|
||||
if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) {
|
||||
mozilla::ScopedGfxFeatureReporter reporter("DWrite");
|
||||
decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
|
||||
GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory");
|
||||
|
||||
if (createDWriteFactory) {
|
||||
/**
|
||||
* I need a direct pointer to be able to cast to IUnknown**, I also
|
||||
* need to remember to release this because the nsRefPtr will
|
||||
* AddRef it.
|
||||
*/
|
||||
IDWriteFactory *factory;
|
||||
HRESULT hr = createDWriteFactory(
|
||||
DWRITE_FACTORY_TYPE_SHARED,
|
||||
__uuidof(IDWriteFactory),
|
||||
reinterpret_cast<IUnknown**>(&factory));
|
||||
|
||||
if (SUCCEEDED(hr) && factory) {
|
||||
mDWriteFactory = factory;
|
||||
factory->Release();
|
||||
hr = mDWriteFactory->CreateTextAnalyzer(
|
||||
getter_AddRefs(mDWriteAnalyzer));
|
||||
}
|
||||
|
||||
SetupClearTypeParams();
|
||||
|
||||
if (hr == S_OK)
|
||||
reporter.SetSuccessful();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
InitD2DSupport();
|
||||
InitDWriteSupport();
|
||||
|
||||
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
|
||||
uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
|
||||
|
@ -1890,6 +1897,163 @@ bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
|
|||
return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
auto
|
||||
gfxWindowsPlatform::CheckD3D11Support() -> D3D11Status
|
||||
{
|
||||
if (gfxPrefs::LayersD3D11ForceWARP()) {
|
||||
return D3D11Status::ForceWARP;
|
||||
}
|
||||
|
||||
if (nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo()) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
// See if we can use WARP instead.
|
||||
//
|
||||
// It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more.
|
||||
if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) {
|
||||
return D3D11Status::Blocked;
|
||||
}
|
||||
|
||||
if (!IsWin8OrLater()) {
|
||||
// We do not use WARP on Windows 7 or earlier.
|
||||
return D3D11Status::Blocked;
|
||||
}
|
||||
|
||||
return D3D11Status::TryWARP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Either nsIGfxInfo was bugged or we're not blacklisted.
|
||||
if (!GetDXGIAdapter()) {
|
||||
return D3D11Status::TryWARP;
|
||||
}
|
||||
return D3D11Status::Ok;
|
||||
}
|
||||
|
||||
// We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
|
||||
// since it doesn't include d3d11.h, so we use a static here. It should only
|
||||
// be used within InitD3D11Devices.
|
||||
decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
|
||||
MOZ_ASSERT(adapter);
|
||||
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY {
|
||||
hr =
|
||||
sD3D11CreateDeviceFn(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Crash during D3D11 device creation";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
|
||||
gfxCriticalError() << "D3D11 device creation failed" << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
if (!mD3D11Device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
|
||||
|
||||
// Only test this when not using WARP since it can fail and cause
|
||||
// GetDeviceRemovedReason to return weird values.
|
||||
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
|
||||
mIsWARP = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mD3D11Device);
|
||||
|
||||
ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
HRESULT hr =
|
||||
sD3D11CreateDeviceFn(nullptr, D3D_DRIVER_TYPE_WARP, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// This should always succeed... in theory.
|
||||
gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
reporterWARP.SetSuccessful();
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
|
||||
return false;
|
||||
}
|
||||
|
||||
mIsWARP = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY {
|
||||
hr =
|
||||
sD3D11CreateDeviceFn(mIsWARP ? nullptr : GetDXGIAdapter(),
|
||||
mIsWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN,
|
||||
nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
bool
|
||||
gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels)
|
||||
{
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY{
|
||||
hr =
|
||||
sD3D11CreateDeviceFn(GetDXGIAdapter(), D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
aFeatureLevels.Elements(), aFeatureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mD3D11ImageBridgeDevice->SetExceptionMode(0);
|
||||
|
||||
return DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice);
|
||||
}
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::InitD3D11Devices()
|
||||
{
|
||||
|
@ -1899,7 +2063,6 @@ gfxWindowsPlatform::InitD3D11Devices()
|
|||
// blacklisted, then this function will abort if WARP is disabled, causing us
|
||||
// to fallback to D3D9 or Basic layers. If WARP is not disabled it will use
|
||||
// a WARP device which should always be available on Windows 7 and higher.
|
||||
|
||||
mD3D11DeviceInitialized = true;
|
||||
mDoesD3D11TextureSharingWork = false;
|
||||
|
||||
|
@ -1910,44 +2073,16 @@ gfxWindowsPlatform::InitD3D11Devices()
|
|||
return;
|
||||
}
|
||||
|
||||
bool useWARP = false;
|
||||
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
if (gfxInfo) {
|
||||
int32_t status;
|
||||
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
|
||||
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
|
||||
// It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more.
|
||||
if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsWin8OrLater()) {
|
||||
/* On Windows 7 WARP runs very badly on the builtin vga driver */
|
||||
nsString driver;
|
||||
gfxInfo->GetAdapterDriver(driver);
|
||||
// driver can start with vga or svga so only look for "framebuf..."
|
||||
if (driver.Find("framebuf vga256 vga64k") != kNotFound) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Disabling WARP on builtin vga driver";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
useWARP = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gfxPrefs::LayersD3D11ForceWARP()) {
|
||||
useWARP = true;
|
||||
D3D11Status status = CheckD3D11Support();
|
||||
if (status == D3D11Status::Blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
|
||||
decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*)
|
||||
GetProcAddress(d3d11Module, "D3D11CreateDevice");
|
||||
sD3D11CreateDeviceFn =
|
||||
(decltype(D3D11CreateDevice)*)GetProcAddress(d3d11Module, "D3D11CreateDevice");
|
||||
|
||||
if (!d3d11CreateDevice) {
|
||||
if (!sD3D11CreateDeviceFn) {
|
||||
// We should just be on Windows Vista or XP in this case.
|
||||
return;
|
||||
}
|
||||
|
@ -1961,114 +2096,36 @@ gfxWindowsPlatform::InitD3D11Devices()
|
|||
featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
|
||||
featureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3);
|
||||
|
||||
RefPtr<IDXGIAdapter1> adapter;
|
||||
|
||||
if (!useWARP) {
|
||||
adapter = GetDXGIAdapter();
|
||||
|
||||
if (!adapter) {
|
||||
if (!gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return;
|
||||
}
|
||||
useWARP = true;
|
||||
if (status == D3D11Status::Ok) {
|
||||
if (!AttemptD3D11DeviceCreation(featureLevels)) {
|
||||
status = D3D11Status::TryWARP;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = E_INVALIDARG;
|
||||
|
||||
if (!useWARP) {
|
||||
MOZ_SEH_TRY {
|
||||
hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Crash during D3D11 device creation";
|
||||
|
||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return;
|
||||
}
|
||||
|
||||
useWARP = true;
|
||||
adapter = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr) || !DoesD3D11DeviceWork(mD3D11Device)) {
|
||||
gfxCriticalError() << "D3D11 device creation failed" << hexa(hr);
|
||||
if (gfxPrefs::LayersD3D11DisableWARP()) {
|
||||
return;
|
||||
}
|
||||
|
||||
useWARP = true;
|
||||
adapter = nullptr;
|
||||
}
|
||||
|
||||
if (mD3D11Device) {
|
||||
CheckIfRenderTargetViewNeedsRecreating(mD3D11Device);
|
||||
// Only test this when not using WARP since it can fail and cause GetDeviceRemovedReason to return
|
||||
// weird values.
|
||||
mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device);
|
||||
}
|
||||
}
|
||||
|
||||
if (useWARP) {
|
||||
MOZ_ASSERT(!gfxPrefs::LayersD3D11DisableWARP());
|
||||
MOZ_ASSERT(!mD3D11Device);
|
||||
MOZ_ASSERT(!adapter);
|
||||
|
||||
ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP());
|
||||
|
||||
MOZ_SEH_TRY {
|
||||
hr = d3d11CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, nullptr,
|
||||
// Use
|
||||
// D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
||||
// to prevent bug 1092260. IE 11 also uses this flag.
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// This should always succeed... in theory.
|
||||
gfxCriticalError() << "Failed to initialize WARP D3D11 device! " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
mIsWARP = true;
|
||||
reporterWARP.SetSuccessful();
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
|
||||
if (status == D3D11Status::TryWARP || status == D3D11Status::ForceWARP) {
|
||||
if (!AttemptWARPDeviceCreation(featureLevels)) {
|
||||
// Nothing more we can do.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mD3D11Device) {
|
||||
return;
|
||||
}
|
||||
|
||||
mD3D11Device->SetExceptionMode(0);
|
||||
|
||||
// We create our device for D2D content drawing here. Normally we don't use
|
||||
// D2D content drawing when using WARP. However when WARP is forced by
|
||||
// default we will let Direct2D use WARP as well.
|
||||
if (Factory::SupportsD2D1() && (!useWARP || gfxPrefs::LayersD3D11ForceWARP())) {
|
||||
MOZ_ASSERT((useWARP && !adapter) || !useWARP);
|
||||
|
||||
hr = E_INVALIDARG;
|
||||
MOZ_SEH_TRY {
|
||||
hr = d3d11CreateDevice(adapter, useWARP ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ContentDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
if (Factory::SupportsD2D1() && (!mIsWARP || (status == D3D11Status::ForceWARP))) {
|
||||
if (!AttemptD3D11ContentDeviceCreation(featureLevels)) {
|
||||
mD3D11ContentDevice = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
d3d11Module.disown();
|
||||
return;
|
||||
}
|
||||
|
||||
mD3D11ContentDevice->SetExceptionMode(0);
|
||||
|
||||
nsRefPtr<ID3D10Multithread> multi;
|
||||
mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
|
||||
multi->SetMultithreadProtected(TRUE);
|
||||
|
@ -2076,26 +2133,8 @@ gfxWindowsPlatform::InitD3D11Devices()
|
|||
Factory::SetDirect3D11Device(mD3D11ContentDevice);
|
||||
}
|
||||
|
||||
if (!useWARP) {
|
||||
hr = E_INVALIDARG;
|
||||
|
||||
MOZ_SEH_TRY{
|
||||
hr = d3d11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr,
|
||||
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
||||
featureLevels.Elements(), featureLevels.Length(),
|
||||
D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr);
|
||||
} MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
||||
mD3D11ImageBridgeDevice = nullptr;
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
d3d11Module.disown();
|
||||
return;
|
||||
}
|
||||
|
||||
mD3D11ImageBridgeDevice->SetExceptionMode(0);
|
||||
|
||||
if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) {
|
||||
if (!mIsWARP) {
|
||||
if (!AttemptD3D11ImageBridgeDeviceCreation(featureLevels)) {
|
||||
mD3D11ImageBridgeDevice = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,7 +275,26 @@ protected:
|
|||
|
||||
private:
|
||||
void Init();
|
||||
|
||||
void InitD3D11Devices();
|
||||
|
||||
// Used by InitD3D11Devices().
|
||||
enum class D3D11Status {
|
||||
Ok,
|
||||
TryWARP,
|
||||
ForceWARP,
|
||||
Blocked
|
||||
};
|
||||
D3D11Status CheckD3D11Support();
|
||||
bool AttemptD3D11DeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
bool AttemptWARPDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
bool AttemptD3D11ImageBridgeDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
bool AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
|
||||
|
||||
// Used by UpdateRenderMode().
|
||||
void InitD2DSupport();
|
||||
void InitDWriteSupport();
|
||||
|
||||
IDXGIAdapter1 *GetDXGIAdapter();
|
||||
bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason);
|
||||
|
||||
|
|
|
@ -867,7 +867,8 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL &&
|
||||
if (mCurrentTransaction &&
|
||||
DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL &&
|
||||
msg->priority() > IPC::Message::PRIORITY_NORMAL)
|
||||
{
|
||||
// Don't allow sending CPOWs while we're dispatching a sync message.
|
||||
|
@ -877,22 +878,23 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
|
||||
if (mCurrentTransaction &&
|
||||
(msg->priority() < DispatchingSyncMessagePriority() ||
|
||||
mAwaitingSyncReplyPriority > msg->priority() ||
|
||||
DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT ||
|
||||
DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT))
|
||||
mAwaitingSyncReplyPriority > msg->priority()))
|
||||
{
|
||||
CancelCurrentTransactionInternal();
|
||||
mLink->SendMessage(new CancelMessage());
|
||||
}
|
||||
|
||||
IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here");
|
||||
IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(),
|
||||
"can't send sync message of a lesser priority than what's being dispatched");
|
||||
IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(),
|
||||
"nested sync message sends must be of increasing priority");
|
||||
|
||||
IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
|
||||
"not allowed to send messages while dispatching urgent messages");
|
||||
if (mCurrentTransaction) {
|
||||
IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(),
|
||||
"can't send sync message of a lesser priority than what's being dispatched");
|
||||
IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(),
|
||||
"nested sync message sends must be of increasing priority");
|
||||
IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
|
||||
"not allowed to send messages while dispatching urgent messages");
|
||||
}
|
||||
|
||||
IPC_ASSERT(DispatchingAsyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
|
||||
"not allowed to send messages while dispatching urgent messages");
|
||||
|
||||
|
@ -1316,11 +1318,6 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
|
|||
MOZ_ASSERT_IF(prio > IPC::Message::PRIORITY_NORMAL, NS_IsMainThread());
|
||||
MaybeScriptBlocker scriptBlocker(this, prio > IPC::Message::PRIORITY_NORMAL);
|
||||
|
||||
IPC_ASSERT(prio >= DispatchingSyncMessagePriority(),
|
||||
"priority inversion while dispatching sync message");
|
||||
IPC_ASSERT(prio >= mAwaitingSyncReplyPriority,
|
||||
"dispatching a message of lower priority while waiting for a response");
|
||||
|
||||
MessageChannel* dummy;
|
||||
MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy;
|
||||
|
||||
|
@ -2022,16 +2019,26 @@ MessageChannel::CancelCurrentTransactionInternal()
|
|||
// tampered with (by us). If so, they don't reset the variable to the old
|
||||
// value.
|
||||
|
||||
MOZ_ASSERT(!mCurrentTransaction);
|
||||
MOZ_ASSERT(mCurrentTransaction);
|
||||
mCurrentTransaction = 0;
|
||||
|
||||
mAwaitingSyncReply = false;
|
||||
mAwaitingSyncReplyPriority = 0;
|
||||
|
||||
// We could also zero out mDispatchingSyncMessage here. However, that would
|
||||
// cause a race because mDispatchingSyncMessage is a worker-thread-only
|
||||
// field and we can be called on the I/O thread. Luckily, we can check to
|
||||
// see if mCurrentTransaction is 0 before examining DispatchSyncMessage.
|
||||
}
|
||||
|
||||
void
|
||||
MessageChannel::CancelCurrentTransaction()
|
||||
{
|
||||
MonitorAutoLock lock(*mMonitor);
|
||||
CancelCurrentTransactionInternal();
|
||||
mLink->SendMessage(new CancelMessage());
|
||||
if (mCurrentTransaction) {
|
||||
CancelCurrentTransactionInternal();
|
||||
mLink->SendMessage(new CancelMessage());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -129,6 +129,11 @@ class MessageChannel : HasResultCodes
|
|||
|
||||
bool CanSend() const;
|
||||
|
||||
// Currently only for debugging purposes, doesn't aquire mMonitor.
|
||||
ChannelState GetChannelState__TotallyRacy() const {
|
||||
return mChannelState;
|
||||
}
|
||||
|
||||
void SetReplyTimeoutMs(int32_t aTimeoutMs);
|
||||
|
||||
bool IsOnCxxStack() const {
|
||||
|
@ -554,7 +559,7 @@ class MessageChannel : HasResultCodes
|
|||
public:
|
||||
explicit AutoEnterTransaction(MessageChannel *aChan, int32_t aMsgSeqno)
|
||||
: mChan(aChan),
|
||||
mNewTransaction(0),
|
||||
mNewTransaction(INT32_MAX),
|
||||
mOldTransaction(mChan->mCurrentTransaction)
|
||||
{
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
|
|
@ -133,7 +133,7 @@ TestBridgeSubParent::Main()
|
|||
bool
|
||||
TestBridgeSubParent::RecvBridgeEm()
|
||||
{
|
||||
if (!PTestBridgeMainSub::Bridge(gBridgeMainChild, this))
|
||||
if (NS_FAILED(PTestBridgeMainSub::Bridge(gBridgeMainChild, this)))
|
||||
fail("bridging Main and Sub");
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4135,28 +4135,48 @@ BytecodeEmitter::emitTemplateString(ParseNode* pn)
|
|||
{
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
|
||||
bool pushedString = false;
|
||||
|
||||
for (ParseNode* pn2 = pn->pn_head; pn2 != NULL; pn2 = pn2->pn_next) {
|
||||
if (pn2->getKind() != PNK_STRING && pn2->getKind() != PNK_TEMPLATE_STRING) {
|
||||
bool isString = (pn2->getKind() == PNK_STRING || pn2->getKind() == PNK_TEMPLATE_STRING);
|
||||
|
||||
// Skip empty strings. These are very common: a template string like
|
||||
// `${a}${b}` has three empty strings and without this optimization
|
||||
// we'd emit four JSOP_ADD operations instead of just one.
|
||||
if (isString && pn2->pn_atom->empty())
|
||||
continue;
|
||||
|
||||
if (!isString) {
|
||||
// We update source notes before emitting the expression
|
||||
if (!updateSourceCoordNotes(pn2->pn_pos.begin))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitTree(pn2))
|
||||
return false;
|
||||
|
||||
if (pn2->getKind() != PNK_STRING && pn2->getKind() != PNK_TEMPLATE_STRING) {
|
||||
if (!isString) {
|
||||
// We need to convert the expression to a string
|
||||
if (!emit1(JSOP_TOSTRING))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pn2 != pn->pn_head) {
|
||||
if (pushedString) {
|
||||
// We've pushed two strings onto the stack. Add them together, leaving just one.
|
||||
if (!emit1(JSOP_ADD))
|
||||
return false;
|
||||
} else {
|
||||
pushedString = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!pushedString) {
|
||||
// All strings were empty, this can happen for something like `${""}`.
|
||||
// Just push an empty string.
|
||||
if (!emitAtomOp(cx->names().empty, JSOP_STRING))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1259,9 +1259,11 @@ SavedNonVolatileRegisters(AllocatableGeneralRegisterSet unused)
|
|||
result.add(reg);
|
||||
}
|
||||
|
||||
// ARM and MIPS require an additional register to be saved, if calls can be made.
|
||||
// Some platforms require the link register to be saved, if calls can be made.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
result.add(Register::FromCode(Registers::lr));
|
||||
#elif defined(JS_CODEGEN_ARM64)
|
||||
result.add(Register::FromCode(Registers::lr));
|
||||
#elif defined(JS_CODEGEN_MIPS)
|
||||
result.add(Register::FromCode(Registers::ra));
|
||||
#endif
|
||||
|
|
|
@ -220,7 +220,7 @@ IsObjectEscaped(MInstruction* ins, JSObject* objDefault)
|
|||
case MDefinition::Op_GuardShape: {
|
||||
MGuardShape* guard = def->toGuardShape();
|
||||
MOZ_ASSERT(!ins->isGuardShape());
|
||||
if (obj->as<NativeObject>().lastProperty() != guard->shape()) {
|
||||
if (obj->maybeShape() != guard->shape()) {
|
||||
JitSpewDef(JitSpew_Escape, "has a non-matching guard shape\n", guard);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1029,8 +1029,9 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
|||
if (!sandbox)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
CompartmentPrivate::Get(sandbox)->writeToGlobalPrototype =
|
||||
options.writeToGlobalPrototype;
|
||||
CompartmentPrivate* priv = CompartmentPrivate::Get(sandbox);
|
||||
priv->allowWaivers = options.allowWaivers;
|
||||
priv->writeToGlobalPrototype = options.writeToGlobalPrototype;
|
||||
|
||||
// Set up the wantXrays flag, which indicates whether xrays are desired even
|
||||
// for same-origin access.
|
||||
|
@ -1041,7 +1042,7 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
|
|||
// Arguably we should just flip the default for chrome and still honor the
|
||||
// flag, but such a change would break code in subtle ways for minimal
|
||||
// benefit. So we just switch it off here.
|
||||
CompartmentPrivate::Get(sandbox)->wantXrays =
|
||||
priv->wantXrays =
|
||||
AccessCheck::isChrome(sandbox) ? false : options.wantXrays;
|
||||
|
||||
{
|
||||
|
@ -1480,6 +1481,7 @@ SandboxOptions::Parse()
|
|||
{
|
||||
bool ok = ParseObject("sandboxPrototype", &proto) &&
|
||||
ParseBoolean("wantXrays", &wantXrays) &&
|
||||
ParseBoolean("allowWaivers", &allowWaivers) &&
|
||||
ParseBoolean("wantComponents", &wantComponents) &&
|
||||
ParseBoolean("wantExportHelpers", &wantExportHelpers) &&
|
||||
ParseString("sandboxName", sandboxName) &&
|
||||
|
|
|
@ -1297,7 +1297,7 @@ class MOZ_STACK_CLASS CallMethodHelper
|
|||
const uint32_t mArgc;
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
GetArraySizeFromParam(uint8_t paramIndex, uint32_t* result) const;
|
||||
GetArraySizeFromParam(uint8_t paramIndex, HandleValue maybeArray, uint32_t* result);
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
GetInterfaceTypeFromParam(uint8_t paramIndex,
|
||||
|
@ -1446,7 +1446,7 @@ CallMethodHelper::~CallMethodHelper()
|
|||
// We need some basic information to properly destroy the array.
|
||||
uint32_t array_count = 0;
|
||||
nsXPTType datum_type;
|
||||
if (!GetArraySizeFromParam(i, &array_count) ||
|
||||
if (!GetArraySizeFromParam(i, UndefinedHandleValue, &array_count) ||
|
||||
!NS_SUCCEEDED(mIFaceInfo->GetTypeForParam(mVTableIndex,
|
||||
¶mInfo,
|
||||
1, &datum_type))) {
|
||||
|
@ -1480,7 +1480,8 @@ CallMethodHelper::~CallMethodHelper()
|
|||
|
||||
bool
|
||||
CallMethodHelper::GetArraySizeFromParam(uint8_t paramIndex,
|
||||
uint32_t* result) const
|
||||
HandleValue maybeArray,
|
||||
uint32_t* result)
|
||||
{
|
||||
nsresult rv;
|
||||
const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
|
||||
|
@ -1491,6 +1492,22 @@ CallMethodHelper::GetArraySizeFromParam(uint8_t paramIndex,
|
|||
if (NS_FAILED(rv))
|
||||
return Throw(NS_ERROR_XPC_CANT_GET_ARRAY_INFO, mCallContext);
|
||||
|
||||
// If the array length wasn't passed, it might have been listed as optional.
|
||||
// When converting arguments from JS to C++, we pass the array as |maybeArray|,
|
||||
// and give ourselves the chance to infer the length. Once we have it, we stick
|
||||
// it in the right slot so that we can find it again when cleaning up the params.
|
||||
// from the array.
|
||||
if (paramIndex >= mArgc && maybeArray.isObject()) {
|
||||
MOZ_ASSERT(mMethodInfo->GetParam(paramIndex).IsOptional());
|
||||
RootedObject arrayOrNull(mCallContext, maybeArray.isObject() ? &maybeArray.toObject()
|
||||
: nullptr);
|
||||
if (!JS_IsArrayObject(mCallContext, maybeArray) ||
|
||||
!JS_GetArrayLength(mCallContext, arrayOrNull, &GetDispatchParam(paramIndex)->val.u32))
|
||||
{
|
||||
return Throw(NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY, mCallContext);
|
||||
}
|
||||
}
|
||||
|
||||
*result = GetDispatchParam(paramIndex)->val.u32;
|
||||
|
||||
return true;
|
||||
|
@ -1586,7 +1603,7 @@ CallMethodHelper::GatherAndConvertResults()
|
|||
datum_type = type;
|
||||
|
||||
if (isArray || isSizedString) {
|
||||
if (!GetArraySizeFromParam(i, &array_count))
|
||||
if (!GetArraySizeFromParam(i, UndefinedHandleValue, &array_count))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1968,7 +1985,7 @@ CallMethodHelper::ConvertDependentParam(uint8_t i)
|
|||
nsresult err;
|
||||
|
||||
if (isArray || isSizedString) {
|
||||
if (!GetArraySizeFromParam(i, &array_count))
|
||||
if (!GetArraySizeFromParam(i, src, &array_count))
|
||||
return false;
|
||||
|
||||
if (isArray) {
|
||||
|
|
|
@ -32,16 +32,14 @@ UnwrapNW(JSContext* cx, unsigned argc, jsval* vp)
|
|||
}
|
||||
|
||||
JS::RootedValue v(cx, args[0]);
|
||||
if (!v.isObject() || !js::IsWrapper(&v.toObject())) {
|
||||
if (!v.isObject() || !js::IsCrossCompartmentWrapper(&v.toObject()) ||
|
||||
!WrapperFactory::AllowWaiver(&v.toObject())) {
|
||||
args.rval().set(v);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (AccessCheck::wrapperSubsumes(&v.toObject())) {
|
||||
bool ok = xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v);
|
||||
NS_ENSURE_TRUE(ok, false);
|
||||
}
|
||||
|
||||
bool ok = xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v);
|
||||
NS_ENSURE_TRUE(ok, false);
|
||||
args.rval().set(v);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3043,7 +3043,7 @@ public:
|
|||
uint32_t flags,
|
||||
const char* category) override;
|
||||
|
||||
NS_IMETHOD GetStack(JS::MutableHandleValue);
|
||||
NS_IMETHOD GetStack(JS::MutableHandleValue) override;
|
||||
|
||||
private:
|
||||
virtual ~nsScriptErrorWithStack();
|
||||
|
@ -3472,6 +3472,7 @@ public:
|
|||
JSObject* options = nullptr)
|
||||
: OptionsBase(cx, options)
|
||||
, wantXrays(true)
|
||||
, allowWaivers(true)
|
||||
, wantComponents(true)
|
||||
, wantExportHelpers(false)
|
||||
, proto(cx)
|
||||
|
@ -3487,6 +3488,7 @@ public:
|
|||
virtual bool Parse();
|
||||
|
||||
bool wantXrays;
|
||||
bool allowWaivers;
|
||||
bool wantComponents;
|
||||
bool wantExportHelpers;
|
||||
JS::RootedObject proto;
|
||||
|
@ -3683,6 +3685,7 @@ public:
|
|||
|
||||
explicit CompartmentPrivate(JSCompartment* c)
|
||||
: wantXrays(false)
|
||||
, allowWaivers(true)
|
||||
, writeToGlobalPrototype(false)
|
||||
, skipWriteToGlobalPrototype(false)
|
||||
, universalXPConnectEnabled(false)
|
||||
|
@ -3710,9 +3713,17 @@ public:
|
|||
return Get(compartment);
|
||||
}
|
||||
|
||||
|
||||
// Controls whether this compartment gets Xrays to same-origin. This behavior
|
||||
// is deprecated, but is still the default for sandboxes for compatibity
|
||||
// reasons.
|
||||
bool wantXrays;
|
||||
|
||||
// Controls whether this compartment is allowed to waive Xrays to content
|
||||
// that it subsumes. This should generally be true, except in cases where we
|
||||
// want to prevent code from depending on Xray Waivers (which might make it
|
||||
// more portable to other browser architectures).
|
||||
bool allowWaivers;
|
||||
|
||||
// This flag is intended for a very specific use, internal to Gecko. It may
|
||||
// go away or change behavior at any time. It should not be added to any
|
||||
// documentation and it should not be used without consulting the XPConnect
|
||||
|
|
|
@ -73,7 +73,13 @@ TestParams.prototype = {
|
|||
testSizedWstring: f_is,
|
||||
testInterfaceIs: f_is,
|
||||
testInterfaceIsArray: f_size_and_iid,
|
||||
testOutAString: function(o) { o.value = "out"; }
|
||||
testOutAString: function(o) { o.value = "out"; },
|
||||
testStringArrayOptionalSize: function(arr, size) {
|
||||
if (arr.length != size) { throw "bad size passed to test method"; }
|
||||
var rv = "";
|
||||
arr.forEach((x) => rv += x);
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TestParams]);
|
||||
|
|
|
@ -346,3 +346,16 @@ NS_IMETHODIMP nsXPCTestParams::TestOutAString(nsAString & o)
|
|||
o.AssignLiteral("out");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* ACString testStringArrayOptionalSize([array, size_is(aLength)] in string a, [optional] in unsigned long aLength);
|
||||
*/
|
||||
NS_IMETHODIMP nsXPCTestParams::TestStringArrayOptionalSize(const char * *a, uint32_t length, nsACString& out)
|
||||
{
|
||||
out.Truncate();
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
out.Append(a[i]);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
interface nsIXPCTestInterfaceA;
|
||||
interface nsIXPCTestInterfaceB;
|
||||
|
||||
[scriptable, uuid(fe2b7433-ac3b-49ef-9344-b67228bfdd46)]
|
||||
[scriptable, uuid(812145c7-9fcc-425e-a878-36ad1b7730b7)]
|
||||
interface nsIXPCTestParams : nsISupports {
|
||||
|
||||
// These types correspond to the ones in typelib.py
|
||||
|
@ -84,4 +84,7 @@ interface nsIXPCTestParams : nsISupports {
|
|||
|
||||
// Test for out dipper parameters
|
||||
void testOutAString(out AString o);
|
||||
|
||||
// Test for optional array size_is.
|
||||
ACString testStringArrayOptionalSize([array, size_is(aLength)] in string a, [optional] in unsigned long aLength);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
const Cu = Components.utils;
|
||||
function checkWaivers(from, allowed) {
|
||||
var sb = new Cu.Sandbox('http://example.com');
|
||||
from.test = sb.eval('var o = {prop: 2, f: function() {return 42;}}; o');
|
||||
|
||||
// Make sure that |from| has Xrays to sb.
|
||||
do_check_eq(from.eval('test.prop'), 2);
|
||||
do_check_eq(from.eval('test.f'), undefined);
|
||||
|
||||
// Make sure that waivability works as expected.
|
||||
do_check_eq(from.eval('!!test.wrappedJSObject'), allowed);
|
||||
do_check_eq(from.eval('XPCNativeWrapper.unwrap(test) !== test'), allowed);
|
||||
|
||||
// Make a sandbox with the same principal as |from|, but without any waiver
|
||||
// restrictions, and make sure that the waiver does not transfer.
|
||||
var friend = new Cu.Sandbox(Cu.getObjectPrincipal(from));
|
||||
friend.test = from.test;
|
||||
friend.eval('var waived = test.wrappedJSObject;');
|
||||
do_check_true(friend.eval('waived.f()'), 42);
|
||||
friend.from = from;
|
||||
friend.eval('from.waived = waived');
|
||||
do_check_eq(from.eval('!!waived.f'), allowed);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
checkWaivers(new Cu.Sandbox('http://example.com'), true);
|
||||
checkWaivers(new Cu.Sandbox('http://example.com', {allowWaivers: false}), false);
|
||||
checkWaivers(new Cu.Sandbox(['http://example.com']), true);
|
||||
checkWaivers(new Cu.Sandbox(['http://example.com'], {allowWaivers: false}), false);
|
||||
}
|
|
@ -188,6 +188,9 @@ function test_component(contractid) {
|
|||
doIs2Test("testInterfaceIsArray", [makeA(), makeA(), makeA(), makeA(), makeA()], 5, Ci['nsIXPCTestInterfaceA'],
|
||||
[makeB(), makeB(), makeB()], 3, Ci['nsIXPCTestInterfaceB']);
|
||||
|
||||
// Test optional array size.
|
||||
do_check_eq(o.testStringArrayOptionalSize(["some", "string", "array"]), "somestringarray");
|
||||
|
||||
// Test incorrect (too big) array size parameter; this should throw NOT_ENOUGH_ELEMENTS.
|
||||
doTypedArrayMismatchTest("testShortArray", new Int16Array([-3, 7, 4]), 4,
|
||||
new Int16Array([1, -32, 6]), 3);
|
||||
|
|
|
@ -18,6 +18,7 @@ support-files =
|
|||
recursive_importB.jsm
|
||||
syntax_error.jsm
|
||||
|
||||
[test_allowWaivers.js]
|
||||
[test_bogus_files.js]
|
||||
[test_bug408412.js]
|
||||
[test_bug451678.js]
|
||||
|
|
|
@ -106,6 +106,20 @@ WrapperFactory::WaiveXray(JSContext* cx, JSObject* objArg)
|
|||
return CreateXrayWaiver(cx, obj);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WrapperFactory::AllowWaiver(JSCompartment* target, JSCompartment* origin)
|
||||
{
|
||||
return CompartmentPrivate::Get(target)->allowWaivers &&
|
||||
AccessCheck::subsumes(target, origin);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WrapperFactory::AllowWaiver(JSObject* wrapper) {
|
||||
MOZ_ASSERT(js::IsCrossCompartmentWrapper(wrapper));
|
||||
return AllowWaiver(js::GetObjectCompartment(wrapper),
|
||||
js::GetObjectCompartment(js::UncheckedUnwrap(wrapper)));
|
||||
}
|
||||
|
||||
inline bool
|
||||
ShouldWaiveXray(JSContext* cx, JSObject* originalObj)
|
||||
{
|
||||
|
@ -468,8 +482,10 @@ WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
|
|||
bool wantXrays = !sameOrigin || sameOriginXrays;
|
||||
|
||||
// If Xrays are warranted, the caller may waive them for non-security
|
||||
// wrappers.
|
||||
bool waiveXrays = wantXrays && !securityWrapper && HasWaiveXrayFlag(obj);
|
||||
// wrappers (unless explicitly forbidden from doing so).
|
||||
bool waiveXrays = wantXrays && !securityWrapper &&
|
||||
CompartmentPrivate::Get(target)->allowWaivers &&
|
||||
HasWaiveXrayFlag(obj);
|
||||
|
||||
// We have slightly different behavior for the case when the object
|
||||
// being wrapped is in an XBL scope.
|
||||
|
@ -542,7 +558,7 @@ WrapperFactory::WaiveXrayAndWrap(JSContext* cx, MutableHandleObject argObj)
|
|||
// to things in |obj|'s compartment.
|
||||
JSCompartment* target = js::GetContextCompartment(cx);
|
||||
JSCompartment* origin = js::GetObjectCompartment(obj);
|
||||
obj = AccessCheck::subsumes(target, origin) ? WaiveXray(cx, obj) : obj;
|
||||
obj = AllowWaiver(target, origin) ? WaiveXray(cx, obj) : obj;
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -37,6 +37,13 @@ class WrapperFactory {
|
|||
static JSObject* CreateXrayWaiver(JSContext* cx, JS::HandleObject obj);
|
||||
static JSObject* WaiveXray(JSContext* cx, JSObject* obj);
|
||||
|
||||
// Computes whether we should allow the creation of an Xray waiver from
|
||||
// |target| to |origin|.
|
||||
static bool AllowWaiver(JSCompartment* target, JSCompartment* origin);
|
||||
|
||||
// Convenience method for the above, operating on a wrapper.
|
||||
static bool AllowWaiver(JSObject* wrapper);
|
||||
|
||||
// Prepare a given object for wrapping in a new compartment.
|
||||
static JSObject* PrepareForWrapping(JSContext* cx,
|
||||
JS::HandleObject scope,
|
||||
|
|
|
@ -1315,7 +1315,7 @@ wrappedJSObject_getter(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
RootedObject wrapper(cx, &args.thisv().toObject());
|
||||
if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper) ||
|
||||
!AccessCheck::wrapperSubsumes(wrapper)) {
|
||||
!WrapperFactory::AllowWaiver(wrapper)) {
|
||||
JS_ReportError(cx, "Unexpected object");
|
||||
return false;
|
||||
}
|
||||
|
@ -1378,7 +1378,7 @@ XrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper,
|
|||
// Handle .wrappedJSObject for subsuming callers. This should move once we
|
||||
// sort out own-ness for the holder.
|
||||
if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT) &&
|
||||
AccessCheck::wrapperSubsumes(wrapper))
|
||||
WrapperFactory::AllowWaiver(wrapper))
|
||||
{
|
||||
if (!JS_AlreadyHasOwnPropertyById(cx, holder, id, &found))
|
||||
return false;
|
||||
|
|
|
@ -1466,10 +1466,11 @@ nsBidiPresUtils::RepositionRubyContentFrame(
|
|||
|
||||
// When ruby-align is not "start", if the content does not fill this
|
||||
// frame, we need to center the children.
|
||||
const nsSize dummyContainerSize;
|
||||
for (nsIFrame* child : childList) {
|
||||
LogicalRect rect = child->GetLogicalRect(aFrameWM, 0);
|
||||
LogicalRect rect = child->GetLogicalRect(aFrameWM, dummyContainerSize);
|
||||
rect.IStart(aFrameWM) += residualISize / 2;
|
||||
child->SetRect(aFrameWM, rect, 0);
|
||||
child->SetRect(aFrameWM, rect, dummyContainerSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1619,28 +1620,23 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
|
|||
frameWM.IsOrthogonalTo(aContainerWM) ? aFrame->BSize() : frameISize;
|
||||
}
|
||||
|
||||
// LogicalRect doesn't correctly calculate the vertical position
|
||||
// in vertical writing modes with right-to-left direction (Bug 1131451).
|
||||
// This does the correct calculation ad hoc pending the fix for that.
|
||||
nsRect rect = aFrame->GetRect();
|
||||
|
||||
LogicalMargin margin = frameMargin.ConvertTo(aContainerWM, frameWM);
|
||||
// In the following variables, if aContainerReverseDir is true, i.e.
|
||||
// the container is positioning its children in reverse of its logical
|
||||
// direction, the "StartOrEnd" refers to the distance from the frame
|
||||
// to the inline end edge of the container, elsewise, it refers to the
|
||||
// distance to the inline start edge.
|
||||
nscoord marginStartOrEnd = aContainerReverseDir ?
|
||||
margin.IEnd(aContainerWM) : margin.IStart(aContainerWM);
|
||||
const LogicalMargin margin = frameMargin.ConvertTo(aContainerWM, frameWM);
|
||||
nscoord marginStartOrEnd =
|
||||
aContainerReverseDir ? margin.IEnd(aContainerWM)
|
||||
: margin.IStart(aContainerWM);
|
||||
nscoord frameStartOrEnd = aStartOrEnd + marginStartOrEnd;
|
||||
// Whether we are placing frames from right to left.
|
||||
// e.g. If the frames are placed reversely in LTR mode, they are
|
||||
// actually placed from right to left.
|
||||
bool orderingRTL = aContainerReverseDir == aContainerWM.IsBidiLTR();
|
||||
(aContainerWM.IsVertical() ? rect.y : rect.x) = orderingRTL ?
|
||||
lineSize - (frameStartOrEnd + icoord) : frameStartOrEnd;
|
||||
(aContainerWM.IsVertical() ? rect.height : rect.width) = icoord;
|
||||
aFrame->SetRect(rect);
|
||||
|
||||
LogicalRect rect = aFrame->GetLogicalRect(aContainerWM, aContainerSize);
|
||||
rect.ISize(aContainerWM) = icoord;
|
||||
rect.IStart(aContainerWM) =
|
||||
aContainerReverseDir ? lineSize - frameStartOrEnd - icoord
|
||||
: frameStartOrEnd;
|
||||
aFrame->SetRect(aContainerWM, rect, aContainerSize);
|
||||
|
||||
return icoord + margin.IStartEnd(aContainerWM);
|
||||
}
|
||||
|
|
|
@ -824,7 +824,7 @@ nsLayoutUtils::AsyncPanZoomEnabled(nsIFrame* aFrame)
|
|||
{
|
||||
// We use this as a shortcut, since if the compositor will never use APZ,
|
||||
// no widget will either.
|
||||
if (!gfxPrefs::AsyncPanZoomEnabledDoNotUseDirectly()) {
|
||||
if (!gfxPlatform::AsyncPanZoomEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5619,7 +5619,7 @@ nsLayoutUtils::GetFirstLinePosition(WritingMode aWM,
|
|||
// kid might be a legend frame here, but that's ok.
|
||||
if (GetFirstLinePosition(aWM, kid, &kidPosition)) {
|
||||
*aResult = kidPosition +
|
||||
kid->GetLogicalNormalPosition(aWM, aFrame->GetSize().width).B(aWM);
|
||||
kid->GetLogicalNormalPosition(aWM, aFrame->GetSize()).B(aWM);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -5639,9 +5639,9 @@ nsLayoutUtils::GetFirstLinePosition(WritingMode aWM,
|
|||
//XXX Not sure if this is the correct value to use for container
|
||||
// width here. It will only be used in vertical-rl layout,
|
||||
// which we don't have full support and testing for yet.
|
||||
nscoord containerWidth = line->mContainerWidth;
|
||||
const nsSize& containerSize = line->mContainerSize;
|
||||
*aResult = kidPosition +
|
||||
kid->GetLogicalNormalPosition(aWM, containerWidth).B(aWM);
|
||||
kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
@ -5674,16 +5674,16 @@ nsLayoutUtils::GetLastLineBaseline(WritingMode aWM,
|
|||
if (line->IsBlock()) {
|
||||
nsIFrame *kid = line->mFirstChild;
|
||||
nscoord kidBaseline;
|
||||
nscoord containerWidth = line->mContainerWidth;
|
||||
const nsSize& containerSize = line->mContainerSize;
|
||||
if (GetLastLineBaseline(aWM, kid, &kidBaseline)) {
|
||||
// Ignore relative positioning for baseline calculations
|
||||
*aResult = kidBaseline +
|
||||
kid->GetLogicalNormalPosition(aWM, containerWidth).B(aWM);
|
||||
kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
|
||||
return true;
|
||||
} else if (kid->GetType() == nsGkAtoms::scrollFrame) {
|
||||
// Use the bottom of the scroll frame.
|
||||
// XXX CSS2.1 really doesn't say what to do here.
|
||||
*aResult = kid->GetLogicalNormalPosition(aWM, containerWidth).B(aWM) +
|
||||
*aResult = kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM) +
|
||||
kid->BSize(aWM);
|
||||
return true;
|
||||
}
|
||||
|
@ -5711,9 +5711,9 @@ CalculateBlockContentBEnd(WritingMode aWM, nsBlockFrame* aFrame)
|
|||
line != line_end; ++line) {
|
||||
if (line->IsBlock()) {
|
||||
nsIFrame* child = line->mFirstChild;
|
||||
nscoord containerWidth = line->mContainerWidth;
|
||||
const nsSize& containerSize = line->mContainerSize;
|
||||
nscoord offset =
|
||||
child->GetLogicalNormalPosition(aWM, containerWidth).B(aWM);
|
||||
child->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
|
||||
contentBEnd =
|
||||
std::max(contentBEnd,
|
||||
nsLayoutUtils::CalculateContentBEnd(aWM, child) + offset);
|
||||
|
@ -5753,7 +5753,7 @@ nsLayoutUtils::CalculateContentBEnd(WritingMode aWM, nsIFrame* aFrame)
|
|||
nsIFrame* child = childFrames.get();
|
||||
nscoord offset =
|
||||
child->GetLogicalNormalPosition(aWM,
|
||||
aFrame->GetSize().width).B(aWM);
|
||||
aFrame->GetSize()).B(aWM);
|
||||
contentBEnd = std::max(contentBEnd,
|
||||
CalculateContentBEnd(aWM, child) + offset);
|
||||
}
|
||||
|
|
|
@ -109,7 +109,6 @@
|
|||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsVolumeService.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
using namespace mozilla::system;
|
||||
#endif
|
||||
|
||||
|
@ -405,7 +404,6 @@ nsLayoutStatics::Shutdown()
|
|||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsVolumeService::Shutdown();
|
||||
SpeakerManagerService::Shutdown();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
|
@ -435,8 +433,6 @@ nsLayoutStatics::Shutdown()
|
|||
nsHyphenationManager::Shutdown();
|
||||
nsDOMMutationObserver::Shutdown();
|
||||
|
||||
AudioChannelService::Shutdown();
|
||||
|
||||
DataStoreService::Shutdown();
|
||||
|
||||
ContentParent::ShutDown();
|
||||
|
|
|
@ -463,19 +463,20 @@ nsComboboxControlFrame::ReflowDropdown(nsPresContext* aPresContext,
|
|||
|
||||
//XXX Can this be different from the dropdown's writing mode?
|
||||
// That would be odd!
|
||||
// Note that we don't need to pass the true frame position or container width
|
||||
// Note that we don't need to pass the true frame position or container size
|
||||
// to ReflowChild or FinishReflowChild here; it will be positioned as needed
|
||||
// by AbsolutelyPositionDropDown().
|
||||
WritingMode outerWM = GetWritingMode();
|
||||
const nsSize dummyContainerSize;
|
||||
nsHTMLReflowMetrics desiredSize(aReflowState);
|
||||
nsReflowStatus ignoredStatus;
|
||||
ReflowChild(mDropdownFrame, aPresContext, desiredSize,
|
||||
kidReflowState, outerWM, LogicalPoint(outerWM), 0,
|
||||
flags, ignoredStatus);
|
||||
kidReflowState, outerWM, LogicalPoint(outerWM),
|
||||
dummyContainerSize, flags, ignoredStatus);
|
||||
|
||||
// Set the child's width and height to its desired size
|
||||
FinishReflowChild(mDropdownFrame, aPresContext, desiredSize, &kidReflowState,
|
||||
outerWM, LogicalPoint(outerWM), 0, flags);
|
||||
outerWM, LogicalPoint(outerWM), dummyContainerSize, flags);
|
||||
}
|
||||
|
||||
nsPoint
|
||||
|
@ -575,16 +576,19 @@ nsComboboxControlFrame::GetAvailableDropdownSpace(WritingMode aWM,
|
|||
// Normal frame geometry (eg GetOffsetTo, mRect) doesn't include transforms.
|
||||
// In the special case that our transform is only a 2D translation we
|
||||
// introduce this hack so that the dropdown will show up in the right place.
|
||||
*aTranslation = LogicalPoint(aWM, GetCSSTransformTranslation(), 0);
|
||||
// Use null container size when converting a vector from logical to physical.
|
||||
const nsSize nullContainerSize;
|
||||
*aTranslation = LogicalPoint(aWM, GetCSSTransformTranslation(),
|
||||
nullContainerSize);
|
||||
*aBefore = 0;
|
||||
*aAfter = 0;
|
||||
|
||||
nsRect screen = nsFormControlFrame::GetUsableScreenRect(PresContext());
|
||||
nscoord containerWidth = screen.width;
|
||||
LogicalRect logicalScreen(aWM, screen, containerWidth);
|
||||
nsSize containerSize = screen.Size();
|
||||
LogicalRect logicalScreen(aWM, screen, containerSize);
|
||||
if (mLastDropDownAfterScreenBCoord == nscoord_MIN) {
|
||||
LogicalRect thisScreenRect(aWM, GetScreenRectInAppUnits(),
|
||||
containerWidth);
|
||||
containerSize);
|
||||
mLastDropDownAfterScreenBCoord = thisScreenRect.BEnd(aWM) +
|
||||
aTranslation->B(aWM);
|
||||
mLastDropDownBeforeScreenBCoord = thisScreenRect.BEnd(aWM) +
|
||||
|
@ -597,7 +601,7 @@ nsComboboxControlFrame::GetAvailableDropdownSpace(WritingMode aWM,
|
|||
if (root) {
|
||||
minBCoord = LogicalRect(aWM,
|
||||
root->GetScreenRectInAppUnits(),
|
||||
containerWidth).BStart(aWM);
|
||||
containerSize).BStart(aWM);
|
||||
if (mLastDropDownAfterScreenBCoord < minBCoord) {
|
||||
// Don't allow the drop-down to be placed before the content area.
|
||||
return;
|
||||
|
@ -669,12 +673,12 @@ nsComboboxControlFrame::AbsolutelyPositionDropDown()
|
|||
|
||||
// Don't position the view unless the position changed since it might cause
|
||||
// a call to NotifyGeometryChange() and an infinite loop here.
|
||||
nscoord containerWidth = GetRect().width;
|
||||
nsSize containerSize = GetSize();
|
||||
const LogicalPoint currentPos =
|
||||
mDropdownFrame->GetLogicalPosition(containerWidth);
|
||||
mDropdownFrame->GetLogicalPosition(containerSize);
|
||||
const LogicalPoint newPos = dropdownPosition + translation;
|
||||
if (currentPos != newPos) {
|
||||
mDropdownFrame->SetPosition(wm, newPos, containerWidth);
|
||||
mDropdownFrame->SetPosition(wm, newPos, containerSize);
|
||||
nsContainerFrame::PositionFrameView(mDropdownFrame);
|
||||
}
|
||||
return eDropDownPositionFinal;
|
||||
|
@ -866,9 +870,8 @@ nsComboboxControlFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
// The button should occupy the same space as a scrollbar
|
||||
WritingMode wm = aReflowState.GetWritingMode();
|
||||
nscoord containerWidth = aReflowState.ComputedWidth() +
|
||||
aReflowState.ComputedPhysicalBorderPadding().LeftRight();
|
||||
LogicalRect buttonRect = mButtonFrame->GetLogicalRect(containerWidth);
|
||||
nsSize containerSize = aReflowState.ComputedSizeAsContainerIfConstrained();
|
||||
LogicalRect buttonRect = mButtonFrame->GetLogicalRect(containerSize);
|
||||
|
||||
buttonRect.IStart(wm) =
|
||||
aReflowState.ComputedLogicalBorderPadding().IStartEnd(wm) +
|
||||
|
@ -881,7 +884,7 @@ nsComboboxControlFrame::Reflow(nsPresContext* aPresContext,
|
|||
buttonRect.BSize(wm) = mDisplayFrame->BSize(wm) +
|
||||
this->GetLogicalUsedPadding(wm).BStartEnd(wm);
|
||||
|
||||
mButtonFrame->SetRect(buttonRect, containerWidth);
|
||||
mButtonFrame->SetRect(buttonRect, containerSize);
|
||||
|
||||
if (!NS_INLINE_IS_BREAK_BEFORE(aStatus) &&
|
||||
!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
|
||||
|
|
|
@ -55,13 +55,13 @@ nsFieldSetFrame::VisualBorderRectRelativeToSelf() const
|
|||
css::Side legendSide = wm.PhysicalSide(eLogicalSideBStart);
|
||||
nscoord legendBorder = StyleBorder()->GetComputedBorderWidth(legendSide);
|
||||
LogicalRect r(wm, LogicalPoint(wm, 0, 0), GetLogicalSize(wm));
|
||||
nscoord containerWidth = r.Width(wm);
|
||||
nsSize containerSize = r.Size(wm).GetPhysicalSize(wm);
|
||||
if (legendBorder < mLegendRect.BSize(wm)) {
|
||||
nscoord off = (mLegendRect.BSize(wm) - legendBorder) / 2;
|
||||
r.BStart(wm) += off;
|
||||
r.BSize(wm) -= off;
|
||||
}
|
||||
return r.GetPhysicalRect(wm, containerWidth);
|
||||
return r.GetPhysicalRect(wm, containerSize);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
|
@ -237,11 +237,11 @@ nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
|
|||
|
||||
// Use the rect of the legend frame, not mLegendRect, so we draw our
|
||||
// border under the legend's inline-start and -end margins.
|
||||
LogicalRect legendRect(wm, legend->GetRect() + aPt, rect.width);
|
||||
LogicalRect legendRect(wm, legend->GetRect() + aPt, rect.Size());
|
||||
|
||||
// Compute clipRect using logical coordinates, so that the legend space
|
||||
// will be clipped out of the appropriate physical side depending on mode.
|
||||
LogicalRect clipRect = LogicalRect(wm, rect, rect.width);
|
||||
LogicalRect clipRect = LogicalRect(wm, rect, rect.Size());
|
||||
DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
|
||||
gfxContext* gfx = aRenderingContext.ThebesContext();
|
||||
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
|
@ -251,33 +251,32 @@ nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
|
|||
clipRect.BSize(wm) = legendBorderWidth;
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.width),
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.Size()),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext);
|
||||
gfx->Restore();
|
||||
|
||||
// draw inline-end portion of the block-start side of the border
|
||||
clipRect = LogicalRect(wm, rect, rect.width);
|
||||
clipRect = LogicalRect(wm, rect, rect.Size());
|
||||
clipRect.ISize(wm) = clipRect.IEnd(wm) - legendRect.IEnd(wm);
|
||||
clipRect.IStart(wm) = legendRect.IEnd(wm);
|
||||
clipRect.BSize(wm) = legendBorderWidth;
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.width),
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.Size()),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext);
|
||||
gfx->Restore();
|
||||
|
||||
// draw remainder of the border (omitting the block-start side)
|
||||
clipRect = LogicalRect(wm, rect, rect.width);
|
||||
clipRect = LogicalRect(wm, rect, rect.Size());
|
||||
clipRect.BStart(wm) += legendBorderWidth;
|
||||
clipRect.BSize(wm) =
|
||||
GetLogicalRect(rect.width).BSize(wm) - (off + legendBorderWidth);
|
||||
clipRect.BSize(wm) = BSize(wm) - (off + legendBorderWidth);
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.width),
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.Size()),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext);
|
||||
|
@ -449,8 +448,12 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
if (reflowLegend) {
|
||||
nsHTMLReflowMetrics legendDesiredSize(aReflowState);
|
||||
|
||||
// We'll move the legend to its proper place later, so the position
|
||||
// and containerSize passed here are unimportant.
|
||||
const nsSize dummyContainerSize;
|
||||
ReflowChild(legend, aPresContext, legendDesiredSize, *legendReflowState,
|
||||
wm, LogicalPoint(wm), 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
|
||||
wm, LogicalPoint(wm), dummyContainerSize,
|
||||
NS_FRAME_NO_MOVE_FRAME, aStatus);
|
||||
#ifdef NOISY_REFLOW
|
||||
printf(" returned (%d, %d)\n",
|
||||
legendDesiredSize.Width(), legendDesiredSize.Height());
|
||||
|
@ -477,10 +480,9 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
reflowInner = true;
|
||||
}
|
||||
|
||||
// We'll move the legend to its proper place later.
|
||||
FinishReflowChild(legend, aPresContext, legendDesiredSize,
|
||||
legendReflowState.ptr(), wm, LogicalPoint(wm), 0,
|
||||
NS_FRAME_NO_MOVE_FRAME);
|
||||
legendReflowState.ptr(), wm, LogicalPoint(wm),
|
||||
dummyContainerSize, NS_FRAME_NO_MOVE_FRAME);
|
||||
} else if (!legend) {
|
||||
mLegendRect.SetEmpty();
|
||||
mLegendSpace = 0;
|
||||
|
@ -490,8 +492,10 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
legendMargin = legend->GetLogicalUsedMargin(wm);
|
||||
}
|
||||
|
||||
nscoord containerWidth = (wm.IsVertical() ? mLegendSpace : 0) +
|
||||
border.LeftRight(wm);
|
||||
// This containerSize is incomplete as yet: it does not include the size
|
||||
// of the |inner| frame itself.
|
||||
nsSize containerSize = (LogicalSize(wm, 0, mLegendSpace) +
|
||||
border.Size(wm)).GetPhysicalSize(wm);
|
||||
// reflow the content frame only if needed
|
||||
if (reflowInner) {
|
||||
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner,
|
||||
|
@ -525,26 +529,31 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
"Margins on anonymous fieldset child not supported!");
|
||||
LogicalPoint pt(wm, border.IStart(wm), border.BStart(wm) + mLegendSpace);
|
||||
|
||||
// We don't know the correct containerSize until we have reflowed |inner|,
|
||||
// so we use a dummy value for now; FinishReflowChild will fix the position
|
||||
// if necessary.
|
||||
const nsSize dummyContainerSize;
|
||||
ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState,
|
||||
wm, pt, containerWidth, 0, aStatus);
|
||||
wm, pt, dummyContainerSize, 0, aStatus);
|
||||
|
||||
// update the container width after reflowing the inner frame
|
||||
// Update containerSize to account for size of the inner frame, so that
|
||||
// FinishReflowChild can position it correctly.
|
||||
containerSize += kidDesiredSize.PhysicalSize();
|
||||
FinishReflowChild(inner, aPresContext, kidDesiredSize,
|
||||
&kidReflowState, wm, pt,
|
||||
containerWidth + kidDesiredSize.Width(), 0);
|
||||
&kidReflowState, wm, pt, containerSize, 0);
|
||||
NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
|
||||
}
|
||||
|
||||
if (inner) {
|
||||
containerWidth += inner->GetSize().width;
|
||||
} else if (inner) {
|
||||
// |inner| didn't need to be reflowed but we do need to include its size
|
||||
// in containerSize.
|
||||
containerSize += inner->GetSize();
|
||||
}
|
||||
|
||||
LogicalRect contentRect(wm);
|
||||
if (inner) {
|
||||
// We don't support margins on inner, so our content rect is just the
|
||||
// inner's border-box. We don't care about container-width at this point,
|
||||
// as we'll figure out the actual positioning later.
|
||||
contentRect = inner->GetLogicalRect(wm, containerWidth);
|
||||
// inner's border-box. (We don't really care about container size at this
|
||||
// point, as we'll figure out the actual positioning later.)
|
||||
contentRect = inner->GetLogicalRect(wm, containerSize);
|
||||
}
|
||||
|
||||
// Our content rect must fill up the available width
|
||||
|
@ -607,9 +616,9 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
|||
ConvertTo(wm, legendReflowState->GetWritingMode());
|
||||
nsHTMLReflowState::ApplyRelativePositioning(legend, wm, offsets,
|
||||
&actualLegendPos,
|
||||
containerWidth);
|
||||
containerSize);
|
||||
|
||||
legend->SetPosition(wm, actualLegendPos, containerWidth);
|
||||
legend->SetPosition(wm, actualLegendPos, containerSize);
|
||||
nsContainerFrame::PositionFrameView(legend);
|
||||
nsContainerFrame::PositionChildViews(legend);
|
||||
}
|
||||
|
@ -682,6 +691,6 @@ nscoord
|
|||
nsFieldSetFrame::GetLogicalBaseline(WritingMode aWritingMode) const
|
||||
{
|
||||
nsIFrame* inner = GetInner();
|
||||
return inner->BStart(aWritingMode, GetParent()->GetSize().width) +
|
||||
return inner->BStart(aWritingMode, GetParent()->GetSize()) +
|
||||
inner->GetLogicalBaseline(aWritingMode);
|
||||
}
|
||||
|
|
|
@ -320,11 +320,12 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
|
|||
childPos.B(wm) = 0; // This will be set properly later, after reflowing the
|
||||
// child to determine its size.
|
||||
|
||||
// We just pass 0 for containerWidth here, as the child will be repositioned
|
||||
// later by FinishReflowChild.
|
||||
// We just pass a dummy containerSize here, as the child will be
|
||||
// repositioned later by FinishReflowChild.
|
||||
nsSize dummyContainerSize;
|
||||
ReflowChild(aFirstKid, aPresContext,
|
||||
contentsDesiredSize, contentsReflowState,
|
||||
wm, childPos, 0, 0, contentsReflowStatus);
|
||||
wm, childPos, dummyContainerSize, 0, contentsReflowStatus);
|
||||
MOZ_ASSERT(NS_FRAME_IS_COMPLETE(contentsReflowStatus),
|
||||
"We gave button-contents frame unconstrained available height, "
|
||||
"so it should be complete");
|
||||
|
@ -373,12 +374,13 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
|
|||
// its focus-padding rect:
|
||||
childPos.B(wm) += focusPadding.BStart(wm) + clbp.BStart(wm);
|
||||
|
||||
nscoord containerWidth = buttonContentBox.Width(wm) + clbp.LeftRight(wm);
|
||||
nsSize containerSize =
|
||||
(buttonContentBox + clbp.Size(wm)).GetPhysicalSize(wm);
|
||||
|
||||
// Place the child
|
||||
FinishReflowChild(aFirstKid, aPresContext,
|
||||
contentsDesiredSize, &contentsReflowState,
|
||||
wm, childPos, containerWidth, 0);
|
||||
wm, childPos, containerSize, 0);
|
||||
|
||||
// Make sure we have a useful 'ascent' value for the child
|
||||
if (contentsDesiredSize.BlockStartAscent() ==
|
||||
|
|
|
@ -175,8 +175,12 @@ nsNumberControlFrame::Reflow(nsPresContext* aPresContext,
|
|||
wrapperMargin.BStart(myWM));
|
||||
|
||||
nsReflowStatus childStatus;
|
||||
// We initially reflow the child with a dummy containerSize; positioning
|
||||
// will be fixed later.
|
||||
const nsSize dummyContainerSize;
|
||||
ReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize,
|
||||
wrapperReflowState, myWM, wrapperOffset, 0, 0, childStatus);
|
||||
wrapperReflowState, myWM, wrapperOffset, dummyContainerSize, 0,
|
||||
childStatus);
|
||||
MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(childStatus),
|
||||
"We gave our child unconstrained available block-size, "
|
||||
"so it should be complete");
|
||||
|
@ -208,18 +212,21 @@ nsNumberControlFrame::Reflow(nsPresContext* aPresContext,
|
|||
wrapperOffset.B(myWM) += std::max(0, extraSpace / 2);
|
||||
|
||||
// Needed in FinishReflowChild, for logical-to-physical conversion:
|
||||
nscoord borderBoxWidth = myWM.IsVertical() ?
|
||||
borderBoxBSize : borderBoxISize;
|
||||
nsSize borderBoxSize = LogicalSize(myWM, borderBoxISize, borderBoxBSize).
|
||||
GetPhysicalSize(myWM);
|
||||
|
||||
// Place the child
|
||||
FinishReflowChild(outerWrapperFrame, aPresContext, wrappersDesiredSize,
|
||||
&wrapperReflowState, myWM, wrapperOffset,
|
||||
borderBoxWidth, 0);
|
||||
borderBoxSize, 0);
|
||||
|
||||
nsSize contentBoxSize =
|
||||
LogicalSize(myWM, contentBoxISize, contentBoxBSize).
|
||||
GetPhysicalSize(myWM);
|
||||
aDesiredSize.SetBlockStartAscent(
|
||||
wrappersDesiredSize.BlockStartAscent() +
|
||||
outerWrapperFrame->BStart(aReflowState.GetWritingMode(),
|
||||
contentBoxISize));
|
||||
contentBoxSize));
|
||||
}
|
||||
|
||||
LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize);
|
||||
|
|
|
@ -263,11 +263,11 @@ TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder,
|
|||
nsIFrame* aBlockFrame)
|
||||
: mContentArea(aBlockFrame->GetWritingMode(),
|
||||
aBlockFrame->GetContentRectRelativeToSelf(),
|
||||
aBlockFrame->GetRect().width)
|
||||
aBlockFrame->GetSize())
|
||||
, mBuilder(aBuilder)
|
||||
, mBlock(aBlockFrame)
|
||||
, mScrollableFrame(nsLayoutUtils::GetScrollableFrameFor(aBlockFrame))
|
||||
, mBlockWidth(aBlockFrame->GetRect().width)
|
||||
, mBlockSize(aBlockFrame->GetSize())
|
||||
, mBlockWM(aBlockFrame->GetWritingMode())
|
||||
, mAdjustForPixelSnapping(false)
|
||||
{
|
||||
|
@ -296,9 +296,12 @@ TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder,
|
|||
// to pixel snapping behaviour in our scrolling code.
|
||||
mAdjustForPixelSnapping = mCanHaveInlineAxisScrollbar;
|
||||
}
|
||||
// Use a null containerSize to convert a vector from logical to physical.
|
||||
const nsSize nullContainerSize;
|
||||
mContentArea.MoveBy(mBlockWM,
|
||||
LogicalPoint(mBlockWM,
|
||||
mScrollableFrame->GetScrollPosition(), 0));
|
||||
mScrollableFrame->GetScrollPosition(),
|
||||
nullContainerSize));
|
||||
nsIFrame* scrollFrame = do_QueryFrame(mScrollableFrame);
|
||||
scrollFrame->AddStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
|
||||
}
|
||||
|
@ -394,7 +397,7 @@ TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame,
|
|||
LogicalRect borderRect(mBlockWM,
|
||||
nsRect(aFrame->GetOffsetTo(mBlock),
|
||||
aFrame->GetSize()),
|
||||
mBlockWidth);
|
||||
mBlockSize);
|
||||
nscoord istartOverlap = std::max(
|
||||
aInsideMarkersArea.IStart(mBlockWM) - borderRect.IStart(mBlockWM), 0);
|
||||
nscoord iendOverlap = std::max(
|
||||
|
@ -468,9 +471,9 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine,
|
|||
bool suppressIEnd = mIEnd.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
|
||||
if (mCanHaveInlineAxisScrollbar) {
|
||||
LogicalPoint pos(mBlockWM, mScrollableFrame->GetScrollPosition(),
|
||||
mBlockWidth);
|
||||
mBlockSize);
|
||||
LogicalRect scrollRange(mBlockWM, mScrollableFrame->GetScrollRange(),
|
||||
mBlockWidth);
|
||||
mBlockSize);
|
||||
// No ellipsing when nothing to scroll to on that side (this includes
|
||||
// overflow:auto that doesn't trigger a horizontal scrollbar).
|
||||
if (pos.I(mBlockWM) <= scrollRange.IStart(mBlockWM)) {
|
||||
|
@ -487,7 +490,7 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine,
|
|||
InflateIStart(mBlockWM, &contentArea, scrollAdjust);
|
||||
InflateIEnd(mBlockWM, &contentArea, scrollAdjust);
|
||||
LogicalRect lineRect(mBlockWM, aLine->GetScrollableOverflowArea(),
|
||||
mBlockWidth);
|
||||
mBlockSize);
|
||||
const bool istartOverflow =
|
||||
!suppressIStart && lineRect.IStart(mBlockWM) < contentArea.IStart(mBlockWM);
|
||||
const bool iendOverflow =
|
||||
|
@ -760,8 +763,8 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine,
|
|||
aLine->BStart(), mIStart.mIntrinsicISize, aLine->BSize());
|
||||
nsPoint offset = mBuilder->ToReferenceFrame(mBlock);
|
||||
nsRect markerRect =
|
||||
markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockWidth) + offset;
|
||||
ClipMarker(mContentArea.GetPhysicalRect(mBlockWM, mBlockWidth) + offset,
|
||||
markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockSize) + offset;
|
||||
ClipMarker(mContentArea.GetPhysicalRect(mBlockWM, mBlockSize) + offset,
|
||||
markerRect, clipState);
|
||||
nsDisplayItem* marker = new (mBuilder)
|
||||
nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
|
||||
|
@ -777,8 +780,8 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine,
|
|||
mIEnd.mIntrinsicISize, aLine->BSize());
|
||||
nsPoint offset = mBuilder->ToReferenceFrame(mBlock);
|
||||
nsRect markerRect =
|
||||
markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockWidth) + offset;
|
||||
ClipMarker(mContentArea.GetPhysicalRect(mBlockWM, mBlockWidth) + offset,
|
||||
markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockSize) + offset;
|
||||
ClipMarker(mContentArea.GetPhysicalRect(mBlockWM, mBlockSize) + offset,
|
||||
markerRect, clipState);
|
||||
nsDisplayItem* marker = new (mBuilder)
|
||||
nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
|
||||
|
|
|
@ -117,7 +117,7 @@ class TextOverflow {
|
|||
return LogicalRect(mBlockWM,
|
||||
aFrame->GetScrollableOverflowRect() +
|
||||
aFrame->GetOffsetTo(mBlock),
|
||||
mBlockWidth);
|
||||
mBlockSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,7 +210,7 @@ class TextOverflow {
|
|||
nsIFrame* mBlock;
|
||||
nsIScrollableFrame* mScrollableFrame;
|
||||
nsDisplayList mMarkerList;
|
||||
nscoord mBlockWidth;
|
||||
nsSize mBlockSize;
|
||||
WritingMode mBlockWM;
|
||||
bool mCanHaveInlineAxisScrollbar;
|
||||
bool mAdjustForPixelSnapping;
|
||||
|
|
|
@ -641,27 +641,29 @@ public:
|
|||
{ }
|
||||
|
||||
// Construct from a writing mode and a physical point, within a given
|
||||
// containing rectangle's width (defining the conversion between LTR
|
||||
// and RTL coordinates).
|
||||
// containing rectangle's size (defining the conversion between LTR
|
||||
// and RTL coordinates, and between TTB and BTT coordinates).
|
||||
LogicalPoint(WritingMode aWritingMode,
|
||||
const nsPoint& aPoint,
|
||||
nscoord aContainerWidth)
|
||||
const nsSize& aContainerSize)
|
||||
#ifdef DEBUG
|
||||
: mWritingMode(aWritingMode)
|
||||
#endif
|
||||
{
|
||||
if (aWritingMode.IsVertical()) {
|
||||
I() = aPoint.y;
|
||||
B() = aWritingMode.IsVerticalLR() ? aPoint.x : aContainerWidth - aPoint.x;
|
||||
I() = aWritingMode.IsBidiLTR() ? aPoint.y
|
||||
: aContainerSize.height - aPoint.y;
|
||||
B() = aWritingMode.IsVerticalLR() ? aPoint.x
|
||||
: aContainerSize.width - aPoint.x;
|
||||
} else {
|
||||
I() = aWritingMode.IsBidiLTR() ? aPoint.x : aContainerWidth - aPoint.x;
|
||||
I() = aWritingMode.IsBidiLTR() ? aPoint.x
|
||||
: aContainerSize.width - aPoint.x;
|
||||
B() = aPoint.y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read-only (const) access to the coordinates, in both logical
|
||||
* and physical terms.
|
||||
* Read-only (const) access to the logical coordinates.
|
||||
*/
|
||||
nscoord I(WritingMode aWritingMode) const // inline-axis
|
||||
{
|
||||
|
@ -674,21 +676,6 @@ public:
|
|||
return mPoint.y;
|
||||
}
|
||||
|
||||
nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
if (aWritingMode.IsVertical()) {
|
||||
return aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B();
|
||||
} else {
|
||||
return aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I();
|
||||
}
|
||||
}
|
||||
nscoord Y(WritingMode aWritingMode) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
return aWritingMode.IsVertical() ? I() : B();
|
||||
}
|
||||
|
||||
/**
|
||||
* These non-const accessors return a reference (lvalue) that can be
|
||||
* assigned to by callers.
|
||||
|
@ -709,14 +696,17 @@ public:
|
|||
* converted according to our writing mode.
|
||||
*/
|
||||
nsPoint GetPhysicalPoint(WritingMode aWritingMode,
|
||||
nscoord aContainerWidth) const
|
||||
const nsSize& aContainerSize) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
if (aWritingMode.IsVertical()) {
|
||||
return nsPoint(aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B(),
|
||||
I());
|
||||
return nsPoint(aWritingMode.IsVerticalLR()
|
||||
? B() : aContainerSize.width - B(),
|
||||
aWritingMode.IsBidiLTR()
|
||||
? I() : aContainerSize.height - I());
|
||||
} else {
|
||||
return nsPoint(aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I(),
|
||||
return nsPoint(aWritingMode.IsBidiLTR()
|
||||
? I() : aContainerSize.width - I(),
|
||||
B());
|
||||
}
|
||||
}
|
||||
|
@ -725,13 +715,13 @@ public:
|
|||
* Return the equivalent point in a different writing mode.
|
||||
*/
|
||||
LogicalPoint ConvertTo(WritingMode aToMode, WritingMode aFromMode,
|
||||
nscoord aContainerWidth) const
|
||||
const nsSize& aContainerSize) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aFromMode);
|
||||
return aToMode == aFromMode ?
|
||||
*this : LogicalPoint(aToMode,
|
||||
GetPhysicalPoint(aFromMode, aContainerWidth),
|
||||
aContainerWidth);
|
||||
GetPhysicalPoint(aFromMode, aContainerSize),
|
||||
aContainerSize);
|
||||
}
|
||||
|
||||
bool operator==(const LogicalPoint& aOther) const
|
||||
|
@ -945,7 +935,7 @@ public:
|
|||
// optimization for non-DEBUG builds where LogicalSize doesn't store
|
||||
// the writing mode
|
||||
return (aToMode == aFromMode || !aToMode.IsOrthogonalTo(aFromMode))
|
||||
? *this : LogicalSize(aToMode, BSize(), ISize());
|
||||
? *this : LogicalSize(aToMode, BSize(), ISize());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1215,16 +1205,16 @@ public:
|
|||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
return aWritingMode.IsVertical()
|
||||
? (aWritingMode.IsVerticalLR()
|
||||
? (aWritingMode.IsBidiLTR()
|
||||
? nsMargin(IStart(), BEnd(), IEnd(), BStart())
|
||||
: nsMargin(IEnd(), BEnd(), IStart(), BStart()))
|
||||
: (aWritingMode.IsBidiLTR()
|
||||
? nsMargin(IStart(), BStart(), IEnd(), BEnd())
|
||||
: nsMargin(IEnd(), BStart(), IStart(), BEnd())))
|
||||
: (aWritingMode.IsBidiLTR()
|
||||
? nsMargin(BStart(), IEnd(), BEnd(), IStart())
|
||||
: nsMargin(BStart(), IStart(), BEnd(), IEnd()));
|
||||
? (aWritingMode.IsVerticalLR()
|
||||
? (aWritingMode.IsBidiLTR()
|
||||
? nsMargin(IStart(), BEnd(), IEnd(), BStart())
|
||||
: nsMargin(IEnd(), BEnd(), IStart(), BStart()))
|
||||
: (aWritingMode.IsBidiLTR()
|
||||
? nsMargin(IStart(), BStart(), IEnd(), BEnd())
|
||||
: nsMargin(IEnd(), BStart(), IStart(), BEnd())))
|
||||
: (aWritingMode.IsBidiLTR()
|
||||
? nsMargin(BStart(), IEnd(), BEnd(), IStart())
|
||||
: nsMargin(BStart(), IStart(), BEnd(), IEnd()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1383,28 +1373,23 @@ public:
|
|||
|
||||
LogicalRect(WritingMode aWritingMode,
|
||||
const nsRect& aRect,
|
||||
nscoord aContainerWidth)
|
||||
const nsSize& aContainerSize)
|
||||
#ifdef DEBUG
|
||||
: mWritingMode(aWritingMode)
|
||||
#endif
|
||||
{
|
||||
if (aWritingMode.IsVertical()) {
|
||||
if (aWritingMode.IsVerticalLR()) {
|
||||
mRect.y = aRect.x;
|
||||
} else {
|
||||
mRect.y = aContainerWidth - aRect.XMost();
|
||||
}
|
||||
mRect.y = aWritingMode.IsVerticalLR()
|
||||
? aRect.x : aContainerSize.width - aRect.XMost();
|
||||
mRect.x = aWritingMode.IsBidiLTR()
|
||||
? aRect.y : aContainerSize.height - aRect.YMost();
|
||||
mRect.height = aRect.width;
|
||||
mRect.x = aRect.y;
|
||||
mRect.width = aRect.height;
|
||||
} else {
|
||||
if (aWritingMode.IsBidiLTR()) {
|
||||
mRect.x = aRect.x;
|
||||
} else {
|
||||
mRect.x = aContainerWidth - aRect.XMost();
|
||||
}
|
||||
mRect.width = aRect.width;
|
||||
mRect.x = aWritingMode.IsBidiLTR()
|
||||
? aRect.x : aContainerSize.width - aRect.XMost();
|
||||
mRect.y = aRect.y;
|
||||
mRect.width = aRect.width;
|
||||
mRect.height = aRect.height;
|
||||
}
|
||||
}
|
||||
|
@ -1472,25 +1457,27 @@ public:
|
|||
/**
|
||||
* Accessors for line-relative coordinates
|
||||
*/
|
||||
nscoord LineLeft(WritingMode aWritingMode, nscoord aContainerWidth) const
|
||||
nscoord LineLeft(WritingMode aWritingMode,
|
||||
const nsSize& aContainerSize) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
if (aWritingMode.IsVertical()) {
|
||||
return IStart(); // sideways-left will require aContainerHeight
|
||||
} else {
|
||||
return aWritingMode.IsBidiLTR() ? IStart()
|
||||
: aContainerWidth - IEnd();
|
||||
if (aWritingMode.IsBidiLTR()) {
|
||||
return IStart();
|
||||
}
|
||||
nscoord containerISize =
|
||||
aWritingMode.IsVertical() ? aContainerSize.height : aContainerSize.width;
|
||||
return containerISize - IEnd();
|
||||
}
|
||||
nscoord LineRight(WritingMode aWritingMode, nscoord aContainerWidth) const
|
||||
nscoord LineRight(WritingMode aWritingMode,
|
||||
const nsSize& aContainerSize) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
if (aWritingMode.IsVertical()) {
|
||||
return IEnd(); // sideways-left will require aContainerHeight
|
||||
} else {
|
||||
return aWritingMode.IsBidiLTR() ? IEnd()
|
||||
: aContainerWidth - IStart();
|
||||
if (aWritingMode.IsBidiLTR()) {
|
||||
return IEnd();
|
||||
}
|
||||
nscoord containerISize =
|
||||
aWritingMode.IsVertical() ? aContainerSize.height : aContainerSize.width;
|
||||
return containerISize - IStart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1508,10 +1495,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
nscoord Y(WritingMode aWritingMode) const
|
||||
nscoord Y(WritingMode aWritingMode, nscoord aContainerHeight) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
return aWritingMode.IsVertical() ? mRect.X() : mRect.Y();
|
||||
if (aWritingMode.IsVertical()) {
|
||||
return aWritingMode.IsBidiLTR() ? mRect.X()
|
||||
: aContainerHeight - mRect.XMost();
|
||||
} else {
|
||||
return mRect.Y();
|
||||
}
|
||||
}
|
||||
|
||||
nscoord Width(WritingMode aWritingMode) const
|
||||
|
@ -1538,10 +1530,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
nscoord YMost(WritingMode aWritingMode) const
|
||||
nscoord YMost(WritingMode aWritingMode, nscoord aContainerHeight) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
return aWritingMode.IsVertical() ? mRect.XMost() : mRect.YMost();
|
||||
if (aWritingMode.IsVertical()) {
|
||||
return aWritingMode.IsBidiLTR() ? mRect.XMost()
|
||||
: aContainerHeight - mRect.x;
|
||||
} else {
|
||||
return mRect.YMost();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
|
@ -1643,19 +1640,21 @@ public:
|
|||
|
||||
/**
|
||||
* Return an nsRect containing our physical coordinates within the given
|
||||
* container width
|
||||
* container size.
|
||||
*/
|
||||
nsRect GetPhysicalRect(WritingMode aWritingMode,
|
||||
nscoord aContainerWidth) const
|
||||
const nsSize& aContainerSize) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aWritingMode);
|
||||
if (aWritingMode.IsVertical()) {
|
||||
return nsRect(aWritingMode.IsVerticalLR() ?
|
||||
BStart() : aContainerWidth - BEnd(),
|
||||
IStart(), BSize(), ISize());
|
||||
return nsRect(aWritingMode.IsVerticalLR()
|
||||
? BStart() : aContainerSize.width - BEnd(),
|
||||
aWritingMode.IsBidiLTR()
|
||||
? IStart() : aContainerSize.height - IEnd(),
|
||||
BSize(), ISize());
|
||||
} else {
|
||||
return nsRect(aWritingMode.IsBidiLTR() ?
|
||||
IStart() : aContainerWidth - IEnd(),
|
||||
return nsRect(aWritingMode.IsBidiLTR()
|
||||
? IStart() : aContainerSize.width - IEnd(),
|
||||
BStart(), ISize(), BSize());
|
||||
}
|
||||
}
|
||||
|
@ -1664,12 +1663,12 @@ public:
|
|||
* Return a LogicalRect representing this rect in a different writing mode
|
||||
*/
|
||||
LogicalRect ConvertTo(WritingMode aToMode, WritingMode aFromMode,
|
||||
nscoord aContainerWidth) const
|
||||
const nsSize& aContainerSize) const
|
||||
{
|
||||
CHECK_WRITING_MODE(aFromMode);
|
||||
return aToMode == aFromMode ?
|
||||
*this : LogicalRect(aToMode, GetPhysicalRect(aFromMode, aContainerWidth),
|
||||
aContainerWidth);
|
||||
*this : LogicalRect(aToMode, GetPhysicalRect(aFromMode, aContainerSize),
|
||||
aContainerSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -408,7 +408,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
|
|||
// Don't split if told not to (e.g. for fixed frames)
|
||||
&& (aDelegatingFrame->GetType() != nsGkAtoms::inlineFrame)
|
||||
//XXX we don't handle splitting frames for inline absolute containing blocks yet
|
||||
&& (aKidFrame->GetLogicalRect(aContainingBlock.width).BStart(wm) <=
|
||||
&& (aKidFrame->GetLogicalRect(aContainingBlock.Size()).BStart(wm) <=
|
||||
aReflowState.AvailableBSize());
|
||||
// Don't split things below the fold. (Ideally we shouldn't *have*
|
||||
// anything totally below the fold, but we can't position frames
|
||||
|
@ -468,12 +468,8 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
|
|||
margin.BStart(outerWM),
|
||||
kidSize.ISize(outerWM), kidSize.BSize(outerWM));
|
||||
nsRect r =
|
||||
rect.GetPhysicalRect(outerWM, logicalCBSize.Width(wm) +
|
||||
border.LeftRight(outerWM));
|
||||
// XXX hack to correct for lack of bidi support in vertical mode
|
||||
if (outerWM.IsVertical() && !outerWM.IsBidiLTR()) {
|
||||
r.y = logicalCBSize.Height(wm) + border.TopBottom(outerWM) - r.YMost();
|
||||
}
|
||||
rect.GetPhysicalRect(outerWM, logicalCBSize.GetPhysicalSize(wm) +
|
||||
border.Size(outerWM).GetPhysicalSize(outerWM));
|
||||
|
||||
// Offset the frame rect by the given origin of the absolute containing block.
|
||||
// If the frame is auto-positioned on both sides of an axis, it will be
|
||||
|
|
|
@ -1244,9 +1244,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
// bullets that are placed next to a child block (bug 92896)
|
||||
|
||||
// Tall bullets won't look particularly nice here...
|
||||
LogicalRect bbox = bullet->GetLogicalRect(wm, metrics.Width());
|
||||
LogicalRect bbox = bullet->GetLogicalRect(wm, metrics.PhysicalSize());
|
||||
bbox.BStart(wm) = position.mBaseline - metrics.BlockStartAscent();
|
||||
bullet->SetRect(wm, bbox, metrics.Width());
|
||||
bullet->SetRect(wm, bbox, metrics.PhysicalSize());
|
||||
}
|
||||
// Otherwise just leave the bullet where it is, up against our
|
||||
// block-start padding.
|
||||
|
@ -1259,12 +1259,11 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
ComputeFinalSize(*reflowState, state, aMetrics, &blockEndEdgeOfChildren);
|
||||
|
||||
// If the block direction is right-to-left, we need to update the bounds of
|
||||
// lines that were placed relative to mContainerWidth during reflow, as
|
||||
// we typically do not know the true container width (block-dir size of the
|
||||
// finished paragraph/block) until we've reflowed all its children. So we
|
||||
// use a "fake" mContainerWidth during reflow (see nsBlockReflowState's
|
||||
// constructor) and then fix up the positions of the lines here, once the
|
||||
// final block size is known.
|
||||
// lines that were placed relative to mContainerSize during reflow, as
|
||||
// we typically do not know the true container size until we've reflowed all
|
||||
// its children. So we use a dummy mContainerSize during reflow (see
|
||||
// nsBlockReflowState's constructor) and then fix up the positions of the
|
||||
// lines here, once the final block size is known.
|
||||
//
|
||||
// Note that writing-mode:vertical-rl is the only case where the block
|
||||
// logical direction progresses in a negative physical direction, and
|
||||
|
@ -1272,12 +1271,12 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
// of the coordinate space in order to translate between the logical and
|
||||
// physical origins.
|
||||
if (wm.IsVerticalRL()) {
|
||||
nscoord containerWidth = aMetrics.Width();
|
||||
nscoord deltaX = containerWidth - state.ContainerWidth();
|
||||
if (deltaX) {
|
||||
nsSize containerSize = aMetrics.PhysicalSize();
|
||||
nscoord deltaX = containerSize.width - state.ContainerSize().width;
|
||||
if (deltaX != 0) {
|
||||
for (line_iterator line = begin_lines(), end = end_lines();
|
||||
line != end; line++) {
|
||||
UpdateLineContainerWidth(line, containerWidth);
|
||||
UpdateLineContainerSize(line, containerSize);
|
||||
}
|
||||
for (nsIFrame* f : mFloats) {
|
||||
nsPoint physicalDelta(deltaX, 0);
|
||||
|
@ -1933,9 +1932,9 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
|
|||
// Scrollable overflow should be sufficient for things that affect
|
||||
// layout.
|
||||
WritingMode wm = aState.mReflowState.GetWritingMode();
|
||||
nscoord containerWidth = aState.ContainerWidth();
|
||||
nsSize containerSize = aState.ContainerSize();
|
||||
LogicalRect overflow = aLine->GetOverflowArea(eScrollableOverflow, wm,
|
||||
containerWidth);
|
||||
containerSize);
|
||||
nscoord lineBCoordCombinedBefore = overflow.BStart(wm) + aDeltaBCoord;
|
||||
nscoord lineBCoordCombinedAfter = lineBCoordCombinedBefore +
|
||||
overflow.BSize(wm);
|
||||
|
@ -2176,11 +2175,11 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
PropagateFloatDamage(aState, line, deltaBCoord);
|
||||
}
|
||||
|
||||
// If the container width has changed reset the container width. If the
|
||||
// If the container size has changed, reset mContainerSize. If the
|
||||
// line's writing mode is not ltr, or if the line is not left-aligned, also
|
||||
// mark the line dirty.
|
||||
if (aState.ContainerWidth() != line->mContainerWidth) {
|
||||
line->mContainerWidth = aState.ContainerWidth();
|
||||
if (aState.ContainerSize() != line->mContainerSize) {
|
||||
line->mContainerSize = aState.ContainerSize();
|
||||
|
||||
bool isLastLine = line == mLines.back() &&
|
||||
!GetNextInFlow() &&
|
||||
|
@ -2817,26 +2816,26 @@ nsBlockFrame::SlideLine(nsBlockReflowState& aState,
|
|||
NS_PRECONDITION(aDeltaBCoord != 0, "why slide a line nowhere?");
|
||||
|
||||
// Adjust line state
|
||||
aLine->SlideBy(aDeltaBCoord, aState.ContainerWidth());
|
||||
aLine->SlideBy(aDeltaBCoord, aState.ContainerSize());
|
||||
|
||||
// Adjust the frames in the line
|
||||
MoveChildFramesOfLine(aLine, aDeltaBCoord);
|
||||
}
|
||||
|
||||
void
|
||||
nsBlockFrame::UpdateLineContainerWidth(nsLineBox* aLine,
|
||||
nscoord aNewContainerWidth)
|
||||
nsBlockFrame::UpdateLineContainerSize(nsLineBox* aLine,
|
||||
const nsSize& aNewContainerSize)
|
||||
{
|
||||
if (aNewContainerWidth == aLine->mContainerWidth) {
|
||||
if (aNewContainerSize == aLine->mContainerSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust line state
|
||||
nscoord widthDelta = aLine->UpdateContainerWidth(aNewContainerWidth);
|
||||
nsSize sizeDelta = aLine->UpdateContainerSize(aNewContainerSize);
|
||||
|
||||
// Changing container width only matters if writing mode is vertical-rl
|
||||
if (GetWritingMode().IsVerticalRL()) {
|
||||
MoveChildFramesOfLine(aLine, widthDelta);
|
||||
MoveChildFramesOfLine(aLine, sizeDelta.width);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3682,7 +3681,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
|||
WritingMode lineWM = GetWritingMode(aLine->mFirstChild);
|
||||
LogicalRect lineRect =
|
||||
aFloatAvailableSpace.mRect.ConvertTo(lineWM, outerWM,
|
||||
aState.ContainerWidth());
|
||||
aState.ContainerSize());
|
||||
|
||||
nscoord iStart = lineRect.IStart(lineWM);
|
||||
nscoord availISize = lineRect.ISize(lineWM);
|
||||
|
@ -6155,14 +6154,14 @@ nsBlockFrame::ReflowPushedFloats(nsBlockReflowState& aState,
|
|||
|
||||
void
|
||||
nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager, WritingMode aWM,
|
||||
nscoord aContainerWidth)
|
||||
const nsSize& aContainerSize)
|
||||
{
|
||||
// Recover our own floats
|
||||
nsIFrame* stop = nullptr; // Stop before we reach pushed floats that
|
||||
// belong to our next-in-flow
|
||||
for (nsIFrame* f = mFloats.FirstChild(); f && f != stop; f = f->GetNextSibling()) {
|
||||
LogicalRect region = nsFloatManager::GetRegionFor(aWM, f, aContainerWidth);
|
||||
aFloatManager.AddFloat(f, region, aWM, aContainerWidth);
|
||||
LogicalRect region = nsFloatManager::GetRegionFor(aWM, f, aContainerSize);
|
||||
aFloatManager.AddFloat(f, region, aWM, aContainerSize);
|
||||
if (!stop && f->GetNextInFlow())
|
||||
stop = f->GetNextInFlow();
|
||||
}
|
||||
|
@ -6170,13 +6169,13 @@ nsBlockFrame::RecoverFloats(nsFloatManager& aFloatManager, WritingMode aWM,
|
|||
// Recurse into our overflow container children
|
||||
for (nsIFrame* oc = GetFirstChild(kOverflowContainersList);
|
||||
oc; oc = oc->GetNextSibling()) {
|
||||
RecoverFloatsFor(oc, aFloatManager, aWM, aContainerWidth);
|
||||
RecoverFloatsFor(oc, aFloatManager, aWM, aContainerSize);
|
||||
}
|
||||
|
||||
// Recurse into our normal children
|
||||
for (nsBlockFrame::line_iterator line = begin_lines(); line != end_lines(); ++line) {
|
||||
if (line->IsBlock()) {
|
||||
RecoverFloatsFor(line->mFirstChild, aFloatManager, aWM, aContainerWidth);
|
||||
RecoverFloatsFor(line->mFirstChild, aFloatManager, aWM, aContainerSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6185,7 +6184,7 @@ void
|
|||
nsBlockFrame::RecoverFloatsFor(nsIFrame* aFrame,
|
||||
nsFloatManager& aFloatManager,
|
||||
WritingMode aWM,
|
||||
nscoord aContainerWidth)
|
||||
const nsSize& aContainerSize)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "null frame");
|
||||
// Only blocks have floats
|
||||
|
@ -6198,11 +6197,11 @@ nsBlockFrame::RecoverFloatsFor(nsIFrame* aFrame,
|
|||
// accordingly so that we consider relatively positioned frames
|
||||
// at their original position.
|
||||
|
||||
LogicalRect rect(aWM, block->GetNormalRect(), aContainerWidth);
|
||||
nscoord lineLeft = rect.LineLeft(aWM, aContainerWidth);
|
||||
LogicalRect rect(aWM, block->GetNormalRect(), aContainerSize);
|
||||
nscoord lineLeft = rect.LineLeft(aWM, aContainerSize);
|
||||
nscoord blockStart = rect.BStart(aWM);
|
||||
aFloatManager.Translate(lineLeft, blockStart);
|
||||
block->RecoverFloats(aFloatManager, aWM, aContainerWidth);
|
||||
block->RecoverFloats(aFloatManager, aWM, aContainerSize);
|
||||
aFloatManager.Translate(-lineLeft, -blockStart);
|
||||
}
|
||||
}
|
||||
|
@ -7051,7 +7050,7 @@ nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
|
|||
aBulletFrame->SetRect(wm, LogicalRect(wm, iStart, bStart,
|
||||
aMetrics.ISize(wm),
|
||||
aMetrics.BSize(wm)),
|
||||
aState.ContainerWidth());
|
||||
aState.ContainerSize());
|
||||
aBulletFrame->DidReflow(aState.mPresContext, &aState.mReflowState,
|
||||
nsDidReflowStatus::FINISHED);
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче