зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
4663ddb53a
|
@ -553,6 +553,11 @@ ARIAGridCellAccessible::NativeAttributes() {
|
|||
Accessible* thisRow = Row();
|
||||
if (!thisRow) return attributes.forget();
|
||||
|
||||
int32_t rowIdx = RowIndexFor(thisRow);
|
||||
if (rowIdx == -1) { // error
|
||||
return attributes.forget();
|
||||
}
|
||||
|
||||
int32_t colIdx = 0, colCount = 0;
|
||||
uint32_t childCount = thisRow->ChildCount();
|
||||
for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
|
||||
|
@ -565,8 +570,6 @@ ARIAGridCellAccessible::NativeAttributes() {
|
|||
colCount++;
|
||||
}
|
||||
|
||||
int32_t rowIdx = RowIndexFor(thisRow);
|
||||
|
||||
nsAutoString stringIdx;
|
||||
stringIdx.AppendInt(rowIdx * colCount + colIdx);
|
||||
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
|
||||
|
|
|
@ -114,6 +114,7 @@ class ARIAGridCellAccessible : public HyperTextAccessibleWrap,
|
|||
|
||||
/**
|
||||
* Return index of the given row.
|
||||
* Returns -1 upon error.
|
||||
*/
|
||||
int32_t RowIndexFor(Accessible* aRow) const;
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ XULMenuitemAccessibleWrap::get_accKeyboardShortcut(
|
|||
pszKeyboardShortcut);
|
||||
}
|
||||
|
||||
if (IsDefunct()) {
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
}
|
||||
|
||||
KeyBinding keyBinding = AccessKey();
|
||||
if (keyBinding.IsEmpty()) {
|
||||
return S_FALSE;
|
||||
|
|
|
@ -56,6 +56,7 @@ skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug
|
|||
[browser_aboutdebugging_devtoolstoolbox_reload.js]
|
||||
[browser_aboutdebugging_devtoolstoolbox_shortcuts.js]
|
||||
skip-if = (os == "win" && ccov) # Bug 1521349
|
||||
[browser_aboutdebugging_devtoolstoolbox_tooltip_markupview.js]
|
||||
[browser_aboutdebugging_navigate.js]
|
||||
[browser_aboutdebugging_persist_connection.js]
|
||||
[browser_aboutdebugging_routes.js]
|
||||
|
|
|
@ -14,37 +14,20 @@ add_task(async function() {
|
|||
prepareCollapsibilitiesTest();
|
||||
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
const { devtoolsBrowser, devtoolsTab } =
|
||||
await openAboutDevtoolsToolbox(document, tab, window);
|
||||
|
||||
info("Show about:devtools-toolbox page");
|
||||
const target = findDebugTargetByText("about:debugging", document);
|
||||
ok(target, "about:debugging tab target appeared");
|
||||
const inspectButton = target.querySelector(".js-debug-target-inspect-button");
|
||||
ok(inspectButton, "Inspect button for about:debugging appeared");
|
||||
inspectButton.click();
|
||||
await Promise.all([
|
||||
waitUntil(() => tab.nextElementSibling),
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-ready"),
|
||||
]);
|
||||
|
||||
info("Wait for about:devtools-toolbox tab will be selected");
|
||||
const devtoolsTab = tab.nextElementSibling;
|
||||
await waitUntil(() => gBrowser.selectedTab === devtoolsTab);
|
||||
info("Check whether the menu item which opens devtools is disabled");
|
||||
const rootDocument = devtoolsTab.ownerDocument;
|
||||
await assertContextMenu(rootDocument, gBrowser.selectedBrowser,
|
||||
await assertContextMenu(rootDocument, devtoolsBrowser,
|
||||
".debug-target-info", false);
|
||||
|
||||
info("Force to select about:debugging page");
|
||||
gBrowser.selectedTab = tab;
|
||||
info("Check whether the menu item which opens devtools is enabled");
|
||||
await assertContextMenu(rootDocument, gBrowser.selectedBrowser, "#mount", true);
|
||||
await assertContextMenu(rootDocument, devtoolsBrowser, "#mount", true);
|
||||
|
||||
await removeTab(devtoolsTab);
|
||||
await Promise.all([
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-destroyed"),
|
||||
]);
|
||||
await closeAboutDevtoolsToolbox(devtoolsTab, window);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
|
|
|
@ -14,51 +14,23 @@ add_task(async function() {
|
|||
prepareCollapsibilitiesTest();
|
||||
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
|
||||
info("Show about:devtools-toolbox page");
|
||||
const target = findDebugTargetByText("about:debugging", document);
|
||||
ok(target, "about:debugging tab target appeared");
|
||||
const inspectButton = target.querySelector(".js-debug-target-inspect-button");
|
||||
ok(inspectButton, "Inspect button for about:debugging appeared");
|
||||
inspectButton.click();
|
||||
await Promise.all([
|
||||
waitUntil(() => tab.nextElementSibling),
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-ready"),
|
||||
]);
|
||||
|
||||
info("Wait for about:devtools-toolbox tab will be selected");
|
||||
const devtoolsTab = tab.nextElementSibling;
|
||||
await waitUntil(() => gBrowser.selectedTab === devtoolsTab);
|
||||
const { devtoolsDocument, devtoolsTab, devtoolsWindow } =
|
||||
await openAboutDevtoolsToolbox(document, tab, window);
|
||||
|
||||
info("Select inspector tool");
|
||||
const devtoolsBrowser = gBrowser.selectedBrowser;
|
||||
const devtoolsDocument = devtoolsBrowser.contentDocument;
|
||||
const devtoolsWindow = devtoolsBrowser.contentWindow;
|
||||
const toolbox = getToolbox(devtoolsWindow);
|
||||
await toolbox.selectTool("inspector");
|
||||
|
||||
info("Show context menu of markup view");
|
||||
const markupFrame = getMarkupViewFrame(devtoolsDocument);
|
||||
const markupDocument = markupFrame.contentDocument;
|
||||
const markupWindow = markupFrame.contentWindow;
|
||||
const markupDocument = toolbox.getPanel("inspector").markup.doc;
|
||||
EventUtils.synthesizeMouseAtCenter(markupDocument.body,
|
||||
{ type: "contextmenu" },
|
||||
markupWindow);
|
||||
markupDocument.ownerGlobal);
|
||||
|
||||
info("Check whether proper context menu of markup view will be shown");
|
||||
await waitUntil(() => devtoolsDocument.querySelector("#node-menu-edithtml"));
|
||||
ok(true, "Context menu of markup view should be shown");
|
||||
|
||||
await removeTab(devtoolsTab);
|
||||
await Promise.all([
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-destroyed"),
|
||||
]);
|
||||
await closeAboutDevtoolsToolbox(devtoolsTab, window);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
function getMarkupViewFrame(rootDocument) {
|
||||
const inspectorFrame = rootDocument.querySelector("#toolbox-panel-iframe-inspector");
|
||||
return inspectorFrame.contentDocument.querySelector("#markup-box iframe");
|
||||
}
|
||||
|
|
|
@ -14,22 +14,8 @@ add_task(async function() {
|
|||
prepareCollapsibilitiesTest();
|
||||
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
const { devtoolsTab } = await openAboutDevtoolsToolbox(document, tab, window);
|
||||
|
||||
info("Show about:devtools-toolbox page");
|
||||
const target = findDebugTargetByText("about:debugging", document);
|
||||
ok(target, "about:debugging tab target appeared");
|
||||
const inspectButton = target.querySelector(".js-debug-target-inspect-button");
|
||||
ok(inspectButton, "Inspect button for about:debugging appeared");
|
||||
inspectButton.click();
|
||||
await Promise.all([
|
||||
waitUntil(() => tab.nextElementSibling),
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-ready"),
|
||||
]);
|
||||
|
||||
info("Wait for about:devtools-toolbox tab will be selected");
|
||||
const devtoolsTab = tab.nextElementSibling;
|
||||
await waitUntil(() => gBrowser.selectedTab === devtoolsTab);
|
||||
info("Check whether the menu items are disabled");
|
||||
const rootDocument = devtoolsTab.ownerDocument;
|
||||
await assertMenusItems(rootDocument, false);
|
||||
|
@ -39,11 +25,7 @@ add_task(async function() {
|
|||
info("Check whether the menu items are enabled");
|
||||
await assertMenusItems(rootDocument, true);
|
||||
|
||||
await removeTab(devtoolsTab);
|
||||
await Promise.all([
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-destroyed"),
|
||||
]);
|
||||
await closeAboutDevtoolsToolbox(devtoolsTab, window);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
|
|
|
@ -14,26 +14,11 @@ add_task(async function() {
|
|||
prepareCollapsibilitiesTest();
|
||||
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
|
||||
info("Show about:devtools-toolbox page");
|
||||
const target = findDebugTargetByText("about:debugging", document);
|
||||
ok(target, "about:debugging tab target appeared");
|
||||
const inspectButton = target.querySelector(".js-debug-target-inspect-button");
|
||||
ok(inspectButton, "Inspect button for about:debugging appeared");
|
||||
inspectButton.click();
|
||||
await Promise.all([
|
||||
waitUntil(() => tab.nextElementSibling),
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-ready"),
|
||||
]);
|
||||
|
||||
info("Wait for about:devtools-toolbox tab will be selected");
|
||||
const devtoolsTab = tab.nextElementSibling;
|
||||
await waitUntil(() => gBrowser.selectedTab === devtoolsTab);
|
||||
const { devtoolsBrowser, devtoolsTab, devtoolsWindow } =
|
||||
await openAboutDevtoolsToolbox(document, tab, window);
|
||||
|
||||
info("Select webconsole tool");
|
||||
const devtoolsBrowser = gBrowser.selectedBrowser;
|
||||
const toolbox = getToolbox(devtoolsBrowser.contentWindow);
|
||||
const toolbox = getToolbox(devtoolsWindow);
|
||||
await toolbox.selectTool("webconsole");
|
||||
|
||||
info("Reload about:devtools-toolbox page");
|
||||
|
@ -45,10 +30,6 @@ add_task(async function() {
|
|||
ok(devtoolsBrowser.contentDocument.querySelector(".debug-target-info"),
|
||||
"about:devtools-toolbox page displays correctly");
|
||||
|
||||
await removeTab(devtoolsTab);
|
||||
await Promise.all([
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-destroyed"),
|
||||
]);
|
||||
await closeAboutDevtoolsToolbox(devtoolsTab, window);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
|
|
@ -14,35 +14,18 @@ add_task(async function() {
|
|||
prepareCollapsibilitiesTest();
|
||||
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
const { devtoolsBrowser, devtoolsTab } =
|
||||
await openAboutDevtoolsToolbox(document, tab, window);
|
||||
|
||||
info("Show about:devtools-toolbox page");
|
||||
const target = findDebugTargetByText("about:debugging", document);
|
||||
ok(target, "about:debugging tab target appeared");
|
||||
const inspectButton = target.querySelector(".js-debug-target-inspect-button");
|
||||
ok(inspectButton, "Inspect button for about:debugging appeared");
|
||||
inspectButton.click();
|
||||
await Promise.all([
|
||||
waitUntil(() => tab.nextElementSibling),
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-ready"),
|
||||
]);
|
||||
|
||||
info("Wait for about:devtools-toolbox tab will be selected");
|
||||
const devtoolsTab = tab.nextElementSibling;
|
||||
await waitUntil(() => gBrowser.selectedTab === devtoolsTab);
|
||||
info("Check whether the shortcut keys which opens devtools is disabled");
|
||||
await assertShortcutKeys(gBrowser.selectedBrowser, false);
|
||||
await assertShortcutKeys(devtoolsBrowser, false);
|
||||
|
||||
info("Force to select about:debugging page");
|
||||
gBrowser.selectedTab = tab;
|
||||
info("Check whether the shortcut keys which opens devtools is enabled");
|
||||
await assertShortcutKeys(gBrowser.selectedBrowser, true);
|
||||
await assertShortcutKeys(tab.linkedBrowser, true);
|
||||
|
||||
await removeTab(devtoolsTab);
|
||||
await Promise.all([
|
||||
waitForRequestsToSettle(window.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-destroyed"),
|
||||
]);
|
||||
await closeAboutDevtoolsToolbox(devtoolsTab, window);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from helper-collapsibilities.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-collapsibilities.js", this);
|
||||
|
||||
/**
|
||||
* Test tooltip of markup view on about:devtools-toolbox page.
|
||||
*/
|
||||
add_task(async function() {
|
||||
info("Force all debug target panes to be expanded");
|
||||
prepareCollapsibilitiesTest();
|
||||
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
const { devtoolsDocument, devtoolsTab, devtoolsWindow } =
|
||||
await openAboutDevtoolsToolbox(document, tab, window);
|
||||
|
||||
info("Select inspector tool");
|
||||
const toolbox = getToolbox(devtoolsWindow);
|
||||
await toolbox.selectTool("inspector");
|
||||
|
||||
const inspector = toolbox.getPanel("inspector");
|
||||
const markupDocument = inspector.markup.doc;
|
||||
const eventBadge = markupDocument.querySelector(".inspector-badge.interactive");
|
||||
|
||||
info("Check tooltip visibility after clicking on an element in the markup view");
|
||||
await checkTooltipVisibility(inspector, eventBadge, markupDocument.body);
|
||||
|
||||
info("Check tooltip visibility after clicking on an element in the DevTools document");
|
||||
await checkTooltipVisibility(
|
||||
inspector, eventBadge, devtoolsDocument.querySelector(".debug-target-info"));
|
||||
|
||||
info("Check tooltip visibility after clicking on an element in the root document");
|
||||
const rootDocument = devtoolsWindow.windowRoot.ownerGlobal.document;
|
||||
await checkTooltipVisibility(
|
||||
inspector, eventBadge, rootDocument.querySelector("#titlebar"));
|
||||
|
||||
await closeAboutDevtoolsToolbox(devtoolsTab, window);
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
async function checkTooltipVisibility(inspector, elementForShowing, elementForHiding) {
|
||||
info("Show event tooltip");
|
||||
elementForShowing.click();
|
||||
const tooltip = inspector.markup.eventDetailsTooltip;
|
||||
await tooltip.once("shown");
|
||||
is(tooltip.container.classList.contains("tooltip-visible"), true,
|
||||
"The tooltip should be shown");
|
||||
|
||||
info("Hide event tooltip");
|
||||
EventUtils.synthesizeMouse(elementForHiding, 1, 1, {}, elementForHiding.ownerGlobal);
|
||||
await tooltip.once("hidden");
|
||||
is(tooltip.container.classList.contains("tooltip-visible"), false,
|
||||
"Tooltip should be hidden");
|
||||
|
||||
if (inspector._updateProgress) {
|
||||
info("Need to wait for the inspector to update");
|
||||
await inspector.once("inspector-updated");
|
||||
}
|
||||
}
|
|
@ -56,6 +56,40 @@ async function openAboutDebugging(page, win) {
|
|||
return { tab, document, window };
|
||||
}
|
||||
|
||||
async function openAboutDevtoolsToolbox(doc, tab, win) {
|
||||
info("Open about:devtools-toolbox page");
|
||||
const target = findDebugTargetByText("about:debugging", doc);
|
||||
ok(target, "about:debugging tab target appeared");
|
||||
const inspectButton = target.querySelector(".js-debug-target-inspect-button");
|
||||
ok(inspectButton, "Inspect button for about:debugging appeared");
|
||||
inspectButton.click();
|
||||
await Promise.all([
|
||||
waitUntil(() => tab.nextElementSibling),
|
||||
waitForRequestsToSettle(win.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-ready"),
|
||||
]);
|
||||
|
||||
info("Wait for about:devtools-toolbox tab will be selected");
|
||||
const devtoolsTab = tab.nextElementSibling;
|
||||
await waitUntil(() => gBrowser.selectedTab === devtoolsTab);
|
||||
const devtoolsBrowser = gBrowser.selectedBrowser;
|
||||
|
||||
return {
|
||||
devtoolsBrowser,
|
||||
devtoolsDocument: devtoolsBrowser.contentDocument,
|
||||
devtoolsTab,
|
||||
devtoolsWindow: devtoolsBrowser.contentWindow,
|
||||
};
|
||||
}
|
||||
|
||||
async function closeAboutDevtoolsToolbox(devtoolsTab, win) {
|
||||
await removeTab(devtoolsTab);
|
||||
await Promise.all([
|
||||
waitForRequestsToSettle(win.AboutDebugging.store),
|
||||
gDevTools.once("toolbox-destroyed"),
|
||||
]);
|
||||
}
|
||||
|
||||
async function reloadAboutDebugging(tab) {
|
||||
info("reload about:debugging");
|
||||
|
||||
|
|
|
@ -894,7 +894,16 @@ HTMLTooltip.prototype = {
|
|||
},
|
||||
|
||||
_getTopWindow: function() {
|
||||
return this.doc.defaultView.top;
|
||||
const win = this.doc.defaultView;
|
||||
if (win.windowRoot) {
|
||||
// In some situations (e.g. about:devtools-toolbox) the current document is loaded
|
||||
// in a Window instead of a ChromeWindow.
|
||||
// To get access to the topmost ChromeWindow, we need to use the chrome privileged
|
||||
// windowRoot getter.
|
||||
return win.windowRoot.ownerGlobal;
|
||||
}
|
||||
// win.top is used as fallback if we are not in a chrome privileged document.
|
||||
return win.top;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -7520,6 +7520,10 @@ void Document::Destroy() {
|
|||
|
||||
mLayoutHistoryState = nullptr;
|
||||
|
||||
if (mOriginalDocument) {
|
||||
mOriginalDocument->mLatestStaticClone = nullptr;
|
||||
}
|
||||
|
||||
// Shut down our external resource map. We might not need this for
|
||||
// leak-fixing if we fix nsDocumentViewer to do cycle-collection, but
|
||||
// tearing down all those frame trees right now is the right thing to do.
|
||||
|
@ -8892,8 +8896,10 @@ already_AddRefed<Document> Document::CreateStaticClone(
|
|||
if (clonedDoc) {
|
||||
if (IsStaticDocument()) {
|
||||
clonedDoc->mOriginalDocument = mOriginalDocument;
|
||||
mOriginalDocument->mLatestStaticClone = clonedDoc;
|
||||
} else {
|
||||
clonedDoc->mOriginalDocument = this;
|
||||
mLatestStaticClone = clonedDoc;
|
||||
}
|
||||
|
||||
clonedDoc->mOriginalDocument->mStaticCloneCount++;
|
||||
|
|
|
@ -437,7 +437,8 @@ class Document : public nsINode,
|
|||
public nsIScriptObjectPrincipal,
|
||||
public nsIApplicationCacheContainer,
|
||||
public nsStubMutationObserver,
|
||||
public DispatcherTrait {
|
||||
public DispatcherTrait,
|
||||
public SupportsWeakPtr<Document> {
|
||||
protected:
|
||||
explicit Document(const char* aContentType);
|
||||
virtual ~Document();
|
||||
|
@ -450,6 +451,8 @@ class Document : public nsINode,
|
|||
ExternalResourceLoad;
|
||||
typedef net::ReferrerPolicy ReferrerPolicyEnum;
|
||||
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(Document)
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_IID)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -610,6 +613,8 @@ class Document : public nsINode,
|
|||
}
|
||||
nsresult CloneDocHelper(Document* clone) const;
|
||||
|
||||
Document* GetLatestStaticClone() const { return mLatestStaticClone; }
|
||||
|
||||
/**
|
||||
* Signal that the document title may have changed
|
||||
* (see Document::GetTitle).
|
||||
|
@ -4326,6 +4331,11 @@ class Document : public nsINode,
|
|||
// Count of live static clones of this document.
|
||||
uint32_t mStaticCloneCount;
|
||||
|
||||
// If the document is currently printing (or in print preview) this will point
|
||||
// to the current static clone of this document. This is weak since the clone
|
||||
// also has a reference to this document.
|
||||
WeakPtr<Document> mLatestStaticClone;
|
||||
|
||||
// Array of nodes that have been blocked to prevent user tracking.
|
||||
// They most likely have had their nsIChannel canceled by the URL
|
||||
// classifier. (Safebrowsing)
|
||||
|
|
|
@ -41,7 +41,8 @@ bool MaybeCrossOriginObjectMixins::IsPlatformObjectSameOrigin(JSContext* cx,
|
|||
|
||||
BasePrincipal* subjectPrincipal =
|
||||
BasePrincipal::Cast(nsContentUtils::SubjectPrincipal(cx));
|
||||
nsIPrincipal* objectPrincipal = nsContentUtils::ObjectPrincipal(obj);
|
||||
BasePrincipal* objectPrincipal =
|
||||
BasePrincipal::Cast(nsContentUtils::ObjectPrincipal(obj));
|
||||
|
||||
// The spec effectively has an EqualsConsideringDomain check here,
|
||||
// because the spec has no concept of asymmetric security
|
||||
|
@ -53,11 +54,25 @@ bool MaybeCrossOriginObjectMixins::IsPlatformObjectSameOrigin(JSContext* cx,
|
|||
// SubsumesConsideringDomain give the same results and use
|
||||
// EqualsConsideringDomain for the check we actually do, since it's
|
||||
// stricter and more closely matches the spec.
|
||||
//
|
||||
// That said, if the (not very well named)
|
||||
// OriginAttributes::IsRestrictOpenerAccessForFPI() method returns
|
||||
// false, we want to use FastSubsumesConsideringDomainIgnoringFPD
|
||||
// instead of FastEqualsConsideringDomain, because in that case we
|
||||
// still want to treat things which are in different first-party
|
||||
// contexts as same-origin.
|
||||
MOZ_ASSERT(
|
||||
subjectPrincipal->FastEqualsConsideringDomain(objectPrincipal) ==
|
||||
subjectPrincipal->FastSubsumesConsideringDomain(objectPrincipal),
|
||||
"Why are we in an asymmetric case here?");
|
||||
return subjectPrincipal->FastEqualsConsideringDomain(objectPrincipal);
|
||||
if (OriginAttributes::IsRestrictOpenerAccessForFPI()) {
|
||||
return subjectPrincipal->FastEqualsConsideringDomain(objectPrincipal);
|
||||
}
|
||||
|
||||
return subjectPrincipal->FastSubsumesConsideringDomainIgnoringFPD(
|
||||
objectPrincipal) &&
|
||||
objectPrincipal->FastSubsumesConsideringDomainIgnoringFPD(
|
||||
subjectPrincipal);
|
||||
}
|
||||
|
||||
bool MaybeCrossOriginObjectMixins::CrossOriginGetOwnPropertyHelper(
|
||||
|
|
|
@ -89,18 +89,12 @@ bool AccessCheck::isChrome(JSObject* obj) {
|
|||
return isChrome(js::GetObjectCompartment(obj));
|
||||
}
|
||||
|
||||
CrossOriginObjectType IdentifyCrossOriginObject(JSObject* obj) {
|
||||
bool IsCrossOriginAccessibleObject(JSObject* obj) {
|
||||
obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
|
||||
const js::Class* clasp = js::GetObjectClass(obj);
|
||||
|
||||
if (clasp->name[0] == 'L' && !strcmp(clasp->name, "Location")) {
|
||||
return CrossOriginLocation;
|
||||
}
|
||||
if (clasp->name[0] == 'W' && !strcmp(clasp->name, "Window")) {
|
||||
return CrossOriginWindow;
|
||||
}
|
||||
|
||||
return CrossOriginOpaque;
|
||||
return (clasp->name[0] == 'L' && !strcmp(clasp->name, "Location")) ||
|
||||
(clasp->name[0] == 'W' && !strcmp(clasp->name, "Window"));
|
||||
}
|
||||
|
||||
bool AccessCheck::checkPassToPrivilegedCode(JSContext* cx, HandleObject wrapper,
|
||||
|
|
|
@ -35,12 +35,13 @@ class AccessCheck {
|
|||
const nsACString& accessType);
|
||||
};
|
||||
|
||||
enum CrossOriginObjectType {
|
||||
CrossOriginWindow,
|
||||
CrossOriginLocation,
|
||||
CrossOriginOpaque
|
||||
};
|
||||
CrossOriginObjectType IdentifyCrossOriginObject(JSObject* obj);
|
||||
/**
|
||||
* Returns true if the given object (which is expected to be stripped of
|
||||
* cross-compartment wrappers in practice, but this function doesn't assume
|
||||
* that) is a WindowProxy or Location object, which need special wrapping
|
||||
* behavior due to being usable cross-origin in limited ways.
|
||||
*/
|
||||
bool IsCrossOriginAccessibleObject(JSObject* obj);
|
||||
|
||||
struct Policy {
|
||||
static bool checkCall(JSContext* cx, JS::HandleObject wrapper,
|
||||
|
|
|
@ -339,13 +339,16 @@ static void DEBUG_CheckUnwrapSafety(HandleObject obj,
|
|||
} else if (AccessCheck::isChrome(target) ||
|
||||
xpc::IsUniversalXPConnectEnabled(target)) {
|
||||
// If the caller is chrome (or effectively so), unwrap should always be
|
||||
// allowed.
|
||||
MOZ_ASSERT(!handler->hasSecurityPolicy());
|
||||
// allowed, but we might have a CrossOriginObjectWrapper here which allows
|
||||
// it dynamically.
|
||||
MOZ_ASSERT(!handler->hasSecurityPolicy() ||
|
||||
handler == &CrossOriginObjectWrapper::singleton);
|
||||
} else if (RealmPrivate::Get(origin)->forcePermissiveCOWs) {
|
||||
// Similarly, if this is a privileged scope that has opted to make itself
|
||||
// accessible to the world (allowed only during automation), unwrap should
|
||||
// be allowed.
|
||||
MOZ_ASSERT(!handler->hasSecurityPolicy());
|
||||
// be allowed. Again, it might be allowed dynamically.
|
||||
MOZ_ASSERT(!handler->hasSecurityPolicy() ||
|
||||
handler == &CrossOriginObjectWrapper::singleton);
|
||||
} else {
|
||||
// Otherwise, it should depend on whether the target subsumes the origin.
|
||||
JS::Compartment* originComp = JS::GetCompartmentForRealm(origin);
|
||||
|
@ -354,7 +357,17 @@ static void DEBUG_CheckUnwrapSafety(HandleObject obj,
|
|||
? AccessCheck::subsumesConsideringDomain(target, originComp)
|
||||
: AccessCheck::subsumesConsideringDomainIgnoringFPD(target,
|
||||
originComp));
|
||||
MOZ_ASSERT(handler->hasSecurityPolicy() == !subsumes);
|
||||
if (!subsumes) {
|
||||
// If the target (which is where the wrapper lives) does not subsume the
|
||||
// origin (which is where the wrapped object lives), then we should have a
|
||||
// security check on the wrapper here.
|
||||
MOZ_ASSERT(handler->hasSecurityPolicy());
|
||||
} else {
|
||||
// Even if target subsumes origin, we might have a wrapper with a security
|
||||
// policy here, if it happens to be a CrossOriginObjectWrapper.
|
||||
MOZ_ASSERT(!handler->hasSecurityPolicy() ||
|
||||
handler == &CrossOriginObjectWrapper::singleton);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -404,12 +417,6 @@ static const Wrapper* SelectWrapper(bool securityWrapper, XrayType xrayType,
|
|||
return &PermissiveXrayOpaque::singleton;
|
||||
}
|
||||
|
||||
// This is a security wrapper. Use the security versions and filter.
|
||||
if (xrayType == XrayForDOMObject &&
|
||||
IdentifyCrossOriginObject(obj) != CrossOriginOpaque) {
|
||||
return &CrossOriginObjectWrapper::singleton;
|
||||
}
|
||||
|
||||
// There's never any reason to expose other objects to non-subsuming actors.
|
||||
// Just use an opaque wrapper in these cases.
|
||||
//
|
||||
|
@ -501,6 +508,18 @@ JSObject* WrapperFactory::Rewrap(JSContext* cx, HandleObject existing,
|
|||
}
|
||||
}
|
||||
|
||||
// Special handling for the web's cross-origin objects (WindowProxy and
|
||||
// Location). We only need or want to do this in web-like contexts, where all
|
||||
// security relationships are symmetric and there are no forced Xrays.
|
||||
else if (originSubsumesTarget == targetSubsumesOrigin &&
|
||||
// Check for the more rare case of cross-origin objects before doing
|
||||
// the more-likely-to-pass checks for wantXrays.
|
||||
IsCrossOriginAccessibleObject(obj) &&
|
||||
(!targetSubsumesOrigin || (!originCompartmentPrivate->wantXrays &&
|
||||
!targetCompartmentPrivate->wantXrays))) {
|
||||
wrapper = &CrossOriginObjectWrapper::singleton;
|
||||
}
|
||||
|
||||
//
|
||||
// Now, handle the regular cases.
|
||||
//
|
||||
|
|
|
@ -6517,15 +6517,8 @@ nsresult PresShell::EventHandler::HandleEvent(nsIFrame* aFrame,
|
|||
}
|
||||
}
|
||||
|
||||
if (aGUIEvent->mClass == eKeyboardEventClass && GetDocument() &&
|
||||
GetDocument()->EventHandlingSuppressed()) {
|
||||
if (aGUIEvent->mMessage == eKeyDown) {
|
||||
mPresShell->mNoDelayedKeyEvents = true;
|
||||
} else if (!mPresShell->mNoDelayedKeyEvents) {
|
||||
auto event = MakeUnique<DelayedKeyEvent>(aGUIEvent->AsKeyboardEvent());
|
||||
PushDelayedEventIntoQueue(std::move(event));
|
||||
}
|
||||
aGUIEvent->mFlags.mIsSuppressedOrDelayed = true;
|
||||
if (MaybeDiscardOrDelayKeyboardEvent(aGUIEvent)) {
|
||||
// The event is discarded or put into the delayed event queue.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -7273,6 +7266,30 @@ bool PresShell::EventHandler::MaybeHandleEventWithAnotherPresShell(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PresShell::EventHandler::MaybeDiscardOrDelayKeyboardEvent(
|
||||
WidgetGUIEvent* aGUIEvent) {
|
||||
MOZ_ASSERT(aGUIEvent);
|
||||
|
||||
if (aGUIEvent->mClass != eKeyboardEventClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Document* document = GetDocument();
|
||||
if (!document || !document->EventHandlingSuppressed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aGUIEvent->mMessage == eKeyDown) {
|
||||
mPresShell->mNoDelayedKeyEvents = true;
|
||||
} else if (!mPresShell->mNoDelayedKeyEvents) {
|
||||
UniquePtr<DelayedKeyEvent> delayedKeyEvent =
|
||||
MakeUnique<DelayedKeyEvent>(aGUIEvent->AsKeyboardEvent());
|
||||
PushDelayedEventIntoQueue(std::move(delayedKeyEvent));
|
||||
}
|
||||
aGUIEvent->mFlags.mIsSuppressedOrDelayed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Document* PresShell::GetPrimaryContentDocument() {
|
||||
nsPresContext* context = GetPresContext();
|
||||
if (!context || !context->IsRoot()) {
|
||||
|
|
|
@ -672,6 +672,17 @@ class PresShell final : public nsIPresShell,
|
|||
bool MaybeHandleEventWithAccessibleCaret(WidgetGUIEvent* aGUIEvent,
|
||||
nsEventStatus* aEventStatus);
|
||||
|
||||
/**
|
||||
* MaybeDiscardOrDelayKeyboardEvent() may discared or put aGUIEvent into
|
||||
* the delayed event queue if it's a keyboard event and if we should do so.
|
||||
* If aGUIEvent is not a keyboard event, this does nothing.
|
||||
*
|
||||
* @param aGUIEvent The handling event.
|
||||
* @return true if this method discard the event or
|
||||
* put it into the delayed event queue.
|
||||
*/
|
||||
bool MaybeDiscardOrDelayKeyboardEvent(WidgetGUIEvent* aGUIEvent);
|
||||
|
||||
/**
|
||||
* XXX Needs better name.
|
||||
* HandleEventInternal() dispatches aEvent into the DOM tree and
|
||||
|
|
|
@ -13,6 +13,8 @@ support-files =
|
|||
printpreview_helper.xul
|
||||
printpreview_font_api.html
|
||||
printpreview_font_api_ref.html
|
||||
printpreview_font_mozprintcallback.html
|
||||
printpreview_font_mozprintcallback_ref.html
|
||||
file_bug1018265.xul
|
||||
|
||||
[test_bug396367-1.html]
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -23,7 +23,7 @@ var file = Cc["@mozilla.org/file/directory_service;1"]
|
|||
.get("TmpD", Ci.nsIFile);
|
||||
filePath = file.path;
|
||||
|
||||
function printpreview() {
|
||||
function printpreview(hasMozPrintCallback) {
|
||||
gWbp = window.frames[1].docShell.printPreview;
|
||||
var listener = {
|
||||
onLocationChange: function(webProgress, request, location, flags) { },
|
||||
|
@ -54,7 +54,11 @@ function printpreview() {
|
|||
window.frames[0].addEventListener("afterprint", afterprint, true);
|
||||
gWbp.printPreview(gWbp.globalPrintSettings, window.frames[0], listener);
|
||||
is(before, 1, "Should have called beforeprint listener!");
|
||||
is(after, 1, "Should have called afterprint listener!");
|
||||
if (!hasMozPrintCallback) {
|
||||
// If there's a mozPrintCallback the after print event won't fire until
|
||||
// later.
|
||||
is(after, 1, "Should have called afterprint listener!");
|
||||
}
|
||||
window.frames[0].removeEventListener("beforeprint", beforeprint, true);
|
||||
window.frames[0].removeEventListener("afterprint", afterprint, true);
|
||||
prefs.clearUserPref('print.show_print_progress');
|
||||
|
@ -345,6 +349,44 @@ async function runTest9() {
|
|||
exitprintpreview();
|
||||
ok(compareCanvases(), "Printing <use> subtrees should create same output");
|
||||
|
||||
requestAnimationFrame(function() { setTimeout(runTest10); } );
|
||||
}
|
||||
|
||||
// Test for bug 1524640
|
||||
async function runTest10() {
|
||||
// Test that fonts loaded during mozprint callback are loaded into the cloned
|
||||
// document.
|
||||
const iframeElement = document.getElementsByTagName("iframe")[0];
|
||||
|
||||
// First, snapshot the page with font defined in CSS.
|
||||
await new Promise((resolve) => {
|
||||
iframeElement.addEventListener("load", resolve, { capture: true, once: true });
|
||||
iframeElement.setAttribute("src", "printpreview_font_mozprintcallback_ref.html");
|
||||
});
|
||||
let mozPrintCallbackDone = new Promise((resolve) => {
|
||||
iframeElement.addEventListener("message", resolve, { capture: true, once: true });
|
||||
});
|
||||
printpreview(true);
|
||||
await mozPrintCallbackDone;
|
||||
ctx1.drawWindow(window.frames[1], 0, 0, 400, 400, "rgb(255,255,255)");
|
||||
exitprintpreview();
|
||||
|
||||
// Second, snapshot the page with font loaded in JS.
|
||||
await new Promise((resolve) => {
|
||||
iframeElement.addEventListener("load", resolve, { capture: true, once: true });
|
||||
iframeElement.setAttribute("src", "printpreview_font_mozprintcallback.html");
|
||||
});
|
||||
mozPrintCallbackDone = new Promise((resolve) => {
|
||||
iframeElement.addEventListener("message", resolve, { capture: true, once: true });
|
||||
});
|
||||
printpreview(true);
|
||||
// Wait for the mozprintcallback to finish.
|
||||
await mozPrintCallbackDone;
|
||||
ctx2.drawWindow(window.frames[1], 0, 0, 400, 400, "rgb(255,255,255)");
|
||||
|
||||
exitprintpreview();
|
||||
ok(compareCanvases(), "Printing pages with fonts loaded from a mozPrintCallback should be the same.");
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -420,6 +420,16 @@ bool FontFaceSet::HasRuleFontFace(FontFace* aFontFace) {
|
|||
}
|
||||
#endif
|
||||
|
||||
bool IsPdfJs(nsIPrincipal* aPrincipal) {
|
||||
if (!aPrincipal) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
return uri && uri->GetSpecOrDefault().EqualsLiteral(
|
||||
"resource://pdf.js/web/viewer.html");
|
||||
}
|
||||
|
||||
void FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv) {
|
||||
FlushUserFontSet();
|
||||
|
||||
|
@ -452,6 +462,16 @@ void FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv) {
|
|||
MarkUserFontSetDirty();
|
||||
mHasLoadingFontFacesIsDirty = true;
|
||||
CheckLoadingStarted();
|
||||
RefPtr<dom::Document> clonedDoc = mDocument->GetLatestStaticClone();
|
||||
if (clonedDoc) {
|
||||
// The document is printing, copy the font to the static clone as well.
|
||||
nsCOMPtr<nsIPrincipal> principal = mDocument->GetPrincipal();
|
||||
if (principal->IsSystemPrincipal() || IsPdfJs(principal)) {
|
||||
ErrorResult rv;
|
||||
clonedDoc->Fonts()->Add(aFontFace, rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FontFaceSet::Clear() {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<Description>다나와 쇼핑 검색</Description>
|
||||
<InputEncoding>EUC-KR</InputEncoding>
|
||||
<Image width="16" height="16">data:image/png;base64,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</Image>
|
||||
<Url type="text/html" method="GET" template="http://m.danawa.com/search/index.html">
|
||||
<Url type="text/html" method="GET" template="http://search.danawa.com/mobile/dsearch.php">
|
||||
<Param name="keyword" value="{searchTerms}"/>
|
||||
<Param name="from" value="firefox"/>
|
||||
</Url>
|
||||
|
|
|
@ -133,6 +133,17 @@ def full_task_graph_to_runnable_jobs(full_task_json):
|
|||
return runnable_jobs
|
||||
|
||||
|
||||
def try_syntax_from_message(message):
|
||||
"""
|
||||
Parse the try syntax out of a commit message, returning '' if none is
|
||||
found.
|
||||
"""
|
||||
try_idx = message.find('try:')
|
||||
if try_idx == -1:
|
||||
return ''
|
||||
return message[try_idx:].split('\n', 1)[0]
|
||||
|
||||
|
||||
def taskgraph_decision(options, parameters=None):
|
||||
"""
|
||||
Run the decision task. This function implements `mach taskgraph decision`,
|
||||
|
@ -221,8 +232,8 @@ def get_decision_parameters(config, options):
|
|||
parameters['build_number'] = 1
|
||||
parameters['version'] = get_version(product_dir)
|
||||
parameters['app_version'] = get_app_version(product_dir)
|
||||
parameters['message'] = get_hg_commit_message(os.path.join(GECKO,
|
||||
product_dir))
|
||||
parameters['message'] = try_syntax_from_message(
|
||||
get_hg_commit_message(os.path.join(GECKO, product_dir)))
|
||||
parameters['hg_branch'] = get_hg_revision_branch(GECKO, revision=parameters['head_rev'])
|
||||
parameters['next_version'] = None
|
||||
parameters['release_type'] = ''
|
||||
|
|
|
@ -107,6 +107,25 @@ class TestGetDecisionParameters(unittest.TestCase):
|
|||
self.assertEqual(params['try_options'], None)
|
||||
self.assertEqual(params['try_task_config'], ttc)
|
||||
|
||||
def test_try_syntax_from_message_empty(self):
|
||||
self.assertEqual(decision.try_syntax_from_message(''), '')
|
||||
|
||||
def test_try_syntax_from_message_no_try_syntax(self):
|
||||
self.assertEqual(decision.try_syntax_from_message('abc | def'), '')
|
||||
|
||||
def test_try_syntax_from_message_initial_try_syntax(self):
|
||||
self.assertEqual(decision.try_syntax_from_message('try: -f -o -o'), 'try: -f -o -o')
|
||||
|
||||
def test_try_syntax_from_message_initial_try_syntax_multiline(self):
|
||||
self.assertEqual(
|
||||
decision.try_syntax_from_message('try: -f -o -o\nabc\ndef'),
|
||||
'try: -f -o -o')
|
||||
|
||||
def test_try_syntax_from_message_embedded_try_syntax_multiline(self):
|
||||
self.assertEqual(
|
||||
decision.try_syntax_from_message('some stuff\ntry: -f -o -o\nabc\ndef'),
|
||||
'try: -f -o -o')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -12,8 +12,6 @@ import shlex
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TRY_DELIMITER = 'try:'
|
||||
|
||||
# The build type aliases are very cryptic and only used in try flags these are
|
||||
# mappings from the single char alias to a longer more recognizable form.
|
||||
BUILD_TYPE_ALIASES = {
|
||||
|
|
|
@ -179,19 +179,43 @@
|
|||
};
|
||||
await handlePrompt(state, action);
|
||||
|
||||
Object.assign(state, {
|
||||
// We don't know what order these prompts appear in so get both states and check them.
|
||||
// We can't use Promise.all here since we can't start the 2nd timer in chromeScript.js until
|
||||
// the first timer is done since the timer variable gets clobbered, plus we don't want
|
||||
// different actions racing each other.
|
||||
let promptStates = [
|
||||
await handlePromptWithoutChecks(action),
|
||||
await handlePromptWithoutChecks(action),
|
||||
];
|
||||
|
||||
let expected1 = Object.assign({}, state, {
|
||||
msg: "http://example.com is requesting your username and password. WARNING: Your password will not be sent to the website you are currently visiting!",
|
||||
textValue: "user1name",
|
||||
passValue: "user1pass",
|
||||
});
|
||||
await handlePrompt(state, action);
|
||||
|
||||
Object.assign(state, {
|
||||
let expected2 = Object.assign({}, state, {
|
||||
msg: "http://example.org is requesting your username and password. WARNING: Your password will not be sent to the website you are currently visiting!",
|
||||
textValue: "user2name",
|
||||
passValue: "user2pass",
|
||||
});
|
||||
await handlePrompt(state, action);
|
||||
|
||||
// The order isn't important.
|
||||
let expectedPromptStates = [
|
||||
expected1,
|
||||
expected2,
|
||||
];
|
||||
|
||||
is(promptStates.length, expectedPromptStates.length,
|
||||
"Check we handled the right number of prompts");
|
||||
for (let promptState of promptStates) {
|
||||
let expectedStateIndexForMessage = expectedPromptStates.findIndex(eps => {
|
||||
return eps.msg == promptState.msg;
|
||||
});
|
||||
isnot(expectedStateIndexForMessage, -1, "Check state message was found in expected array");
|
||||
let expectedPromptState = expectedPromptStates.splice(expectedStateIndexForMessage, 1)[0];
|
||||
checkPromptState(promptState, expectedPromptState);
|
||||
}
|
||||
|
||||
let iframe1Doc = await iframe1DocPromise;
|
||||
let iframe2aDoc = await iframe2aDocPromise;
|
||||
|
|
|
@ -24,19 +24,31 @@ function onloadPromiseFor(id) {
|
|||
});
|
||||
}
|
||||
|
||||
function handlePrompt(state, action) {
|
||||
/**
|
||||
* Take an action on the next prompt that appears without checking the state in advance.
|
||||
* This is useful when the action doesn't depend on which prompt is shown and you
|
||||
* are expecting multiple prompts at once in an indeterminate order.
|
||||
* If you know the state of the prompt you expect you should use `handlePrompt` instead.
|
||||
* @param {object} action defining how to handle the prompt
|
||||
* @returns {Promise} resolving with the prompt state.
|
||||
*/
|
||||
function handlePromptWithoutChecks(action) {
|
||||
return new Promise(resolve => {
|
||||
gChromeScript.addMessageListener("promptHandled", function handled(msg) {
|
||||
gChromeScript.removeMessageListener("promptHandled", handled);
|
||||
checkPromptState(msg.promptState, state);
|
||||
resolve(true);
|
||||
resolve(msg.promptState);
|
||||
});
|
||||
gChromeScript.sendAsyncMessage("handlePrompt", { action, isTabModal});
|
||||
});
|
||||
}
|
||||
|
||||
async function handlePrompt(state, action) {
|
||||
let actualState = await handlePromptWithoutChecks(action);
|
||||
checkPromptState(actualState, state);
|
||||
}
|
||||
|
||||
function checkPromptState(promptState, expectedState) {
|
||||
info(`checkPromptState: ${expectedState.msg}`);
|
||||
info(`checkPromptState: Expected: ${expectedState.msg}`);
|
||||
// XXX check title? OS X has title in content
|
||||
is(promptState.msg, expectedState.msg, "Checking expected message");
|
||||
if (isOSX && !isTabModal)
|
||||
|
|
Загрузка…
Ссылка в новой задаче