Home | History | Annotate | Download | only in mac
      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" {
     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 
     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 
     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 
     82 static void set_axisscale(HIAxisScale* axis, HIViewRef parent) {
     83     axis->toView = parent;
     84     axis->kind = kHILayoutScaleAbsolute;
     85     axis->ratio = 1;
     86 }
     87 
     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 
     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 
    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 
    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 
    205 void SkOSWindow::onHandleInval(const SkIRect& r)
    206 {
    207     (new SkEvent("inval-imageview", this->getSinkID()))->post();
    208 }
    209 
    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 
    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 
    234 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
    235 {
    236 }
    237 
    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 
    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 
    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 
    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 
    433 void SkEvent::SignalNonEmptyQueue()
    434 {
    435     post_skmacevent();
    436 //    SkDebugf("signal nonempty\n");
    437 }
    438 
    439 static TMTask    gTMTaskRec;
    440 static TMTask*    gTMTaskPtr;
    441 
    442 static void sk_timer_proc(TMTask* rec)
    443 {
    444     SkEvent::ServiceQueueTimer();
    445 //    SkDebugf("timer task fired\n");
    446 }
    447 
    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 
    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 
    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 
    534 void SkOSWindow::detach() {
    535     aglSetWindowRef((AGLContext)fAGLCtx, NULL);
    536 }
    537 
    538 void SkOSWindow::present() {
    539     aglSwapBuffers((AGLContext)fAGLCtx);
    540 }
    541 
    542 #endif
    543