Skip to content

Commit

Permalink
Created the GuestView object to manage a guestview from javascript. I…
Browse files Browse the repository at this point in the history
…t exposes a public API to allow the guestview to be created, attached, and destroyed, and hides other implementation details in an internal GuestViewImpl object. It also enforces proper usage/ordering of the API using an internal queue and state machine.

BUG=431002,434226

Review URL: https://codereview.chromium.org/723453006

Cr-Commit-Position: refs/heads/master@{#304875}
  • Loading branch information
paulmeyer90 authored and Commit bot committed Nov 19, 2014
1 parent 08fb143 commit 5c9d08f
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 0 deletions.
1 change: 1 addition & 0 deletions extensions/renderer/dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ std::vector<std::pair<std::string, int> > Dispatcher::GetJsResources() {
IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS));
// Note: webView not webview so that this doesn't interfere with the
// chrome.webview API bindings.
resources.push_back(std::make_pair("guestView", IDR_GUEST_VIEW_JS));
resources.push_back(std::make_pair("webView", IDR_WEB_VIEW_JS));
resources.push_back(std::make_pair("webViewApiMethods",
IDR_WEB_VIEW_API_METHODS_JS));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<include name="IDR_UNCAUGHT_EXCEPTION_HANDLER_JS" file="uncaught_exception_handler.js" type="BINDATA" />
<include name="IDR_UNLOAD_EVENT_JS" file="unload_event.js" type="BINDATA" />
<include name="IDR_UTILS_JS" file="utils.js" type="BINDATA" />
<include name="IDR_GUEST_VIEW_JS" file="guest_view/guest_view.js" type="BINDATA" />
<include name="IDR_WEB_VIEW_API_METHODS_JS" file="guest_view/web_view_api_methods.js" type="BINDATA" />
<include name="IDR_WEB_VIEW_ATTRIBUTES_JS" file="guest_view/web_view_attributes.js" type="BINDATA" />
<include name="IDR_WEB_VIEW_CONSTANTS_JS" file="guest_view/web_view_constants.js" type="BINDATA" />
Expand Down
196 changes: 196 additions & 0 deletions extensions/renderer/resources/guest_view/guest_view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This module implements a wrapper for a guestview that manages its
// creation, attaching, and destruction.

var GuestViewInternal =
require('binding').Binding.create('guestViewInternal').generate();
var GuestViewInternalNatives = requireNative('guest_view_internal');

// Possible states.
var GUEST_STATE_ATTACHED = 'attached';
var GUEST_STATE_CREATED = 'created';
var GUEST_STATE_DESTROYED = 'destroyed';
var GUEST_STATE_START = 'start';

// Error messages.
var ERROR_MSG_ATTACH = 'Error calling attach: ';
var ERROR_MSG_CREATE = 'Error calling create: ';
var ERROR_MSG_DESTROY = 'Error calling destroy: ';
var ERROR_MSG_ALREADY_CREATED = 'The guest has already been created.';
var ERROR_MSG_DESTROYED = 'The guest is destroyed.';
var ERROR_MSG_INVALID_STATE = 'The guest is in an invalid state.';
var ERROR_MSG_NOT_CREATED = 'The guest has not been created.';

// Contains and hides the internal implementation details of |GuestView|,
// including maintaining its state and enforcing the proper usage of its API
// fucntions.
function GuestViewImpl(viewType) {
this.contentWindow = null;
this.actionQueue = [];
this.pendingAction = null;
this.id = 0;
this.state = GUEST_STATE_START;
this.viewType = viewType;
}

// Callback wrapper that is used to call the callback of the pending action (if
// one exists), and then performs the next action in the queue.
GuestViewImpl.prototype.handleCallback = function(callback) {
if (callback) {
callback();
}
this.pendingAction = null;
this.performNextAction();
}

// Perform the next action in the queue, if one exists.
GuestViewImpl.prototype.performNextAction = function() {
// Make sure that there is not already an action in progress, and that there
// exists a queued action to perform.
if (!this.pendingAction && this.actionQueue.length) {
this.pendingAction = this.actionQueue.shift();
this.pendingAction();
}
};

// Internal implementation of attach().
GuestViewImpl.prototype.attachImpl = function(
internalInstanceId, attachParams, callback) {
// Check the current state.
switch (this.state) {
case GUEST_STATE_START:
window.console.error(ERROR_MSG_ATTACH + ERROR_MSG_NOT_CREATED);
return;
case GUEST_STATE_DESTROYED:
window.console.error(ERROR_MSG_ATTACH + ERROR_MSG_DESTROYED);
return;
case GUEST_STATE_ATTACHED:
case GUEST_STATE_CREATED:
break;
default:
window.console.error(ERROR_MSG_ATTACH + ERROR_MSG_INVALID_STATE);
return;
}

// Callback wrapper function to store the contentWindow from the attachGuest()
// callback, and advance the queue.
var storeContentWindow = function(callback, contentWindow) {
this.contentWindow = contentWindow;
this.handleCallback(callback);
}

GuestViewInternalNatives.AttachGuest(internalInstanceId,
this.id,
attachParams,
storeContentWindow.bind(this, callback));

this.state = GUEST_STATE_ATTACHED;
};

// Internal implementation of create().
GuestViewImpl.prototype.createImpl = function(createParams, callback) {
// Check the current state.
switch (this.state) {
case GUEST_STATE_DESTROYED:
window.console.error(ERROR_MSG_CREATE + ERROR_MSG_DESTROYED);
return;
case GUEST_STATE_ATTACHED:
case GUEST_STATE_CREATED:
window.console.error(ERROR_MSG_CREATE + ERROR_MSG_ALREADY_CREATED);
return;
case GUEST_STATE_START:
break;
default:
window.console.error(ERROR_MSG_CREATE + ERROR_MSG_INVALID_STATE);
return;
}

// Callback wrapper function to store the guestInstanceId from the
// createGuest() callback, and advance the queue.
var storeId = function(callback, guestInstanceId) {
this.id = guestInstanceId;
this.handleCallback(callback);
}

GuestViewInternal.createGuest(this.viewType,
createParams,
storeId.bind(this, callback));

this.state = GUEST_STATE_CREATED;
};

// Internal implementation of destroy().
GuestViewImpl.prototype.destroyImpl = function() {
// Check the current state.
switch (this.state) {
case GUEST_STATE_DESTROYED:
window.console.error(ERROR_MSG_DESTROY + ERROR_MSG_DESTROYED);
return;
case GUEST_STATE_START:
window.console.error(ERROR_MSG_DESTROY + ERROR_MSG_NOT_CREATED);
return;
case GUEST_STATE_ATTACHED:
case GUEST_STATE_CREATED:
break;
default:
window.console.error(ERROR_MSG_DESTROY + ERROR_MSG_INVALID_STATE);
return;
}

GuestViewInternal.destroyGuest(this.id);
this.contentWindow = null;
this.id = 0;
this.handleCallback();

this.state = GUEST_STATE_DESTROYED;
};

// The exposed interface to a guestview. Exposes in its API the functions
// attach(), create(), destroy(), and getId(). All other implementation details
// are hidden.
function GuestView(viewType) {
privates(this).internal = new GuestViewImpl(viewType);
}

// Attaches the guestview to the container with ID |internalInstanceId|.
GuestView.prototype.attach = function(
internalInstanceId, attachParams, callback) {
var internal = privates(this).internal;
internal.actionQueue.push(internal.attachImpl.bind(
internal, internalInstanceId, attachParams, callback));
internal.performNextAction();
};

// Creates the guestview.
GuestView.prototype.create = function(createParams, callback) {
var internal = privates(this).internal;
internal.actionQueue.push(internal.createImpl.bind(
internal, createParams, callback));
internal.performNextAction();
};

// Destroys the guestview. Nothing can be done with the guestview after it has
// been destroyed.
GuestView.prototype.destroy = function() {
var internal = privates(this).internal;
internal.actionQueue.push(internal.destroyImpl.bind(internal));
internal.performNextAction();
};

// Returns the contentWindow for this guestview.
GuestView.prototype.getContentWindow = function() {
var internal = privates(this).internal;
return internal.contentWindow;
};

// Returns the ID for this guestview.
GuestView.prototype.getId = function() {
var internal = privates(this).internal;
return internal.id;
};

// Exports
exports.GuestView = GuestView;

0 comments on commit 5c9d08f

Please sign in to comment.