From fc2bc20572815b3953680bbed672a1c83a883903 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 13:51:52 +0800 Subject: [PATCH 1/8] Determine wheter a navigation entry is in-page --- atom/browser/api/atom_api_web_contents.cc | 5 +++-- .../api/lib/navigation-controller.coffee | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index c998deca5e..2fedd10cf4 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -348,8 +348,9 @@ void WebContents::WebContentsDestroyed() { } void WebContents::NavigationEntryCommitted( - const content::LoadCommittedDetails& load_details) { - Emit("navigation-entry-commited", load_details.entry->GetURL()); + const content::LoadCommittedDetails& details) { + Emit("navigation-entry-commited", details.entry->GetURL(), + details.is_in_page, details.did_replace_entry); } void WebContents::DidAttach(int guest_proxy_routing_id) { diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee index 75f9dd2097..28404b1214 100644 --- a/atom/browser/api/lib/navigation-controller.coffee +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -9,16 +9,21 @@ class NavigationController @currentIndex = -1 @pendingIndex = -1 - @webContents.on 'navigation-entry-commited', (event, url) => + @webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) => + if replaceEntry + @history[@currentIndex] = {url, inPage} + return + if @pendingIndex is -1 # Normal navigation. @history = @history.slice 0, @currentIndex + 1 # Clear history. - if @history[@currentIndex] isnt url + currentEntry = @history[@currentIndex] + if currentEntry?.url isnt url or currentEntry?.inPage isnt inPage @currentIndex++ - @history.push url + @history.push {url, inPage} else # Go to index. @currentIndex = @pendingIndex @pendingIndex = -1 - @history[@currentIndex] = url + @history[@currentIndex] = {url, inPage} loadUrl: (url, options={}) -> @pendingIndex = -1 @@ -28,7 +33,7 @@ class NavigationController if @currentIndex is -1 '' else - @history[@currentIndex] + @history[@currentIndex].url stop: -> @pendingIndex = -1 @@ -57,17 +62,17 @@ class NavigationController goBack: -> return unless @canGoBack() @pendingIndex = @getActiveIndex() - 1 - @webContents._loadUrl @history[@pendingIndex], {} + @webContents._loadUrl @history[@pendingIndex].url, {} goForward: -> return unless @canGoForward() @pendingIndex = @getActiveIndex() + 1 - @webContents._loadUrl @history[@pendingIndex], {} + @webContents._loadUrl @history[@pendingIndex].url, {} goToIndex: (index) -> return unless @canGoToIndex index @pendingIndex = index - @webContents._loadUrl @history[@pendingIndex], {} + @webContents._loadUrl @history[@pendingIndex].url, {} goToOffset: (offset) -> return unless @canGoToOffset offset From 4c109256946e32ce21301ecfe8be7065bc270d90 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 14:05:20 +0800 Subject: [PATCH 2/8] Add remote.getCurrentWebContents API --- atom/browser/lib/rpc-server.coffee | 3 +++ atom/renderer/api/lib/remote.coffee | 9 ++++++++- docs/api/remote.md | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/atom/browser/lib/rpc-server.coffee b/atom/browser/lib/rpc-server.coffee index 1703f1e247..48d00e9bd2 100644 --- a/atom/browser/lib/rpc-server.coffee +++ b/atom/browser/lib/rpc-server.coffee @@ -107,6 +107,9 @@ ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, guestInstanceId) -> catch e event.returnValue = errorToMeta e +ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) -> + event.returnValue = valueToMeta event.sender, event.sender + ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) -> try args = unwrapArgs event.sender, args diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 673a01cb20..5696784765 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -110,13 +110,20 @@ exports.require = (module) -> meta = ipc.sendSync 'ATOM_BROWSER_REQUIRE', module moduleCache[module] = metaToValue meta -# Get current window object. +# Get current BrowserWindow object. windowCache = null exports.getCurrentWindow = -> return windowCache if windowCache? meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WINDOW', process.guestInstanceId windowCache = metaToValue meta +# Get current WebContents object. +webContentsCache = null +exports.getCurrentWebContents = -> + return webContentsCache if webContentsCache? + meta = ipc.sendSync 'ATOM_BROWSER_CURRENT_WEB_CONTENTS' + webContentsCache = metaToValue meta + # Get a global object in browser. exports.getGlobal = (name) -> meta = ipc.sendSync 'ATOM_BROWSER_GLOBAL', name diff --git a/docs/api/remote.md b/docs/api/remote.md index 77e76ea57f..89bbc1f060 100644 --- a/docs/api/remote.md +++ b/docs/api/remote.md @@ -138,6 +138,10 @@ Returns the object returned by `require(module)` in the main process. Returns the [BrowserWindow](browser-window.md) object which this web page belongs to. +## remote.getCurrentWebContent() + +Returns the WebContents object of this web page. + ## remote.getGlobal(name) * `name` String From 4d1cd7e15f6f0ad780d04c4a5a0b34baa1a3df9a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 14:29:44 +0800 Subject: [PATCH 3/8] Redirect history operations in renderer to browser --- atom/renderer/lib/override.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee index 6e02c2eb82..3ac5177e80 100644 --- a/atom/renderer/lib/override.coffee +++ b/atom/renderer/lib/override.coffee @@ -74,6 +74,12 @@ window.confirm = (message, title='') -> window.prompt = -> throw new Error('prompt() is and will not be supported.') +# Forward history operations to browser. +window.history.back = -> + remote.getCurrentWebContents().goBack() +window.history.forward = -> + remote.getCurrentWebContents().goForward() + window.opener = postMessage: (message, targetOrigin='*') -> ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', message, targetOrigin From 40631edb70abfe1803a8e912dfc0c27fcaed8ea4 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 14:30:26 +0800 Subject: [PATCH 4/8] Use Chrome's navigation controller for in-page navigations --- atom/browser/api/atom_api_web_contents.cc | 10 +++++++ atom/browser/api/atom_api_web_contents.h | 3 ++ .../api/lib/navigation-controller.coffee | 28 ++++++++++++------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 2fedd10cf4..558b26b9d1 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -443,6 +443,14 @@ void WebContents::ReloadIgnoringCache() { web_contents()->GetController().ReloadIgnoringCache(false); } +void WebContents::GoBack() { + web_contents()->GetController().GoBack(); +} + +void WebContents::GoForward() { + web_contents()->GetController().GoForward(); +} + int WebContents::GetRoutingID() const { return web_contents()->GetRoutingID(); } @@ -611,6 +619,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse) .SetMethod("_stop", &WebContents::Stop) .SetMethod("_reloadIgnoringCache", &WebContents::ReloadIgnoringCache) + .SetMethod("_goBack", &WebContents::GoBack) + .SetMethod("_goForward", &WebContents::GoForward) .SetMethod("getRoutingId", &WebContents::GetRoutingID) .SetMethod("getProcessId", &WebContents::GetProcessID) .SetMethod("isCrashed", &WebContents::IsCrashed) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index cc2fd30c83..aa0ee8d6f6 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -53,6 +53,9 @@ class WebContents : public mate::EventEmitter, bool IsWaitingForResponse() const; void Stop(); void ReloadIgnoringCache(); + void GoBack(); + void GoForward(); + void GoToIndex(); int GetRoutingID() const; int GetProcessID() const; bool IsCrashed() const; diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee index 28404b1214..675f34e85f 100644 --- a/atom/browser/api/lib/navigation-controller.coffee +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -10,20 +10,20 @@ class NavigationController @pendingIndex = -1 @webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) => - if replaceEntry - @history[@currentIndex] = {url, inPage} - return + console.log 'navigation-entry-commited', url, inPage, replaceEntry - if @pendingIndex is -1 # Normal navigation. + if @pendingIndex >= 0 # Go to index. + @currentIndex = @pendingIndex + @pendingIndex = -1 + @history[@currentIndex] = {url, inPage} + else if replaceEntry # Non-user initialized navigation. + @history[@currentIndex] = {url, inPage} + else # Normal navigation. @history = @history.slice 0, @currentIndex + 1 # Clear history. currentEntry = @history[@currentIndex] if currentEntry?.url isnt url or currentEntry?.inPage isnt inPage @currentIndex++ @history.push {url, inPage} - else # Go to index. - @currentIndex = @pendingIndex - @pendingIndex = -1 - @history[@currentIndex] = {url, inPage} loadUrl: (url, options={}) -> @pendingIndex = -1 @@ -62,12 +62,20 @@ class NavigationController goBack: -> return unless @canGoBack() @pendingIndex = @getActiveIndex() - 1 - @webContents._loadUrl @history[@pendingIndex].url, {} + pendingEntry = @history[@pendingIndex] + if pendingEntry.inPage + @webContents._goBack() + else + @webContents._loadUrl pendingEntry.url, {} goForward: -> return unless @canGoForward() @pendingIndex = @getActiveIndex() + 1 - @webContents._loadUrl @history[@pendingIndex].url, {} + pendingEntry = @history[@pendingIndex] + if pendingEntry.inPage + @webContents._goForward() + else + @webContents._loadUrl pendingEntry.url, {} goToIndex: (index) -> return unless @canGoToIndex index From d1545a64aeffcbd7ae4f207d72ea4fb29b3840f6 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 14:40:40 +0800 Subject: [PATCH 5/8] Don't force restart renderer process for in-page navigation --- atom/browser/api/atom_api_web_contents.cc | 3 +++ atom/browser/atom_browser_client.cc | 13 +++++++++++++ atom/browser/atom_browser_client.h | 3 +++ 3 files changed, 19 insertions(+) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 558b26b9d1..ddb05cfdfe 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -6,6 +6,7 @@ #include +#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_javascript_dialog_manager.h" #include "atom/browser/native_window.h" @@ -444,10 +445,12 @@ void WebContents::ReloadIgnoringCache() { } void WebContents::GoBack() { + atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); web_contents()->GetController().GoBack(); } void WebContents::GoForward() { + atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); web_contents()->GetController().GoForward(); } diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 1d00f6bdcf..fbc09d9fe1 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -32,6 +32,9 @@ namespace atom { namespace { +// Next navigation should not restart renderer process. +bool g_suppress_renderer_process_restart = false; + struct FindByProcessId { explicit FindByProcessId(int child_process_id) : child_process_id_(child_process_id) { @@ -51,6 +54,11 @@ struct FindByProcessId { } // namespace +// static +void AtomBrowserClient::SuppressRendererProcessRestartForOnce() { + g_suppress_renderer_process_restart = true; +} + AtomBrowserClient::AtomBrowserClient() : dying_render_process_(nullptr) { } @@ -131,6 +139,11 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation( content::SiteInstance* current_instance, const GURL& url, content::SiteInstance** new_instance) { + if (g_suppress_renderer_process_restart) { + g_suppress_renderer_process_restart = false; + return; + } + if (current_instance->HasProcess()) dying_render_process_ = current_instance->GetProcess(); diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index cda0bd8e5c..cc69a1e12d 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -18,6 +18,9 @@ class AtomBrowserClient : public brightray::BrowserClient { AtomBrowserClient(); virtual ~AtomBrowserClient(); + // Don't force renderer process to restart for once. + static void SuppressRendererProcessRestartForOnce(); + protected: // content::ContentBrowserClient: void RenderProcessWillLaunch(content::RenderProcessHost* host) override; From 82ffa4d2b10d765e9fecb4030412f4ee051daf10 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 16:03:25 +0800 Subject: [PATCH 6/8] Send history operations as asynchronous messages Sending as sync message will cause weird results for NavigationController --- atom/browser/api/lib/navigation-controller.coffee | 6 ++++++ atom/browser/api/lib/web-contents.coffee | 1 - atom/renderer/lib/override.coffee | 13 +++++++------ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee index 675f34e85f..9c3159ce40 100644 --- a/atom/browser/api/lib/navigation-controller.coffee +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -1,3 +1,9 @@ +ipc = require 'ipc' + +# The history operation in renderer is redirected to browser. +ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) -> + event.sender[method] args... + # JavaScript implementation of Chromium's NavigationController. # Instead of relying on Chromium for history control, we compeletely do history # control on user land, and only rely on WebContents.loadUrl for navigation. diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index e249ccfb80..eb86c94500 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -29,7 +29,6 @@ module.exports.wrap = (webContents) -> # The navigation controller. controller = new NavigationController(webContents) - webContents.controller = controller for name, method of NavigationController.prototype when method instanceof Function do (name, method) -> webContents[name] = -> method.apply controller, arguments diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee index 3ac5177e80..1bc1e612c5 100644 --- a/atom/renderer/lib/override.coffee +++ b/atom/renderer/lib/override.coffee @@ -74,15 +74,16 @@ window.confirm = (message, title='') -> window.prompt = -> throw new Error('prompt() is and will not be supported.') -# Forward history operations to browser. -window.history.back = -> - remote.getCurrentWebContents().goBack() -window.history.forward = -> - remote.getCurrentWebContents().goForward() - +# Simple implementation of postMessage. window.opener = postMessage: (message, targetOrigin='*') -> ipc.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', message, targetOrigin ipc.on 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', (message, targetOrigin) -> window.postMessage message, targetOrigin + +# Forward history operations to browser. +sendHistoryOperation = (args...) -> + ipc.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args... +window.history.back = -> sendHistoryOperation 'goBack' +window.history.forward = -> sendHistoryOperation 'goForward' From 2bb74973121a0933237bed60eb0c0037e465bff9 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 16:37:53 +0800 Subject: [PATCH 7/8] Handle when in-page entries are cleared --- .../api/lib/navigation-controller.coffee | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee index 9c3159ce40..82c4ab4da7 100644 --- a/atom/browser/api/lib/navigation-controller.coffee +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -14,22 +14,28 @@ class NavigationController @history = [] @currentIndex = -1 @pendingIndex = -1 + @inPageIndex = -1 @webContents.on 'navigation-entry-commited', (event, url, inPage, replaceEntry) => - console.log 'navigation-entry-commited', url, inPage, replaceEntry + if @inPageIndex > -1 and not inPage + # Navigated to a new page, clear in-page mark. + @inPageIndex = -1 + else if @inPageIndex is -1 and inPage + # Started in-page navigations. + @inPageIndex = @currentIndex if @pendingIndex >= 0 # Go to index. @currentIndex = @pendingIndex @pendingIndex = -1 - @history[@currentIndex] = {url, inPage} + @history[@currentIndex] = url else if replaceEntry # Non-user initialized navigation. - @history[@currentIndex] = {url, inPage} + @history[@currentIndex] = url else # Normal navigation. @history = @history.slice 0, @currentIndex + 1 # Clear history. currentEntry = @history[@currentIndex] - if currentEntry?.url isnt url or currentEntry?.inPage isnt inPage + if currentEntry?.url isnt url @currentIndex++ - @history.push {url, inPage} + @history.push url loadUrl: (url, options={}) -> @pendingIndex = -1 @@ -39,7 +45,7 @@ class NavigationController if @currentIndex is -1 '' else - @history[@currentIndex].url + @history[@currentIndex] stop: -> @pendingIndex = -1 @@ -68,20 +74,18 @@ class NavigationController goBack: -> return unless @canGoBack() @pendingIndex = @getActiveIndex() - 1 - pendingEntry = @history[@pendingIndex] - if pendingEntry.inPage + if @inPageIndex > -1 and @pendingIndex >= @inPageIndex @webContents._goBack() else - @webContents._loadUrl pendingEntry.url, {} + @webContents._loadUrl @history[@pendingIndex], {} goForward: -> return unless @canGoForward() @pendingIndex = @getActiveIndex() + 1 - pendingEntry = @history[@pendingIndex] - if pendingEntry.inPage + if @inPageIndex > -1 and @pendingIndex >= @inPageIndex @webContents._goForward() else - @webContents._loadUrl pendingEntry.url, {} + @webContents._loadUrl @history[@pendingIndex], {} goToIndex: (index) -> return unless @canGoToIndex index From e817192df3db3b415bf277777625924e6d84d981 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 11 May 2015 16:44:01 +0800 Subject: [PATCH 8/8] Make history.go work --- atom/browser/api/atom_api_web_contents.cc | 6 ++++++ atom/browser/api/atom_api_web_contents.h | 2 +- atom/browser/api/lib/navigation-controller.coffee | 7 ++++++- atom/renderer/lib/override.coffee | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index ddb05cfdfe..e228a064f4 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -454,6 +454,11 @@ void WebContents::GoForward() { web_contents()->GetController().GoForward(); } +void WebContents::GoToOffset(int offset) { + atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); + web_contents()->GetController().GoToOffset(offset); +} + int WebContents::GetRoutingID() const { return web_contents()->GetRoutingID(); } @@ -624,6 +629,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("_reloadIgnoringCache", &WebContents::ReloadIgnoringCache) .SetMethod("_goBack", &WebContents::GoBack) .SetMethod("_goForward", &WebContents::GoForward) + .SetMethod("_goToOffset", &WebContents::GoToOffset) .SetMethod("getRoutingId", &WebContents::GetRoutingID) .SetMethod("getProcessId", &WebContents::GetProcessID) .SetMethod("isCrashed", &WebContents::IsCrashed) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index aa0ee8d6f6..e75cfb0267 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -55,7 +55,7 @@ class WebContents : public mate::EventEmitter, void ReloadIgnoringCache(); void GoBack(); void GoForward(); - void GoToIndex(); + void GoToOffset(int offset); int GetRoutingID() const; int GetProcessID() const; bool IsCrashed() const; diff --git a/atom/browser/api/lib/navigation-controller.coffee b/atom/browser/api/lib/navigation-controller.coffee index 82c4ab4da7..f7945e07bf 100644 --- a/atom/browser/api/lib/navigation-controller.coffee +++ b/atom/browser/api/lib/navigation-controller.coffee @@ -94,7 +94,12 @@ class NavigationController goToOffset: (offset) -> return unless @canGoToOffset offset - @goToIndex @currentIndex + offset + pendingIndex = @currentIndex + offset + if @inPageIndex > -1 and pendingIndex >= @inPageIndex + @pendingIndex = pendingIndex + @webContents._goToOffset offset + else + @goToIndex pendingIndex getActiveIndex: -> if @pendingIndex is -1 then @currentIndex else @pendingIndex diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee index 1bc1e612c5..1ca6e692ba 100644 --- a/atom/renderer/lib/override.coffee +++ b/atom/renderer/lib/override.coffee @@ -87,3 +87,4 @@ sendHistoryOperation = (args...) -> ipc.send 'ATOM_SHELL_NAVIGATION_CONTROLLER', args... window.history.back = -> sendHistoryOperation 'goBack' window.history.forward = -> sendHistoryOperation 'goForward' +window.history.go = (offset) -> sendHistoryOperation 'goToOffset', offset