diff --git a/atom.gyp b/atom.gyp index 357763e3578c..283c2c4eec49 100644 --- a/atom.gyp +++ b/atom.gyp @@ -49,6 +49,7 @@ 'atom/renderer/lib/override.coffee', 'atom/renderer/lib/web-view/guest-view-internal.coffee', 'atom/renderer/lib/web-view/web-view.coffee', + 'atom/renderer/lib/web-view/web-view-constants.coffee', 'atom/renderer/api/lib/ipc.coffee', 'atom/renderer/api/lib/remote.coffee', 'atom/renderer/api/lib/web-frame.coffee', diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 427a2281093a..19b6d3276a27 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -37,12 +37,14 @@ v8::Persistent template_; WebContents::WebContents(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), guest_instance_id_(-1), + element_instance_id_(-1), guest_opaque_(true), auto_size_enabled_(false) { } WebContents::WebContents(const mate::Dictionary& options) : guest_instance_id_(-1), + element_instance_id_(-1), guest_opaque_(true), auto_size_enabled_(false) { options.Get("guestInstanceId", &guest_instance_id_); @@ -226,9 +228,7 @@ void WebContents::WebContentsDestroyed() { } void WebContents::DidAttach(int guest_proxy_routing_id) { - base::ListValue args; - args.Append(extra_params_.release()); - Emit("did-attach", args); + Emit("did-attach"); } void WebContents::ElementSizeChanged(const gfx::Size& old_size, @@ -252,6 +252,7 @@ void WebContents::RegisterDestructionCallback( void WebContents::WillAttach(content::WebContents* embedder_web_contents, int browser_plugin_instance_id) { embedder_web_contents_ = embedder_web_contents; + element_instance_id_ = browser_plugin_instance_id; } void WebContents::Destroy() { diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index f6442e8a80c9..8371a65560b8 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -163,17 +163,15 @@ class WebContents : public mate::EventEmitter, // Unique ID for a guest WebContents. int guest_instance_id_; + // |element_instance_id_| is an identifer that's unique to a particular + // element. + int element_instance_id_; + DestructionCallback destruction_callback_; // Stores whether the contents of the guest can be transparent. bool guest_opaque_; - // The extra parameters associated with this guest view passed - // in from JavaScript. This will typically be the view instance ID, - // the API to use, and view-specific parameters. These parameters - // are passed along to new guests that are created from this guest. - scoped_ptr extra_params_; - // Stores the WebContents that managed by this class. scoped_ptr storage_; diff --git a/atom/browser/lib/guest-view-manager.coffee b/atom/browser/lib/guest-view-manager.coffee index db8ed44848eb..4f2af53f5765 100644 --- a/atom/browser/lib/guest-view-manager.coffee +++ b/atom/browser/lib/guest-view-manager.coffee @@ -18,6 +18,8 @@ supportedWebViewEvents = [ nextInstanceId = 0 guestInstances = {} +embedderElementsMap = {} +reverseEmbedderElementsMap = {} # Generate guestInstanceId. getNextInstanceId = (webContents) -> @@ -41,7 +43,10 @@ createGuest = (embedder, params) -> destroyGuest id if guestInstances[id]? # Init guest web view after attached. - guest.once 'did-attach', (event, params) -> + guest.once 'did-attach', -> + params = @attachParams + delete @attachParams + @viewInstanceId = params.instanceId min = width: params.minwidth, height: params.minheight max = width: params.maxwidth, height: params.maxheight @@ -66,15 +71,42 @@ createGuest = (embedder, params) -> id +# Attach the guest to an element of embedder. +attachGuest = (embedder, elementInstanceId, guestInstanceId, params) -> + guest = guestInstances[guestInstanceId].guest + + # Destroy the old guest when attaching. + key = "#{embedder.getId()}-#{elementInstanceId}" + oldGuestInstanceId = embedderElementsMap[key] + if oldGuestInstanceId? + # Reattachment to the same guest is not currently supported. + return unless oldGuestInstanceId != guestInstanceId + + return unless guestInstances[oldGuestInstanceId]? + destroyGuest oldGuestInstanceId + + guest.attachParams = params + embedderElementsMap[key] = guestInstanceId + reverseEmbedderElementsMap[guestInstanceId] = key + # Destroy an existing guest instance. destroyGuest = (id) -> webViewManager.removeGuest id guestInstances[id].guest.destroy() delete guestInstances[id] + key = reverseEmbedderElementsMap[id] + if key? + delete reverseEmbedderElementsMap[id] + delete embedderElementsMap[key] + ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, type, params, requestId) -> event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}", createGuest(event.sender, params) +ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId, guestInstanceId, params, requestId) -> + attachGuest event.sender, elementInstanceId, guestInstanceId, params + event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}" + ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', (event, id) -> destroyGuest id diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc index 0b80de8e4ccb..9fc9008ea3c5 100644 --- a/atom/renderer/api/atom_api_web_frame.cc +++ b/atom/renderer/api/atom_api_web_frame.cc @@ -5,6 +5,7 @@ #include "atom/renderer/api/atom_api_web_frame.h" #include "atom/common/native_mate_converters/string16_converter.h" +#include "content/public/renderer/render_frame.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" #include "third_party/WebKit/public/web/WebDocument.h" @@ -51,6 +52,10 @@ v8::Handle WebFrame::RegisterEmbedderCustomElement( return web_frame_->document().registerEmbedderCustomElement(name, options, c); } +void WebFrame::AttachGuest(int id) { + content::RenderFrame::FromWebFrame(web_frame_)->AttachGuest(id); +} + mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) @@ -60,7 +65,8 @@ mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder( .SetMethod("setZoomFactor", &WebFrame::SetZoomFactor) .SetMethod("getZoomFactor", &WebFrame::GetZoomFactor) .SetMethod("registerEmbedderCustomElement", - &WebFrame::RegisterEmbedderCustomElement); + &WebFrame::RegisterEmbedderCustomElement) + .SetMethod("attachGuest", &WebFrame::AttachGuest); } // static diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h index 955794f22929..132199e3fe7e 100644 --- a/atom/renderer/api/atom_api_web_frame.h +++ b/atom/renderer/api/atom_api_web_frame.h @@ -35,6 +35,7 @@ class WebFrame : public mate::Wrappable { v8::Handle RegisterEmbedderCustomElement( const base::string16& name, v8::Handle options); + void AttachGuest(int element_instance_id); // mate::Wrappable: virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( diff --git a/atom/renderer/lib/web-view/guest-view-internal.coffee b/atom/renderer/lib/web-view/guest-view-internal.coffee index 76474d27ec54..96a8c6edea72 100644 --- a/atom/renderer/lib/web-view/guest-view-internal.coffee +++ b/atom/renderer/lib/web-view/guest-view-internal.coffee @@ -1,4 +1,5 @@ ipc = require 'ipc' +webFrame = require 'web-frame' requestId = 0 @@ -36,7 +37,12 @@ module.exports = createGuest: (type, params, callback) -> requestId++ ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', type, params, requestId - ipc.on "ATOM_SHELL_RESPONSE_#{requestId}", callback + ipc.once "ATOM_SHELL_RESPONSE_#{requestId}", callback + + attachGuest: (elementInstanceId, guestInstanceId, params, callback) -> + ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params + ipc.once "ATOM_SHELL_RESPONSE_#{requestId}", callback + webFrame.attachGuest elementInstanceId destroyGuest: (guestInstanceId) -> ipc.send 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId diff --git a/atom/renderer/lib/web-view/web-view-constants.coffee b/atom/renderer/lib/web-view/web-view-constants.coffee new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee index 2bae4a902199..d9e8d8e15218 100644 --- a/atom/renderer/lib/web-view/web-view.coffee +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -7,10 +7,6 @@ remote = require 'remote' nextId = 0 getNextId = -> ++nextId -# FIXME -# Discarded after Chrome 39 -PLUGIN_METHOD_ATTACH = '-internal-attach' - # Attributes. WEB_VIEW_ATTRIBUTE_ALLOWTRANSPARENCY = 'allowtransparency' WEB_VIEW_ATTRIBUTE_AUTOSIZE = 'autosize' @@ -103,6 +99,8 @@ class WebView @setupWebviewNodeProperties() @viewInstanceId = getNextId() + + # UPSTREAM: new WebViewEvents(this, this.viewInstanceId); guestViewInternal.registerEvents this, @viewInstanceId shadowRoot.appendChild @browserPluginNode @@ -126,6 +124,7 @@ class WebView # heard back from createGuest yet. We will not reset the flag in this case so # that we don't end up allocating a second guest. if @guestInstanceId + # FIXME guestViewInternal.destroyGuest @guestInstanceId @guestInstanceId = undefined @beforeFirstNavigation = true @@ -295,23 +294,14 @@ class WebView @partition.fromAttribute newValue, @hasNavigated() handleBrowserPluginAttributeMutation: (name, oldValue, newValue) -> - # FIXME - # internalbindings => internalInstanceid after Chrome 39 - if name is 'internalbindings' and !oldValue and !!newValue - @browserPluginNode.removeAttribute 'internalbindings' - # FIXME - # @internalInstanceId = parseInt newValue + if name is 'internalinstanceid' and !oldValue and !!newValue + @browserPluginNode.removeAttribute 'internalinstanceid' + @internalInstanceId = parseInt newValue if !!@guestInstanceId and @guestInstanceId != 0 isNewWindow = if @deferredAttachState then @deferredAttachState.isNewWindow else false params = @buildAttachParams isNewWindow - # FIXME - # guestViewInternalNatives.AttachGuest - # @internalInstanceId, - # @guestInstanceId, - # params, - # (w) => @contentWindow = w - @browserPluginNode[PLUGIN_METHOD_ATTACH] @guestInstanceId, params + guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, params, (w) => @contentWindow = w onSizeChanged: (webViewEvent) -> newWidth = webViewEvent.newWidth @@ -363,9 +353,7 @@ class WebView # Returns if is in the render tree. isPluginInRenderTree: -> - # FIXME - # !!@internalInstanceId && @internalInstanceId != 0 - 'function' == typeof this.browserPluginNode[PLUGIN_METHOD_ATTACH] + !!@internalInstanceId && @internalInstanceId != 0 hasNavigated: -> not @beforeFirstNavigation @@ -480,9 +468,7 @@ class WebView return true @deferredAttachState = null - # FIXME - # guestViewInternalNatives.AttachGuest @internalInstanceId, @guestInstanceId, params, (w) => @contentWindow = w - @browserPluginNode[PLUGIN_METHOD_ATTACH] @guestInstanceId, params + guestViewInternal.attachGuest @internalInstanceId, @guestInstanceId, params, (w) => @contentWindow = w # Registers browser plugin custom element. registerBrowserPluginElement = ->