This commit is contained in:
Ryan VanderMeulen 2015-07-16 14:53:39 -04:00
Родитель ad4d03f6ef c5f205c7ca
Коммит 5f9582530e
177 изменённых файлов: 2522 добавлений и 1900 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

499
gfx/thebes/gfxWindowsPlatform.cpp Normal file → Executable file
Просмотреть файл

@ -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,
&paramInfo,
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);
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше