1/* 2 IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in 3 consideration of your agreement to the following terms, and your use, installation, 4 modification or redistribution of this Apple software constitutes acceptance of these 5 terms. If you do not agree with these terms, please do not use, install, modify or 6 redistribute this Apple software. 7 8 In consideration of your agreement to abide by the following terms, and subject to these 9 terms, Apple grants you a personal, non-exclusive license, under Apple’s copyrights in 10 this original Apple software (the "Apple Software"), to use, reproduce, modify and 11 redistribute the Apple Software, with or without modifications, in source and/or binary 12 forms; provided that if you redistribute the Apple Software in its entirety and without 13 modifications, you must retain this notice and the following text and disclaimers in all 14 such redistributions of the Apple Software. Neither the name, trademarks, service marks 15 or logos of Apple Computer, Inc. may be used to endorse or promote products derived from 16 the Apple Software without specific prior written permission from Apple. Except as expressly 17 stated in this notice, no other rights or licenses, express or implied, are granted by Apple 18 herein, including but not limited to any patent rights that may be infringed by your 19 derivative works or by other works in which the Apple Software may be incorporated. 20 21 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, 22 EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 23 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS 24 USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 25 26 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 27 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 28 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 29 REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 30 WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 31 OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#import <WebKit/npapi.h> 35#import <WebKit/npfunctions.h> 36#import <WebKit/npruntime.h> 37 38#import <Cocoa/Cocoa.h> 39 40#import "MenuHandler.h" 41 42// Browser function table 43static NPNetscapeFuncs* browser; 44 45// Structure for per-instance storage 46typedef struct PluginObject 47{ 48 NPP npp; 49 50 NPWindow window; 51 52 NSString *string; 53 bool hasFocus; 54 bool mouseIsInsidePlugin; 55 56 MenuHandler *menuHandler; 57} PluginObject; 58 59NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved); 60NPError NPP_Destroy(NPP instance, NPSavedData** save); 61NPError NPP_SetWindow(NPP instance, NPWindow* window); 62NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype); 63NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason); 64int32_t NPP_WriteReady(NPP instance, NPStream* stream); 65int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); 66void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname); 67void NPP_Print(NPP instance, NPPrint* platformPrint); 68int16_t NPP_HandleEvent(NPP instance, void* event); 69void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData); 70NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); 71NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value); 72 73#pragma export on 74// Mach-o entry points 75NPError NP_Initialize(NPNetscapeFuncs *browserFuncs); 76NPError NP_GetEntryPoints(NPPluginFuncs *pluginFuncs); 77void NP_Shutdown(void); 78#pragma export off 79 80NPError NP_Initialize(NPNetscapeFuncs* browserFuncs) 81{ 82 browser = browserFuncs; 83 return NPERR_NO_ERROR; 84} 85 86NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs) 87{ 88 pluginFuncs->version = 11; 89 pluginFuncs->size = sizeof(pluginFuncs); 90 pluginFuncs->newp = NPP_New; 91 pluginFuncs->destroy = NPP_Destroy; 92 pluginFuncs->setwindow = NPP_SetWindow; 93 pluginFuncs->newstream = NPP_NewStream; 94 pluginFuncs->destroystream = NPP_DestroyStream; 95 pluginFuncs->asfile = NPP_StreamAsFile; 96 pluginFuncs->writeready = NPP_WriteReady; 97 pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; 98 pluginFuncs->print = NPP_Print; 99 pluginFuncs->event = NPP_HandleEvent; 100 pluginFuncs->urlnotify = NPP_URLNotify; 101 pluginFuncs->getvalue = NPP_GetValue; 102 pluginFuncs->setvalue = NPP_SetValue; 103 104 return NPERR_NO_ERROR; 105} 106 107void NP_Shutdown(void) 108{ 109 110} 111 112NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved) 113{ 114 // Create per-instance storage 115 PluginObject *obj = (PluginObject *)malloc(sizeof(PluginObject)); 116 bzero(obj, sizeof(PluginObject)); 117 118 obj->npp = instance; 119 instance->pdata = obj; 120 121 // Ask the browser if it supports the CoreGraphics drawing model 122 NPBool supportsCoreGraphics; 123 if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR) 124 supportsCoreGraphics = FALSE; 125 126 if (!supportsCoreGraphics) 127 return NPERR_INCOMPATIBLE_VERSION_ERROR; 128 129 // If the browser supports the CoreGraphics drawing model, enable it. 130 browser->setvalue(instance, NPPVpluginDrawingModel, (void *)NPDrawingModelCoreGraphics); 131 132 // If the browser supports the Cocoa event model, enable it. 133 NPBool supportsCocoa; 134 if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR) 135 supportsCocoa = FALSE; 136 137 if (!supportsCocoa) 138 return NPERR_INCOMPATIBLE_VERSION_ERROR; 139 140 browser->setvalue(instance, NPPVpluginEventModel, (void *)NPEventModelCocoa); 141 142 return NPERR_NO_ERROR; 143} 144 145NPError NPP_Destroy(NPP instance, NPSavedData** save) 146{ 147 // Free per-instance storage 148 PluginObject *obj = instance->pdata; 149 150 [obj->string release]; 151 [obj->menuHandler release]; 152 153 free(obj); 154 155 return NPERR_NO_ERROR; 156} 157 158NPError NPP_SetWindow(NPP instance, NPWindow* window) 159{ 160 PluginObject *obj = instance->pdata; 161 obj->window = *window; 162 163 return NPERR_NO_ERROR; 164} 165 166 167NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype) 168{ 169 *stype = NP_ASFILEONLY; 170 return NPERR_NO_ERROR; 171} 172 173NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) 174{ 175 return NPERR_NO_ERROR; 176} 177 178int32_t NPP_WriteReady(NPP instance, NPStream* stream) 179{ 180 return 0; 181} 182 183int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer) 184{ 185 return 0; 186} 187 188void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) 189{ 190} 191 192void NPP_Print(NPP instance, NPPrint* platformPrint) 193{ 194 195} 196 197static void handleDraw(PluginObject *obj, NPCocoaEvent *event) 198{ 199 NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain]; 200 201 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:event->data.draw.context 202 flipped:YES]; 203 204 [NSGraphicsContext setCurrentContext:context]; 205 206 NSRect rect = NSMakeRect(0, 0, obj->window.width, obj->window.height); 207 208 [[NSColor lightGrayColor] set]; 209 [NSBezierPath fillRect:rect]; 210 211 // If the plugin has focus, draw a focus indicator 212 if (obj->hasFocus) { 213 [[NSColor blackColor] set]; 214 NSBezierPath *path = [NSBezierPath bezierPathWithRect:rect]; 215 [path setLineWidth:5]; 216 [path stroke]; 217 } 218 219 [obj->string drawAtPoint:NSMakePoint(10, 10) withAttributes:nil]; 220 221 [NSGraphicsContext setCurrentContext:oldContext]; 222} 223 224static NSString *eventType(NPCocoaEventType type) 225{ 226 switch (type) { 227 case NPCocoaEventScrollWheel: 228 return @"NPCocoaEventScrollWheel"; 229 case NPCocoaEventMouseDown: 230 return @"NPCocoaEventMouseDown"; 231 case NPCocoaEventMouseUp: 232 return @"NPCocoaEventMouseUp"; 233 case NPCocoaEventMouseMoved: 234 return @"NPCocoaEventMouseMoved"; 235 case NPCocoaEventMouseDragged: 236 return @"NPCocoaEventMouseDragged"; 237 case NPCocoaEventMouseEntered: 238 return @"NPCocoaEventMouseEntered"; 239 case NPCocoaEventMouseExited: 240 return @"NPCocoaEventMouseExited"; 241 case NPCocoaEventKeyDown: 242 return @"NPCocoaEventKeyDown"; 243 case NPCocoaEventKeyUp: 244 return @"NPCocoaEventKeyUp"; 245 case NPCocoaEventFlagsChanged: 246 return @"NPCocoaEventFlagsChanged"; 247 default: 248 return @"unknown"; 249 } 250} 251 252static void invalidatePlugin(PluginObject *obj) 253{ 254 NPRect rect; 255 rect.left = 0; 256 rect.top = 0; 257 rect.right = obj->window.width; 258 rect.bottom = obj->window.height; 259 260 browser->invalidaterect(obj->npp, &rect); 261} 262 263 264static void handleMouseEvent(PluginObject *obj, NPCocoaEvent *event) 265{ 266 NSString *string = [NSString stringWithFormat:@"Type: %@\n" 267 "Modifier flags: 0x%x\n" 268 "Coordinates: (%g, %g)\n" 269 "Button number: %d\n" 270 "Click count: %d\n" 271 "Delta: (%g, %g, %g)", 272 eventType(event->type), 273 event->data.mouse.modifierFlags, 274 event->data.mouse.pluginX, 275 event->data.mouse.pluginY, 276 event->data.mouse.buttonNumber, 277 event->data.mouse.clickCount, 278 event->data.mouse.deltaX, event->data.mouse.deltaY, event->data.mouse.deltaZ]; 279 280 281 [obj->string release]; 282 obj->string = [string retain]; 283 284 invalidatePlugin(obj); 285 286 if (event->data.mouse.buttonNumber == 1) { 287 if (!obj->menuHandler) 288 obj->menuHandler = [[MenuHandler alloc] initWithBrowserFuncs:browser instance:obj->npp]; 289 290 browser->popupcontextmenu(obj->npp, (NPNSMenu *)[obj->menuHandler menu]); 291 } 292} 293 294static void handleKeyboardEvent(PluginObject *obj, NPCocoaEvent *event) 295{ 296 NSString *string = [NSString stringWithFormat:@"Type: %@\n" 297 "Modifier flags: 0x%x\n" 298 "Characters: %@\n" 299 "Characters ignoring modifiers: %@\n" 300 "Is a repeat: %@\n" 301 "Key code: %d", 302 eventType(event->type), 303 event->data.key.modifierFlags, 304 event->data.key.characters, 305 event->data.key.charactersIgnoringModifiers, 306 event->data.key.isARepeat ? @"YES" : @"NO", 307 event->data.key.keyCode]; 308 309 310 [obj->string release]; 311 obj->string = [string retain]; 312 313 invalidatePlugin(obj); 314} 315 316int16_t NPP_HandleEvent(NPP instance, void* event) 317{ 318 PluginObject *obj = instance->pdata; 319 320 NPCocoaEvent *cocoaEvent = event; 321 322 switch(cocoaEvent->type) { 323 case NPCocoaEventFocusChanged: 324 obj->hasFocus = cocoaEvent->data.focus.hasFocus; 325 invalidatePlugin(obj); 326 return 1; 327 328 case NPCocoaEventDrawRect: 329 handleDraw(obj, cocoaEvent); 330 return 1; 331 332 case NPCocoaEventKeyDown: 333 case NPCocoaEventKeyUp: 334 case NPCocoaEventFlagsChanged: 335 handleKeyboardEvent(obj, cocoaEvent); 336 return 1; 337 338 case NPCocoaEventMouseDown: 339 case NPCocoaEventMouseUp: 340 341 // FIXME: NPCocoaEventMouseMoved is currently disabled in order to see other events more clearly 342 // without "drowning" in mouse moved events. 343// case NPCocoaEventMouseMoved: 344 case NPCocoaEventMouseEntered: 345 case NPCocoaEventMouseExited: 346 case NPCocoaEventMouseDragged: 347 case NPCocoaEventScrollWheel: 348 handleMouseEvent(obj, cocoaEvent); 349 return 1; 350 } 351 352 return 0; 353} 354 355void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) 356{ 357 358} 359 360NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) 361{ 362 return NPERR_GENERIC_ERROR; 363} 364 365NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) 366{ 367 return NPERR_GENERIC_ERROR; 368} 369