OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This module implements a wrapper for a guestview that manages its | 5 // This module implements a wrapper for a guestview that manages its |
6 // creation, attaching, and destruction. | 6 // creation, attaching, and destruction. |
7 | 7 |
8 var CreateEvent = require('guestViewEvents').CreateEvent; | 8 var CreateEvent = require('guestViewEvents').CreateEvent; |
9 var EventBindings = require('event_bindings'); | 9 var EventBindings = require('event_bindings'); |
10 var GuestViewInternal = | 10 var GuestViewInternal = |
11 require('binding').Binding.create('guestViewInternal').generate(); | 11 require('binding').Binding.create('guestViewInternal').generate(); |
12 var GuestViewInternalNatives = requireNative('guest_view_internal'); | 12 var GuestViewInternalNatives = requireNative('guest_view_internal'); |
13 | 13 |
14 // Events. | 14 // Events. |
15 var ResizeEvent = CreateEvent('guestViewInternal.onResize'); | 15 var ResizeEvent = CreateEvent('guestViewInternal.onResize'); |
16 | 16 |
17 // Possible states. | |
18 var GUEST_STATE_ATTACHED = 2; | |
19 var GUEST_STATE_CREATED = 1; | |
20 var GUEST_STATE_START = 0; | |
21 | |
22 // Error messages. | 17 // Error messages. |
23 var ERROR_MSG_ALREADY_ATTACHED = 'The guest has already been attached.'; | 18 var ERROR_MSG_ALREADY_ATTACHED = 'The guest has already been attached.'; |
24 var ERROR_MSG_ALREADY_CREATED = 'The guest has already been created.'; | 19 var ERROR_MSG_ALREADY_CREATED = 'The guest has already been created.'; |
25 var ERROR_MSG_INVALID_STATE = 'The guest is in an invalid state.'; | 20 var ERROR_MSG_INVALID_STATE = 'The guest is in an invalid state.'; |
26 var ERROR_MSG_NOT_ATTACHED = 'The guest is not attached.'; | 21 var ERROR_MSG_NOT_ATTACHED = 'The guest is not attached.'; |
27 var ERROR_MSG_NOT_CREATED = 'The guest has not been created.'; | 22 var ERROR_MSG_NOT_CREATED = 'The guest has not been created.'; |
28 | 23 |
29 // Properties. | 24 // Properties. |
30 var PROPERTY_ON_RESIZE = 'onresize'; | 25 var PROPERTY_ON_RESIZE = 'onresize'; |
31 | 26 |
32 // Contains and hides the internal implementation details of |GuestView|, | 27 // Contains and hides the internal implementation details of |GuestView|, |
33 // including maintaining its state and enforcing the proper usage of its API | 28 // including maintaining its state and enforcing the proper usage of its API |
34 // fucntions. | 29 // fucntions. |
35 function GuestViewImpl(guestView, viewType, guestInstanceId) { | 30 function GuestViewImpl(guestView, viewType, guestInstanceId) { |
36 if (guestInstanceId) { | 31 if (guestInstanceId) { |
37 this.id = guestInstanceId; | 32 this.id = guestInstanceId; |
38 this.state = GUEST_STATE_CREATED; | 33 this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED; |
39 } else { | 34 } else { |
40 this.id = 0; | 35 this.id = 0; |
41 this.state = GUEST_STATE_START; | 36 this.state = GuestViewImpl.GuestState.GUEST_STATE_START; |
42 } | 37 } |
43 this.actionQueue = []; | 38 this.actionQueue = []; |
44 this.contentWindow = null; | 39 this.contentWindow = null; |
45 this.guestView = guestView; | 40 this.guestView = guestView; |
46 this.pendingAction = null; | 41 this.pendingAction = null; |
47 this.viewType = viewType; | 42 this.viewType = viewType; |
48 this.internalInstanceId = 0; | 43 this.internalInstanceId = 0; |
49 | 44 |
50 this.setupOnResize(); | 45 this.setupOnResize(); |
51 } | 46 } |
52 | 47 |
| 48 // Possible states. |
| 49 GuestViewImpl.GuestState = { |
| 50 GUEST_STATE_START: 0, |
| 51 GUEST_STATE_CREATED: 1, |
| 52 GUEST_STATE_ATTACHED: 2 |
| 53 }; |
| 54 |
53 // Sets up the onResize property on the GuestView. | 55 // Sets up the onResize property on the GuestView. |
54 GuestViewImpl.prototype.setupOnResize = function() { | 56 GuestViewImpl.prototype.setupOnResize = function() { |
55 $Object.defineProperty(this.guestView, PROPERTY_ON_RESIZE, { | 57 $Object.defineProperty(this.guestView, PROPERTY_ON_RESIZE, { |
56 get: function() { | 58 get: function() { |
57 return this[PROPERTY_ON_RESIZE]; | 59 return this[PROPERTY_ON_RESIZE]; |
58 }.bind(this), | 60 }.bind(this), |
59 set: function(value) { | 61 set: function(value) { |
60 this[PROPERTY_ON_RESIZE] = value; | 62 this[PROPERTY_ON_RESIZE] = value; |
61 }.bind(this), | 63 }.bind(this), |
62 enumerable: true | 64 enumerable: true |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 var view = GuestViewInternalNatives.GetViewFromID(viewInstanceId); | 140 var view = GuestViewInternalNatives.GetViewFromID(viewInstanceId); |
139 if (view && view.guest) { | 141 if (view && view.guest) { |
140 return $Function.apply(func, | 142 return $Function.apply(func, |
141 privates(view.guest).internal, | 143 privates(view.guest).internal, |
142 $Array.slice(arguments)); | 144 $Array.slice(arguments)); |
143 } | 145 } |
144 }; | 146 }; |
145 }; | 147 }; |
146 | 148 |
147 // Internal implementation of attach(). | 149 // Internal implementation of attach(). |
148 GuestViewImpl.prototype.attachImpl = function( | 150 GuestViewImpl.prototype.attachImpl$ = function( |
149 internalInstanceId, viewInstanceId, attachParams, callback) { | 151 internalInstanceId, viewInstanceId, attachParams, callback) { |
150 // Check the current state. | 152 // Check the current state. |
151 if (!this.checkState('attach')) { | 153 if (!this.checkState('attach')) { |
152 this.handleCallback(callback); | 154 this.handleCallback(callback); |
153 return; | 155 return; |
154 } | 156 } |
155 | 157 |
156 // Callback wrapper function to store the contentWindow from the attachGuest() | 158 // Callback wrapper function to store the contentWindow from the attachGuest() |
157 // callback, handle potential attaching failure, register an automatic detach, | 159 // callback, handle potential attaching failure, register an automatic detach, |
158 // and advance the queue. | 160 // and advance the queue. |
159 var callbackWrapper = function(callback, contentWindow) { | 161 var callbackWrapper = function(callback, contentWindow) { |
160 // Check if attaching failed. | 162 // Check if attaching failed. |
161 if (!contentWindow) { | 163 if (!contentWindow) { |
162 this.state = GUEST_STATE_CREATED; | 164 this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED; |
163 this.internalInstanceId = 0; | 165 this.internalInstanceId = 0; |
164 } else { | 166 } else { |
165 // Only update the contentWindow if attaching is successful. | 167 // Only update the contentWindow if attaching is successful. |
166 this.contentWindow = contentWindow; | 168 this.contentWindow = contentWindow; |
167 } | 169 } |
168 | 170 |
169 this.handleCallback(callback); | 171 this.handleCallback(callback); |
170 }; | 172 }; |
171 | 173 |
172 attachParams['instanceId'] = viewInstanceId; | 174 attachParams['instanceId'] = viewInstanceId; |
173 GuestViewInternalNatives.AttachGuest(internalInstanceId, | 175 GuestViewInternalNatives.AttachGuest(internalInstanceId, |
174 this.id, | 176 this.id, |
175 attachParams, | 177 attachParams, |
176 callbackWrapper.bind(this, callback)); | 178 callbackWrapper.bind(this, callback)); |
177 | 179 |
178 this.internalInstanceId = internalInstanceId; | 180 this.internalInstanceId = internalInstanceId; |
179 this.state = GUEST_STATE_ATTACHED; | 181 this.state = GuestViewImpl.GuestState.GUEST_STATE_ATTACHED; |
180 | 182 |
181 // Detach automatically when the container is destroyed. | 183 // Detach automatically when the container is destroyed. |
182 GuestViewInternalNatives.RegisterDestructionCallback( | 184 GuestViewInternalNatives.RegisterDestructionCallback( |
183 internalInstanceId, this.weakWrapper(function() { | 185 internalInstanceId, this.weakWrapper(function() { |
184 if (this.state != GUEST_STATE_ATTACHED || | 186 if (this.state != GuestViewImpl.GuestState.GUEST_STATE_ATTACHED || |
185 this.internalInstanceId != internalInstanceId) { | 187 this.internalInstanceId != internalInstanceId) { |
186 return; | 188 return; |
187 } | 189 } |
188 | 190 |
189 this.internalInstanceId = 0; | 191 this.internalInstanceId = 0; |
190 this.state = GUEST_STATE_CREATED; | 192 this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED; |
191 }, viewInstanceId)); | 193 }, viewInstanceId)); |
192 }; | 194 }; |
193 | 195 |
194 // Internal implementation of create(). | 196 // Internal implementation of create(). |
195 GuestViewImpl.prototype.createImpl = function(createParams, callback) { | 197 GuestViewImpl.prototype.createImpl$ = function(createParams, callback) { |
196 // Check the current state. | 198 // Check the current state. |
197 if (!this.checkState('create')) { | 199 if (!this.checkState('create')) { |
198 this.handleCallback(callback); | 200 this.handleCallback(callback); |
199 return; | 201 return; |
200 } | 202 } |
201 | 203 |
202 // Callback wrapper function to store the guestInstanceId from the | 204 // Callback wrapper function to store the guestInstanceId from the |
203 // createGuest() callback, handle potential creation failure, and advance the | 205 // createGuest() callback, handle potential creation failure, and advance the |
204 // queue. | 206 // queue. |
205 var callbackWrapper = function(callback, guestInfo) { | 207 var callbackWrapper = function(callback, guestInfo) { |
206 this.id = guestInfo.id; | 208 this.id = guestInfo.id; |
207 this.contentWindow = | 209 this.contentWindow = |
208 GuestViewInternalNatives.GetContentWindow(guestInfo.contentWindowId); | 210 GuestViewInternalNatives.GetContentWindow(guestInfo.contentWindowId); |
209 | 211 |
210 // Check if creation failed. | 212 // Check if creation failed. |
211 if (this.id === 0) { | 213 if (this.id === 0) { |
212 this.state = GUEST_STATE_START; | 214 this.state = GuestViewImpl.GuestState.GUEST_STATE_START; |
213 this.contentWindow = null; | 215 this.contentWindow = null; |
214 } | 216 } |
215 | 217 |
216 ResizeEvent.addListener(this.callOnResize, {instanceId: this.id}); | 218 ResizeEvent.addListener(this.callOnResize, {instanceId: this.id}); |
217 this.handleCallback(callback); | 219 this.handleCallback(callback); |
218 }; | 220 }; |
219 | 221 |
220 GuestViewInternal.createGuest(this.viewType, | 222 this.sendCreateRequest(createParams, callbackWrapper.bind(this, callback)); |
221 createParams, | |
222 callbackWrapper.bind(this, callback)); | |
223 | 223 |
224 this.state = GUEST_STATE_CREATED; | 224 this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED; |
| 225 }; |
| 226 |
| 227 GuestViewImpl.prototype.sendCreateRequest = function( |
| 228 createParams, boundCallback) { |
| 229 GuestViewInternal.createGuest(this.viewType, createParams, boundCallback); |
225 }; | 230 }; |
226 | 231 |
227 // Internal implementation of destroy(). | 232 // Internal implementation of destroy(). |
228 GuestViewImpl.prototype.destroyImpl = function(callback) { | 233 GuestViewImpl.prototype.destroyImpl = function(callback) { |
229 // Check the current state. | 234 // Check the current state. |
230 if (!this.checkState('destroy')) { | 235 if (!this.checkState('destroy')) { |
231 this.handleCallback(callback); | 236 this.handleCallback(callback); |
232 return; | 237 return; |
233 } | 238 } |
234 | 239 |
235 if (this.state == GUEST_STATE_START) { | 240 if (this.state == GuestViewImpl.GuestState.GUEST_STATE_START) { |
236 // destroy() does nothing in this case. | 241 // destroy() does nothing in this case. |
237 this.handleCallback(callback); | 242 this.handleCallback(callback); |
238 return; | 243 return; |
239 } | 244 } |
240 | 245 |
241 // If this guest is attached, then detach it first. | 246 // If this guest is attached, then detach it first. |
242 if (!!this.internalInstanceId) { | 247 if (!!this.internalInstanceId) { |
243 GuestViewInternalNatives.DetachGuest(this.internalInstanceId); | 248 GuestViewInternalNatives.DetachGuest(this.internalInstanceId); |
244 } | 249 } |
245 | 250 |
246 GuestViewInternal.destroyGuest(this.id, | 251 GuestViewInternal.destroyGuest(this.id, |
247 this.handleCallback.bind(this, callback)); | 252 this.handleCallback.bind(this, callback)); |
248 | 253 |
249 // Reset the state of the destroyed guest; | 254 // Reset the state of the destroyed guest; |
250 this.contentWindow = null; | 255 this.contentWindow = null; |
251 this.id = 0; | 256 this.id = 0; |
252 this.internalInstanceId = 0; | 257 this.internalInstanceId = 0; |
253 this.state = GUEST_STATE_START; | 258 this.state = GuestViewImpl.GuestState.GUEST_STATE_START; |
254 if (ResizeEvent.hasListener(this.callOnResize)) { | 259 if (ResizeEvent.hasListener(this.callOnResize)) { |
255 ResizeEvent.removeListener(this.callOnResize); | 260 ResizeEvent.removeListener(this.callOnResize); |
256 } | 261 } |
257 }; | 262 }; |
258 | 263 |
259 // Internal implementation of detach(). | 264 // Internal implementation of detach(). |
260 GuestViewImpl.prototype.detachImpl = function(callback) { | 265 GuestViewImpl.prototype.detachImpl = function(callback) { |
261 // Check the current state. | 266 // Check the current state. |
262 if (!this.checkState('detach')) { | 267 if (!this.checkState('detach')) { |
263 this.handleCallback(callback); | 268 this.handleCallback(callback); |
264 return; | 269 return; |
265 } | 270 } |
266 | 271 |
267 GuestViewInternalNatives.DetachGuest( | 272 GuestViewInternalNatives.DetachGuest( |
268 this.internalInstanceId, | 273 this.internalInstanceId, |
269 this.handleCallback.bind(this, callback)); | 274 this.handleCallback.bind(this, callback)); |
270 | 275 |
271 this.internalInstanceId = 0; | 276 this.internalInstanceId = 0; |
272 this.state = GUEST_STATE_CREATED; | 277 this.state = GuestViewImpl.GuestState.GUEST_STATE_CREATED; |
273 }; | 278 }; |
274 | 279 |
275 // Internal implementation of setSize(). | 280 // Internal implementation of setSize(). |
276 GuestViewImpl.prototype.setSizeImpl = function(sizeParams, callback) { | 281 GuestViewImpl.prototype.setSizeImpl = function(sizeParams, callback) { |
277 // Check the current state. | 282 // Check the current state. |
278 if (!this.checkState('setSize')) { | 283 if (!this.checkState('setSize')) { |
279 this.handleCallback(callback); | 284 this.handleCallback(callback); |
280 return; | 285 return; |
281 } | 286 } |
282 | 287 |
283 GuestViewInternal.setSize(this.id, sizeParams, | 288 GuestViewInternal.setSize(this.id, sizeParams, |
284 this.handleCallback.bind(this, callback)); | 289 this.handleCallback.bind(this, callback)); |
285 }; | 290 }; |
286 | 291 |
287 // The exposed interface to a guestview. Exposes in its API the functions | 292 // The exposed interface to a guestview. Exposes in its API the functions |
288 // attach(), create(), destroy(), and getId(). All other implementation details | 293 // attach(), create(), destroy(), and getId(). All other implementation details |
289 // are hidden. | 294 // are hidden. |
290 function GuestView(viewType, guestInstanceId) { | 295 function GuestView(viewType, guestInstanceId) { |
291 privates(this).internal = new GuestViewImpl(this, viewType, guestInstanceId); | 296 privates(this).internal = new GuestViewImpl(this, viewType, guestInstanceId); |
292 } | 297 } |
293 | 298 |
294 // Attaches the guestview to the container with ID |internalInstanceId|. | 299 // Attaches the guestview to the container with ID |internalInstanceId|. |
295 GuestView.prototype.attach = function( | 300 GuestView.prototype.attach = function( |
296 internalInstanceId, viewInstanceId, attachParams, callback) { | 301 internalInstanceId, viewInstanceId, attachParams, callback) { |
297 var internal = privates(this).internal; | 302 var internal = privates(this).internal; |
298 internal.actionQueue.push(internal.attachImpl.bind( | 303 internal.actionQueue.push(internal.attachImpl$.bind( |
299 internal, internalInstanceId, viewInstanceId, attachParams, callback)); | 304 internal, internalInstanceId, viewInstanceId, attachParams, callback)); |
300 internal.performNextAction(); | 305 internal.performNextAction(); |
301 }; | 306 }; |
302 | 307 |
303 // Creates the guestview. | 308 // Creates the guestview. |
304 GuestView.prototype.create = function(createParams, callback) { | 309 GuestView.prototype.create = function(createParams, callback) { |
305 var internal = privates(this).internal; | 310 var internal = privates(this).internal; |
306 internal.actionQueue.push(internal.createImpl.bind( | 311 internal.actionQueue.push(internal.createImpl$.bind( |
307 internal, createParams, callback)); | 312 internal, createParams, callback)); |
308 internal.performNextAction(); | 313 internal.performNextAction(); |
309 }; | 314 }; |
310 | 315 |
311 // Destroys the guestview. Nothing can be done with the guestview after it has | 316 // Destroys the guestview. Nothing can be done with the guestview after it has |
312 // been destroyed. | 317 // been destroyed. |
313 GuestView.prototype.destroy = function(callback) { | 318 GuestView.prototype.destroy = function(callback) { |
314 var internal = privates(this).internal; | 319 var internal = privates(this).internal; |
315 internal.actionQueue.push(internal.destroyImpl.bind(internal, callback)); | 320 internal.actionQueue.push(internal.destroyImpl.bind(internal, callback)); |
316 internal.performNextAction(); | 321 internal.performNextAction(); |
(...skipping 22 matching lines...) Expand all Loading... |
339 }; | 344 }; |
340 | 345 |
341 // Returns the ID for this guestview. | 346 // Returns the ID for this guestview. |
342 GuestView.prototype.getId = function() { | 347 GuestView.prototype.getId = function() { |
343 var internal = privates(this).internal; | 348 var internal = privates(this).internal; |
344 return internal.id; | 349 return internal.id; |
345 }; | 350 }; |
346 | 351 |
347 // Exports | 352 // Exports |
348 exports.GuestView = GuestView; | 353 exports.GuestView = GuestView; |
| 354 exports.GuestViewImpl = GuestViewImpl; |
| 355 exports.ResizeEvent = ResizeEvent; |
OLD | NEW |