Home | History | Annotate | Download | only in NetscapeCoreAnimationMoviePlugin
      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 mode, int16 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 NPP_WriteReady(NPP instance, NPStream* stream);
     81 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer);
     82 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
     83 void NPP_Print(NPP instance, NPPrint* platformPrint);
     84 int16 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 mode, int16 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 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 NPP_WriteReady(NPP instance, NPStream* stream)
    205 {
    206     return 0;
    207 }
    208 
    209 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 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 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 }
    394