• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkTypes.h"
9 
10 #if defined(SK_BUILD_FOR_MAC)
11 
12 #include <AGL/agl.h>
13 
14 #include <Carbon/Carbon.h>
15 #include "SkCGUtils.h"
16 
17 #include "SkWindow.h"
18 #include "SkCanvas.h"
19 #include "SkOSMenu.h"
20 #include "SkTime.h"
21 
22 #include "SkGraphics.h"
23 #include <new.h>
24 
25 static void (*gPrevNewHandler)();
26 
27 extern "C" {
sk_new_handler()28     static void sk_new_handler()
29     {
30         if (SkGraphics::SetFontCacheUsed(0))
31             return;
32         if (gPrevNewHandler)
33             gPrevNewHandler();
34         else
35             sk_throw();
36     }
37 }
38 
39 static SkOSWindow* gCurrOSWin;
40 static EventTargetRef gEventTarget;
41 static EventQueueRef gCurrEventQ;
42 
MyDrawEventHandler(EventHandlerCallRef myHandler,EventRef event,void * userData)43 static OSStatus MyDrawEventHandler(EventHandlerCallRef myHandler,
44                                    EventRef event, void *userData) {
45     // NOTE: GState is save/restored by the HIView system doing the callback,
46     // so the draw handler doesn't need to do it
47 
48     OSStatus status = noErr;
49     CGContextRef context;
50     HIRect        bounds;
51 
52     // Get the CGContextRef
53     status = GetEventParameter (event, kEventParamCGContextRef,
54                                 typeCGContextRef, NULL,
55                                 sizeof (CGContextRef),
56                                 NULL,
57                                 &context);
58 
59     if (status != noErr) {
60         SkDebugf("Got error %d getting the context!\n", status);
61         return status;
62     }
63 
64     // Get the bounding rectangle
65     HIViewGetBounds ((HIViewRef) userData, &bounds);
66 
67     gCurrOSWin->doPaint(context);
68     return status;
69 }
70 
71 #define SK_MacEventClass            FOUR_CHAR_CODE('SKec')
72 #define SK_MacEventKind                FOUR_CHAR_CODE('SKek')
73 #define SK_MacEventParamName        FOUR_CHAR_CODE('SKev')
74 #define SK_MacEventSinkIDParamName    FOUR_CHAR_CODE('SKes')
75 
set_bindingside(HISideBinding * side,HIViewRef parent,HIBindingKind kind)76 static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) {
77     side->toView = parent;
78     side->kind = kind;
79     side->offset = 0;
80 }
81 
set_axisscale(HIAxisScale * axis,HIViewRef parent)82 static void set_axisscale(HIAxisScale* axis, HIViewRef parent) {
83     axis->toView = parent;
84     axis->kind = kHILayoutScaleAbsolute;
85     axis->ratio = 1;
86 }
87 
set_axisposition(HIAxisPosition * pos,HIViewRef parent,HIPositionKind kind)88 static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) {
89     pos->toView = parent;
90     pos->kind = kind;
91     pos->offset = 0;
92 }
93 
SkOSWindow(void * hWnd)94 SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd), fAGLCtx(NULL)
95 {
96     OSStatus    result;
97     WindowRef   wr = (WindowRef)hWnd;
98 
99     HIViewRef imageView, parent;
100     HIViewRef rootView = HIViewGetRoot(wr);
101     HIViewFindByID(rootView, kHIViewWindowContentID, &parent);
102     result = HIImageViewCreate(NULL, &imageView);
103     SkASSERT(result == noErr);
104 
105     result = HIViewAddSubview(parent, imageView);
106     SkASSERT(result == noErr);
107 
108     fHVIEW = imageView;
109 
110     HIViewSetVisible(imageView, true);
111     HIViewPlaceInSuperviewAt(imageView, 0, 0);
112 
113     if (true) {
114         HILayoutInfo layout;
115         layout.version = kHILayoutInfoVersionZero;
116         set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft);
117         set_bindingside(&layout.binding.top, parent, kHILayoutBindTop);
118         set_bindingside(&layout.binding.right, parent, kHILayoutBindRight);
119         set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom);
120         set_axisscale(&layout.scale.x, parent);
121         set_axisscale(&layout.scale.y, parent);
122         set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft);
123         set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop);
124         HIViewSetLayoutInfo(imageView, &layout);
125     }
126 
127     HIImageViewSetOpaque(imageView, true);
128     HIImageViewSetScaleToFit(imageView, false);
129 
130     static const EventTypeSpec  gTypes[] = {
131         { kEventClassKeyboard,  kEventRawKeyDown            },
132         { kEventClassKeyboard,  kEventRawKeyUp              },
133         { kEventClassMouse,        kEventMouseDown                },
134         { kEventClassMouse,        kEventMouseDragged            },
135         { kEventClassMouse,        kEventMouseMoved            },
136         { kEventClassMouse,        kEventMouseUp                },
137         { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent   },
138         { kEventClassWindow,    kEventWindowBoundsChanged    },
139 //        { kEventClassWindow,    kEventWindowDrawContent        },
140         { SK_MacEventClass,        SK_MacEventKind                }
141     };
142 
143     EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler);
144     int                count = SK_ARRAY_COUNT(gTypes);
145 
146     result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP,
147                         count, gTypes, this, nil);
148     SkASSERT(result == noErr);
149 
150     gCurrOSWin = this;
151     gCurrEventQ = GetCurrentEventQueue();
152     gEventTarget = GetWindowEventTarget(wr);
153 
154     static bool gOnce = true;
155     if (gOnce) {
156         gOnce = false;
157         gPrevNewHandler = set_new_handler(sk_new_handler);
158     }
159 }
160 
doPaint(void * ctx)161 void SkOSWindow::doPaint(void* ctx)
162 {
163 #if 0
164     this->update(NULL);
165 
166     const SkBitmap& bm = this->getBitmap();
167     CGImageRef img = SkCreateCGImageRef(bm);
168 
169     if (img) {
170         CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
171 
172         CGContextRef cg = reinterpret_cast<CGContextRef>(ctx);
173 
174         CGContextSaveGState(cg);
175         CGContextTranslateCTM(cg, 0, r.size.height);
176         CGContextScaleCTM(cg, 1, -1);
177 
178         CGContextDrawImage(cg, r, img);
179 
180         CGContextRestoreGState(cg);
181 
182         CGImageRelease(img);
183     }
184 #endif
185 }
186 
updateSize()187 void SkOSWindow::updateSize()
188 {
189     Rect    r;
190 
191     GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r);
192     this->resize(r.right - r.left, r.bottom - r.top);
193 
194 #if 0
195     HIRect    frame;
196     HIViewRef imageView = (HIViewRef)getHVIEW();
197     HIViewRef parent = HIViewGetSuperview(imageView);
198 
199     HIViewGetBounds(imageView, &frame);
200     SkDebugf("------ %d bounds %g %g %g %g\n", r.right - r.left,
201              frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
202 #endif
203 }
204 
onHandleInval(const SkIRect & r)205 void SkOSWindow::onHandleInval(const SkIRect& r)
206 {
207     (new SkEvent("inval-imageview", this->getSinkID()))->post();
208 }
209 
onEvent(const SkEvent & evt)210 bool SkOSWindow::onEvent(const SkEvent& evt) {
211     if (evt.isType("inval-imageview")) {
212         this->update(NULL);
213 
214         SkEvent query("ignore-window-bitmap");
215         if (!this->doQuery(&query) || !query.getFast32()) {
216             const SkBitmap& bm = this->getBitmap();
217 
218             CGImageRef img = SkCreateCGImageRef(bm);
219             HIImageViewSetImage((HIViewRef)getHVIEW(), img);
220             CGImageRelease(img);
221         }
222         return true;
223     }
224     return INHERITED::onEvent(evt);
225 }
226 
onSetTitle(const char title[])227 void SkOSWindow::onSetTitle(const char title[])
228 {
229     CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
230     SetWindowTitleWithCFString((WindowRef)fHWND, str);
231     CFRelease(str);
232 }
233 
onAddMenu(const SkOSMenu * sk_menu)234 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
235 {
236 }
237 
getparam(EventRef inEvent,OSType name,OSType type,UInt32 size,void * data)238 static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data)
239 {
240     EventParamType  actualType;
241     UInt32            actualSize;
242     OSStatus        status;
243 
244     status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data);
245     SkASSERT(status == noErr);
246     SkASSERT(actualType == type);
247     SkASSERT(actualSize == size);
248 }
249 
250 enum {
251     SK_MacReturnKey        = 36,
252     SK_MacDeleteKey        = 51,
253     SK_MacEndKey        = 119,
254     SK_MacLeftKey        = 123,
255     SK_MacRightKey        = 124,
256     SK_MacDownKey        = 125,
257     SK_MacUpKey            = 126,
258 
259     SK_Mac0Key          = 0x52,
260     SK_Mac1Key          = 0x53,
261     SK_Mac2Key          = 0x54,
262     SK_Mac3Key          = 0x55,
263     SK_Mac4Key          = 0x56,
264     SK_Mac5Key          = 0x57,
265     SK_Mac6Key          = 0x58,
266     SK_Mac7Key          = 0x59,
267     SK_Mac8Key          = 0x5b,
268     SK_Mac9Key          = 0x5c
269 };
270 
raw2key(UInt32 raw)271 static SkKey raw2key(UInt32 raw)
272 {
273     static const struct {
274         UInt32  fRaw;
275         SkKey   fKey;
276     } gKeys[] = {
277         { SK_MacUpKey,        kUp_SkKey        },
278         { SK_MacDownKey,    kDown_SkKey        },
279         { SK_MacLeftKey,    kLeft_SkKey        },
280         { SK_MacRightKey,   kRight_SkKey    },
281         { SK_MacReturnKey,  kOK_SkKey        },
282         { SK_MacDeleteKey,  kBack_SkKey        },
283         { SK_MacEndKey,        kEnd_SkKey        },
284         { SK_Mac0Key,       k0_SkKey        },
285         { SK_Mac1Key,       k1_SkKey        },
286         { SK_Mac2Key,       k2_SkKey        },
287         { SK_Mac3Key,       k3_SkKey        },
288         { SK_Mac4Key,       k4_SkKey        },
289         { SK_Mac5Key,       k5_SkKey        },
290         { SK_Mac6Key,       k6_SkKey        },
291         { SK_Mac7Key,       k7_SkKey        },
292         { SK_Mac8Key,       k8_SkKey        },
293         { SK_Mac9Key,       k9_SkKey        }
294     };
295 
296     for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
297         if (gKeys[i].fRaw == raw)
298             return gKeys[i].fKey;
299     return kNONE_SkKey;
300 }
301 
post_skmacevent()302 static void post_skmacevent()
303 {
304     EventRef    ref;
305     OSStatus    status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref);
306     SkASSERT(status == noErr);
307 
308 #if 0
309     status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
310     SkASSERT(status == noErr);
311     status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
312     SkASSERT(status == noErr);
313 #endif
314 
315     EventTargetRef target = gEventTarget;
316     SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target);
317     SkASSERT(status == noErr);
318 
319     status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard);
320     SkASSERT(status == noErr);
321 
322     ReleaseEvent(ref);
323 }
324 
EventHandler(EventHandlerCallRef inHandler,EventRef inEvent,void * userData)325 pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData )
326 {
327     SkOSWindow* win = (SkOSWindow*)userData;
328     OSStatus    result = eventNotHandledErr;
329     UInt32        wClass = GetEventClass(inEvent);
330     UInt32        wKind = GetEventKind(inEvent);
331 
332     gCurrOSWin = win;    // will need to be in TLS. Set this so PostEvent will work
333 
334     switch (wClass) {
335         case kEventClassMouse: {
336             Point   pt;
337             getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt);
338             SetPortWindowPort((WindowRef)win->getHWND());
339             GlobalToLocal(&pt);
340 
341             switch (wKind) {
342                 case kEventMouseDown:
343                     if (win->handleClick(pt.h, pt.v, Click::kDown_State)) {
344                         result = noErr;
345                     }
346                     break;
347                 case kEventMouseMoved:
348                     // fall through
349                 case kEventMouseDragged:
350                     (void)win->handleClick(pt.h, pt.v, Click::kMoved_State);
351                   //  result = noErr;
352                     break;
353                 case kEventMouseUp:
354                     (void)win->handleClick(pt.h, pt.v, Click::kUp_State);
355                   //  result = noErr;
356                     break;
357                 default:
358                     break;
359             }
360             break;
361         }
362         case kEventClassKeyboard:
363             if (wKind == kEventRawKeyDown) {
364                 UInt32  raw;
365                 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
366                 SkKey key = raw2key(raw);
367                 if (key != kNONE_SkKey)
368                     (void)win->handleKey(key);
369             } else if (wKind == kEventRawKeyUp) {
370                 UInt32 raw;
371                 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
372                 SkKey key = raw2key(raw);
373                 if (key != kNONE_SkKey)
374                     (void)win->handleKeyUp(key);
375             }
376             break;
377         case kEventClassTextInput:
378             if (wKind == kEventTextInputUnicodeForKeyEvent) {
379                 UInt16  uni;
380                 getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni);
381                 win->handleChar(uni);
382             }
383             break;
384         case kEventClassWindow:
385             switch (wKind) {
386                 case kEventWindowBoundsChanged:
387                     win->updateSize();
388                     break;
389                 case kEventWindowDrawContent: {
390                     CGContextRef cg;
391                     result = GetEventParameter(inEvent,
392                                                kEventParamCGContextRef,
393                                                typeCGContextRef,
394                                                NULL,
395                                                sizeof (CGContextRef),
396                                                NULL,
397                                                &cg);
398                     if (result != 0) {
399                         cg = NULL;
400                     }
401                     win->doPaint(cg);
402                     break;
403                 }
404                 default:
405                     break;
406             }
407             break;
408         case SK_MacEventClass: {
409             SkASSERT(wKind == SK_MacEventKind);
410             if (SkEvent::ProcessEvent()) {
411                     post_skmacevent();
412             }
413     #if 0
414             SkEvent*        evt;
415             SkEventSinkID    sinkID;
416             getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
417             getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
418     #endif
419             result = noErr;
420             break;
421         }
422         default:
423             break;
424     }
425     if (result == eventNotHandledErr) {
426         result = CallNextEventHandler(inHandler, inEvent);
427     }
428     return result;
429 }
430 
431 ///////////////////////////////////////////////////////////////////////////////////////
432 
SignalNonEmptyQueue()433 void SkEvent::SignalNonEmptyQueue()
434 {
435     post_skmacevent();
436 //    SkDebugf("signal nonempty\n");
437 }
438 
439 static TMTask    gTMTaskRec;
440 static TMTask*    gTMTaskPtr;
441 
sk_timer_proc(TMTask * rec)442 static void sk_timer_proc(TMTask* rec)
443 {
444     SkEvent::ServiceQueueTimer();
445 //    SkDebugf("timer task fired\n");
446 }
447 
SignalQueueTimer(SkMSec delay)448 void SkEvent::SignalQueueTimer(SkMSec delay)
449 {
450     if (gTMTaskPtr)
451     {
452         RemoveTimeTask((QElem*)gTMTaskPtr);
453         DisposeTimerUPP(gTMTaskPtr->tmAddr);
454         gTMTaskPtr = nil;
455     }
456     if (delay)
457     {
458         gTMTaskPtr = &gTMTaskRec;
459         memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));
460         gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);
461         OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);
462 //        SkDebugf("installtimetask of %d returned %d\n", delay, err);
463         PrimeTimeTask((QElem*)gTMTaskPtr, delay);
464     }
465 }
466 
467 #define USE_MSAA 0
468 
create_gl(WindowRef wref)469 AGLContext create_gl(WindowRef wref)
470 {
471     GLint major, minor;
472     AGLContext ctx;
473 
474     aglGetVersion(&major, &minor);
475     SkDebugf("---- agl version %d %d\n", major, minor);
476 
477     const GLint pixelAttrs[] = {
478         AGL_RGBA,
479         AGL_STENCIL_SIZE, 8,
480 #if USE_MSAA
481         AGL_SAMPLE_BUFFERS_ARB, 1,
482         AGL_MULTISAMPLE,
483         AGL_SAMPLES_ARB, 8,
484 #endif
485         AGL_ACCELERATED,
486         AGL_DOUBLEBUFFER,
487         AGL_NONE
488     };
489     AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs);
490     //AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
491     SkDebugf("----- agl format %p\n", format);
492     ctx = aglCreateContext(format, NULL);
493     SkDebugf("----- agl context %p\n", ctx);
494     aglDestroyPixelFormat(format);
495 
496     static const GLint interval = 1;
497     aglSetInteger(ctx, AGL_SWAP_INTERVAL, &interval);
498     aglSetCurrentContext(ctx);
499     return ctx;
500 }
501 
attach(SkBackEndTypes)502 bool SkOSWindow::attach(SkBackEndTypes /* attachType */)
503 {
504     if (NULL == fAGLCtx) {
505         fAGLCtx = create_gl((WindowRef)fHWND);
506         if (NULL == fAGLCtx) {
507             return false;
508         }
509     }
510 
511     GLboolean success = true;
512 
513     int width, height;
514 
515     success = aglSetWindowRef((AGLContext)fAGLCtx, (WindowRef)fHWND);
516     width = this->width();
517     height = this->height();
518 
519     GLenum err = aglGetError();
520     if (err) {
521         SkDebugf("---- aglSetWindowRef %d %d %s [%d %d]\n", success, err,
522                  aglErrorString(err), width, height);
523     }
524 
525     if (success) {
526         glViewport(0, 0, width, height);
527         glClearColor(0, 0, 0, 0);
528         glClearStencil(0);
529         glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
530     }
531     return success;
532 }
533 
detach()534 void SkOSWindow::detach() {
535     aglSetWindowRef((AGLContext)fAGLCtx, NULL);
536 }
537 
present()538 void SkOSWindow::present() {
539     aglSwapBuffers((AGLContext)fAGLCtx);
540 }
541 
542 #endif
543