grab from latest android



git-svn-id: http://skia.googlecode.com/svn/trunk@27 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
new file mode 100644
index 0000000..5ff8362
--- /dev/null
+++ b/samplecode/SampleApp.cpp
@@ -0,0 +1,563 @@
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkGLCanvas.h"
+#include "SkGraphics.h"
+#include "SkPaint.h"
+#include "SkPicture.h"
+#include "SkStream.h"
+#include "SkWindow.h"
+
+#include "SampleCode.h"
+
+#include <AGL/agl.h>
+#include <OpenGL/gl.h>
+
+#define ANIMATING_EVENTTYPE "nextSample"
+#define ANIMATING_DELAY     750
+
+#define USE_OFFSCREEN
+
+SkViewRegister* SkViewRegister::gHead;
+SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
+    static bool gOnce;
+    if (!gOnce) {
+        gHead = NULL;
+        gOnce = true;
+    }
+    
+    fChain = gHead;
+    gHead = this;
+}
+
+static AGLContext   gAGLContext;
+
+static void init_gl(WindowRef wref) {
+    GLint major, minor;
+    
+    aglGetVersion(&major, &minor);
+    SkDebugf("---- agl version %d %d\n", major, minor);
+    
+    const GLint pixelAttrs[] = {
+        AGL_RGBA,
+        AGL_DEPTH_SIZE, 32,
+        AGL_OFFSCREEN,
+        AGL_NONE
+    };
+    
+    AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
+    SkDebugf("----- agl format %p\n", format);
+    gAGLContext = aglCreateContext(format, NULL);
+    SkDebugf("----- agl context %p\n", gAGLContext);
+    aglDestroyPixelFormat(format);
+
+    aglEnable(gAGLContext, GL_BLEND);
+    aglEnable(gAGLContext, GL_LINE_SMOOTH);
+    aglEnable(gAGLContext, GL_POINT_SMOOTH);
+    aglEnable(gAGLContext, GL_POLYGON_SMOOTH);
+    
+    aglSetCurrentContext(gAGLContext);
+}
+
+static void setup_offscreen_gl(const SkBitmap& offscreen, WindowRef wref) {
+    GLboolean success = true;
+
+#ifdef USE_OFFSCREEN
+    success = aglSetOffScreen(gAGLContext,
+                                        offscreen.width(),
+                                        offscreen.height(),
+                                        offscreen.rowBytes(),
+                                        offscreen.getPixels());
+#else
+    success = aglSetWindowRef(gAGLContext, wref);
+#endif
+
+    GLenum err = aglGetError();
+    if (err) {
+        SkDebugf("---- setoffscreen %d %d %s [%d %d]\n", success, err,
+                 aglErrorString(err), offscreen.width(), offscreen.height());
+    }
+    
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
+    glEnable(GL_TEXTURE_2D);
+
+    glClearColor(0, 0, 0, 0);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static const char gTitleEvtName[] = "SampleCode_Title_Event";
+static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
+
+bool SampleCode::TitleQ(const SkEvent& evt) {
+    return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
+}
+
+void SampleCode::TitleR(SkEvent* evt, const char title[]) {
+    SkASSERT(evt && TitleQ(*evt));
+    evt->setString(gTitleEvtName, title);
+}
+
+bool SampleCode::PrefSizeQ(const SkEvent& evt) {
+    return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
+}
+
+void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
+    SkASSERT(evt && PrefSizeQ(*evt));
+    SkScalar size[2];
+    size[0] = width;
+    size[1] = height;
+    evt->setScalars(gPrefSizeEvtName, 2, size);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SampleWindow : public SkOSWindow {
+public:
+	SampleWindow(void* hwnd);
+	virtual ~SampleWindow();
+
+protected:
+    virtual void onDraw(SkCanvas* canvas);
+	virtual bool onHandleKey(SkKey key);
+    virtual bool onHandleChar(SkUnichar);
+    virtual void onSizeChange();
+    
+    virtual SkCanvas* beforeChildren(SkCanvas*);
+    virtual void afterChildren(SkCanvas*);
+
+	virtual bool onEvent(const SkEvent& evt);
+
+#if 0
+	virtual bool handleChar(SkUnichar uni);
+	virtual bool handleEvent(const SkEvent& evt);
+	virtual bool handleKey(SkKey key);
+	virtual bool handleKeyUp(SkKey key);
+    
+	virtual bool onClick(Click* click);
+	virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
+    virtual bool onHandleKeyUp(SkKey key);
+#endif
+private:
+    const SkViewRegister* fCurr;
+    
+    SkPicture* fPicture;
+    SkGLCanvas* fGLCanvas;
+    SkPath fClipPath;
+    
+    enum CanvasType {
+        kRaster_CanvasType,
+        kPicture_CanvasType,
+        kOpenGL_CanvasType
+    };
+    CanvasType fCanvasType;
+
+    bool fUseClip;
+    bool fRepeatDrawing;
+    bool fAnimating;
+    
+    int fScrollTestX, fScrollTestY;
+    
+    void loadView(SkView*);
+    void updateTitle();
+    bool nextSample();
+
+    void postAnimatingEvent() {
+        if (fAnimating) {
+            SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
+            evt->post(this->getSinkID(), ANIMATING_DELAY);
+        }
+    }
+    
+    
+    static CanvasType cycle_canvastype(CanvasType);
+
+    typedef SkOSWindow INHERITED;
+};
+
+SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
+    static const CanvasType gCT[] = {
+        kPicture_CanvasType,
+        kOpenGL_CanvasType,
+        kRaster_CanvasType
+    };
+    return gCT[ct];
+}
+
+SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
+    init_gl((WindowRef)hwnd);
+    
+    fPicture = NULL;
+    fGLCanvas = NULL;
+
+    fCanvasType = kRaster_CanvasType;
+    fUseClip = false;
+    fRepeatDrawing = false;
+    fAnimating = false;
+
+    fScrollTestX = fScrollTestY = 0;
+
+//	this->setConfig(SkBitmap::kRGB_565_Config);
+	this->setConfig(SkBitmap::kARGB_8888_Config);
+	this->setVisibleP(true);
+
+    fCurr = SkViewRegister::Head();
+    this->loadView(fCurr->factory()());
+}
+
+SampleWindow::~SampleWindow() {
+    delete fPicture;
+    delete fGLCanvas;
+}
+
+void SampleWindow::onDraw(SkCanvas* canvas) {
+    if (fRepeatDrawing) {
+        this->inval(NULL);
+    }
+}
+
+#include "SkColorPriv.h"
+
+static void reverseRedAndBlue(const SkBitmap& bm) {
+    SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
+    uint8_t* p = (uint8_t*)bm.getPixels();
+    uint8_t* stop = p + bm.getSize();
+    while (p < stop) {
+        // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
+        unsigned scale = SkAlpha255To256(p[3]);
+        unsigned r = p[2];
+        unsigned b = p[0];
+        p[0] = SkAlphaMul(r, scale);
+        p[1] = SkAlphaMul(p[1], scale);
+        p[2] = SkAlphaMul(b, scale);
+        p += 4;
+    }
+}
+
+SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
+#ifndef USE_OFFSCREEN
+    aglSetWindowRef(gAGLContext, NULL);
+#endif
+    switch (fCanvasType) {
+        case kRaster_CanvasType:
+            canvas = this->INHERITED::beforeChildren(canvas);
+            break;
+        case kPicture_CanvasType:
+            fPicture = new SkPicture;
+            canvas = fPicture->beginRecording(9999, 9999);
+            break;
+        case kOpenGL_CanvasType: {
+            //SkGLCanvas::DeleteAllTextures();  // just for testing
+            SkDevice* device = canvas->getDevice();
+            const SkBitmap& bitmap = device->accessBitmap(true);
+            // first clear the raster bitmap, so we don't see any leftover bits
+            bitmap.eraseColor(0);
+            // now setup our glcanvas
+            setup_offscreen_gl(bitmap, (WindowRef)this->getHWND());
+            fGLCanvas = new SkGLCanvas;
+            fGLCanvas->setViewport(bitmap.width(), bitmap.height());
+            canvas = fGLCanvas;
+            break;
+        }
+    }
+
+    if (fUseClip) {
+        canvas->drawColor(0xFFFF88FF);
+        canvas->clipPath(fClipPath);
+    }
+
+    return canvas;
+}
+
+static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
+                      const SkRegion& rgn) {
+    SkCanvas    canvas(bm);
+    SkRegion    inval(rgn);
+
+    inval.translate(r.fLeft, r.fTop);
+    canvas.clipRegion(inval);
+    canvas.drawColor(0xFFFF8080);
+}
+
+void SampleWindow::afterChildren(SkCanvas* orig) {
+    switch (fCanvasType) {
+        case kRaster_CanvasType:
+            break;
+        case kPicture_CanvasType:
+            if (false) {
+                SkPicture* pict = new SkPicture(*fPicture);
+                fPicture->unref();
+                orig->drawPicture(*pict);
+                pict->unref();
+            } if (true) {
+                SkDynamicMemoryWStream ostream;
+                fPicture->serialize(&ostream);
+                fPicture->unref();
+                
+                SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
+                SkPicture pict(&istream);
+                orig->drawPicture(pict);
+            } else {
+                fPicture->draw(orig);
+                fPicture->unref();
+            }
+            fPicture = NULL;
+            break;
+        case kOpenGL_CanvasType:
+            glFlush();
+            delete fGLCanvas;
+            fGLCanvas = NULL;
+#ifdef USE_OFFSCREEN
+            reverseRedAndBlue(orig->getDevice()->accessBitmap(true));
+#endif
+            break;
+    }
+    
+//    if ((fScrollTestX | fScrollTestY) != 0)
+    {
+        const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
+        int dx = fScrollTestX * 7;
+        int dy = fScrollTestY * 7;
+        SkIRect r;
+        SkRegion inval;
+        
+        r.set(50, 50, 50+100, 50+100);
+        bm.scrollRect(&r, dx, dy, &inval);
+        paint_rgn(bm, r, inval);
+    }
+}
+
+static SkBitmap::Config gConfigCycle[] = {
+    SkBitmap::kNo_Config,           // none -> none
+    SkBitmap::kNo_Config,           // a1 -> none
+    SkBitmap::kNo_Config,           // a8 -> none
+    SkBitmap::kNo_Config,           // index8 -> none
+    SkBitmap::kARGB_4444_Config,    // 565 -> 4444
+    SkBitmap::kARGB_8888_Config,    // 4444 -> 8888
+    SkBitmap::kRGB_565_Config       // 8888 -> 565
+};
+
+static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
+    return gConfigCycle[c];
+}
+
+bool SampleWindow::nextSample() {
+    if (fCurr) {
+        fCurr = fCurr->next();
+        if (NULL == fCurr) {
+            fCurr = SkViewRegister::Head();
+        }
+        this->loadView(fCurr->factory()());
+        return true;
+    }
+    return false;
+}
+
+bool SampleWindow::onEvent(const SkEvent& evt) {
+    if (evt.isType(ANIMATING_EVENTTYPE)) {
+        if (fAnimating) {
+            this->nextSample();
+            this->postAnimatingEvent();
+        }
+        return true;
+    }
+    return this->INHERITED::onEvent(evt);
+}
+
+
+bool SampleWindow::onHandleChar(SkUnichar uni) {
+    int dx = 0xFF;
+    int dy = 0xFF;
+
+    switch (uni) {
+        case '5': dx =  0; dy =  0; break;
+        case '8': dx =  0; dy = -1; break;
+        case '6': dx =  1; dy =  0; break;
+        case '2': dx =  0; dy =  1; break;
+        case '4': dx = -1; dy =  0; break;
+        case '7': dx = -1; dy = -1; break;
+        case '9': dx =  1; dy = -1; break;
+        case '3': dx =  1; dy =  1; break;
+        case '1': dx = -1; dy =  1; break;
+            
+        default:
+            break;
+    }
+    
+    if (0xFF != dx && 0xFF != dy) {
+        if ((dx | dy) == 0) {
+            fScrollTestX = fScrollTestY = 0;
+        } else {
+            fScrollTestX += dx;
+            fScrollTestY += dy;
+        }
+        this->inval(NULL);
+        return true;
+    }
+    
+    if ('a' == uni) {
+        fAnimating = !fAnimating;
+        this->postAnimatingEvent();
+        this->updateTitle();
+    }
+    
+    return this->INHERITED::onHandleChar(uni);
+}
+
+#include "SkDumpCanvas.h"
+
+bool SampleWindow::onHandleKey(SkKey key) {
+    switch (key) {
+        case kRight_SkKey:
+            if (this->nextSample()) {
+                return true;
+            }
+            break;
+        case kLeft_SkKey:
+            fCanvasType = cycle_canvastype(fCanvasType);
+            this->updateTitle();
+            this->inval(NULL);
+            return true;
+        case kUp_SkKey:
+            fUseClip = !fUseClip;
+            this->updateTitle();
+            this->inval(NULL);
+            return true;
+        case kDown_SkKey:
+            this->setConfig(cycle_configs(this->getBitmap().config()));
+            this->updateTitle();
+            return true;
+        case kOK_SkKey:
+            if (true) {
+                SkDebugfDumper dumper;
+                SkDumpCanvas dc(&dumper);
+                this->draw(&dc);
+            } else {
+                fRepeatDrawing = !fRepeatDrawing;
+                if (fRepeatDrawing) {
+                    this->inval(NULL);
+                }
+            }
+            return true;
+        default:
+            break;
+    }
+    return this->INHERITED::onHandleKey(key);
+}
+
+void SampleWindow::loadView(SkView* view) {
+    SkView::F2BIter iter(this);
+    SkView* prev = iter.next();
+    if (prev) {
+        prev->detachFromParent();
+    }
+    view->setVisibleP(true);
+    this->attachChildToFront(view)->unref();
+    view->setSize(this->width(), this->height());
+
+    this->updateTitle();
+}
+
+static const char* gConfigNames[] = {
+    "unknown config",
+    "A1",
+    "A8",
+    "Index8",
+    "565",
+    "4444",
+    "8888"
+};
+
+static const char* configToString(SkBitmap::Config c) {
+    return gConfigNames[c];
+}
+
+static const char* gCanvasTypePrefix[] = {
+    "raster: ",
+    "picture: ",
+    "opengl: "
+};
+
+void SampleWindow::updateTitle() {
+    SkString title;
+
+    SkView::F2BIter iter(this);
+    SkView* view = iter.next();
+    SkEvent evt(gTitleEvtName);
+    if (view->doQuery(&evt)) {
+        title.set(evt.findString(gTitleEvtName));
+    }
+    if (title.size() == 0) {
+        title.set("<unknown>");
+    }
+    
+    title.prepend(gCanvasTypePrefix[fCanvasType]);
+
+    title.prepend(" ");
+    title.prepend(configToString(this->getBitmap().config()));
+    
+    if (fAnimating) {
+        title.prepend("<A> ");
+    }
+
+    this->setTitle(title.c_str());
+}
+
+void SampleWindow::onSizeChange() {
+    this->INHERITED::onSizeChange();
+
+    SkView::F2BIter iter(this);
+    SkView* view = iter.next();
+    view->setSize(this->width(), this->height());
+    
+    // rebuild our clippath
+    {
+        const SkScalar W = this->width();
+        const SkScalar H = this->height();
+        
+        fClipPath.reset();
+#if 0
+        for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
+            SkRect r;
+            r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
+            for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
+                fClipPath.addRect(r);
+        }
+#else
+        SkRect r;
+        r.set(0, 0, W, H);
+        fClipPath.addRect(r, SkPath::kCCW_Direction);
+        r.set(W/4, H/4, W*3/4, H*3/4);
+        fClipPath.addRect(r, SkPath::kCW_Direction);
+#endif
+    }
+    
+    this->updateTitle();    // to refresh our config
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkOSWindow* create_sk_window(void* hwnd) {
+	return new SampleWindow(hwnd);
+}
+
+void get_preferred_size(int* x, int* y, int* width, int* height) {
+    *x = 10;
+    *y = 50;
+    *width = 640;
+    *height = 480;
+}
+
+void application_init() {
+//    setenv("ANDROID_ROOT", "../../../data", 0);
+    setenv("ANDROID_ROOT", "/android/device/data", 0);
+	SkGraphics::Init(true);
+	SkEvent::Init();
+}
+
+void application_term() {
+	SkEvent::Term();
+	SkGraphics::Term();
+}