|
1 /* |
|
2 File: MovieControllerLayer.m |
|
3 |
|
4 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
|
5 Inc. ("Apple") in consideration of your agreement to the following |
|
6 terms, and your use, installation, modification or redistribution of |
|
7 this Apple software constitutes acceptance of these terms. If you do |
|
8 not agree with these terms, please do not use, install, modify or |
|
9 redistribute this Apple software. |
|
10 |
|
11 In consideration of your agreement to abide by the following terms, and |
|
12 subject to these terms, Apple grants you a personal, non-exclusive |
|
13 license, under Apple's copyrights in this original Apple software (the |
|
14 "Apple Software"), to use, reproduce, modify and redistribute the Apple |
|
15 Software, with or without modifications, in source and/or binary forms; |
|
16 provided that if you redistribute the Apple Software in its entirety and |
|
17 without modifications, you must retain this notice and the following |
|
18 text and disclaimers in all such redistributions of the Apple Software. |
|
19 Neither the name, trademarks, service marks or logos of Apple Inc. may |
|
20 be used to endorse or promote products derived from the Apple Software |
|
21 without specific prior written permission from Apple. Except as |
|
22 expressly stated in this notice, no other rights or licenses, express or |
|
23 implied, are granted by Apple herein, including but not limited to any |
|
24 patent rights that may be infringed by your derivative works or by other |
|
25 works in which the Apple Software may be incorporated. |
|
26 |
|
27 The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
|
28 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
|
29 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
|
30 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
|
31 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
|
32 |
|
33 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
|
34 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
35 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
36 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
|
37 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
|
38 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
|
39 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
|
40 POSSIBILITY OF SUCH DAMAGE. |
|
41 |
|
42 Copyright (C) 2009 Apple Inc. All Rights Reserved. |
|
43 |
|
44 */ |
|
45 |
|
46 #import <WebKit/npapi.h> |
|
47 #import <WebKit/npfunctions.h> |
|
48 #import <WebKit/npruntime.h> |
|
49 |
|
50 #import <QuartzCore/QuartzCore.h> |
|
51 #import <QTKit/QTKit.h> |
|
52 |
|
53 #import "MovieControllerLayer.h" |
|
54 |
|
55 // Browser function table |
|
56 static NPNetscapeFuncs* browser; |
|
57 |
|
58 // Structure for per-instance storage |
|
59 typedef struct PluginObject |
|
60 { |
|
61 NPP npp; |
|
62 |
|
63 NPWindow window; |
|
64 |
|
65 CALayer *rootLayer; |
|
66 MovieControllerLayer *controllerLayer; |
|
67 QTMovieLayer *movieLayer; |
|
68 |
|
69 CALayer *mouseDownLayer; |
|
70 |
|
71 NSURL *movieURL; |
|
72 QTMovie *movie; |
|
73 } PluginObject; |
|
74 |
|
75 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved); |
|
76 NPError NPP_Destroy(NPP instance, NPSavedData** save); |
|
77 NPError NPP_SetWindow(NPP instance, NPWindow* window); |
|
78 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); |
|
79 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason); |
|
80 int32_t NPP_WriteReady(NPP instance, NPStream* stream); |
|
81 int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); |
|
82 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname); |
|
83 void NPP_Print(NPP instance, NPPrint* platformPrint); |
|
84 int16_t NPP_HandleEvent(NPP instance, void* event); |
|
85 void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData); |
|
86 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); |
|
87 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value); |
|
88 |
|
89 #pragma export on |
|
90 // Mach-o entry points |
|
91 NPError NP_Initialize(NPNetscapeFuncs *browserFuncs); |
|
92 NPError NP_GetEntryPoints(NPPluginFuncs *pluginFuncs); |
|
93 void NP_Shutdown(void); |
|
94 #pragma export off |
|
95 |
|
96 NPError NP_Initialize(NPNetscapeFuncs* browserFuncs) |
|
97 { |
|
98 browser = browserFuncs; |
|
99 return NPERR_NO_ERROR; |
|
100 } |
|
101 |
|
102 NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs) |
|
103 { |
|
104 pluginFuncs->version = 11; |
|
105 pluginFuncs->size = sizeof(pluginFuncs); |
|
106 pluginFuncs->newp = NPP_New; |
|
107 pluginFuncs->destroy = NPP_Destroy; |
|
108 pluginFuncs->setwindow = NPP_SetWindow; |
|
109 pluginFuncs->newstream = NPP_NewStream; |
|
110 pluginFuncs->destroystream = NPP_DestroyStream; |
|
111 pluginFuncs->asfile = NPP_StreamAsFile; |
|
112 pluginFuncs->writeready = NPP_WriteReady; |
|
113 pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; |
|
114 pluginFuncs->print = NPP_Print; |
|
115 pluginFuncs->event = NPP_HandleEvent; |
|
116 pluginFuncs->urlnotify = NPP_URLNotify; |
|
117 pluginFuncs->getvalue = NPP_GetValue; |
|
118 pluginFuncs->setvalue = NPP_SetValue; |
|
119 |
|
120 return NPERR_NO_ERROR; |
|
121 } |
|
122 |
|
123 void NP_Shutdown(void) |
|
124 { |
|
125 |
|
126 } |
|
127 |
|
128 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved) |
|
129 { |
|
130 // Create per-instance storage |
|
131 PluginObject *obj = (PluginObject *)malloc(sizeof(PluginObject)); |
|
132 bzero(obj, sizeof(PluginObject)); |
|
133 |
|
134 obj->npp = instance; |
|
135 instance->pdata = obj; |
|
136 |
|
137 // Ask the browser if it supports the Core Animation drawing model |
|
138 NPBool supportsCoreAnimation; |
|
139 if (browser->getvalue(instance, NPNVsupportsCoreAnimationBool, &supportsCoreAnimation) != NPERR_NO_ERROR) |
|
140 supportsCoreAnimation = FALSE; |
|
141 |
|
142 if (!supportsCoreAnimation) |
|
143 return NPERR_INCOMPATIBLE_VERSION_ERROR; |
|
144 |
|
145 // If the browser supports the Core Animation drawing model, enable it. |
|
146 browser->setvalue(instance, NPPVpluginDrawingModel, (void *)NPDrawingModelCoreAnimation); |
|
147 |
|
148 // If the browser supports the Cocoa event model, enable it. |
|
149 NPBool supportsCocoa; |
|
150 if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR) |
|
151 supportsCocoa = FALSE; |
|
152 |
|
153 if (!supportsCocoa) |
|
154 return NPERR_INCOMPATIBLE_VERSION_ERROR; |
|
155 |
|
156 browser->setvalue(instance, NPPVpluginEventModel, (void *)NPEventModelCocoa); |
|
157 |
|
158 for (int16_t i = 0; i < argc; i++) { |
|
159 if (strcasecmp(argn[i], "movieurl") == 0) { |
|
160 NSString *urlString = [NSString stringWithUTF8String:argv[i]]; |
|
161 if (urlString) |
|
162 obj->movieURL = [[NSURL URLWithString:urlString] retain]; |
|
163 break; |
|
164 } |
|
165 |
|
166 } |
|
167 |
|
168 return NPERR_NO_ERROR; |
|
169 } |
|
170 |
|
171 NPError NPP_Destroy(NPP instance, NPSavedData** save) |
|
172 { |
|
173 // Free per-instance storage |
|
174 PluginObject *obj = instance->pdata; |
|
175 |
|
176 [obj->movie stop]; |
|
177 [obj->rootLayer release]; |
|
178 |
|
179 free(obj); |
|
180 |
|
181 return NPERR_NO_ERROR; |
|
182 } |
|
183 |
|
184 NPError NPP_SetWindow(NPP instance, NPWindow* window) |
|
185 { |
|
186 PluginObject *obj = instance->pdata; |
|
187 obj->window = *window; |
|
188 |
|
189 return NPERR_NO_ERROR; |
|
190 } |
|
191 |
|
192 |
|
193 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype) |
|
194 { |
|
195 *stype = NP_ASFILEONLY; |
|
196 return NPERR_NO_ERROR; |
|
197 } |
|
198 |
|
199 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) |
|
200 { |
|
201 return NPERR_NO_ERROR; |
|
202 } |
|
203 |
|
204 int32_t NPP_WriteReady(NPP instance, NPStream* stream) |
|
205 { |
|
206 return 0; |
|
207 } |
|
208 |
|
209 int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer) |
|
210 { |
|
211 return 0; |
|
212 } |
|
213 |
|
214 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) |
|
215 { |
|
216 } |
|
217 |
|
218 void NPP_Print(NPP instance, NPPrint* platformPrint) |
|
219 { |
|
220 |
|
221 } |
|
222 |
|
223 static void handleMouseDown(PluginObject *obj, NPCocoaEvent *event) |
|
224 { |
|
225 CGPoint point = CGPointMake(event->data.mouse.pluginX, |
|
226 // Flip the y coordinate |
|
227 obj->window.height - event->data.mouse.pluginY); |
|
228 |
|
229 obj->mouseDownLayer = [obj->rootLayer hitTest:point]; |
|
230 if (obj->mouseDownLayer == obj->controllerLayer) { |
|
231 [obj->controllerLayer handleMouseDown:[obj->rootLayer convertPoint:point toLayer:obj->controllerLayer]]; |
|
232 return; |
|
233 } |
|
234 } |
|
235 |
|
236 static void togglePlayPause(PluginObject *obj) |
|
237 { |
|
238 if (!obj->movie) |
|
239 return; |
|
240 |
|
241 if ([obj->movie rate] == 0) |
|
242 [obj->movie play]; |
|
243 else |
|
244 [obj->movie stop]; |
|
245 |
|
246 } |
|
247 |
|
248 static void handleMouseUp(PluginObject *obj, NPCocoaEvent *event) |
|
249 { |
|
250 CGPoint point = CGPointMake(event->data.mouse.pluginX, |
|
251 // Flip the y coordinate |
|
252 obj->window.height - event->data.mouse.pluginY); |
|
253 |
|
254 CALayer *mouseDownLayer = obj->mouseDownLayer; |
|
255 obj->mouseDownLayer = nil; |
|
256 if (mouseDownLayer == obj->controllerLayer) { |
|
257 [obj->controllerLayer handleMouseUp:[obj->rootLayer convertPoint:point toLayer:obj->controllerLayer]]; |
|
258 return; |
|
259 } |
|
260 } |
|
261 |
|
262 static void handleMouseDragged(PluginObject *obj, NPCocoaEvent *event) |
|
263 { |
|
264 CGPoint point = CGPointMake(event->data.mouse.pluginX, |
|
265 // Flip the y coordinate |
|
266 obj->window.height - event->data.mouse.pluginY); |
|
267 |
|
268 if (obj->mouseDownLayer == obj->controllerLayer) { |
|
269 [obj->controllerLayer handleMouseDragged:[obj->rootLayer convertPoint:point toLayer:obj->controllerLayer]]; |
|
270 return; |
|
271 } |
|
272 } |
|
273 |
|
274 static void handleMouseEntered(PluginObject *obj) |
|
275 { |
|
276 // Show the controller layer. |
|
277 obj->controllerLayer.opacity = 1.0; |
|
278 } |
|
279 |
|
280 static void handleMouseExited(PluginObject *obj) |
|
281 { |
|
282 // Hide the controller layer if the movie is playing. |
|
283 if ([obj->movie rate]) |
|
284 obj->controllerLayer.opacity = 0.0; |
|
285 } |
|
286 |
|
287 static int handleKeyDown(PluginObject *obj, NPCocoaEvent *event) |
|
288 { |
|
289 NSString *characters = (NSString *)event->data.key.characters; |
|
290 |
|
291 if ([characters length] == 1 && [characters characterAtIndex:0] == ' ') { |
|
292 togglePlayPause(obj); |
|
293 return 1; |
|
294 } |
|
295 |
|
296 return 0; |
|
297 } |
|
298 |
|
299 |
|
300 static int handleScrollEvent(PluginObject *obj, NPCocoaEvent *event) |
|
301 { |
|
302 double delta = event->data.mouse.deltaY; |
|
303 if (delta < 0) |
|
304 [obj->movie stepForward]; |
|
305 else |
|
306 [obj->movie stepBackward]; |
|
307 return 0; |
|
308 } |
|
309 |
|
310 |
|
311 |
|
312 int16_t NPP_HandleEvent(NPP instance, void* event) |
|
313 { |
|
314 PluginObject *obj = instance->pdata; |
|
315 |
|
316 NPCocoaEvent *cocoaEvent = event; |
|
317 |
|
318 switch(cocoaEvent->type) { |
|
319 case NPCocoaEventMouseDown: |
|
320 handleMouseDown(obj, cocoaEvent); |
|
321 return 1; |
|
322 case NPCocoaEventMouseUp: |
|
323 handleMouseUp(obj, cocoaEvent); |
|
324 return 1; |
|
325 case NPCocoaEventMouseDragged: |
|
326 handleMouseDragged(obj, cocoaEvent); |
|
327 return 1; |
|
328 case NPCocoaEventMouseEntered: |
|
329 handleMouseEntered(obj); |
|
330 return 1; |
|
331 case NPCocoaEventMouseExited: |
|
332 handleMouseExited(obj); |
|
333 return 1; |
|
334 case NPCocoaEventKeyDown: |
|
335 return handleKeyDown(obj, cocoaEvent); |
|
336 case NPCocoaEventScrollWheel: |
|
337 return handleScrollEvent(obj, cocoaEvent); |
|
338 } |
|
339 |
|
340 return 0; |
|
341 } |
|
342 |
|
343 void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) |
|
344 { |
|
345 |
|
346 } |
|
347 |
|
348 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) |
|
349 { |
|
350 PluginObject *obj = instance->pdata; |
|
351 |
|
352 switch (variable) { |
|
353 case NPPVpluginCoreAnimationLayer: |
|
354 if (!obj->rootLayer) { |
|
355 // Setup layer hierarchy. |
|
356 obj->rootLayer = [[CALayer layer] retain]; |
|
357 |
|
358 obj->movieLayer = [QTMovieLayer layer]; |
|
359 obj->movieLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; |
|
360 [obj->rootLayer addSublayer:obj->movieLayer]; |
|
361 |
|
362 obj->controllerLayer = [MovieControllerLayer layer]; |
|
363 [obj->rootLayer addSublayer:obj->controllerLayer]; |
|
364 |
|
365 if (obj->movieURL) { |
|
366 NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:obj->movieURL, QTMovieURLAttribute, |
|
367 [NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute, |
|
368 [NSNumber numberWithBool:YES], QTMovieLoopsAttribute, |
|
369 nil]; |
|
370 obj->movie = [QTMovie movieWithAttributes:attributes error:nil]; |
|
371 |
|
372 if (obj->movie) { |
|
373 obj->movieLayer.movie = obj->movie; |
|
374 [obj->controllerLayer setMovie:obj->movie]; |
|
375 } |
|
376 } |
|
377 |
|
378 } |
|
379 |
|
380 // Make sure to return a retained layer |
|
381 *((CALayer **)value) = [obj->rootLayer retain]; |
|
382 |
|
383 return NPERR_NO_ERROR; |
|
384 |
|
385 default: |
|
386 return NPERR_GENERIC_ERROR; |
|
387 } |
|
388 } |
|
389 |
|
390 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) |
|
391 { |
|
392 return NPERR_GENERIC_ERROR; |
|
393 } |