2 File: MovieControllerLayer.m
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.
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.
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.
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.
42 Copyright (C) 2009 Apple Inc. All Rights Reserved.
46 #import <WebKit/npapi.h>
47 #import <WebKit/npfunctions.h>
48 #import <WebKit/npruntime.h>
50 #import <QuartzCore/QuartzCore.h>
51 #import <QTKit/QTKit.h>
53 #import "MovieControllerLayer.h"
55 // Browser function table
56 static NPNetscapeFuncs* browser;
58 // Structure for per-instance storage
59 typedef struct PluginObject
66 MovieControllerLayer *controllerLayer;
67 QTMovieLayer *movieLayer;
69 CALayer *mouseDownLayer;
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);
90 // Mach-o entry points
91 NPError NP_Initialize(NPNetscapeFuncs *browserFuncs);
92 NPError NP_GetEntryPoints(NPPluginFuncs *pluginFuncs);
93 void NP_Shutdown(void);
96 NPError NP_Initialize(NPNetscapeFuncs* browserFuncs)
98 browser = browserFuncs;
99 return NPERR_NO_ERROR;
102 NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs)
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;
120 return NPERR_NO_ERROR;
123 void NP_Shutdown(void)
128 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved)
130 // Create per-instance storage
131 PluginObject *obj = (PluginObject *)malloc(sizeof(PluginObject));
132 bzero(obj, sizeof(PluginObject));
135 instance->pdata = obj;
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;
142 if (!supportsCoreAnimation)
143 return NPERR_INCOMPATIBLE_VERSION_ERROR;
145 // If the browser supports the Core Animation drawing model, enable it.
146 browser->setvalue(instance, NPPVpluginDrawingModel, (void *)NPDrawingModelCoreAnimation);
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;
154 return NPERR_INCOMPATIBLE_VERSION_ERROR;
156 browser->setvalue(instance, NPPVpluginEventModel, (void *)NPEventModelCocoa);
158 for (int16_t i = 0; i < argc; i++) {
159 if (strcasecmp(argn[i], "movieurl") == 0) {
160 NSString *urlString = [NSString stringWithUTF8String:argv[i]];
162 obj->movieURL = [[NSURL URLWithString:urlString] retain];
168 return NPERR_NO_ERROR;
171 NPError NPP_Destroy(NPP instance, NPSavedData** save)
173 // Free per-instance storage
174 PluginObject *obj = instance->pdata;
177 [obj->rootLayer release];
181 return NPERR_NO_ERROR;
184 NPError NPP_SetWindow(NPP instance, NPWindow* window)
186 PluginObject *obj = instance->pdata;
187 obj->window = *window;
189 return NPERR_NO_ERROR;
193 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
195 *stype = NP_ASFILEONLY;
196 return NPERR_NO_ERROR;
199 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
201 return NPERR_NO_ERROR;
204 int32_t NPP_WriteReady(NPP instance, NPStream* stream)
209 int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
214 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
218 void NPP_Print(NPP instance, NPPrint* platformPrint)
223 static void handleMouseDown(PluginObject *obj, NPCocoaEvent *event)
225 CGPoint point = CGPointMake(event->data.mouse.pluginX,
226 // Flip the y coordinate
227 obj->window.height - event->data.mouse.pluginY);
229 obj->mouseDownLayer = [obj->rootLayer hitTest:point];
230 if (obj->mouseDownLayer == obj->controllerLayer) {
231 [obj->controllerLayer handleMouseDown:[obj->rootLayer convertPoint:point toLayer:obj->controllerLayer]];
236 static void togglePlayPause(PluginObject *obj)
241 if ([obj->movie rate] == 0)
248 static void handleMouseUp(PluginObject *obj, NPCocoaEvent *event)
250 CGPoint point = CGPointMake(event->data.mouse.pluginX,
251 // Flip the y coordinate
252 obj->window.height - event->data.mouse.pluginY);
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]];
262 static void handleMouseDragged(PluginObject *obj, NPCocoaEvent *event)
264 CGPoint point = CGPointMake(event->data.mouse.pluginX,
265 // Flip the y coordinate
266 obj->window.height - event->data.mouse.pluginY);
268 if (obj->mouseDownLayer == obj->controllerLayer) {
269 [obj->controllerLayer handleMouseDragged:[obj->rootLayer convertPoint:point toLayer:obj->controllerLayer]];
274 static void handleMouseEntered(PluginObject *obj)
276 // Show the controller layer.
277 obj->controllerLayer.opacity = 1.0;
280 static void handleMouseExited(PluginObject *obj)
282 // Hide the controller layer if the movie is playing.
283 if ([obj->movie rate])
284 obj->controllerLayer.opacity = 0.0;
287 static int handleKeyDown(PluginObject *obj, NPCocoaEvent *event)
289 NSString *characters = (NSString *)event->data.key.characters;
291 if ([characters length] == 1 && [characters characterAtIndex:0] == ' ') {
292 togglePlayPause(obj);
300 static int handleScrollEvent(PluginObject *obj, NPCocoaEvent *event)
302 double delta = event->data.mouse.deltaY;
304 [obj->movie stepForward];
306 [obj->movie stepBackward];
312 int16_t NPP_HandleEvent(NPP instance, void* event)
314 PluginObject *obj = instance->pdata;
316 NPCocoaEvent *cocoaEvent = event;
318 switch(cocoaEvent->type) {
319 case NPCocoaEventMouseDown:
320 handleMouseDown(obj, cocoaEvent);
322 case NPCocoaEventMouseUp:
323 handleMouseUp(obj, cocoaEvent);
325 case NPCocoaEventMouseDragged:
326 handleMouseDragged(obj, cocoaEvent);
328 case NPCocoaEventMouseEntered:
329 handleMouseEntered(obj);
331 case NPCocoaEventMouseExited:
332 handleMouseExited(obj);
334 case NPCocoaEventKeyDown:
335 return handleKeyDown(obj, cocoaEvent);
336 case NPCocoaEventScrollWheel:
337 return handleScrollEvent(obj, cocoaEvent);
343 void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
348 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
350 PluginObject *obj = instance->pdata;
353 case NPPVpluginCoreAnimationLayer:
354 if (!obj->rootLayer) {
355 // Setup layer hierarchy.
356 obj->rootLayer = [[CALayer layer] retain];
358 obj->movieLayer = [QTMovieLayer layer];
359 obj->movieLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
360 [obj->rootLayer addSublayer:obj->movieLayer];
362 obj->controllerLayer = [MovieControllerLayer layer];
363 [obj->rootLayer addSublayer:obj->controllerLayer];
366 NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:obj->movieURL, QTMovieURLAttribute,
367 [NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute,
368 [NSNumber numberWithBool:YES], QTMovieLoopsAttribute,
370 obj->movie = [QTMovie movieWithAttributes:attributes error:nil];
373 obj->movieLayer.movie = obj->movie;
374 [obj->controllerLayer setMovie:obj->movie];
380 // Make sure to return a retained layer
381 *((CALayer **)value) = [obj->rootLayer retain];
383 return NPERR_NO_ERROR;
386 return NPERR_GENERIC_ERROR;
390 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
392 return NPERR_GENERIC_ERROR;