first cut at event-based test app



git-svn-id: http://skia.googlecode.com/svn/trunk@37 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/mac/SkBitmap_Mac.cpp b/src/utils/mac/SkBitmap_Mac.cpp
new file mode 100644
index 0000000..06c2b27
--- /dev/null
+++ b/src/utils/mac/SkBitmap_Mac.cpp
@@ -0,0 +1,142 @@
+#include "SkBitmap.h"
+#include "SkColorPriv.h"
+#include "SkMath.h"
+
+#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#ifndef __ppc__
+    #define SWAP_16BIT
+#endif
+
+static void convertGL32_to_Mac32(uint32_t dst[], const SkBitmap& bm) {
+    memcpy(dst, bm.getPixels(), bm.getSize());
+    return;
+    
+    uint32_t* stop = dst + (bm.getSize() >> 2);
+    const uint8_t* src = (const uint8_t*)bm.getPixels();
+    while (dst < stop) {
+        *dst++ = src[2] << 24 | src[1] << 16 | src[0] << 8 | src[3] << 0;
+        src += sizeof(uint32_t);
+    }
+}
+
+static void convert565_to_32(uint32_t dst[], const SkBitmap& bm) {
+    for (int y = 0; y < bm.height(); y++) {
+        const uint16_t* src = bm.getAddr16(0, y);
+        const uint16_t* stop = src + bm.width();
+        while (src < stop) {
+            unsigned c = *src++;
+            unsigned r = SkPacked16ToR32(c);
+            unsigned g = SkPacked16ToG32(c);
+            unsigned b = SkPacked16ToB32(c);
+        
+            *dst++ = (b << 24) | (g << 16) | (r << 8) | 0xFF;
+        }
+    }
+}
+
+static void convert4444_to_555(uint16_t dst[], const uint16_t src[], int count)
+{
+    const uint16_t* stop = src + count;
+    
+    while (src < stop)
+    {
+        unsigned c = *src++;
+        
+        unsigned r = SkGetPackedR4444(c);
+        unsigned g = SkGetPackedG4444(c);
+        unsigned b = SkGetPackedB4444(c);
+        // convert to 5 bits
+        r = (r << 1) | (r >> 3);
+        g = (g << 1) | (g >> 3);
+        b = (b << 1) | (b >> 3);
+        // build the 555
+        c = (r << 10) | (g << 5) | b;
+        
+#ifdef SWAP_16BIT
+        c = (c >> 8) | (c << 8);
+#endif
+        *dst++ = c;
+    }
+}
+
+#include "SkTemplates.h"
+
+static CGImageRef bitmap2imageref(const SkBitmap& bm) {
+    size_t  bitsPerComp;
+    size_t  bitsPerPixel;
+    CGBitmapInfo info;
+    CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+    CGDataProviderRef data = CGDataProviderCreateWithData(NULL,
+                                                           bm.getPixels(),
+                                                           bm.getSize(),
+                                                           NULL);
+    SkAutoTCallVProc<CGDataProvider, CGDataProviderRelease> acp(data);
+    SkAutoTCallVProc<CGColorSpace, CGColorSpaceRelease> acp2(cs);
+
+    switch (bm.config()) {
+        case SkBitmap::kARGB_8888_Config:
+            bitsPerComp = 8;
+            bitsPerPixel = 32;
+            info = kCGImageAlphaPremultipliedLast;
+            break;
+        case SkBitmap::kARGB_4444_Config:
+            bitsPerComp = 4;
+            bitsPerPixel = 16;
+            info = kCGImageAlphaPremultipliedLast |  kCGBitmapByteOrder16Little;
+            break;
+#if 0   // not supported by quartz !!!
+        case SkBitmap::kRGB_565_Config:
+            bitsPerComp = 5;
+            bitsPerPixel = 16;
+            info = kCGImageAlphaNone | kCGBitmapByteOrder16Little;
+            break;
+#endif
+        default:
+            return NULL;
+    }
+
+    return CGImageCreate(bm.width(), bm.height(), bitsPerComp, bitsPerPixel,
+                         bm.rowBytes(), cs, info, data,
+                         NULL, false, kCGRenderingIntentDefault);
+}
+
+void SkBitmap::drawToPort(WindowRef wind, CGContextRef cg) const {
+	if (fPixels == NULL || fWidth == 0 || fHeight == 0) {
+		return;
+    }
+    
+    bool useQD = false;
+    if (NULL == cg) {
+        SetPortWindowPort(wind);
+        QDBeginCGContext(GetWindowPort(wind), &cg);
+        useQD = true;
+    }
+
+    SkBitmap bm;
+    if (this->config() == kRGB_565_Config) {
+        this->copyTo(&bm, kARGB_8888_Config);
+    } else {
+        bm = *this;
+    }
+    bm.lockPixels();
+
+    CGImageRef image = bitmap2imageref(bm);
+    if (image) {
+        CGRect rect;
+        rect.origin.x = rect.origin.y = 0;
+        rect.size.width = bm.width();
+        rect.size.height = bm.height();
+        
+        CGContextDrawImage(cg, rect, image);
+        CGImageRelease(image);
+    }
+
+    if (useQD) {
+        QDEndCGContext(GetWindowPort(wind), &cg);
+    }
+}
+
+#endif
diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp
new file mode 100644
index 0000000..2c93721
--- /dev/null
+++ b/src/utils/mac/SkOSWindow_Mac.cpp
@@ -0,0 +1,451 @@
+#include "SkTypes.h"
+
+#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS)
+
+#include <Carbon/Carbon.h>
+#include "SkCGUtils.h"
+
+#include "SkWindow.h"
+#include "SkCanvas.h"
+#include "SkOSMenu.h"
+#include "SkTime.h"
+
+#include "SkGraphics.h"
+#include <new.h>
+
+static void (*gPrevNewHandler)();
+
+extern "C" {
+	static void sk_new_handler()
+	{
+		if (SkGraphics::SetFontCacheUsed(0))
+			return;
+		if (gPrevNewHandler)
+			gPrevNewHandler();
+		else
+			sk_throw();
+	}
+}
+
+static SkOSWindow* gCurrOSWin;
+static EventTargetRef gEventTarget;
+static EventQueueRef gCurrEventQ;
+
+static OSStatus MyDrawEventHandler(EventHandlerCallRef myHandler,
+                                   EventRef event, void *userData) {
+	// NOTE: GState is save/restored by the HIView system doing the callback,
+    // so the draw handler doesn't need to do it
+    
+	OSStatus status = noErr;
+	CGContextRef context;
+	HIRect		bounds;
+    
+	// Get the CGContextRef
+	status = GetEventParameter (event, kEventParamCGContextRef, 
+                                typeCGContextRef, NULL, 
+                                sizeof (CGContextRef),
+                                NULL,
+                                &context);
+    
+	if (status != noErr) {
+		SkDebugf("Got error %d getting the context!\n", status);
+		return status;
+	}		
+    
+	// Get the bounding rectangle
+	HIViewGetBounds ((HIViewRef) userData, &bounds);
+	
+    gCurrOSWin->doPaint(context);
+	return status;
+}
+
+#define SK_MacEventClass			FOUR_CHAR_CODE('SKec')
+#define SK_MacEventKind				FOUR_CHAR_CODE('SKek')
+#define SK_MacEventParamName		FOUR_CHAR_CODE('SKev')
+#define SK_MacEventSinkIDParamName	FOUR_CHAR_CODE('SKes')
+
+static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) {
+    side->toView = parent;
+    side->kind = kind;
+    side->offset = 0;
+}
+
+static void set_axisscale(HIAxisScale* axis, HIViewRef parent) {
+    axis->toView = parent;
+    axis->kind = kHILayoutScaleAbsolute;
+    axis->ratio = 1;
+}
+
+static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) {
+    pos->toView = parent;
+    pos->kind = kind;
+    pos->offset = 0;
+}
+
+SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd)
+{
+	OSStatus    result;
+    WindowRef   wr = (WindowRef)hWnd;
+    
+    HIViewRef imageView, parent;
+    HIViewRef rootView = HIViewGetRoot(wr);
+    HIViewFindByID(rootView, kHIViewWindowContentID, &parent);
+    result = HIImageViewCreate(NULL, &imageView);
+	SkASSERT(result == noErr);
+    
+    result = HIViewAddSubview(parent, imageView);
+	SkASSERT(result == noErr);
+
+    fHVIEW = imageView;
+
+    HIViewSetVisible(imageView, true);
+    HIViewPlaceInSuperviewAt(imageView, 0, 0);
+
+    if (true) {
+        HILayoutInfo layout;
+        layout.version = kHILayoutInfoVersionZero;
+        set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft);
+        set_bindingside(&layout.binding.top, parent, kHILayoutBindTop);
+        set_bindingside(&layout.binding.right, parent, kHILayoutBindRight);
+        set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom);
+        set_axisscale(&layout.scale.x, parent);
+        set_axisscale(&layout.scale.y, parent);
+        set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft);
+        set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop);
+        HIViewSetLayoutInfo(imageView, &layout);
+    }
+
+    HIImageViewSetOpaque(imageView, true);
+    HIImageViewSetScaleToFit(imageView, false);
+
+	static const EventTypeSpec  gTypes[] = {
+		{ kEventClassKeyboard,  kEventRawKeyDown			},
+        { kEventClassKeyboard,  kEventRawKeyUp              },
+		{ kEventClassMouse,		kEventMouseDown				},
+		{ kEventClassMouse,		kEventMouseDragged			},
+		{ kEventClassMouse,		kEventMouseUp				},
+		{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent   },
+		{ kEventClassWindow,	kEventWindowBoundsChanged	},
+//		{ kEventClassWindow,	kEventWindowDrawContent		},
+		{ SK_MacEventClass,		SK_MacEventKind				}
+	};
+
+	EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler);
+	int				count = SK_ARRAY_COUNT(gTypes);
+
+	result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP,
+						count, gTypes, this, nil);
+	SkASSERT(result == noErr);
+    
+	gCurrOSWin = this;
+	gCurrEventQ = GetCurrentEventQueue();
+	gEventTarget = GetWindowEventTarget(wr);
+
+	static bool gOnce = true;
+	if (gOnce) {
+		gOnce = false;
+		gPrevNewHandler = set_new_handler(sk_new_handler);
+	}
+}
+
+void SkOSWindow::doPaint(void* ctx)
+{
+#if 0
+	this->update(NULL);
+
+    const SkBitmap& bm = this->getBitmap();
+    CGImageRef img = SkCreateCGImageRef(bm);
+
+    if (img) {
+        CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
+
+        CGContextRef cg = reinterpret_cast<CGContextRef>(ctx);
+
+        CGContextSaveGState(cg);
+        CGContextTranslateCTM(cg, 0, r.size.height);
+        CGContextScaleCTM(cg, 1, -1);
+
+        CGContextDrawImage(cg, r, img);
+        
+        CGContextRestoreGState(cg);
+
+        CGImageRelease(img);
+    }
+#endif
+}
+
+void SkOSWindow::updateSize()
+{
+	Rect	r;
+	
+	GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r);
+	this->resize(r.right - r.left, r.bottom - r.top);
+    
+#if 0
+    HIRect    frame;
+    HIViewRef imageView = (HIViewRef)getHVIEW();
+    HIViewRef parent = HIViewGetSuperview(imageView);
+  
+    HIViewGetBounds(imageView, &frame);
+    SkDebugf("------ %d bounds %g %g %g %g\n", r.right - r.left,
+             frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+#endif
+}
+
+void SkOSWindow::onHandleInval(const SkIRect& r)
+{
+    SkEvent* evt = new SkEvent("inval-imageview");
+    evt->post(this->getSinkID());
+}
+
+bool SkOSWindow::onEvent(const SkEvent& evt) {
+    if (evt.isType("inval-imageview")) {
+        this->update(NULL);
+
+        const SkBitmap& bm = this->getBitmap();
+        SkDebugf("------ bitmap %d %d\n", bm.width(), bm.height());
+
+        CGImageRef img = SkCreateCGImageRef(bm);
+        HIImageViewSetImage((HIViewRef)getHVIEW(), img);
+        CGImageRelease(img);
+        return true;
+    }
+    return INHERITED::onEvent(evt);
+}
+
+void SkOSWindow::onSetTitle(const char title[])
+{
+    CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
+    SetWindowTitleWithCFString((WindowRef)fHWND, str);
+    CFRelease(str);
+}
+
+void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
+{
+}
+
+static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data)
+{
+	EventParamType  actualType;
+	UInt32			actualSize;
+	OSStatus		status;
+
+	status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data);
+	SkASSERT(status == noErr);
+	SkASSERT(actualType == type);
+	SkASSERT(actualSize == size);
+}
+
+enum {
+	SK_MacReturnKey		= 36,
+	SK_MacDeleteKey		= 51,
+	SK_MacEndKey		= 119,
+	SK_MacLeftKey		= 123,
+	SK_MacRightKey		= 124,
+	SK_MacDownKey		= 125,
+	SK_MacUpKey			= 126,
+    
+    SK_Mac0Key          = 0x52,
+    SK_Mac1Key          = 0x53,
+    SK_Mac2Key          = 0x54,
+    SK_Mac3Key          = 0x55,
+    SK_Mac4Key          = 0x56,
+    SK_Mac5Key          = 0x57,
+    SK_Mac6Key          = 0x58,
+    SK_Mac7Key          = 0x59,
+    SK_Mac8Key          = 0x5b,
+    SK_Mac9Key          = 0x5c
+};
+	
+static SkKey raw2key(UInt32 raw)
+{
+	static const struct {
+		UInt32  fRaw;
+		SkKey   fKey;
+	} gKeys[] = {
+		{ SK_MacUpKey,		kUp_SkKey		},
+		{ SK_MacDownKey,	kDown_SkKey		},
+		{ SK_MacLeftKey,	kLeft_SkKey		},
+		{ SK_MacRightKey,   kRight_SkKey	},
+		{ SK_MacReturnKey,  kOK_SkKey		},
+		{ SK_MacDeleteKey,  kBack_SkKey		},
+		{ SK_MacEndKey,		kEnd_SkKey		},
+        { SK_Mac0Key,       k0_SkKey        },
+        { SK_Mac1Key,       k1_SkKey        },
+        { SK_Mac2Key,       k2_SkKey        },
+        { SK_Mac3Key,       k3_SkKey        },
+        { SK_Mac4Key,       k4_SkKey        },
+        { SK_Mac5Key,       k5_SkKey        },
+        { SK_Mac6Key,       k6_SkKey        },
+        { SK_Mac7Key,       k7_SkKey        },
+        { SK_Mac8Key,       k8_SkKey        },
+        { SK_Mac9Key,       k9_SkKey        }
+	};
+	
+	for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
+		if (gKeys[i].fRaw == raw)
+			return gKeys[i].fKey;
+	return kNONE_SkKey;
+}
+
+static void post_skmacevent()
+{
+	EventRef	ref;
+	OSStatus	status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref);
+	SkASSERT(status == noErr);
+	
+#if 0
+	status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
+	SkASSERT(status == noErr);
+	status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
+	SkASSERT(status == noErr);
+#endif
+	
+	EventTargetRef target = gEventTarget;
+	SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target);
+	SkASSERT(status == noErr);
+	
+	status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard);
+	SkASSERT(status == noErr);
+
+	ReleaseEvent(ref);
+}
+
+pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData )
+{
+	SkOSWindow* win = (SkOSWindow*)userData;
+	OSStatus	result = eventNotHandledErr;
+	UInt32		wClass = GetEventClass(inEvent);
+	UInt32		wKind = GetEventKind(inEvent);
+
+	gCurrOSWin = win;	// will need to be in TLS. Set this so PostEvent will work
+
+	switch (wClass) {
+        case kEventClassMouse: {
+			Point   pt;
+			getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt);
+			SetPortWindowPort((WindowRef)win->getHWND());
+			GlobalToLocal(&pt);
+
+			switch (wKind) {
+			case kEventMouseDown:
+				(void)win->handleClick(pt.h, pt.v, Click::kDown_State);
+				break;
+			case kEventMouseDragged:
+				(void)win->handleClick(pt.h, pt.v, Click::kMoved_State);
+				break;
+			case kEventMouseUp:
+				(void)win->handleClick(pt.h, pt.v, Click::kUp_State);
+				break;
+			default:
+				break;
+			}
+            break;
+		}
+        case kEventClassKeyboard:
+            if (wKind == kEventRawKeyDown) {
+                UInt32  raw;
+                getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
+                SkKey key = raw2key(raw);
+                if (key != kNONE_SkKey)
+                    (void)win->handleKey(key);
+            } else if (wKind == kEventRawKeyUp) {
+                UInt32 raw;
+                getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
+                SkKey key = raw2key(raw);
+                if (key != kNONE_SkKey)
+                    (void)win->handleKeyUp(key);
+            }
+            break;
+        case kEventClassTextInput:
+            if (wKind == kEventTextInputUnicodeForKeyEvent) {
+                UInt16  uni;
+                getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni);
+                win->handleChar(uni);
+            }
+            break;
+        case kEventClassWindow:
+            switch (wKind) {
+                case kEventWindowBoundsChanged:
+                    win->updateSize();
+                    break;
+                case kEventWindowDrawContent: {
+                    CGContextRef cg;
+                    result = GetEventParameter(inEvent,
+                                               kEventParamCGContextRef,
+                                               typeCGContextRef,
+                                               NULL,
+                                               sizeof (CGContextRef),
+                                               NULL,
+                                               &cg);
+                    if (result != 0) {
+                        cg = NULL;
+                    }
+                    win->doPaint(cg);
+                    break;
+                }
+                default:
+                    break;
+            }
+            break;
+        case SK_MacEventClass: {
+            SkASSERT(wKind == SK_MacEventKind);
+            if (SkEvent::ProcessEvent()) {
+                    post_skmacevent();
+            }
+    #if 0
+            SkEvent*		evt;
+            SkEventSinkID	sinkID;
+            getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
+            getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
+    #endif
+            result = noErr;
+            break;
+        }
+        default:
+            break;
+	}
+	if (result == eventNotHandledErr) {
+		result = CallNextEventHandler(inHandler, inEvent);
+    }
+	return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void SkEvent::SignalNonEmptyQueue()
+{
+	post_skmacevent();
+//	SkDebugf("signal nonempty\n");
+}
+
+static TMTask	gTMTaskRec;
+static TMTask*	gTMTaskPtr;
+
+static void sk_timer_proc(TMTask* rec)
+{
+	SkEvent::ServiceQueueTimer();
+//	SkDebugf("timer task fired\n");
+}
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+	if (gTMTaskPtr)
+	{
+		RemoveTimeTask((QElem*)gTMTaskPtr);
+		DisposeTimerUPP(gTMTaskPtr->tmAddr);
+		gTMTaskPtr = nil;
+	}
+	if (delay)
+	{
+		gTMTaskPtr = &gTMTaskRec;
+		memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));
+		gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);
+		OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);
+//		SkDebugf("installtimetask of %d returned %d\n", delay, err);
+		PrimeTimeTask((QElem*)gTMTaskPtr, delay);
+	}
+}
+
+#endif
+
diff --git a/src/utils/mac/skia_mac.cp b/src/utils/mac/skia_mac.cp
new file mode 100644
index 0000000..f6be570
--- /dev/null
+++ b/src/utils/mac/skia_mac.cp
@@ -0,0 +1,43 @@
+#include <Carbon/Carbon.h>
+#include "SkApplication.h"
+#include "SkWindow.h"
+
+int main(int argc, char* argv[])
+{
+    IBNibRef			nibRef;
+    WindowRef			window;
+    OSStatus			err = noErr;
+
+    // Create a Nib reference passing the name of the nib file (without the .nib extension)
+    // CreateNibReference only searches into the application bundle.
+    err = CreateNibReference(CFSTR("main"), &nibRef);
+    require_noerr( err, CantGetNibRef );
+    
+    // Then create a window. "MainWindow" is the name of the window object. This name is set in 
+    // InterfaceBuilder when the nib is created.
+    err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &window);
+    require_noerr( err, CantCreateWindow );
+    
+    // We don't need the nib reference anymore.
+    DisposeNibReference(nibRef);
+    
+    // if we get here, we can start our normal Skia sequence
+    {
+        application_init();
+        (void)create_sk_window(window);
+        SizeWindow(window, 640, 480, false);
+    }
+    
+    // The window was created hidden so show it.
+    ShowWindow( window );
+    
+    // Call the event loop
+    RunApplicationEventLoop();
+
+	application_term();
+
+CantCreateWindow:
+CantGetNibRef:
+	return err;
+}
+