1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/views/mac/SkOSWindow_Mac.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,542 @@ 1.4 +/* 1.5 + * Copyright 2011 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkTypes.h" 1.12 + 1.13 +#if defined(SK_BUILD_FOR_MAC) 1.14 + 1.15 +#include <AGL/agl.h> 1.16 + 1.17 +#include <Carbon/Carbon.h> 1.18 +#include "SkCGUtils.h" 1.19 + 1.20 +#include "SkWindow.h" 1.21 +#include "SkCanvas.h" 1.22 +#include "SkOSMenu.h" 1.23 +#include "SkTime.h" 1.24 + 1.25 +#include "SkGraphics.h" 1.26 +#include <new.h> 1.27 + 1.28 +static void (*gPrevNewHandler)(); 1.29 + 1.30 +extern "C" { 1.31 + static void sk_new_handler() 1.32 + { 1.33 + if (SkGraphics::SetFontCacheUsed(0)) 1.34 + return; 1.35 + if (gPrevNewHandler) 1.36 + gPrevNewHandler(); 1.37 + else 1.38 + sk_throw(); 1.39 + } 1.40 +} 1.41 + 1.42 +static SkOSWindow* gCurrOSWin; 1.43 +static EventTargetRef gEventTarget; 1.44 +static EventQueueRef gCurrEventQ; 1.45 + 1.46 +static OSStatus MyDrawEventHandler(EventHandlerCallRef myHandler, 1.47 + EventRef event, void *userData) { 1.48 + // NOTE: GState is save/restored by the HIView system doing the callback, 1.49 + // so the draw handler doesn't need to do it 1.50 + 1.51 + OSStatus status = noErr; 1.52 + CGContextRef context; 1.53 + HIRect bounds; 1.54 + 1.55 + // Get the CGContextRef 1.56 + status = GetEventParameter (event, kEventParamCGContextRef, 1.57 + typeCGContextRef, NULL, 1.58 + sizeof (CGContextRef), 1.59 + NULL, 1.60 + &context); 1.61 + 1.62 + if (status != noErr) { 1.63 + SkDebugf("Got error %d getting the context!\n", status); 1.64 + return status; 1.65 + } 1.66 + 1.67 + // Get the bounding rectangle 1.68 + HIViewGetBounds ((HIViewRef) userData, &bounds); 1.69 + 1.70 + gCurrOSWin->doPaint(context); 1.71 + return status; 1.72 +} 1.73 + 1.74 +#define SK_MacEventClass FOUR_CHAR_CODE('SKec') 1.75 +#define SK_MacEventKind FOUR_CHAR_CODE('SKek') 1.76 +#define SK_MacEventParamName FOUR_CHAR_CODE('SKev') 1.77 +#define SK_MacEventSinkIDParamName FOUR_CHAR_CODE('SKes') 1.78 + 1.79 +static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) { 1.80 + side->toView = parent; 1.81 + side->kind = kind; 1.82 + side->offset = 0; 1.83 +} 1.84 + 1.85 +static void set_axisscale(HIAxisScale* axis, HIViewRef parent) { 1.86 + axis->toView = parent; 1.87 + axis->kind = kHILayoutScaleAbsolute; 1.88 + axis->ratio = 1; 1.89 +} 1.90 + 1.91 +static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) { 1.92 + pos->toView = parent; 1.93 + pos->kind = kind; 1.94 + pos->offset = 0; 1.95 +} 1.96 + 1.97 +SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd), fAGLCtx(NULL) 1.98 +{ 1.99 + OSStatus result; 1.100 + WindowRef wr = (WindowRef)hWnd; 1.101 + 1.102 + HIViewRef imageView, parent; 1.103 + HIViewRef rootView = HIViewGetRoot(wr); 1.104 + HIViewFindByID(rootView, kHIViewWindowContentID, &parent); 1.105 + result = HIImageViewCreate(NULL, &imageView); 1.106 + SkASSERT(result == noErr); 1.107 + 1.108 + result = HIViewAddSubview(parent, imageView); 1.109 + SkASSERT(result == noErr); 1.110 + 1.111 + fHVIEW = imageView; 1.112 + 1.113 + HIViewSetVisible(imageView, true); 1.114 + HIViewPlaceInSuperviewAt(imageView, 0, 0); 1.115 + 1.116 + if (true) { 1.117 + HILayoutInfo layout; 1.118 + layout.version = kHILayoutInfoVersionZero; 1.119 + set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft); 1.120 + set_bindingside(&layout.binding.top, parent, kHILayoutBindTop); 1.121 + set_bindingside(&layout.binding.right, parent, kHILayoutBindRight); 1.122 + set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom); 1.123 + set_axisscale(&layout.scale.x, parent); 1.124 + set_axisscale(&layout.scale.y, parent); 1.125 + set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft); 1.126 + set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop); 1.127 + HIViewSetLayoutInfo(imageView, &layout); 1.128 + } 1.129 + 1.130 + HIImageViewSetOpaque(imageView, true); 1.131 + HIImageViewSetScaleToFit(imageView, false); 1.132 + 1.133 + static const EventTypeSpec gTypes[] = { 1.134 + { kEventClassKeyboard, kEventRawKeyDown }, 1.135 + { kEventClassKeyboard, kEventRawKeyUp }, 1.136 + { kEventClassMouse, kEventMouseDown }, 1.137 + { kEventClassMouse, kEventMouseDragged }, 1.138 + { kEventClassMouse, kEventMouseMoved }, 1.139 + { kEventClassMouse, kEventMouseUp }, 1.140 + { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, 1.141 + { kEventClassWindow, kEventWindowBoundsChanged }, 1.142 +// { kEventClassWindow, kEventWindowDrawContent }, 1.143 + { SK_MacEventClass, SK_MacEventKind } 1.144 + }; 1.145 + 1.146 + EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler); 1.147 + int count = SK_ARRAY_COUNT(gTypes); 1.148 + 1.149 + result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP, 1.150 + count, gTypes, this, nil); 1.151 + SkASSERT(result == noErr); 1.152 + 1.153 + gCurrOSWin = this; 1.154 + gCurrEventQ = GetCurrentEventQueue(); 1.155 + gEventTarget = GetWindowEventTarget(wr); 1.156 + 1.157 + static bool gOnce = true; 1.158 + if (gOnce) { 1.159 + gOnce = false; 1.160 + gPrevNewHandler = set_new_handler(sk_new_handler); 1.161 + } 1.162 +} 1.163 + 1.164 +void SkOSWindow::doPaint(void* ctx) 1.165 +{ 1.166 +#if 0 1.167 + this->update(NULL); 1.168 + 1.169 + const SkBitmap& bm = this->getBitmap(); 1.170 + CGImageRef img = SkCreateCGImageRef(bm); 1.171 + 1.172 + if (img) { 1.173 + CGRect r = CGRectMake(0, 0, bm.width(), bm.height()); 1.174 + 1.175 + CGContextRef cg = reinterpret_cast<CGContextRef>(ctx); 1.176 + 1.177 + CGContextSaveGState(cg); 1.178 + CGContextTranslateCTM(cg, 0, r.size.height); 1.179 + CGContextScaleCTM(cg, 1, -1); 1.180 + 1.181 + CGContextDrawImage(cg, r, img); 1.182 + 1.183 + CGContextRestoreGState(cg); 1.184 + 1.185 + CGImageRelease(img); 1.186 + } 1.187 +#endif 1.188 +} 1.189 + 1.190 +void SkOSWindow::updateSize() 1.191 +{ 1.192 + Rect r; 1.193 + 1.194 + GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r); 1.195 + this->resize(r.right - r.left, r.bottom - r.top); 1.196 + 1.197 +#if 0 1.198 + HIRect frame; 1.199 + HIViewRef imageView = (HIViewRef)getHVIEW(); 1.200 + HIViewRef parent = HIViewGetSuperview(imageView); 1.201 + 1.202 + HIViewGetBounds(imageView, &frame); 1.203 + SkDebugf("------ %d bounds %g %g %g %g\n", r.right - r.left, 1.204 + frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); 1.205 +#endif 1.206 +} 1.207 + 1.208 +void SkOSWindow::onHandleInval(const SkIRect& r) 1.209 +{ 1.210 + (new SkEvent("inval-imageview", this->getSinkID()))->post(); 1.211 +} 1.212 + 1.213 +bool SkOSWindow::onEvent(const SkEvent& evt) { 1.214 + if (evt.isType("inval-imageview")) { 1.215 + this->update(NULL); 1.216 + 1.217 + SkEvent query("ignore-window-bitmap"); 1.218 + if (!this->doQuery(&query) || !query.getFast32()) { 1.219 + const SkBitmap& bm = this->getBitmap(); 1.220 + 1.221 + CGImageRef img = SkCreateCGImageRef(bm); 1.222 + HIImageViewSetImage((HIViewRef)getHVIEW(), img); 1.223 + CGImageRelease(img); 1.224 + } 1.225 + return true; 1.226 + } 1.227 + return INHERITED::onEvent(evt); 1.228 +} 1.229 + 1.230 +void SkOSWindow::onSetTitle(const char title[]) 1.231 +{ 1.232 + CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); 1.233 + SetWindowTitleWithCFString((WindowRef)fHWND, str); 1.234 + CFRelease(str); 1.235 +} 1.236 + 1.237 +void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu) 1.238 +{ 1.239 +} 1.240 + 1.241 +static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data) 1.242 +{ 1.243 + EventParamType actualType; 1.244 + UInt32 actualSize; 1.245 + OSStatus status; 1.246 + 1.247 + status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data); 1.248 + SkASSERT(status == noErr); 1.249 + SkASSERT(actualType == type); 1.250 + SkASSERT(actualSize == size); 1.251 +} 1.252 + 1.253 +enum { 1.254 + SK_MacReturnKey = 36, 1.255 + SK_MacDeleteKey = 51, 1.256 + SK_MacEndKey = 119, 1.257 + SK_MacLeftKey = 123, 1.258 + SK_MacRightKey = 124, 1.259 + SK_MacDownKey = 125, 1.260 + SK_MacUpKey = 126, 1.261 + 1.262 + SK_Mac0Key = 0x52, 1.263 + SK_Mac1Key = 0x53, 1.264 + SK_Mac2Key = 0x54, 1.265 + SK_Mac3Key = 0x55, 1.266 + SK_Mac4Key = 0x56, 1.267 + SK_Mac5Key = 0x57, 1.268 + SK_Mac6Key = 0x58, 1.269 + SK_Mac7Key = 0x59, 1.270 + SK_Mac8Key = 0x5b, 1.271 + SK_Mac9Key = 0x5c 1.272 +}; 1.273 + 1.274 +static SkKey raw2key(UInt32 raw) 1.275 +{ 1.276 + static const struct { 1.277 + UInt32 fRaw; 1.278 + SkKey fKey; 1.279 + } gKeys[] = { 1.280 + { SK_MacUpKey, kUp_SkKey }, 1.281 + { SK_MacDownKey, kDown_SkKey }, 1.282 + { SK_MacLeftKey, kLeft_SkKey }, 1.283 + { SK_MacRightKey, kRight_SkKey }, 1.284 + { SK_MacReturnKey, kOK_SkKey }, 1.285 + { SK_MacDeleteKey, kBack_SkKey }, 1.286 + { SK_MacEndKey, kEnd_SkKey }, 1.287 + { SK_Mac0Key, k0_SkKey }, 1.288 + { SK_Mac1Key, k1_SkKey }, 1.289 + { SK_Mac2Key, k2_SkKey }, 1.290 + { SK_Mac3Key, k3_SkKey }, 1.291 + { SK_Mac4Key, k4_SkKey }, 1.292 + { SK_Mac5Key, k5_SkKey }, 1.293 + { SK_Mac6Key, k6_SkKey }, 1.294 + { SK_Mac7Key, k7_SkKey }, 1.295 + { SK_Mac8Key, k8_SkKey }, 1.296 + { SK_Mac9Key, k9_SkKey } 1.297 + }; 1.298 + 1.299 + for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++) 1.300 + if (gKeys[i].fRaw == raw) 1.301 + return gKeys[i].fKey; 1.302 + return kNONE_SkKey; 1.303 +} 1.304 + 1.305 +static void post_skmacevent() 1.306 +{ 1.307 + EventRef ref; 1.308 + OSStatus status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref); 1.309 + SkASSERT(status == noErr); 1.310 + 1.311 +#if 0 1.312 + status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt); 1.313 + SkASSERT(status == noErr); 1.314 + status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID); 1.315 + SkASSERT(status == noErr); 1.316 +#endif 1.317 + 1.318 + EventTargetRef target = gEventTarget; 1.319 + SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target); 1.320 + SkASSERT(status == noErr); 1.321 + 1.322 + status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard); 1.323 + SkASSERT(status == noErr); 1.324 + 1.325 + ReleaseEvent(ref); 1.326 +} 1.327 + 1.328 +pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData ) 1.329 +{ 1.330 + SkOSWindow* win = (SkOSWindow*)userData; 1.331 + OSStatus result = eventNotHandledErr; 1.332 + UInt32 wClass = GetEventClass(inEvent); 1.333 + UInt32 wKind = GetEventKind(inEvent); 1.334 + 1.335 + gCurrOSWin = win; // will need to be in TLS. Set this so PostEvent will work 1.336 + 1.337 + switch (wClass) { 1.338 + case kEventClassMouse: { 1.339 + Point pt; 1.340 + getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt); 1.341 + SetPortWindowPort((WindowRef)win->getHWND()); 1.342 + GlobalToLocal(&pt); 1.343 + 1.344 + switch (wKind) { 1.345 + case kEventMouseDown: 1.346 + if (win->handleClick(pt.h, pt.v, Click::kDown_State)) { 1.347 + result = noErr; 1.348 + } 1.349 + break; 1.350 + case kEventMouseMoved: 1.351 + // fall through 1.352 + case kEventMouseDragged: 1.353 + (void)win->handleClick(pt.h, pt.v, Click::kMoved_State); 1.354 + // result = noErr; 1.355 + break; 1.356 + case kEventMouseUp: 1.357 + (void)win->handleClick(pt.h, pt.v, Click::kUp_State); 1.358 + // result = noErr; 1.359 + break; 1.360 + default: 1.361 + break; 1.362 + } 1.363 + break; 1.364 + } 1.365 + case kEventClassKeyboard: 1.366 + if (wKind == kEventRawKeyDown) { 1.367 + UInt32 raw; 1.368 + getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw); 1.369 + SkKey key = raw2key(raw); 1.370 + if (key != kNONE_SkKey) 1.371 + (void)win->handleKey(key); 1.372 + } else if (wKind == kEventRawKeyUp) { 1.373 + UInt32 raw; 1.374 + getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw); 1.375 + SkKey key = raw2key(raw); 1.376 + if (key != kNONE_SkKey) 1.377 + (void)win->handleKeyUp(key); 1.378 + } 1.379 + break; 1.380 + case kEventClassTextInput: 1.381 + if (wKind == kEventTextInputUnicodeForKeyEvent) { 1.382 + UInt16 uni; 1.383 + getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni); 1.384 + win->handleChar(uni); 1.385 + } 1.386 + break; 1.387 + case kEventClassWindow: 1.388 + switch (wKind) { 1.389 + case kEventWindowBoundsChanged: 1.390 + win->updateSize(); 1.391 + break; 1.392 + case kEventWindowDrawContent: { 1.393 + CGContextRef cg; 1.394 + result = GetEventParameter(inEvent, 1.395 + kEventParamCGContextRef, 1.396 + typeCGContextRef, 1.397 + NULL, 1.398 + sizeof (CGContextRef), 1.399 + NULL, 1.400 + &cg); 1.401 + if (result != 0) { 1.402 + cg = NULL; 1.403 + } 1.404 + win->doPaint(cg); 1.405 + break; 1.406 + } 1.407 + default: 1.408 + break; 1.409 + } 1.410 + break; 1.411 + case SK_MacEventClass: { 1.412 + SkASSERT(wKind == SK_MacEventKind); 1.413 + if (SkEvent::ProcessEvent()) { 1.414 + post_skmacevent(); 1.415 + } 1.416 + #if 0 1.417 + SkEvent* evt; 1.418 + SkEventSinkID sinkID; 1.419 + getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt); 1.420 + getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID); 1.421 + #endif 1.422 + result = noErr; 1.423 + break; 1.424 + } 1.425 + default: 1.426 + break; 1.427 + } 1.428 + if (result == eventNotHandledErr) { 1.429 + result = CallNextEventHandler(inHandler, inEvent); 1.430 + } 1.431 + return result; 1.432 +} 1.433 + 1.434 +/////////////////////////////////////////////////////////////////////////////////////// 1.435 + 1.436 +void SkEvent::SignalNonEmptyQueue() 1.437 +{ 1.438 + post_skmacevent(); 1.439 +// SkDebugf("signal nonempty\n"); 1.440 +} 1.441 + 1.442 +static TMTask gTMTaskRec; 1.443 +static TMTask* gTMTaskPtr; 1.444 + 1.445 +static void sk_timer_proc(TMTask* rec) 1.446 +{ 1.447 + SkEvent::ServiceQueueTimer(); 1.448 +// SkDebugf("timer task fired\n"); 1.449 +} 1.450 + 1.451 +void SkEvent::SignalQueueTimer(SkMSec delay) 1.452 +{ 1.453 + if (gTMTaskPtr) 1.454 + { 1.455 + RemoveTimeTask((QElem*)gTMTaskPtr); 1.456 + DisposeTimerUPP(gTMTaskPtr->tmAddr); 1.457 + gTMTaskPtr = nil; 1.458 + } 1.459 + if (delay) 1.460 + { 1.461 + gTMTaskPtr = &gTMTaskRec; 1.462 + memset(gTMTaskPtr, 0, sizeof(gTMTaskRec)); 1.463 + gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc); 1.464 + OSErr err = InstallTimeTask((QElem*)gTMTaskPtr); 1.465 +// SkDebugf("installtimetask of %d returned %d\n", delay, err); 1.466 + PrimeTimeTask((QElem*)gTMTaskPtr, delay); 1.467 + } 1.468 +} 1.469 + 1.470 +#define USE_MSAA 0 1.471 + 1.472 +AGLContext create_gl(WindowRef wref) 1.473 +{ 1.474 + GLint major, minor; 1.475 + AGLContext ctx; 1.476 + 1.477 + aglGetVersion(&major, &minor); 1.478 + SkDebugf("---- agl version %d %d\n", major, minor); 1.479 + 1.480 + const GLint pixelAttrs[] = { 1.481 + AGL_RGBA, 1.482 + AGL_STENCIL_SIZE, 8, 1.483 +#if USE_MSAA 1.484 + AGL_SAMPLE_BUFFERS_ARB, 1, 1.485 + AGL_MULTISAMPLE, 1.486 + AGL_SAMPLES_ARB, 8, 1.487 +#endif 1.488 + AGL_ACCELERATED, 1.489 + AGL_DOUBLEBUFFER, 1.490 + AGL_NONE 1.491 + }; 1.492 + AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs); 1.493 + //AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs); 1.494 + SkDebugf("----- agl format %p\n", format); 1.495 + ctx = aglCreateContext(format, NULL); 1.496 + SkDebugf("----- agl context %p\n", ctx); 1.497 + aglDestroyPixelFormat(format); 1.498 + 1.499 + static const GLint interval = 1; 1.500 + aglSetInteger(ctx, AGL_SWAP_INTERVAL, &interval); 1.501 + aglSetCurrentContext(ctx); 1.502 + return ctx; 1.503 +} 1.504 + 1.505 +bool SkOSWindow::attach(SkBackEndTypes /* attachType */) 1.506 +{ 1.507 + if (NULL == fAGLCtx) { 1.508 + fAGLCtx = create_gl((WindowRef)fHWND); 1.509 + if (NULL == fAGLCtx) { 1.510 + return false; 1.511 + } 1.512 + } 1.513 + 1.514 + GLboolean success = true; 1.515 + 1.516 + int width, height; 1.517 + 1.518 + success = aglSetWindowRef((AGLContext)fAGLCtx, (WindowRef)fHWND); 1.519 + width = this->width(); 1.520 + height = this->height(); 1.521 + 1.522 + GLenum err = aglGetError(); 1.523 + if (err) { 1.524 + SkDebugf("---- aglSetWindowRef %d %d %s [%d %d]\n", success, err, 1.525 + aglErrorString(err), width, height); 1.526 + } 1.527 + 1.528 + if (success) { 1.529 + glViewport(0, 0, width, height); 1.530 + glClearColor(0, 0, 0, 0); 1.531 + glClearStencil(0); 1.532 + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 1.533 + } 1.534 + return success; 1.535 +} 1.536 + 1.537 +void SkOSWindow::detach() { 1.538 + aglSetWindowRef((AGLContext)fAGLCtx, NULL); 1.539 +} 1.540 + 1.541 +void SkOSWindow::present() { 1.542 + aglSwapBuffers((AGLContext)fAGLCtx); 1.543 +} 1.544 + 1.545 +#endif