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 Apples 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 43 static NPNetscapeFuncs* browser; 44 45 // Structure for per-instance storage 46 typedef 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 59 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); 60 NPError NPP_Destroy(NPP instance, NPSavedData** save); 61 NPError NPP_SetWindow(NPP instance, NPWindow* window); 62 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); 63 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason); 64 int32 NPP_WriteReady(NPP instance, NPStream* stream); 65 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer); 66 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname); 67 void NPP_Print(NPP instance, NPPrint* platformPrint); 68 int16 NPP_HandleEvent(NPP instance, void* event); 69 void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData); 70 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); 71 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value); 72 73 #pragma export on 74 // Mach-o entry points 75 NPError NP_Initialize(NPNetscapeFuncs *browserFuncs); 76 NPError NP_GetEntryPoints(NPPluginFuncs *pluginFuncs); 77 void NP_Shutdown(void); 78 #pragma export off 79 80 NPError NP_Initialize(NPNetscapeFuncs* browserFuncs) 81 { 82 browser = browserFuncs; 83 return NPERR_NO_ERROR; 84 } 85 86 NPError 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 107 void NP_Shutdown(void) 108 { 109 110 } 111 112 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 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 145 NPError 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 158 NPError 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 167 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype) 168 { 169 *stype = NP_ASFILEONLY; 170 return NPERR_NO_ERROR; 171 } 172 173 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) 174 { 175 return NPERR_NO_ERROR; 176 } 177 178 int32 NPP_WriteReady(NPP instance, NPStream* stream) 179 { 180 return 0; 181 } 182 183 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer) 184 { 185 return 0; 186 } 187 188 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) 189 { 190 } 191 192 void NPP_Print(NPP instance, NPPrint* platformPrint) 193 { 194 195 } 196 197 static 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 224 static 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 252 static 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 264 static 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 294 static 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 316 int16 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 355 void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) 356 { 357 358 } 359 360 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) 361 { 362 return NPERR_GENERIC_ERROR; 363 } 364 365 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) 366 { 367 return NPERR_GENERIC_ERROR; 368 } 369