Element's renderer factory should return RenderPtrs.
[WebKit-https.git] / Source / WebCore / Modules / plugins / QuickTimePluginReplacement.js
1
2 function createPluginReplacement(root, parent, host, attributeNames, attributeValues)
3 {
4     return new Replacement(root, parent, host, attributeNames, attributeValues);
5 };
6
7 function Replacement(root, parent, host, attributeNames, attributeValues)
8 {
9     this.root = root;
10     this.parent = parent;
11     this.host = host;
12     this.listeners = {};
13     this.scriptObject = {};
14
15     this.autoExitFullScreen = true;
16     this.postEvents = false;
17     this.height = 0;
18     this.width = 0;
19     this.src = "";
20     this.autohref = false;
21     this.href = "";
22     this.qtsrc = "";
23     this.baseUrl = "";
24     this.target = "";
25
26     this.createVideoElement(attributeNames, attributeValues);
27     this.createScriptInterface();
28 };
29
30 Replacement.prototype = {
31
32     HandledVideoEvents: {
33         loadstart: 'handleLoadStart',
34         error: 'handleError',
35         loadedmetadata: 'handleLoadedMetaData',
36         canplay: 'qt_canplay',
37         canplaythrough: 'qt_canplaythrough',
38         play: 'qt_play',
39         pause: 'qt_pause',
40         ended: 'handleEnded',
41         webkitfullscreenchange: 'handleFullscreenChange',
42     },
43
44     AttributeMap: {
45         autoexitfullscreen: 'autoExitFullScreen',
46         postdomevents: 'postEvents',
47         height: 'height',
48         width: 'width',
49         qtsrc: 'qtsrc',
50         src: 'src',
51         airplay: 'x-webkit-airplay=',
52         href: 'href',
53         target: 'target',
54     },
55     
56     MethodMap: {
57         SetURL : 'setURL',
58         GetURL : 'url',
59         Play : 'play',
60         Stop : 'pause',
61         GetRate : 'rate',
62         SetRate : 'setRate',
63         IsFullScreen : 'isFullScreen',
64         ExitFullScreen : 'exitFullScreen',
65         GetPluginStatus : 'pluginStatus',
66         GetTime : 'currentTime',
67         SetTime : 'setCurrentTime',
68         SeekToDate : 'seekToDate',
69         GetDate : 'date',
70         GetDuration : 'duration',
71         GetTimeScale : 'timeScale',
72         GetMaxTimeLoaded : 'maxTimeLoaded',
73         GetMaxBytesLoaded : 'maxBytesLoaded',
74         GetMovieSize : 'movieSize',
75         GetTimedMetadataUpdates : 'timedMetadataUpdates',
76         GetAccessLog : 'accessLog',
77         GetErrorLog : 'errorLog',
78     },
79
80     TimeScale: 30000,
81
82     createVideoElement: function(attributeNames, attributeValues)
83     {
84         var video = this.video = document.createElement('video');
85
86         for (name in this.HandledVideoEvents)
87             video.addEventListener(name, this, false);
88         
89         for (i = 0; i < attributeNames.length; i++) {
90             var property = this.AttributeMap[attributeNames[i]];
91             if (this[property] != undefined)
92                 this[property] = attributeValues[i];
93         }
94
95         video.setAttribute('pseudo', '-webkit-plugin-replacement');
96         video.setAttribute('controls', 'controls');
97         this.setStatus('Waiting');
98
99         var src = this.resolveRelativeToUrl(this.src, "");
100         this.baseUrl = src;
101
102         // The 'qtsrc' attribute is used when a page author wanted to always use the QuickTime plug-in
103         // to load a media type even if another plug-in was registered for that type. It tells the
104         // plug-in to ignore the 'src' url, and to load the 'qtsrc' url instead.
105         if (this.qtsrc)
106             src = this.resolveRelativeToUrl(this.qtsrc, this.src);
107         if (this.href && this.target) {
108             src = this.resolveRelativeToUrl(this.href, this.src);
109             video.poster = this.src;
110             video.setAttribute('preload', 'none');
111         }
112         
113         if (src.length) {
114             this.setStatus('Validating');
115             this.video.src = src;
116         }
117
118         this.root.appendChild(video);
119     },
120
121     resolveRelativeToUrl: function(url, baseUrl)
122     {
123         if (url.indexOf('://') != -1)
124             return url;
125         if (baseUrl.indexOf('://') == -1)
126             baseUrl = this.resolveRelativeToUrl(baseUrl, document.baseURI);
127
128         var base = document.createElement('base');
129         base.href = baseUrl;
130         document.head.appendChild(base);
131
132         var resolver = document.createElement('a');
133         resolver.href = url;
134         url = resolver.href;
135
136         document.head.removeChild(base);
137         base = null;
138
139         return url;
140     },
141  
142     createScriptInterface: function()
143     {
144         for (name in this.MethodMap) {
145             var methodName = this.MethodMap[name];
146             this.scriptObject[name] = this[methodName].bind(this);
147         }
148     },
149
150     handleEvent: function(event)
151     {
152         if (event.target !== this.video)
153             return;
154
155         try {
156             var eventData = this.HandledVideoEvents[event.type];
157             if (!eventData)
158                 return;
159
160             if (this[eventData] && this[eventData] instanceof Function)
161                 this[eventData].call(this, event);
162             else
163                 this.postEvent(eventData);
164         } catch(e) {
165             if (window.console)
166                 console.error(e);
167         }
168     },
169
170     postEvent: function(eventName)
171     {
172         try {
173             if (this.postEvents)
174                 this.host.postEvent(eventName);
175         } catch(e) { }
176     },
177
178     setStatus: function(status)
179     {
180         this.status = status;
181     },
182
183     handleLoadedMetaData: function(event)
184     {
185         this.setStatus('Playable');
186         this.postEvent('qt_validated');
187         this.postEvent('qt_loadedfirstframe');
188         this.postEvent('qt_loadedmetadata');
189     },
190
191     handleFullscreenChange: function(event)
192     {
193         this.postEvent(this.isFullScreen() ? 'qt_enterfullscreen' : 'qt_exitfullscreen');
194     },
195
196     handleError: function(event)
197     {
198         this.setStatus('Error');
199         this.postEvent('qt_error');
200     },
201
202     handleLoadStart:function(event)
203     {
204         if (this.video.poster)
205             this.setStatus('Waiting');
206         else
207             this.setStatus('Loading');
208         this.postEvent('qt_begin');
209     },
210
211     handleEnded: function(event)
212     {
213         this.postEvent('qt_ended');
214         if (this.isFullScreen() && this.autoExitFullScreen)
215             document.webkitExitFullscreen();
216     },
217
218     isFullScreen: function()
219     {
220         return document.webkitCurrentFullScreenElement === this.video;
221     },
222
223     setURL: function(url)
224     {
225         this.setStatus('Validating');
226         if (url.length)
227             url = this.resolveRelativeToUrl(url, this.baseUrl);
228         this.video.src = url;
229     },
230     
231     url: function()
232     {
233         return this.video.currentSrc;
234     },
235     
236     play: function()
237     {
238         this.video.play();
239     },
240     
241     pause: function()
242     {
243         this.video.playbackRate = 0;
244         this.video.pause();
245     },
246     
247     rate: function()
248     {
249         return this.video.paused ? 0 : 1;
250     },
251     
252     setRate: function(rate)
253     {
254         if (rate)
255             this.video.play();
256         else
257             this.video.pause();
258     },
259     
260     exitFullScreen: function()
261     {
262         document.webkitExitFullscreen();
263     },
264     
265     pluginStatus: function()
266     {
267         return this.status;
268     },
269
270     currentTime: function()
271     {
272         return this.video.currentTime * this.TimeScale;
273     },
274
275     setCurrentTime: function(time)
276     {
277         this.video.currentTime = time / this.TimeScale;
278     },
279
280     seekToDate: function()
281     {
282         // FIXME: not implemented yet.
283     },
284     
285     date: function()
286     {
287         return new Date();
288     },
289     
290     duration: function()
291     {
292         return this.video.duration * this.TimeScale;
293     },
294     
295     timeScale: function()
296     {
297         // Note: QuickTime movies and MPEG-4 files have a timescale, but it is not exposed by all media engines.
298         // 30000 works well with common frame rates, eg. 29.97 NTSC can be represented accurately as a time
299         // scale of 30000 and frame duration of 1001.
300         return 30000;
301     },
302     
303     maxTimeLoaded: function()
304     {
305         return this.video.duration * this.TimeScale;
306     },
307     
308     maxBytesLoaded: function()
309     {
310         var percentLoaded = this.video.buffered.end(0) / this.video.duration;
311         return percentLoaded * this.movieSize();
312     },
313     
314     movieSize: function()
315     {
316         try {
317             return this.host.movieSize;
318         } catch(e) { }
319
320         return 0;
321     },
322     
323     timedMetadataUpdates: function()
324     {
325         // FIXME: not implemented yet.
326         return null;
327     },
328     
329     accessLog: function()
330     {
331         // FIXME: not implemented yet.
332         return null;
333     },
334     
335     errorLog: function()
336     {
337         // FIXME: not implemented yet.
338         return null;
339     },
340 };
341