Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Oana Pop Rus 2019-02-07 11:57:33 +02:00
Родитель f9cf535efc 490ab7f9b8
Коммит 4663ddb53a
31 изменённых файлов: 447 добавлений и 176 удалений

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

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