Reland the ULONG -> SIZE_T change from 317177
[chromium-blink-merge.git] / extensions / renderer / resources / guest_view / web_view.js
blobff8c6718e1ffc70bdeea1379d05f32f33eea7bf2
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This module implements WebView (<webview>) as a custom element that wraps a
6 // BrowserPlugin object element. The object element is hidden within
7 // the shadow DOM of the WebView element.
9 var DocumentNatives = requireNative('document_natives');
10 var GuestView = require('guestView').GuestView;
11 var GuestViewContainer = require('guestViewContainer').GuestViewContainer;
12 var WebViewConstants = require('webViewConstants').WebViewConstants;
13 var WebViewEvents = require('webViewEvents').WebViewEvents;
14 var WebViewInternal = require('webViewInternal').WebViewInternal;
16 // Represents the internal state of <webview>.
17 function WebViewImpl(webviewElement) {
18   GuestViewContainer.call(this, webviewElement, 'webview');
20   this.setupWebViewAttributes();
21   this.setupElementProperties();
23   new WebViewEvents(this, this.viewInstanceId);
26 WebViewImpl.prototype.__proto__ = GuestViewContainer.prototype;
28 WebViewImpl.VIEW_TYPE = 'WebView';
30 // Add extra functionality to |this.element|.
31 WebViewImpl.setupElement = function(proto) {
32   // Public-facing API methods.
33   var apiMethods = WebViewImpl.getApiMethods();
35   // Add the experimental API methods, if available.
36   var experimentalApiMethods =
37       WebViewImpl.maybeGetExperimentalApiMethods();
38   apiMethods = $Array.concat(apiMethods, experimentalApiMethods);
40   // Create default implementations for undefined API methods.
41   var createDefaultApiMethod = function(m) {
42     return function(var_args) {
43       if (!this.guest.getId()) {
44         return false;
45       }
46       var args = $Array.concat([this.guest.getId()], $Array.slice(arguments));
47       $Function.apply(WebViewInternal[m], null, args);
48       return true;
49     };
50   };
51   for (var i = 0; i != apiMethods.length; ++i) {
52     if (WebViewImpl.prototype[apiMethods[i]] == undefined) {
53       WebViewImpl.prototype[apiMethods[i]] =
54           createDefaultApiMethod(apiMethods[i]);
55     }
56   }
58   // Forward proto.foo* method calls to WebViewImpl.foo*.
59   GuestViewContainer.forwardApiMethods(proto, apiMethods);
62 // Initiates navigation once the <webview> element is attached to the DOM.
63 WebViewImpl.prototype.onElementAttached = function() {
64   for (var i in this.attributes) {
65     this.attributes[i].attach();
66   }
69 // Resets some state upon detaching <webview> element from the DOM.
70 WebViewImpl.prototype.onElementDetached = function() {
71   this.guest.destroy();
72   for (var i in this.attributes) {
73     this.attributes[i].detach();
74   }
77 // Sets the <webview>.request property.
78 WebViewImpl.prototype.setRequestPropertyOnWebViewElement = function(request) {
79   Object.defineProperty(
80       this.element,
81       'request',
82       {
83         value: request,
84         enumerable: true
85       }
86   );
89 WebViewImpl.prototype.setupElementProperties = function() {
90   // We cannot use {writable: true} property descriptor because we want a
91   // dynamic getter value.
92   Object.defineProperty(this.element, 'contentWindow', {
93     get: function() {
94       if (this.guest.getContentWindow()) {
95         return this.guest.getContentWindow();
96       }
97       window.console.error(
98           WebViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE);
99     }.bind(this),
100     // No setter.
101     enumerable: true
102   });
105 // This observer monitors mutations to attributes of the <webview>.
106 WebViewImpl.prototype.handleAttributeMutation = function(
107     attributeName, oldValue, newValue) {
108   if (!this.attributes[attributeName]) {
109     return;
110   }
112   // Let the changed attribute handle its own mutation;
113   this.attributes[attributeName].maybeHandleMutation(oldValue, newValue);
116 WebViewImpl.prototype.onSizeChanged = function(webViewEvent) {
117   var newWidth = webViewEvent.newWidth;
118   var newHeight = webViewEvent.newHeight;
120   var element = this.element;
122   var width = element.offsetWidth;
123   var height = element.offsetHeight;
125   // Check the current bounds to make sure we do not resize <webview>
126   // outside of current constraints.
127   var maxWidth = this.attributes[
128     WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || width;
129   var minWidth = this.attributes[
130     WebViewConstants.ATTRIBUTE_MINWIDTH].getValue() || width;
131   var maxHeight = this.attributes[
132     WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || height;
133   var minHeight = this.attributes[
134     WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || height;
136   minWidth = Math.min(minWidth, maxWidth);
137   minHeight = Math.min(minHeight, maxHeight);
139   if (!this.attributes[WebViewConstants.ATTRIBUTE_AUTOSIZE].getValue() ||
140       (newWidth >= minWidth &&
141       newWidth <= maxWidth &&
142       newHeight >= minHeight &&
143       newHeight <= maxHeight)) {
144     element.style.width = newWidth + 'px';
145     element.style.height = newHeight + 'px';
146     // Only fire the DOM event if the size of the <webview> has actually
147     // changed.
148     this.dispatchEvent(webViewEvent);
149   }
152 WebViewImpl.prototype.createGuest = function() {
153   this.guest.create(this.buildParams(), function() {
154     this.attachWindow();
155   }.bind(this));
158 WebViewImpl.prototype.onFrameNameChanged = function(name) {
159   this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValueIgnoreMutation(name);
162 WebViewImpl.prototype.dispatchEvent = function(webViewEvent) {
163   return this.element.dispatchEvent(webViewEvent);
166 // Updates state upon loadcommit.
167 WebViewImpl.prototype.onLoadCommit = function(
168     baseUrlForDataUrl, currentEntryIndex, entryCount,
169     processId, url, isTopLevel) {
170   this.baseUrlForDataUrl = baseUrlForDataUrl;
171   this.currentEntryIndex = currentEntryIndex;
172   this.entryCount = entryCount;
173   this.processId = processId;
174   if (isTopLevel) {
175     // Touching the src attribute triggers a navigation. To avoid
176     // triggering a page reload on every guest-initiated navigation,
177     // we do not handle this mutation.
178     this.attributes[
179         WebViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation(url);
180   }
183 WebViewImpl.prototype.onAttach = function(storagePartitionId) {
184   this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValueIgnoreMutation(
185       storagePartitionId);
188 WebViewImpl.prototype.buildContainerParams = function() {
189   var params = { 'userAgentOverride': this.userAgentOverride };
190   for (var i in this.attributes) {
191     params[i] = this.attributes[i].getValue();
192   }
193   return params;
196 WebViewImpl.prototype.attachWindow = function(opt_guestInstanceId) {
197   // If |opt_guestInstanceId| was provided, then a different existing guest is
198   // being attached to this webview, and the current one will get destroyed.
199   if (opt_guestInstanceId) {
200     if (this.guest.getId() == opt_guestInstanceId) {
201       return true;
202     }
203     this.guest.destroy();
204     this.guest = new GuestView('webview', opt_guestInstanceId);
205   }
207   return GuestViewContainer.prototype.attachWindow.call(this);
210 // Shared implementation of executeScript() and insertCSS().
211 WebViewImpl.prototype.executeCode = function(func, args) {
212   if (!this.guest.getId()) {
213     window.console.error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT);
214     return false;
215   }
217   var webviewSrc = this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue();
218   if (this.baseUrlForDataUrl) {
219     webviewSrc = this.baseUrlForDataUrl;
220   }
222   args = $Array.concat([this.guest.getId(), webviewSrc],
223                        $Array.slice(args));
224   $Function.apply(func, null, args);
225   return true;
228 // Implemented when the ChromeWebView API is available.
229 WebViewImpl.prototype.maybeGetChromeWebViewEvents = function() {};
231 // Implemented when the experimental WebView API is available.
232 WebViewImpl.maybeGetExperimentalApiMethods = function() { return []; };
233 WebViewImpl.prototype.setupExperimentalContextMenus = function() {};
234 WebViewImpl.prototype.maybeSetupExperimentalChromeWebViewEvents =
235   function(request) {
236     return request;
239 GuestViewContainer.registerElement(WebViewImpl);
241 // Exports.
242 exports.WebViewImpl = WebViewImpl;