diff --git a/accessible/base/EventQueue.cpp b/accessible/base/EventQueue.cpp index a62f24b201be..bfa2c4833a33 100644 --- a/accessible/base/EventQueue.cpp +++ b/accessible/base/EventQueue.cpp @@ -480,44 +480,6 @@ EventQueue::CreateTextChangeEventFor(AccMutationEvent* aEvent) aEvent->mIsFromUserInput ? eFromUserInput : eNoUserInput); } -void -EventQueue::SendIPCEvent(AccEvent* aEvent) const -{ - DocAccessibleChild* ipcDoc = mDocument->IPCDoc(); - uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 : - reinterpret_cast(aEvent->GetAccessible()); - - switch(aEvent->GetEventType()) { - case nsIAccessibleEvent::EVENT_SHOW: - ipcDoc->ShowEvent(downcast_accEvent(aEvent)); - break; - - case nsIAccessibleEvent::EVENT_HIDE: - ipcDoc->SendHideEvent(id); - break; - - case nsIAccessibleEvent::EVENT_REORDER: - // reorder events on the application acc aren't necessary to tell the parent - // about new top level documents. - if (!aEvent->GetAccessible()->IsApplication()) - ipcDoc->SendEvent(id, aEvent->GetEventType()); - break; - case nsIAccessibleEvent::EVENT_STATE_CHANGE: { - AccStateChangeEvent* event = downcast_accEvent(aEvent); - ipcDoc->SendStateChangeEvent(id, event->GetState(), - event->IsStateEnabled()); - break; - } - case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: { - AccCaretMoveEvent* event = downcast_accEvent(aEvent); - ipcDoc->SendEvent(id, event->GetCaretOffset()); - break; - } - default: - ipcDoc->SendEvent(id, aEvent->GetEventType()); - } -} - //////////////////////////////////////////////////////////////////////////////// // EventQueue: event queue @@ -594,8 +556,5 @@ EventQueue::ProcessEventQueue() if (!mDocument) return; - - if (IPCAccessibilityActive()) - SendIPCEvent(event); } } diff --git a/accessible/base/EventQueue.h b/accessible/base/EventQueue.h index 482407cc4fc5..31082f293bc4 100644 --- a/accessible/base/EventQueue.h +++ b/accessible/base/EventQueue.h @@ -53,11 +53,6 @@ private: AccSelChangeEvent* aThisEvent, uint32_t aThisIndex); - /** - * Notify the parent process of events being fired by this event queue. - */ - void SendIPCEvent(AccEvent* aEvent) const; - /** * Coalesce text change events caused by sibling hide events. */ diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp index 00781b9e3529..f3a18320a890 100644 --- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -15,6 +15,7 @@ #include "ApplicationAccessible.h" #include "nsEventShell.h" #include "nsTextEquivUtils.h" +#include "DocAccessibleChild.h" #include "Relation.h" #include "Role.h" #include "RootAccessible.h" @@ -832,6 +833,42 @@ Accessible::HandleAccEvent(AccEvent* aEvent) { NS_ENSURE_ARG_POINTER(aEvent); + if (IPCAccessibilityActive() && Document()) { + DocAccessibleChild* ipcDoc = mDoc->IPCDoc(); + uint64_t id = aEvent->GetAccessible()->IsDoc() ? 0 : + reinterpret_cast(aEvent->GetAccessible()); + + switch(aEvent->GetEventType()) { + case nsIAccessibleEvent::EVENT_SHOW: + ipcDoc->ShowEvent(downcast_accEvent(aEvent)); + break; + + case nsIAccessibleEvent::EVENT_HIDE: + ipcDoc->SendHideEvent(id); + break; + + case nsIAccessibleEvent::EVENT_REORDER: + // reorder events on the application acc aren't necessary to tell the parent + // about new top level documents. + if (!aEvent->GetAccessible()->IsApplication()) + ipcDoc->SendEvent(id, aEvent->GetEventType()); + break; + case nsIAccessibleEvent::EVENT_STATE_CHANGE: { + AccStateChangeEvent* event = downcast_accEvent(aEvent); + ipcDoc->SendStateChangeEvent(id, event->GetState(), + event->IsStateEnabled()); + break; + } + case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED: { + AccCaretMoveEvent* event = downcast_accEvent(aEvent); + ipcDoc->SendEvent(id, event->GetCaretOffset()); + break; + } + default: + ipcDoc->SendEvent(id, aEvent->GetEventType()); + } + } + nsCOMPtr obsService = services::GetObserverService(); NS_ENSURE_TRUE(obsService, NS_ERROR_FAILURE); diff --git a/accessible/generic/DocAccessible.h b/accessible/generic/DocAccessible.h index 243fbde0f52f..e48b56a81661 100644 --- a/accessible/generic/DocAccessible.h +++ b/accessible/generic/DocAccessible.h @@ -336,6 +336,12 @@ public: */ void RecreateAccessible(nsIContent* aContent); + /** + * If this document is in a content process return the object responsible for + * communicating with the main process for it. + */ + DocAccessibleChild* IPCDoc() const { return mIPCDoc; } + protected: virtual ~DocAccessible(); @@ -519,12 +525,6 @@ protected: */ bool IsLoadEventTarget() const; - /** - * If this document is in a content process return the object responsible for - * communicating with the main process for it. - */ - DocAccessibleChild* IPCDoc() const { return mIPCDoc; } - /* * Set the object responsible for communicating with the main process on * behalf of this document. diff --git a/accessible/generic/OuterDocAccessible.h b/accessible/generic/OuterDocAccessible.h index 02b455941378..5d0489a1be9e 100644 --- a/accessible/generic/OuterDocAccessible.h +++ b/accessible/generic/OuterDocAccessible.h @@ -52,6 +52,7 @@ Accessible::AsOuterDoc() { return IsOuterDoc() ? static_cast(this) : nullptr; } + } // namespace a11y } // namespace mozilla diff --git a/accessible/windows/msaa/AccessibleWrap.h b/accessible/windows/msaa/AccessibleWrap.h index a3d730f927d8..05ce578910a3 100644 --- a/accessible/windows/msaa/AccessibleWrap.h +++ b/accessible/windows/msaa/AccessibleWrap.h @@ -223,6 +223,7 @@ WrapperFor(ProxyAccessible* aProxy) { return reinterpret_cast(aProxy->GetWrapper()); } + } // namespace a11y } // namespace mozilla diff --git a/browser/base/content/browser-fullScreen.js b/browser/base/content/browser-fullScreen.js index 8dea4a869824..fb3f776aac10 100644 --- a/browser/base/content/browser-fullScreen.js +++ b/browser/base/content/browser-fullScreen.js @@ -8,6 +8,7 @@ var FullScreen = { "DOMFullscreen:Request", "DOMFullscreen:NewOrigin", "DOMFullscreen:Exit", + "DOMFullscreen:Painted", ], init: function() { @@ -166,6 +167,10 @@ var FullScreen = { this._windowUtils.remoteFrameFullscreenReverted(); break; } + case "DOMFullscreen:Painted": { + Services.obs.notifyObservers(window, "fullscreen-painted", ""); + break; + } } }, diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index 50e4dfffd257..2167b253b529 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -82,7 +82,6 @@ - @@ -357,8 +356,6 @@ #endif - - #ifndef XP_MACOSX diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index e1a66e64160a..52edda1bc977 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -7648,16 +7648,6 @@ var MousePosTracker = { } }; -function focusNextFrame(event) { - let fm = Services.focus; - let dir = event.shiftKey ? fm.MOVEFOCUS_BACKWARDDOC : fm.MOVEFOCUS_FORWARDDOC; - let element = fm.moveFocus(window, null, dir, fm.FLAG_BYKEY); - let panelOrNotificationSelector = "popupnotification " + element.localName + ", " + - "panel " + element.localName; - if (element.ownerDocument == document && !element.matches(panelOrNotificationSelector)) - focusAndSelectUrlBar(); -} - function BrowserOpenNewTabOrWindow(event) { if (event.shiftKey) { OpenBrowserWindow(); diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul index 521b2d9e1282..de1a32947204 100644 --- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -58,6 +58,7 @@ screenX="4" screenY="4" fullscreenbutton="true" sizemode="normal" + retargetdocumentfocus="urlbar" persist="screenX screenY width height sizemode"> # All JS files which are not content (only) dependent that browser.xul diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js index 2316b34b4a1e..2249aaa001d2 100644 --- a/browser/base/content/tab-content.js +++ b/browser/base/content/tab-content.js @@ -624,8 +624,10 @@ let DOMFullscreenHandler = { addMessageListener("DOMFullscreen:Approved", this); addMessageListener("DOMFullscreen:CleanUp", this); addEventListener("MozDOMFullscreen:Request", this); + addEventListener("MozDOMFullscreen:Entered", this); addEventListener("MozDOMFullscreen:NewOrigin", this); addEventListener("MozDOMFullscreen:Exit", this); + addEventListener("MozDOMFullscreen:Exited", this); }, get _windowUtils() { @@ -678,6 +680,16 @@ let DOMFullscreenHandler = { sendAsyncMessage("DOMFullscreen:Exit"); break; } + case "MozDOMFullscreen:Entered": + case "MozDOMFullscreen:Exited": { + addEventListener("MozAfterPaint", this); + break; + } + case "MozAfterPaint": { + removeEventListener("MozAfterPaint", this); + sendAsyncMessage("DOMFullscreen:Painted"); + break; + } } } }; diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 4937e8944762..d642c943e7e7 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -57,6 +57,7 @@ support-files = file_bug970276_popup2.html file_bug970276_favicon1.ico file_bug970276_favicon2.ico + file_documentnavigation_frameset.html file_dom_notifications.html file_double_close_tab.html file_favicon_change.html @@ -287,6 +288,7 @@ skip-if = e10s # Bug 1071623 [browser_discovery.js] [browser_double_close_tab.js] skip-if = e10s +[browser_documentnavigation.js] [browser_duplicateIDs.js] [browser_drag.js] skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638. diff --git a/browser/base/content/test/general/browser_documentnavigation.js b/browser/base/content/test/general/browser_documentnavigation.js new file mode 100644 index 000000000000..7f72affe120c --- /dev/null +++ b/browser/base/content/test/general/browser_documentnavigation.js @@ -0,0 +1,266 @@ +/* + * This test checks that focus is adjusted properly in a browser when pressing F6 and Shift+F6. + * There are additional tests in dom/tests/mochitest/chrome/test_focus_docnav.xul which test + * non-browser cases. + */ + +let testPage1 = "data:text/html,"; +let testPage2 = "data:text/html,"; +let testPage3 = "data:text/html,"; + +let fm = Services.focus; + +function* expectFocusOnF6(backward, expectedDocument, expectedElement, onContent, desc) +{ + let focusChangedInChildResolver = null; + let focusPromise = onContent ? new Promise(resolve => focusChangedInChildResolver = resolve) : + BrowserTestUtils.waitForEvent(window, "focus", true); + + function focusChangedListener(msg) { + let expected = expectedDocument; + if (!expectedElement.startsWith("html")) { + expected += "," + expectedElement; + } + + is(msg.data.details, expected, desc + " child focus matches"); + focusChangedInChildResolver(); + } + + if (onContent) { + messageManager.addMessageListener("BrowserTest:FocusChanged", focusChangedListener); + + yield ContentTask.spawn(gBrowser.selectedBrowser, { expectedElementId: expectedElement }, function* (arg) { + let expectedElement = content.document.getElementById(arg.expectedElementId); + if (!expectedElement) { + // Element not found, so look in the child frames. + for (let f = 0; f < content.frames.length; f++) { + if (content.frames[f].document.getElementById(arg.expectedElementId)) { + expectedElement = content.frames[f].document; + break; + } + } + } + else if (expectedElement.localName == "html") { + expectedElement = expectedElement.ownerDocument; + } + + if (!expectedElement) { + sendSyncMessage("BrowserTest:FocusChanged", + { details : "expected element " + arg.expectedElementId + " not found" }); + return; + } + + expectedElement.addEventListener("focus", function focusReceived() { + expectedElement.removeEventListener("focus", focusReceived, true); + + const fm = Components.classes["@mozilla.org/focus-manager;1"]. + getService(Components.interfaces.nsIFocusManager); + let details = fm.focusedWindow.document.documentElement.id; + if (fm.focusedElement) { + details += "," + fm.focusedElement.id; + } + + sendSyncMessage("BrowserTest:FocusChanged", { details : details }); + }, true); + }); + } + + EventUtils.synthesizeKey("VK_F6", { shiftKey: backward }); + yield focusPromise; + + if (typeof expectedElement == "string") { + expectedElement = fm.focusedWindow.document.getElementById(expectedElement); + } + + if (gMultiProcessBrowser && onContent) { + expectedDocument = "main-window"; + expectedElement = gBrowser.selectedBrowser; + } + + is(fm.focusedWindow.document.documentElement.id, expectedDocument, desc + " document matches"); + is(fm.focusedElement, expectedElement, desc + " element matches"); + + if (onContent) { + messageManager.removeMessageListener("BrowserTest:FocusChanged", focusChangedListener); + } +} + +// Load a page and navigate between it and the chrome window. +add_task(function* () +{ + let page1Promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + gBrowser.selectedBrowser.loadURI(testPage1); + yield page1Promise; + + // When the urlbar is focused, pressing F6 should focus the root of the content page. + gURLBar.focus(); + yield* expectFocusOnF6(false, "html1", "html1", + true, "basic focus content page"); + + // When the content is focused, pressing F6 should focus the urlbar. + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "basic focus content page urlbar"); + + // When a button in content is focused, pressing F6 should focus the urlbar. + yield* expectFocusOnF6(false, "html1", "html1", + true, "basic focus content page with button focused"); + + return ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () { + return content.document.getElementById("button1").focus(); + }); + + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "basic focus content page with button focused urlbar"); + + // The document root should be focused, not the button + yield* expectFocusOnF6(false, "html1", "html1", + true, "basic focus again content page with button focused"); + + // Check to ensure that the root element is focused + let match = yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* () { + return content.document.activeElement == content.document.documentElement; + }); + ok(match, "basic focus again content page with button focused child root is focused"); +}); + +// Open a second tab. Document focus should skip the background tab. +add_task(function* () +{ + yield BrowserTestUtils.openNewForegroundTab(gBrowser, testPage2); + + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "basic focus content page and second tab urlbar"); + yield* expectFocusOnF6(false, "html2", "html2", + true, "basic focus content page with second tab"); + + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); +}); + +// Shift+F6 should navigate backwards. There's only one document here so the effect +// is the same. +add_task(function* () +{ + gURLBar.focus(); + yield* expectFocusOnF6(true, "html1", "html1", + true, "back focus content page"); + yield* expectFocusOnF6(true, "main-window", gURLBar.inputField, + false, "back focus content page urlbar"); +}); + +// Open the sidebar and navigate between the sidebar, content and top-level window +add_task(function* () +{ + let sidebar = document.getElementById("sidebar"); + + let loadPromise = BrowserTestUtils.waitForEvent(sidebar, "load", true); + SidebarUI.toggle('viewBookmarksSidebar'); + yield loadPromise; + + + gURLBar.focus(); + yield* expectFocusOnF6(false, "bookmarksPanel", + sidebar.contentDocument.getElementById("search-box").inputField, + false, "focus with sidebar open sidebar"); + yield* expectFocusOnF6(false, "html1", "html1", + true, "focus with sidebar open content"); + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "focus with sidebar urlbar"); + + // Now go backwards + yield* expectFocusOnF6(true, "html1", "html1", + true, "back focus with sidebar open content"); + yield* expectFocusOnF6(true, "bookmarksPanel", + sidebar.contentDocument.getElementById("search-box").inputField, + false, "back focus with sidebar open sidebar"); + yield* expectFocusOnF6(true, "main-window", gURLBar.inputField, + false, "back focus with sidebar urlbar"); + + SidebarUI.toggle('viewBookmarksSidebar'); +}); + +// Navigate when the downloads panel is open +add_task(function* () +{ + yield pushPrefs(["accessibility.tabfocus", 7]); + + let popupShownPromise = BrowserTestUtils.waitForEvent(document, "popupshown", true); + EventUtils.synthesizeMouseAtCenter(document.getElementById("downloads-button"), { }); + yield popupShownPromise; + + gURLBar.focus(); + yield* expectFocusOnF6(false, "main-window", document.getElementById("downloadsHistory"), + false, "focus with downloads panel open panel"); + yield* expectFocusOnF6(false, "html1", "html1", + true, "focus with downloads panel open"); + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "focus downloads panel open urlbar"); + + // Now go backwards + yield* expectFocusOnF6(true, "html1", "html1", + true, "back focus with downloads panel open"); + yield* expectFocusOnF6(true, "main-window", document.getElementById("downloadsHistory"), + false, "back focus with downloads panel open"); + yield* expectFocusOnF6(true, "main-window", gURLBar.inputField, + false, "back focus downloads panel open urlbar"); + + let downloadsPopup = document.getElementById("downloadsPanel"); + let popupHiddenPromise = BrowserTestUtils.waitForEvent(downloadsPopup, "popuphidden", true); + downloadsPopup.hidePopup(); + yield popupHiddenPromise; +}); + +// Navigation with a contenteditable body +add_task(function* () +{ + yield BrowserTestUtils.openNewForegroundTab(gBrowser, testPage3); + + // The body should be focused when it is editable, not the root. + gURLBar.focus(); + yield* expectFocusOnF6(false, "html3", "body3", + true, "focus with contenteditable body"); + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "focus with contenteditable body urlbar"); + + // Now go backwards + + yield* expectFocusOnF6(false, "html3", "body3", + true, "back focus with contenteditable body"); + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "back focus with contenteditable body urlbar"); + + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); +}); + +// Navigation with a frameset loaded +add_task(function* () +{ + yield BrowserTestUtils.openNewForegroundTab(gBrowser, + "http://mochi.test:8888/browser/browser/base/content/test/general/file_documentnavigation_frameset.html"); + + gURLBar.focus(); + yield* expectFocusOnF6(false, "htmlframe1", "htmlframe1", + true, "focus on frameset frame 0"); + yield* expectFocusOnF6(false, "htmlframe2", "htmlframe2", + true, "focus on frameset frame 1"); + yield* expectFocusOnF6(false, "htmlframe3", "htmlframe3", + true, "focus on frameset frame 2"); + yield* expectFocusOnF6(false, "htmlframe4", "htmlframe4", + true, "focus on frameset frame 3"); + yield* expectFocusOnF6(false, "main-window", gURLBar.inputField, + false, "focus on frameset frame urlbar"); + + yield* expectFocusOnF6(true, "htmlframe4", "htmlframe4", + true, "back focus on frameset frame 3"); + yield* expectFocusOnF6(true, "htmlframe3", "htmlframe3", + true, "back focus on frameset frame 2"); + yield* expectFocusOnF6(true, "htmlframe2", "htmlframe2", + true, "back focus on frameset frame 1"); + yield* expectFocusOnF6(true, "htmlframe1", "htmlframe1", + true, "back focus on frameset frame 0"); + yield* expectFocusOnF6(true, "main-window", gURLBar.inputField, + false, "back focus on frameset frame urlbar"); + + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); +}); + +// XXXndeakin add tests for browsers inside of panels diff --git a/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js b/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js index 7ca92c8c3abd..24e8a0570b89 100644 --- a/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js +++ b/browser/base/content/test/general/browser_domFullscreen_fullscreenMode.js @@ -121,6 +121,10 @@ let gTests = [ ]; add_task(function* () { + yield pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"]); + let tab = gBrowser.addTab("about:robots"); let browser = tab.linkedBrowser; gBrowser.selectedTab = tab; diff --git a/browser/base/content/test/general/file_documentnavigation_frameset.html b/browser/base/content/test/general/file_documentnavigation_frameset.html new file mode 100644 index 000000000000..beb01addfc56 --- /dev/null +++ b/browser/base/content/test/general/file_documentnavigation_frameset.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/browser/base/content/test/general/test_contextmenu.html b/browser/base/content/test/general/test_contextmenu.html index 450231af4016..5e9dd35f7092 100644 --- a/browser/base/content/test/general/test_contextmenu.html +++ b/browser/base/content/test/general/test_contextmenu.html @@ -507,6 +507,8 @@ function runTest(testNum) { subwindow.addEventListener("mozfullscreenchange", openDomFullScreen, false); SpecialPowers.setBoolPref("full-screen-api.approval-required", false); SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false); + SpecialPowers.setCharPref("full-screen-api.transition-duration.enter", "0 0"); + SpecialPowers.setCharPref("full-screen-api.transition-duration.leave", "0 0"); full_screen_element.mozRequestFullScreen(); }, diff --git a/browser/components/downloads/content/downloadsOverlay.xul b/browser/components/downloads/content/downloadsOverlay.xul index 56eec0d4dd7e..c3146d5e0353 100644 --- a/browser/components/downloads/content/downloadsOverlay.xul +++ b/browser/components/downloads/content/downloadsOverlay.xul @@ -39,7 +39,7 @@ oncommand="goDoCommand('downloadsCmd_clearList')"/> - +