Reland the ULONG -> SIZE_T change from 317177
[chromium-blink-merge.git] / extensions / renderer / resources / guest_view / web_view_attributes.js
bloba70e9f9a15e46e35e79720db7674d7c101434994
1 // Copyright 2014 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 the attributes of the <webview> tag.
7 var GuestViewInternal =
8     require('binding').Binding.create('guestViewInternal').generate();
9 var WebViewImpl = require('webView').WebViewImpl;
10 var WebViewConstants = require('webViewConstants').WebViewConstants;
11 var WebViewInternal = require('webViewInternal').WebViewInternal;
13 // -----------------------------------------------------------------------------
14 // Attribute objects.
16 // Default implementation of a WebView attribute.
17 function WebViewAttribute(name, webViewImpl) {
18   this.name = name;
19   this.webViewImpl = webViewImpl;
20   this.ignoreMutation = false;
22   this.defineProperty();
25 // Retrieves and returns the attribute's value.
26 WebViewAttribute.prototype.getValue = function() {
27   return this.webViewImpl.element.getAttribute(this.name) || '';
30 // Sets the attribute's value.
31 WebViewAttribute.prototype.setValue = function(value) {
32   this.webViewImpl.element.setAttribute(this.name, value || '');
35 // Changes the attribute's value without triggering its mutation handler.
36 WebViewAttribute.prototype.setValueIgnoreMutation = function(value) {
37   this.ignoreMutation = true;
38   this.setValue(value);
39   this.ignoreMutation = false;
42 // Defines this attribute as a property on the webview node.
43 WebViewAttribute.prototype.defineProperty = function() {
44   Object.defineProperty(this.webViewImpl.element, this.name, {
45     get: function() {
46       return this.getValue();
47     }.bind(this),
48     set: function(value) {
49       this.setValue(value);
50     }.bind(this),
51     enumerable: true
52   });
55 // Called when the attribute's value changes.
56 WebViewAttribute.prototype.maybeHandleMutation = function(oldValue, newValue) {
57   if (this.ignoreMutation) {
58     return;
59   }
61   this.handleMutation(oldValue, newValue);
64 // Called when a change that isn't ignored occurs to the attribute's value.
65 WebViewAttribute.prototype.handleMutation = function(oldValue, newValue) {};
67 // Called when the <webview> element is attached to the DOM tree.
68 WebViewAttribute.prototype.attach = function() {};
70 // Called when the <webview> element is detached from the DOM tree.
71 WebViewAttribute.prototype.detach = function() {};
73 // An attribute that is treated as a Boolean.
74 function BooleanAttribute(name, webViewImpl) {
75   WebViewAttribute.call(this, name, webViewImpl);
78 BooleanAttribute.prototype.__proto__ = WebViewAttribute.prototype;
80 BooleanAttribute.prototype.getValue = function() {
81   return this.webViewImpl.element.hasAttribute(this.name);
84 BooleanAttribute.prototype.setValue = function(value) {
85   if (!value) {
86     this.webViewImpl.element.removeAttribute(this.name);
87   } else {
88     this.webViewImpl.element.setAttribute(this.name, '');
89   }
92 // Attribute that specifies whether transparency is allowed in the webview.
93 function AllowTransparencyAttribute(webViewImpl) {
94   BooleanAttribute.call(
95       this, WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl);
98 AllowTransparencyAttribute.prototype.__proto__ = BooleanAttribute.prototype;
100 AllowTransparencyAttribute.prototype.handleMutation = function(oldValue,
101                                                                newValue) {
102   if (!this.webViewImpl.guest.getId()) {
103     return;
104   }
106   WebViewInternal.setAllowTransparency(this.webViewImpl.guest.getId(),
107                                        this.getValue());
110 // Attribute that specifies whether transparency is allowed in the webview.
111 function AllowScalingAttribute(webViewImpl) {
112   BooleanAttribute.call(
113       this, WebViewConstants.ATTRIBUTE_ALLOWSCALING, webViewImpl);
116 AllowScalingAttribute.prototype.__proto__ = BooleanAttribute.prototype;
118 AllowScalingAttribute.prototype.handleMutation = function(oldValue,
119                                                           newValue) {
120   if (!this.webViewImpl.guest.getId()) {
121     return;
122   }
124   WebViewInternal.setAllowScaling(this.webViewImpl.guest.getId(),
125                                   this.getValue());
128 // Attribute used to define the demension limits of autosizing.
129 function AutosizeDimensionAttribute(name, webViewImpl) {
130   WebViewAttribute.call(this, name, webViewImpl);
133 AutosizeDimensionAttribute.prototype.__proto__ = WebViewAttribute.prototype;
135 AutosizeDimensionAttribute.prototype.getValue = function() {
136   return parseInt(this.webViewImpl.element.getAttribute(this.name)) || 0;
139 AutosizeDimensionAttribute.prototype.handleMutation = function(
140     oldValue, newValue) {
141   if (!this.webViewImpl.guest.getId()) {
142     return;
143   }
144   this.webViewImpl.guest.setSize({
145     'enableAutoSize': this.webViewImpl.attributes[
146         WebViewConstants.ATTRIBUTE_AUTOSIZE].getValue(),
147     'min': {
148       'width': this.webViewImpl.attributes[
149           WebViewConstants.ATTRIBUTE_MINWIDTH].getValue(),
150       'height': this.webViewImpl.attributes[
151           WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue()
152     },
153     'max': {
154       'width': this.webViewImpl.attributes[
155           WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue(),
156       'height': this.webViewImpl.attributes[
157           WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue()
158     }
159   });
160   return;
163 // Attribute that specifies whether the webview should be autosized.
164 function AutosizeAttribute(webViewImpl) {
165   BooleanAttribute.call(this, WebViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl);
168 AutosizeAttribute.prototype.__proto__ = BooleanAttribute.prototype;
170 AutosizeAttribute.prototype.handleMutation =
171     AutosizeDimensionAttribute.prototype.handleMutation;
173 // Attribute that sets the guest content's window.name object.
174 function NameAttribute(webViewImpl) {
175   WebViewAttribute.call(this, WebViewConstants.ATTRIBUTE_NAME, webViewImpl);
178 NameAttribute.prototype.__proto__ = WebViewAttribute.prototype
180 NameAttribute.prototype.handleMutation = function(oldValue, newValue) {
181   oldValue = oldValue || '';
182   newValue = newValue || '';
183   if (oldValue === newValue || !this.webViewImpl.guest.getId()) {
184     return;
185   }
187   WebViewInternal.setName(this.webViewImpl.guest.getId(), newValue);
190 NameAttribute.prototype.setValue = function(value) {
191   value = value || '';
192   if (value === '') {
193     this.webViewImpl.element.removeAttribute(this.name);
194   } else {
195     this.webViewImpl.element.setAttribute(this.name, value);
196   }
199 // Attribute representing the state of the storage partition.
200 function PartitionAttribute(webViewImpl) {
201   WebViewAttribute.call(
202       this, WebViewConstants.ATTRIBUTE_PARTITION, webViewImpl);
203   this.validPartitionId = true;
206 PartitionAttribute.prototype.__proto__ = WebViewAttribute.prototype;
208 PartitionAttribute.prototype.handleMutation = function(oldValue, newValue) {
209   newValue = newValue || '';
211   // The partition cannot change if the webview has already navigated.
212   if (!this.webViewImpl.attributes[
213           WebViewConstants.ATTRIBUTE_SRC].beforeFirstNavigation) {
214     window.console.error(WebViewConstants.ERROR_MSG_ALREADY_NAVIGATED);
215     this.setValueIgnoreMutation(oldValue);
216     return;
217   }
218   if (newValue == 'persist:') {
219     this.validPartitionId = false;
220     window.console.error(
221         WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE);
222   }
225 PartitionAttribute.prototype.detach = function() {
226   this.validPartitionId = true;
229 // Attribute that handles the location and navigation of the webview.
230 function SrcAttribute(webViewImpl) {
231   WebViewAttribute.call(this, WebViewConstants.ATTRIBUTE_SRC, webViewImpl);
232   this.setupMutationObserver();
233   this.beforeFirstNavigation = true;
234   this.elementAttached = false;
237 SrcAttribute.prototype.__proto__ = WebViewAttribute.prototype;
239 SrcAttribute.prototype.setValueIgnoreMutation = function(value) {
240   WebViewAttribute.prototype.setValueIgnoreMutation.call(this, value);
241   // takeRecords() is needed to clear queued up src mutations. Without it, it is
242   // possible for this change to get picked up asyncronously by src's mutation
243   // observer |observer|, and then get handled even though we do not want to
244   // handle this mutation.
245   this.observer.takeRecords();
248 SrcAttribute.prototype.handleMutation = function(oldValue, newValue) {
249   // Once we have navigated, we don't allow clearing the src attribute.
250   // Once <webview> enters a navigated state, it cannot return to a
251   // placeholder state.
252   if (!newValue && oldValue) {
253     // src attribute changes normally initiate a navigation. We suppress
254     // the next src attribute handler call to avoid reloading the page
255     // on every guest-initiated navigation.
256     this.setValueIgnoreMutation(oldValue);
257     return;
258   }
259   this.parse();
262 SrcAttribute.prototype.attach = function() {
263   this.elementAttached = true;
264   this.parse();
267 SrcAttribute.prototype.detach = function() {
268   this.beforeFirstNavigation = true;
269   this.elementAttached = false;
272 // The purpose of this mutation observer is to catch assignment to the src
273 // attribute without any changes to its value. This is useful in the case
274 // where the webview guest has crashed and navigating to the same address
275 // spawns off a new process.
276 SrcAttribute.prototype.setupMutationObserver =
277     function() {
278   this.observer = new MutationObserver(function(mutations) {
279     $Array.forEach(mutations, function(mutation) {
280       var oldValue = mutation.oldValue;
281       var newValue = this.getValue();
282       if (oldValue != newValue) {
283         return;
284       }
285       this.handleMutation(oldValue, newValue);
286     }.bind(this));
287   }.bind(this));
288   var params = {
289     attributes: true,
290     attributeOldValue: true,
291     attributeFilter: [this.name]
292   };
293   this.observer.observe(this.webViewImpl.element, params);
296 SrcAttribute.prototype.parse = function() {
297   if (!this.elementAttached ||
298       !this.webViewImpl.attributes[
299           WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId ||
300       !this.getValue()) {
301     return;
302   }
304   if (!this.webViewImpl.guest.getId()) {
305     if (this.beforeFirstNavigation) {
306       this.beforeFirstNavigation = false;
307       this.webViewImpl.createGuest();
308     }
309     return;
310   }
312   // Navigate to |src|.
313   WebViewInternal.navigate(this.webViewImpl.guest.getId(), this.getValue());
316 // -----------------------------------------------------------------------------
318 // Sets up all of the webview attributes.
319 WebViewImpl.prototype.setupWebViewAttributes = function() {
320   this.attributes = {};
322   this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY] =
323       new AllowTransparencyAttribute(this);
324   this.attributes[WebViewConstants.ATTRIBUTE_ALLOWSCALING] =
325       new AllowScalingAttribute(this);
326   this.attributes[WebViewConstants.ATTRIBUTE_AUTOSIZE] =
327       new AutosizeAttribute(this);
328   this.attributes[WebViewConstants.ATTRIBUTE_NAME] =
329       new NameAttribute(this);
330   this.attributes[WebViewConstants.ATTRIBUTE_PARTITION] =
331       new PartitionAttribute(this);
332   this.attributes[WebViewConstants.ATTRIBUTE_SRC] =
333       new SrcAttribute(this);
335   var autosizeAttributes = [WebViewConstants.ATTRIBUTE_MAXHEIGHT,
336                             WebViewConstants.ATTRIBUTE_MAXWIDTH,
337                             WebViewConstants.ATTRIBUTE_MINHEIGHT,
338                             WebViewConstants.ATTRIBUTE_MINWIDTH];
339   for (var i = 0; autosizeAttributes[i]; ++i) {
340     this.attributes[autosizeAttributes[i]] =
341         new AutosizeDimensionAttribute(autosizeAttributes[i], this);
342   }