• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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// Browser function table
41static NPNetscapeFuncs* browser;
42
43// Structure for per-instance storage
44typedef struct PluginObject
45{
46    NPP npp;
47
48    NPWindow window;
49
50    bool pluginHasFocus;
51
52    bool textFieldHasFocus;
53    NSRect textFieldRect;
54
55    NSRange selectedRange;
56    NSTextStorage *textStorage;
57    NSLayoutManager *layoutManager;
58    NSTextContainer *textContainer;
59
60} PluginObject;
61
62NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved);
63NPError NPP_Destroy(NPP instance, NPSavedData** save);
64NPError NPP_SetWindow(NPP instance, NPWindow* window);
65NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype);
66NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
67int32 NPP_WriteReady(NPP instance, NPStream* stream);
68int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer);
69void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
70void NPP_Print(NPP instance, NPPrint* platformPrint);
71int16 NPP_HandleEvent(NPP instance, void* event);
72void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData);
73NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value);
74NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value);
75
76#pragma export on
77// Mach-o entry points
78NPError NP_Initialize(NPNetscapeFuncs* browserFuncs);
79NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs);
80void NP_Shutdown(void);
81#pragma export off
82
83NPError NP_Initialize(NPNetscapeFuncs* browserFuncs)
84{
85    browser = browserFuncs;
86    return NPERR_NO_ERROR;
87}
88
89NPError NP_GetEntryPoints(NPPluginFuncs* pluginFuncs)
90{
91    pluginFuncs->version = 11;
92    pluginFuncs->size = sizeof(pluginFuncs);
93    pluginFuncs->newp = NPP_New;
94    pluginFuncs->destroy = NPP_Destroy;
95    pluginFuncs->setwindow = NPP_SetWindow;
96    pluginFuncs->newstream = NPP_NewStream;
97    pluginFuncs->destroystream = NPP_DestroyStream;
98    pluginFuncs->asfile = NPP_StreamAsFile;
99    pluginFuncs->writeready = NPP_WriteReady;
100    pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
101    pluginFuncs->print = NPP_Print;
102    pluginFuncs->event = NPP_HandleEvent;
103    pluginFuncs->urlnotify = NPP_URLNotify;
104    pluginFuncs->getvalue = NPP_GetValue;
105    pluginFuncs->setvalue = NPP_SetValue;
106
107    return NPERR_NO_ERROR;
108}
109
110void NP_Shutdown(void)
111{
112}
113
114NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved)
115{
116    // Create per-instance storage
117    PluginObject* obj = (PluginObject*)malloc(sizeof(PluginObject));
118    bzero(obj, sizeof(PluginObject));
119
120    obj->npp = instance;
121    instance->pdata = obj;
122
123    // Ask the browser if it supports the CoreGraphics drawing model
124    NPBool supportsCoreGraphics;
125    if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR)
126        supportsCoreGraphics = FALSE;
127
128    if (!supportsCoreGraphics)
129        return NPERR_INCOMPATIBLE_VERSION_ERROR;
130
131    // If the browser supports the CoreGraphics drawing model, enable it.
132    browser->setvalue(instance, NPPVpluginDrawingModel, (void*)NPDrawingModelCoreGraphics);
133
134    // If the browser supports the Cocoa event model, enable it.
135    NPBool supportsCocoa;
136    if (browser->getvalue(instance, NPNVsupportsCocoaBool, &supportsCocoa) != NPERR_NO_ERROR)
137        supportsCocoa = FALSE;
138
139    if (!supportsCocoa)
140        return NPERR_INCOMPATIBLE_VERSION_ERROR;
141
142    browser->setvalue(instance, NPPVpluginEventModel, (void*)NPEventModelCocoa);
143
144    obj->textFieldRect = NSMakeRect(10, 10, 200, 100);
145
146    obj->textStorage = [[NSTextStorage alloc] initWithString:@""];
147    obj->layoutManager = [[NSLayoutManager alloc] init];
148    [obj->textStorage addLayoutManager:obj->layoutManager];
149
150    obj->textContainer = [[NSTextContainer alloc] initWithContainerSize:obj->textFieldRect.size];
151    [obj->layoutManager addTextContainer:obj->textContainer];
152
153    obj->selectedRange.location = [obj->textStorage length];
154
155    return NPERR_NO_ERROR;
156}
157
158NPError NPP_Destroy(NPP instance, NPSavedData** save)
159{
160    // Free per-instance storage
161    PluginObject* obj = instance->pdata;
162
163    [obj->textStorage release];
164    [obj->layoutManager release];
165
166    free(obj);
167
168    return NPERR_NO_ERROR;
169}
170
171NPError NPP_SetWindow(NPP instance, NPWindow* window)
172{
173    PluginObject* obj = instance->pdata;
174    obj->window = *window;
175
176    return NPERR_NO_ERROR;
177}
178
179
180NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
181{
182    *stype = NP_ASFILEONLY;
183    return NPERR_NO_ERROR;
184}
185
186NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
187{
188    return NPERR_NO_ERROR;
189}
190
191int32 NPP_WriteReady(NPP instance, NPStream* stream)
192{
193    return 0;
194}
195
196int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
197{
198    return 0;
199}
200
201void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
202{
203}
204
205void NPP_Print(NPP instance, NPPrint* platformPrint)
206{
207
208}
209
210static void handleDraw(PluginObject* obj, NPCocoaEvent *event)
211{
212    NSGraphicsContext *oldContext = [[NSGraphicsContext currentContext] retain];
213
214    NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithGraphicsPort:event->data.draw.context
215                                                                            flipped:YES];
216
217
218    [NSGraphicsContext setCurrentContext:context];
219
220    NSRect rect = NSMakeRect(0, 0, obj->window.width, obj->window.height);
221
222    [[NSColor lightGrayColor] set];
223    [NSBezierPath fillRect:rect];
224
225    if (obj->pluginHasFocus) {
226        [[NSColor blackColor] set];
227        [NSBezierPath strokeRect:rect];
228    }
229
230    [[NSColor whiteColor] set];
231    [NSBezierPath fillRect:obj->textFieldRect];
232
233    // Draw the text
234    NSRange glyphRange = [obj->layoutManager glyphRangeForTextContainer:obj->textContainer];
235    if (glyphRange.length > 0) {
236        [obj->layoutManager drawBackgroundForGlyphRange:glyphRange atPoint:obj->textFieldRect.origin];
237        [obj->layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:obj->textFieldRect.origin];
238    }
239
240    NSBezierPath *textInputBorder = [NSBezierPath bezierPathWithRect:obj->textFieldRect];
241    [[NSColor blackColor] set];
242
243    if (obj->pluginHasFocus && obj->textFieldHasFocus)
244        [textInputBorder setLineWidth:2];
245    else
246        [textInputBorder setLineWidth:1];
247
248    [textInputBorder stroke];
249
250    if (obj->pluginHasFocus && obj->textFieldHasFocus) {
251        NSUInteger rectCount;
252        NSRect *rectArray = [obj->layoutManager rectArrayForCharacterRange:obj->selectedRange
253                                            withinSelectedCharacterRange:obj->selectedRange
254                                                        inTextContainer:obj->textContainer
255                                                                rectCount:&rectCount];
256
257        [[NSColor blackColor] set];
258        for (unsigned i = 0; i < rectCount; i++) {
259            NSRect rect = rectArray[i];
260            rect.origin.x += obj->textFieldRect.origin.x;
261            rect.origin.y += obj->textFieldRect.origin.y;
262
263            [NSBezierPath strokeRect:rect];
264        }
265    }
266
267    [NSGraphicsContext setCurrentContext:oldContext];
268}
269
270static void invalidatePlugin(PluginObject* obj)
271{
272    NPRect rect;
273    rect.left = 0;
274    rect.top = 0;
275    rect.right = obj->window.width;
276    rect.bottom = obj->window.height;
277
278    browser->invalidaterect(obj->npp, &rect);
279}
280
281static void handleFocusChanged(NPCocoaEvent* cocoaEvent, PluginObject* obj)
282{
283    obj->pluginHasFocus = cocoaEvent->data.focus.hasFocus;
284
285    invalidatePlugin(obj);
286}
287
288static void handleMouseMoved(NPCocoaEvent* cocoaEvent, PluginObject* obj)
289{
290    NSPoint point = NSMakePoint(cocoaEvent->data.mouse.pluginX, cocoaEvent->data.mouse.pluginY);
291
292    if (NSPointInRect(point, obj->textFieldRect))
293        [[NSCursor IBeamCursor] set];
294    else
295        [[NSCursor arrowCursor] set];
296}
297
298static void handleMouseDown(NPCocoaEvent* cocoaEvent, PluginObject* obj)
299{
300    NSPoint point = NSMakePoint(cocoaEvent->data.mouse.pluginX, cocoaEvent->data.mouse.pluginY);
301
302    obj->textFieldHasFocus = NSPointInRect(point, obj->textFieldRect);
303
304    invalidatePlugin(obj);
305}
306
307static int16_t handleTextFieldKeyDown(NPCocoaEvent* event, PluginObject* obj)
308{
309    NSString *string = (NSString *)event->data.key.charactersIgnoringModifiers;
310
311    unichar c = [string length] > 0 ? [string characterAtIndex:0] : 0;
312
313    switch (c) {
314        case NSLeftArrowFunctionKey:
315            if (obj->selectedRange.location > 0) {
316                obj->selectedRange.location--;
317                invalidatePlugin(obj);
318            }
319            return 1;
320
321        case NSRightArrowFunctionKey:
322            if (obj->selectedRange.location < [obj->textStorage length]) {
323                obj->selectedRange.location++;
324                invalidatePlugin(obj);
325            }
326
327            return 1;
328
329        default:
330            // Return 0 and let the text input system handle it.
331            return 0;
332    }
333}
334
335
336static int16_t handleTextInput(NPCocoaEvent* event, PluginObject* obj)
337{
338    NSString *string = (NSString *)event->data.text.text;
339    NSRange range = obj->selectedRange;
340
341    [obj->textStorage replaceCharactersInRange:range withString:string];
342
343    obj->selectedRange.location = range.location + [string length];
344    obj->selectedRange.length = 0;
345
346    invalidatePlugin(obj);
347
348    return 1;
349}
350
351int16 NPP_HandleEvent(NPP instance, void* event)
352{
353    PluginObject* obj = instance->pdata;
354
355    NPCocoaEvent* cocoaEvent = event;
356
357    switch (cocoaEvent->type) {
358        case NPCocoaEventDrawRect:
359            handleDraw(obj, cocoaEvent);
360            return 1;
361        case NPCocoaEventFocusChanged:
362            handleFocusChanged(cocoaEvent, obj);
363            return 1;
364        case NPCocoaEventMouseMoved:
365            handleMouseMoved(cocoaEvent, obj);
366            return 1;
367        case NPCocoaEventMouseDown:
368            handleMouseDown(cocoaEvent, obj);
369            return 1;
370        case NPCocoaEventKeyDown:
371            // If the text field has focus we ignore the event, causing it
372            // to be sent to the input manager.
373            if (obj->textFieldHasFocus)
374                return handleTextFieldKeyDown(cocoaEvent, obj);
375            else
376                return 1;
377        case NPCocoaEventTextInput:
378            return handleTextInput(cocoaEvent, obj);
379            return 1;
380
381    }
382
383    return 0;
384}
385
386void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
387{
388}
389
390NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value)
391{
392    return NPERR_GENERIC_ERROR;
393}
394
395NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value)
396{
397    return NPERR_GENERIC_ERROR;
398}
399