[Modern Media Controls] Only show controls when the controls attribute is set
[WebKit-https.git] / Examples / NetscapeCoreAnimationMoviePlugin / main.m
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 }