SampleApp.cpp revision 0f185c2709f638c0f4d452cb38b434cadfd15ab9
1#include "SkCanvas.h"
2#include "SkDevice.h"
3#include "SkGpuCanvas.h"
4#include "SkGraphics.h"
5#include "SkImageEncoder.h"
6#include "SkPaint.h"
7#include "SkPicture.h"
8#include "SkStream.h"
9#include "SkTime.h"
10#include "SkWindow.h"
11
12#include "SampleCode.h"
13#include "GrContext.h"
14#include "SkTouchGesture.h"
15#include "SkTypeface.h"
16
17#define USE_ARROWS_FOR_ZOOM true
18//#define DEFAULT_TO_GPU
19
20extern SkView* create_overview(int, const SkViewFactory[]);
21
22#define SK_SUPPORT_GL
23
24#define ANIMATING_EVENTTYPE "nextSample"
25#define ANIMATING_DELAY     750
26
27#ifdef SK_SUPPORT_GL
28    #include "GrGLConfig.h"
29#endif
30
31SkViewRegister* SkViewRegister::gHead;
32SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
33    static bool gOnce;
34    if (!gOnce) {
35        gHead = NULL;
36        gOnce = true;
37    }
38
39    fChain = gHead;
40    gHead = this;
41}
42
43#if defined(SK_SUPPORT_GL)
44    #define SK_USE_SHADERS
45#endif
46
47#ifdef SK_BUILD_FOR_MAC
48#include <CoreFoundation/CoreFoundation.h>
49#include <CoreFoundation/CFURLAccess.h>
50
51static void testpdf() {
52    CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf",
53                                                 kCFStringEncodingUTF8);
54    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path,
55                                              kCFURLPOSIXPathStyle,
56                                              false);
57    CFRelease(path);
58    CGRect box = CGRectMake(0, 0, 8*72, 10*72);
59    CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL);
60    CFRelease(url);
61
62    CGContextBeginPage(cg, &box);
63    CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5);
64    CGContextFillEllipseInRect(cg, r);
65    CGContextEndPage(cg);
66    CGContextRelease(cg);
67
68    if (false) {
69        SkBitmap bm;
70        bm.setConfig(SkBitmap::kA8_Config, 64, 64);
71        bm.allocPixels();
72        bm.eraseColor(0);
73
74        SkCanvas canvas(bm);
75
76    }
77}
78#endif
79
80//////////////////////////////////////////////////////////////////////////////
81
82#include "SkDrawFilter.h"
83
84class LCDTextDrawFilter : public SkDrawFilter {
85public:
86    enum Mode {
87        kNeutral_Mode,
88        kForceOn_Mode,
89        kForceOff_Mode
90    };
91
92    LCDTextDrawFilter(Mode mode) : fMode(mode) {}
93
94    virtual bool filter(SkCanvas*, SkPaint* paint, Type t) {
95        if (kText_Type == t && kNeutral_Mode != fMode) {
96            fPrevLCD = paint->isLCDRenderText();
97            paint->setLCDRenderText(kForceOn_Mode == fMode);
98        }
99        return true;
100    }
101
102    /** If filter() returned true, then restore() will be called to restore the
103     canvas/paint to their previous states
104     */
105    virtual void restore(SkCanvas*, SkPaint* paint, Type t) {
106        if (kText_Type == t && kNeutral_Mode != fMode) {
107            paint->setLCDRenderText(fPrevLCD);
108        }
109    }
110
111private:
112    Mode    fMode;
113    bool    fPrevLCD;
114};
115
116LCDTextDrawFilter::Mode cycle_lcdmode(LCDTextDrawFilter::Mode mode) {
117    static const LCDTextDrawFilter::Mode gCycle[] = {
118        /* kNeutral_Mode  -> */  LCDTextDrawFilter::kForceOn_Mode,
119        /* kForceOn_Mode  -> */  LCDTextDrawFilter::kForceOff_Mode,
120        /* kForceOff_Mode -> */  LCDTextDrawFilter::kNeutral_Mode
121    };
122    return gCycle[mode];
123}
124
125//////////////////////////////////////////////////////////////////////////////
126
127#define MAX_ZOOM_LEVEL  8
128#define MIN_ZOOM_LEVEL  -8
129
130static const char gCharEvtName[] = "SampleCode_Char_Event";
131static const char gKeyEvtName[] = "SampleCode_Key_Event";
132static const char gTitleEvtName[] = "SampleCode_Title_Event";
133static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
134static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
135
136bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
137    if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
138        if (outUni) {
139            *outUni = evt.getFast32();
140        }
141        return true;
142    }
143    return false;
144}
145
146bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
147    if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
148        if (outKey) {
149            *outKey = (SkKey)evt.getFast32();
150        }
151        return true;
152    }
153    return false;
154}
155
156bool SampleCode::TitleQ(const SkEvent& evt) {
157    return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
158}
159
160void SampleCode::TitleR(SkEvent* evt, const char title[]) {
161    SkASSERT(evt && TitleQ(*evt));
162    evt->setString(gTitleEvtName, title);
163}
164
165bool SampleCode::PrefSizeQ(const SkEvent& evt) {
166    return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
167}
168
169void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
170    SkASSERT(evt && PrefSizeQ(*evt));
171    SkScalar size[2];
172    size[0] = width;
173    size[1] = height;
174    evt->setScalars(gPrefSizeEvtName, 2, size);
175}
176
177bool SampleCode::FastTextQ(const SkEvent& evt) {
178    return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
179}
180
181///////////////////////////////////////////////////////////////////////////////
182
183static SkMSec gAnimTime;
184static SkMSec gAnimTimePrev;
185
186SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
187SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
188SkScalar SampleCode::GetAnimSecondsDelta() {
189    return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
190}
191
192SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
193    // since gAnimTime can be up to 32 bits, we can't convert it to a float
194    // or we'll lose the low bits. Hence we use doubles for the intermediate
195    // calculations
196    double seconds = (double)gAnimTime / 1000.0;
197    double value = SkScalarToDouble(speed) * seconds;
198    if (period) {
199        value = ::fmod(value, SkScalarToDouble(period));
200    }
201    return SkDoubleToScalar(value);
202}
203
204//////////////////////////////////////////////////////////////////////////////
205
206static SkView* curr_view(SkWindow* wind) {
207    SkView::F2BIter iter(wind);
208    return iter.next();
209}
210
211class SampleWindow : public SkOSWindow {
212    SkTDArray<SkViewFactory> fSamples;
213public:
214    SampleWindow(void* hwnd);
215    virtual ~SampleWindow();
216
217    virtual void draw(SkCanvas* canvas);
218
219protected:
220    virtual void onDraw(SkCanvas* canvas);
221    virtual bool onHandleKey(SkKey key);
222    virtual bool onHandleChar(SkUnichar);
223    virtual void onSizeChange();
224
225    virtual SkCanvas* beforeChildren(SkCanvas*);
226    virtual void afterChildren(SkCanvas*);
227    virtual void beforeChild(SkView* child, SkCanvas* canvas);
228    virtual void afterChild(SkView* child, SkCanvas* canvas);
229
230    virtual bool onEvent(const SkEvent& evt);
231    virtual bool onQuery(SkEvent* evt);
232
233    virtual bool onDispatchClick(int x, int y, Click::State);
234    virtual bool onClick(Click* click);
235    virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
236
237#if 0
238    virtual bool handleChar(SkUnichar uni);
239    virtual bool handleEvent(const SkEvent& evt);
240    virtual bool handleKey(SkKey key);
241    virtual bool handleKeyUp(SkKey key);
242    virtual bool onHandleKeyUp(SkKey key);
243#endif
244
245private:
246    int fCurrIndex;
247
248    SkPicture* fPicture;
249    SkGpuCanvas* fGpuCanvas;
250    GrContext* fGrContext;
251    SkPath fClipPath;
252
253    SkTouchGesture fGesture;
254    int      fZoomLevel;
255    SkScalar fZoomScale;
256
257    enum CanvasType {
258        kRaster_CanvasType,
259        kPicture_CanvasType,
260        kGPU_CanvasType
261    };
262    CanvasType fCanvasType;
263
264    bool fUseClip;
265    bool fNClip;
266    bool fRepeatDrawing;
267    bool fAnimating;
268    bool fRotate;
269    bool fScale;
270    bool fRequestGrabImage;
271
272    // The following are for the 'fatbits' drawing
273    // Latest position of the mouse.
274    int fMouseX, fMouseY;
275    int fFatBitsScale;
276    // Used by the text showing position and color values.
277    SkTypeface* fTypeface;
278    bool fShowZoomer;
279
280    LCDTextDrawFilter::Mode fLCDMode;
281
282    int fScrollTestX, fScrollTestY;
283
284    bool make3DReady();
285    void changeZoomLevel(int delta);
286
287    void loadView(SkView*);
288    void updateTitle();
289    bool nextSample();
290
291    void toggleZoomer();
292    bool zoomIn();
293    bool zoomOut();
294    void updatePointer(int x, int y);
295
296    void postAnimatingEvent() {
297        if (fAnimating) {
298            SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
299            evt->post(this->getSinkID(), ANIMATING_DELAY);
300        }
301    }
302
303
304    static CanvasType cycle_canvastype(CanvasType);
305
306    typedef SkOSWindow INHERITED;
307};
308
309bool SampleWindow::zoomIn()
310{
311    // Arbitrarily decided
312    if (fFatBitsScale == 25) return false;
313    fFatBitsScale++;
314    this->inval(NULL);
315    return true;
316}
317
318bool SampleWindow::zoomOut()
319{
320    if (fFatBitsScale == 1) return false;
321    fFatBitsScale--;
322    this->inval(NULL);
323    return true;
324}
325
326void SampleWindow::toggleZoomer()
327{
328    fShowZoomer = !fShowZoomer;
329    this->inval(NULL);
330}
331
332void SampleWindow::updatePointer(int x, int y)
333{
334    fMouseX = x;
335    fMouseY = y;
336    if (fShowZoomer) {
337        this->inval(NULL);
338    }
339}
340
341bool SampleWindow::make3DReady() {
342
343#if defined(SK_SUPPORT_GL)
344    if (attachGL()) {
345        if (NULL == fGrContext) {
346        #if defined(SK_USE_SHADERS)
347            fGrContext = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
348        #else
349            fGrContext = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, NULL);
350        #endif
351        }
352
353        if (NULL != fGrContext) {
354            return true;
355        } else {
356            detachGL();
357        }
358    }
359#endif
360    SkDebugf("Failed to setup 3D");
361    return false;
362}
363
364SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
365    static const CanvasType gCT[] = {
366        kPicture_CanvasType,
367        kGPU_CanvasType,
368        kRaster_CanvasType
369    };
370    return gCT[ct];
371}
372
373SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
374    fPicture = NULL;
375    fGpuCanvas = NULL;
376
377    fGrContext = NULL;
378
379#ifdef DEFAULT_TO_GPU
380    fCanvasType = kGPU_CanvasType;
381#else
382    fCanvasType = kRaster_CanvasType;
383#endif
384    fUseClip = false;
385    fNClip = false;
386    fRepeatDrawing = false;
387    fAnimating = false;
388    fRotate = false;
389    fScale = false;
390    fRequestGrabImage = false;
391    fLCDMode = LCDTextDrawFilter::kNeutral_Mode;
392    fScrollTestX = fScrollTestY = 0;
393
394    fMouseX = fMouseY = 0;
395    fFatBitsScale = 1;
396    fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
397    fShowZoomer = false;
398
399    fZoomLevel = 0;
400    fZoomScale = SK_Scalar1;
401
402//    this->setConfig(SkBitmap::kRGB_565_Config);
403    this->setConfig(SkBitmap::kARGB_8888_Config);
404    this->setVisibleP(true);
405    this->setClipToBounds(false);
406
407    {
408        const SkViewRegister* reg = SkViewRegister::Head();
409        while (reg) {
410            *fSamples.append() = reg->factory();
411            reg = reg->next();
412        }
413    }
414    fCurrIndex = 0;
415    this->loadView(fSamples[fCurrIndex]());
416
417#ifdef SK_BUILD_FOR_MAC
418    testpdf();
419#endif
420}
421
422SampleWindow::~SampleWindow() {
423    delete fPicture;
424    delete fGpuCanvas;
425    if (NULL != fGrContext) {
426        fGrContext->unref();
427    }
428    fTypeface->unref();
429}
430
431static SkBitmap capture_bitmap(SkCanvas* canvas) {
432    SkBitmap bm;
433    const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
434    src.copyTo(&bm, src.config());
435    return bm;
436}
437
438static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
439                        SkBitmap* diff) {
440    const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
441
442    SkAutoLockPixels alp0(src);
443    SkAutoLockPixels alp1(orig);
444    for (int y = 0; y < src.height(); y++) {
445        const void* srcP = src.getAddr(0, y);
446        const void* origP = orig.getAddr(0, y);
447        size_t bytes = src.width() * src.bytesPerPixel();
448        if (memcmp(srcP, origP, bytes)) {
449            SkDebugf("---------- difference on line %d\n", y);
450            return true;
451        }
452    }
453    return false;
454}
455
456static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
457{
458    SkColor desiredColor = paint.getColor();
459    paint.setColor(SK_ColorWHITE);
460    const char* c_str = string.c_str();
461    size_t size = string.size();
462    SkRect bounds;
463    paint.measureText(c_str, size, &bounds);
464    bounds.offset(left, top);
465    SkScalar inset = SkIntToScalar(-2);
466    bounds.inset(inset, inset);
467    canvas->drawRect(bounds, paint);
468    if (desiredColor != SK_ColorBLACK) {
469        paint.setColor(SK_ColorBLACK);
470        canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
471    }
472    paint.setColor(desiredColor);
473    canvas->drawText(c_str, size, left, top, paint);
474}
475
476#define XCLIP_N  8
477#define YCLIP_N  8
478
479void SampleWindow::draw(SkCanvas* canvas) {
480    // update the animation time
481    gAnimTimePrev = gAnimTime;
482    gAnimTime = SkTime::GetMSecs();
483
484    if (fZoomLevel) {
485        SkMatrix m;
486        SkScalar cx = SkScalarHalf(this->width());
487        SkScalar cy = SkScalarHalf(this->height());
488        SkPoint center;
489        m = canvas->getTotalMatrix();//.invert(&m);
490        m.mapXY(cx, cy, &center);
491        cx = center.fX;
492        cy = center.fY;
493
494        m.setTranslate(-cx, -cy);
495        m.postScale(fZoomScale, fZoomScale);
496        m.postTranslate(cx, cy);
497
498        canvas->concat(m);
499    }
500
501    // Apply any gesture matrix
502    if (true) {
503        const SkMatrix& localM = fGesture.localM();
504        if (localM.getType() & SkMatrix::kScale_Mask) {
505            canvas->setExternalMatrix(&localM);
506        }
507        canvas->concat(localM);
508        canvas->concat(fGesture.globalM());
509
510        if (fGesture.isActive()) {
511            this->inval(NULL);
512        }
513    }
514
515    if (fNClip) {
516        this->INHERITED::draw(canvas);
517        SkBitmap orig = capture_bitmap(canvas);
518
519        const SkScalar w = this->width();
520        const SkScalar h = this->height();
521        const SkScalar cw = w / XCLIP_N;
522        const SkScalar ch = h / YCLIP_N;
523        for (int y = 0; y < YCLIP_N; y++) {
524            SkRect r;
525            r.fTop = y * ch;
526            r.fBottom = (y + 1) * ch;
527            if (y == YCLIP_N - 1) {
528                r.fBottom = h;
529            }
530            for (int x = 0; x < XCLIP_N; x++) {
531                SkAutoCanvasRestore acr(canvas, true);
532                r.fLeft = x * cw;
533                r.fRight = (x + 1) * cw;
534                if (x == XCLIP_N - 1) {
535                    r.fRight = w;
536                }
537                canvas->clipRect(r);
538                this->INHERITED::draw(canvas);
539            }
540        }
541
542        SkBitmap diff;
543        if (bitmap_diff(canvas, orig, &diff)) {
544        }
545    } else {
546        this->INHERITED::draw(canvas);
547    }
548    if (fShowZoomer) {
549        int count = canvas->save();
550        canvas->resetMatrix();
551        // Ensure the mouse position is on screen.
552        int width = this->width();
553        int height = this->height();
554        if (fMouseX >= width) fMouseX = width - 1;
555        else if (fMouseX < 0) fMouseX = 0;
556        if (fMouseY >= height) fMouseY = height - 1;
557        else if (fMouseY < 0) fMouseY = 0;
558        SkBitmap bitmap = capture_bitmap(canvas);
559        // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
560        int zoomedWidth = (width >> 2) | 1;
561        int zoomedHeight = (height >> 2) | 1;
562        SkIRect src;
563        src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
564        src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
565        SkRect dest;
566        dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
567        dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
568        SkPaint paint;
569        // Clear the background behind our zoomed in view
570        paint.setColor(SK_ColorWHITE);
571        canvas->drawRect(dest, paint);
572        canvas->drawBitmapRect(bitmap, &src, dest);
573        paint.setColor(SK_ColorBLACK);
574        paint.setStyle(SkPaint::kStroke_Style);
575        // Draw a border around the pixel in the middle
576        SkRect originalPixel;
577        originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
578        SkMatrix matrix;
579        SkRect scalarSrc;
580        scalarSrc.set(src);
581        SkColor color = bitmap.getColor(fMouseX, fMouseY);
582        if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
583            SkRect pixel;
584            matrix.mapRect(&pixel, originalPixel);
585            // TODO Perhaps measure the values and make the outline white if it's "dark"
586            if (color == SK_ColorBLACK) {
587                paint.setColor(SK_ColorWHITE);
588            }
589            canvas->drawRect(pixel, paint);
590        }
591        paint.setColor(SK_ColorBLACK);
592        // Draw a border around the destination rectangle
593        canvas->drawRect(dest, paint);
594        paint.setStyle(SkPaint::kStrokeAndFill_Style);
595        // Identify the pixel and its color on screen
596        paint.setTypeface(fTypeface);
597        paint.setAntiAlias(true);
598        SkScalar lineHeight = paint.getFontMetrics(NULL);
599        SkString string;
600        string.appendf("(%i, %i)", fMouseX, fMouseY);
601        SkScalar left = dest.fLeft + SkIntToScalar(3);
602        SkScalar i = SK_Scalar1;
603        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
604        // Alpha
605        i += SK_Scalar1;
606        string.reset();
607        string.appendf("A: %X", SkColorGetA(color));
608        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
609        // Red
610        i += SK_Scalar1;
611        string.reset();
612        string.appendf("R: %X", SkColorGetR(color));
613        paint.setColor(SK_ColorRED);
614        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
615        // Green
616        i += SK_Scalar1;
617        string.reset();
618        string.appendf("G: %X", SkColorGetG(color));
619        paint.setColor(SK_ColorGREEN);
620        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
621        // Blue
622        i += SK_Scalar1;
623        string.reset();
624        string.appendf("B: %X", SkColorGetB(color));
625        paint.setColor(SK_ColorBLUE);
626        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
627        canvas->restoreToCount(count);
628    }
629}
630
631void SampleWindow::onDraw(SkCanvas* canvas) {
632    if (fRepeatDrawing) {
633        this->inval(NULL);
634    }
635}
636
637#include "SkColorPriv.h"
638
639static void reverseRedAndBlue(const SkBitmap& bm) {
640    SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
641    uint8_t* p = (uint8_t*)bm.getPixels();
642    uint8_t* stop = p + bm.getSize();
643    while (p < stop) {
644        // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
645        unsigned scale = SkAlpha255To256(p[3]);
646        unsigned r = p[2];
647        unsigned b = p[0];
648        p[0] = SkAlphaMul(r, scale);
649        p[1] = SkAlphaMul(p[1], scale);
650        p[2] = SkAlphaMul(b, scale);
651        p += 4;
652    }
653}
654
655SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
656    SkIPoint viewport;
657    bool alreadyGPU = canvas->getViewport(&viewport);
658
659    if (kGPU_CanvasType != fCanvasType) {
660#ifdef SK_SUPPORT_GL
661        detachGL();
662#endif
663    }
664
665    switch (fCanvasType) {
666        case kRaster_CanvasType:
667            canvas = this->INHERITED::beforeChildren(canvas);
668            break;
669        case kPicture_CanvasType:
670            fPicture = new SkPicture;
671            canvas = fPicture->beginRecording(9999, 9999);
672            break;
673        case kGPU_CanvasType: {
674            if (!alreadyGPU && make3DReady()) {
675                SkDevice* device = canvas->getDevice();
676                const SkBitmap& bitmap = device->accessBitmap(true);
677
678                GrRenderTarget* renderTarget;
679                renderTarget = fGrContext->createRenderTargetFrom3DApiState();
680                fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
681                renderTarget->unref();
682
683                device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
684                                                  bitmap.width(), bitmap.height(),
685                                                  false, false);
686                fGpuCanvas->setDevice(device)->unref();
687
688                fGpuCanvas->concat(canvas->getTotalMatrix());
689                canvas = fGpuCanvas;
690
691            } else {
692                canvas = this->INHERITED::beforeChildren(canvas);
693            }
694            break;
695        }
696    }
697
698    if (fUseClip) {
699        canvas->drawColor(0xFFFF88FF);
700        canvas->clipPath(fClipPath);
701    }
702
703    return canvas;
704}
705
706static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
707                      const SkRegion& rgn) {
708    SkCanvas    canvas(bm);
709    SkRegion    inval(rgn);
710
711    inval.translate(r.fLeft, r.fTop);
712    canvas.clipRegion(inval);
713    canvas.drawColor(0xFFFF8080);
714}
715
716void SampleWindow::afterChildren(SkCanvas* orig) {
717    if (fRequestGrabImage) {
718        fRequestGrabImage = false;
719
720        SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
721        SkDevice* device = canvas->getDevice();
722        SkBitmap bitmap;
723        SkIRect bounds = {
724            0, 0,
725            SkScalarRound(this->width()),
726            SkScalarRound(this->height())
727        };
728        if (device->readPixels(bounds, &bitmap)) {
729            static int gSampleGrabCounter;
730            SkString name;
731            name.printf("sample_grab_%d", gSampleGrabCounter++);
732            SkImageEncoder::EncodeFile(name.c_str(), bitmap,
733                                       SkImageEncoder::kPNG_Type, 100);
734        }
735    }
736
737    switch (fCanvasType) {
738        case kRaster_CanvasType:
739            break;
740        case kPicture_CanvasType:
741            if (true) {
742                SkPicture* pict = new SkPicture(*fPicture);
743                fPicture->unref();
744                orig->drawPicture(*pict);
745                pict->unref();
746            } else if (true) {
747                SkDynamicMemoryWStream ostream;
748                fPicture->serialize(&ostream);
749                fPicture->unref();
750
751                SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
752                SkPicture pict(&istream);
753                orig->drawPicture(pict);
754            } else {
755                fPicture->draw(orig);
756                fPicture->unref();
757            }
758            fPicture = NULL;
759            break;
760#ifdef SK_SUPPORT_GL
761        case kGPU_CanvasType:
762            delete fGpuCanvas;
763            fGpuCanvas = NULL;
764            presentGL();
765            break;
766#endif
767    }
768
769//    if ((fScrollTestX | fScrollTestY) != 0)
770    if (false) {
771        const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
772        int dx = fScrollTestX * 7;
773        int dy = fScrollTestY * 7;
774        SkIRect r;
775        SkRegion inval;
776
777        r.set(50, 50, 50+100, 50+100);
778        bm.scrollRect(&r, dx, dy, &inval);
779        paint_rgn(bm, r, inval);
780    }
781}
782
783void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
784    if (fScale) {
785        SkScalar scale = SK_Scalar1 * 7 / 10;
786        SkScalar cx = this->width() / 2;
787        SkScalar cy = this->height() / 2;
788        canvas->translate(cx, cy);
789        canvas->scale(scale, scale);
790        canvas->translate(-cx, -cy);
791    }
792    if (fRotate) {
793        SkScalar cx = this->width() / 2;
794        SkScalar cy = this->height() / 2;
795        canvas->translate(cx, cy);
796        canvas->rotate(SkIntToScalar(30));
797        canvas->translate(-cx, -cy);
798    }
799
800    if (LCDTextDrawFilter::kNeutral_Mode != fLCDMode) {
801        canvas->setDrawFilter(new LCDTextDrawFilter(fLCDMode))->unref();
802    }
803}
804
805void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
806    canvas->setDrawFilter(NULL);
807}
808
809static SkBitmap::Config gConfigCycle[] = {
810    SkBitmap::kNo_Config,           // none -> none
811    SkBitmap::kNo_Config,           // a1 -> none
812    SkBitmap::kNo_Config,           // a8 -> none
813    SkBitmap::kNo_Config,           // index8 -> none
814    SkBitmap::kARGB_4444_Config,    // 565 -> 4444
815    SkBitmap::kARGB_8888_Config,    // 4444 -> 8888
816    SkBitmap::kRGB_565_Config       // 8888 -> 565
817};
818
819static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
820    return gConfigCycle[c];
821}
822
823void SampleWindow::changeZoomLevel(int delta) {
824    fZoomLevel += delta;
825    if (fZoomLevel > 0) {
826        fZoomLevel = SkMin32(fZoomLevel, MAX_ZOOM_LEVEL);
827        fZoomScale = SkIntToScalar(fZoomLevel + 1);
828    } else if (fZoomLevel < 0) {
829        fZoomLevel = SkMax32(fZoomLevel, MIN_ZOOM_LEVEL);
830        fZoomScale = SK_Scalar1 / (1 - fZoomLevel);
831    } else {
832        fZoomScale = SK_Scalar1;
833    }
834
835    this->inval(NULL);
836}
837
838bool SampleWindow::nextSample() {
839    fCurrIndex = (fCurrIndex + 1) % fSamples.count();
840    this->loadView(fSamples[fCurrIndex]());
841    return true;
842}
843
844bool SampleWindow::onEvent(const SkEvent& evt) {
845    if (evt.isType(ANIMATING_EVENTTYPE)) {
846        if (fAnimating) {
847            this->nextSample();
848            this->postAnimatingEvent();
849        }
850        return true;
851    }
852    if (evt.isType("set-curr-index")) {
853        fCurrIndex = evt.getFast32() % fSamples.count();
854        this->loadView(fSamples[fCurrIndex]());
855        return true;
856    }
857    return this->INHERITED::onEvent(evt);
858}
859
860bool SampleWindow::onQuery(SkEvent* query) {
861    if (query->isType("get-slide-count")) {
862        query->setFast32(fSamples.count());
863        return true;
864    }
865    if (query->isType("get-slide-title")) {
866        SkView* view = fSamples[query->getFast32()]();
867        SkEvent evt(gTitleEvtName);
868        if (view->doQuery(&evt)) {
869            query->setString("title", evt.findString(gTitleEvtName));
870        }
871        SkSafeUnref(view);
872        return true;
873    }
874    if (query->isType("use-fast-text")) {
875        SkEvent evt(gFastTextEvtName);
876        return curr_view(this)->doQuery(&evt);
877    }
878    return this->INHERITED::onQuery(query);
879}
880
881static void cleanup_for_filename(SkString* name) {
882    char* str = name->writable_str();
883    for (size_t i = 0; i < name->size(); i++) {
884        switch (str[i]) {
885            case ':': str[i] = '-'; break;
886            case '/': str[i] = '-'; break;
887            case ' ': str[i] = '_'; break;
888            default: break;
889        }
890    }
891}
892
893bool SampleWindow::onHandleChar(SkUnichar uni) {
894    {
895        SkView* view = curr_view(this);
896        if (view) {
897            SkEvent evt(gCharEvtName);
898            evt.setFast32(uni);
899            if (view->doQuery(&evt)) {
900                return true;
901            }
902        }
903    }
904
905    int dx = 0xFF;
906    int dy = 0xFF;
907
908    switch (uni) {
909        case '5': dx =  0; dy =  0; break;
910        case '8': dx =  0; dy = -1; break;
911        case '6': dx =  1; dy =  0; break;
912        case '2': dx =  0; dy =  1; break;
913        case '4': dx = -1; dy =  0; break;
914        case '7': dx = -1; dy = -1; break;
915        case '9': dx =  1; dy = -1; break;
916        case '3': dx =  1; dy =  1; break;
917        case '1': dx = -1; dy =  1; break;
918
919        default:
920            break;
921    }
922
923    if (0xFF != dx && 0xFF != dy) {
924        if ((dx | dy) == 0) {
925            fScrollTestX = fScrollTestY = 0;
926        } else {
927            fScrollTestX += dx;
928            fScrollTestY += dy;
929        }
930        this->inval(NULL);
931        return true;
932    }
933
934    switch (uni) {
935        case 'a':
936            fAnimating = !fAnimating;
937            this->postAnimatingEvent();
938            this->updateTitle();
939            return true;
940        case 'f': {
941            const char* title = this->getTitle();
942            if (title[0] == 0) {
943                title = "sampleapp";
944            }
945            SkString name(title);
946            cleanup_for_filename(&name);
947            name.append(".png");
948            if (SkImageEncoder::EncodeFile(name.c_str(), this->getBitmap(),
949                                           SkImageEncoder::kPNG_Type, 100)) {
950                SkDebugf("Created %s\n", name.c_str());
951            }
952            return true;
953        }
954        case 'r':
955            fRotate = !fRotate;
956            this->inval(NULL);
957            this->updateTitle();
958            return true;
959        case 's':
960            fScale = !fScale;
961            this->inval(NULL);
962            this->updateTitle();
963            return true;
964        case 'c':
965            fUseClip = !fUseClip;
966            this->inval(NULL);
967            this->updateTitle();
968            return true;
969        case 'd':
970            SkGraphics::SetFontCacheUsed(0);
971            return true;
972        case 'g':
973            fRequestGrabImage = true;
974            this->inval(NULL);
975            break;
976        case 'l':
977            fLCDMode = cycle_lcdmode(fLCDMode);
978            this->updateTitle();
979            this->inval(NULL);
980            break;
981        case 'i':
982            this->zoomIn();
983            break;
984        case 'o':
985            this->zoomOut();
986            break;
987        case 'z':
988            this->toggleZoomer();
989            break;
990        default:
991            break;
992    }
993
994    return this->INHERITED::onHandleChar(uni);
995}
996
997#include "SkDumpCanvas.h"
998
999bool SampleWindow::onHandleKey(SkKey key) {
1000    {
1001        SkView* view = curr_view(this);
1002        if (view) {
1003            SkEvent evt(gKeyEvtName);
1004            evt.setFast32(key);
1005            if (view->doQuery(&evt)) {
1006                return true;
1007            }
1008        }
1009    }
1010
1011    switch (key) {
1012        case kRight_SkKey:
1013            if (this->nextSample()) {
1014                return true;
1015            }
1016            break;
1017        case kLeft_SkKey:
1018            fCanvasType = cycle_canvastype(fCanvasType);
1019            this->updateTitle();
1020            this->inval(NULL);
1021            return true;
1022        case kUp_SkKey:
1023            if (USE_ARROWS_FOR_ZOOM) {
1024                this->changeZoomLevel(1);
1025            } else {
1026                fNClip = !fNClip;
1027                this->inval(NULL);
1028            }
1029            this->updateTitle();
1030            return true;
1031        case kDown_SkKey:
1032            if (USE_ARROWS_FOR_ZOOM) {
1033                this->changeZoomLevel(-1);
1034            } else {
1035                this->setConfig(cycle_configs(this->getBitmap().config()));
1036            }
1037            this->updateTitle();
1038            return true;
1039        case kOK_SkKey:
1040            if (false) {
1041                SkDebugfDumper dumper;
1042                SkDumpCanvas dc(&dumper);
1043                this->draw(&dc);
1044            } else {
1045                fRepeatDrawing = !fRepeatDrawing;
1046                if (fRepeatDrawing) {
1047                    this->inval(NULL);
1048                }
1049            }
1050            return true;
1051        case kBack_SkKey:
1052            this->loadView(NULL);
1053            return true;
1054        default:
1055            break;
1056    }
1057    return this->INHERITED::onHandleKey(key);
1058}
1059
1060///////////////////////////////////////////////////////////////////////////////
1061
1062static const char gGestureClickType[] = "GestureClickType";
1063
1064bool SampleWindow::onDispatchClick(int x, int y, Click::State state) {
1065    if (Click::kMoved_State == state) {
1066        updatePointer(x, y);
1067    }
1068    int w = SkScalarRound(this->width());
1069    int h = SkScalarRound(this->height());
1070
1071    // check for the resize-box
1072    if (w - x < 16 && h - y < 16) {
1073        return false;   // let the OS handle the click
1074    } else {
1075        return this->INHERITED::onDispatchClick(x, y, state);
1076    }
1077}
1078
1079class GestureClick : public SkView::Click {
1080public:
1081    GestureClick(SkView* target) : SkView::Click(target) {
1082        this->setType(gGestureClickType);
1083    }
1084
1085    static bool IsGesture(Click* click) {
1086        return click->isType(gGestureClickType);
1087    }
1088};
1089
1090SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
1091    return new GestureClick(this);
1092}
1093
1094bool SampleWindow::onClick(Click* click) {
1095    if (GestureClick::IsGesture(click)) {
1096        float x = SkScalarToFloat(click->fCurr.fX);
1097        float y = SkScalarToFloat(click->fCurr.fY);
1098        switch (click->fState) {
1099            case SkView::Click::kDown_State:
1100                fGesture.touchBegin(click, x, y);
1101                break;
1102            case SkView::Click::kMoved_State:
1103                fGesture.touchMoved(click, x, y);
1104                this->inval(NULL);
1105                break;
1106            case SkView::Click::kUp_State:
1107                fGesture.touchEnd(click);
1108                this->inval(NULL);
1109                break;
1110        }
1111        return true;
1112    }
1113    return false;
1114}
1115
1116///////////////////////////////////////////////////////////////////////////////
1117
1118void SampleWindow::loadView(SkView* view) {
1119    SkView::F2BIter iter(this);
1120    SkView* prev = iter.next();
1121    if (prev) {
1122        prev->detachFromParent();
1123    }
1124
1125    if (NULL == view) {
1126        view = create_overview(fSamples.count(), fSamples.begin());
1127    }
1128    view->setVisibleP(true);
1129    view->setClipToBounds(false);
1130    this->attachChildToFront(view)->unref();
1131    view->setSize(this->width(), this->height());
1132
1133    this->updateTitle();
1134}
1135
1136static const char* gConfigNames[] = {
1137    "unknown config",
1138    "A1",
1139    "A8",
1140    "Index8",
1141    "565",
1142    "4444",
1143    "8888"
1144};
1145
1146static const char* configToString(SkBitmap::Config c) {
1147    return gConfigNames[c];
1148}
1149
1150static const char* gCanvasTypePrefix[] = {
1151    "raster: ",
1152    "picture: ",
1153    "opengl: "
1154};
1155
1156void SampleWindow::updateTitle() {
1157    SkString title;
1158
1159    SkView::F2BIter iter(this);
1160    SkView* view = iter.next();
1161    SkEvent evt(gTitleEvtName);
1162    if (view->doQuery(&evt)) {
1163        title.set(evt.findString(gTitleEvtName));
1164    }
1165    if (title.size() == 0) {
1166        title.set("<unknown>");
1167    }
1168
1169    title.prepend(gCanvasTypePrefix[fCanvasType]);
1170
1171    title.prepend(" ");
1172    title.prepend(configToString(this->getBitmap().config()));
1173
1174    if (fAnimating) {
1175        title.prepend("<A> ");
1176    }
1177    if (fScale) {
1178        title.prepend("<S> ");
1179    }
1180    if (fRotate) {
1181        title.prepend("<R> ");
1182    }
1183    if (fNClip) {
1184        title.prepend("<C> ");
1185    }
1186    if (LCDTextDrawFilter::kForceOn_Mode == fLCDMode) {
1187        title.prepend("LCD ");
1188    } else if (LCDTextDrawFilter::kForceOff_Mode == fLCDMode) {
1189        title.prepend("lcd ");
1190    }
1191
1192    if (fZoomLevel) {
1193        title.prependf("{%d} ", fZoomLevel);
1194    }
1195    this->setTitle(title.c_str());
1196}
1197
1198void SampleWindow::onSizeChange() {
1199    this->INHERITED::onSizeChange();
1200
1201    SkView::F2BIter iter(this);
1202    SkView* view = iter.next();
1203    view->setSize(this->width(), this->height());
1204
1205    // rebuild our clippath
1206    {
1207        const SkScalar W = this->width();
1208        const SkScalar H = this->height();
1209
1210        fClipPath.reset();
1211#if 0
1212        for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
1213            SkRect r;
1214            r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
1215            for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
1216                fClipPath.addRect(r);
1217        }
1218#else
1219        SkRect r;
1220        r.set(0, 0, W, H);
1221        fClipPath.addRect(r, SkPath::kCCW_Direction);
1222        r.set(W/4, H/4, W*3/4, H*3/4);
1223        fClipPath.addRect(r, SkPath::kCW_Direction);
1224#endif
1225    }
1226
1227    this->updateTitle();    // to refresh our config
1228}
1229
1230///////////////////////////////////////////////////////////////////////////////
1231
1232template <typename T> void SkTBSort(T array[], int count) {
1233    for (int i = 1; i < count - 1; i++) {
1234        bool didSwap = false;
1235        for (int j = count - 1; j > i; --j) {
1236            if (array[j] < array[j-1]) {
1237                T tmp(array[j-1]);
1238                array[j-1] = array[j];
1239                array[j] = tmp;
1240                didSwap = true;
1241            }
1242        }
1243        if (!didSwap) {
1244            break;
1245        }
1246    }
1247
1248    for (int k = 0; k < count - 1; k++) {
1249        SkASSERT(!(array[k+1] < array[k]));
1250    }
1251}
1252
1253#include "SkRandom.h"
1254
1255static void rand_rect(SkIRect* rect, SkRandom& rand) {
1256    int bits = 8;
1257    int shift = 32 - bits;
1258    rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
1259              rand.nextU() >> shift, rand.nextU() >> shift);
1260    rect->sort();
1261}
1262
1263static void dumpRect(const SkIRect& r) {
1264    SkDebugf(" { %d, %d, %d, %d },\n",
1265             r.fLeft, r.fTop,
1266             r.fRight, r.fBottom);
1267}
1268
1269static void test_rects(const SkIRect rect[], int count) {
1270    SkRegion rgn0, rgn1;
1271
1272    for (int i = 0; i < count; i++) {
1273        rgn0.op(rect[i], SkRegion::kUnion_Op);
1274     //   dumpRect(rect[i]);
1275    }
1276    rgn1.setRects(rect, count);
1277
1278    if (rgn0 != rgn1) {
1279        SkDebugf("\n");
1280        for (int i = 0; i < count; i++) {
1281            dumpRect(rect[i]);
1282        }
1283        SkDebugf("\n");
1284    }
1285}
1286
1287static void test() {
1288    size_t i;
1289
1290    const SkIRect r0[] = {
1291        { 0, 0, 1, 1 },
1292        { 2, 2, 3, 3 },
1293    };
1294    const SkIRect r1[] = {
1295        { 0, 0, 1, 3 },
1296        { 1, 1, 2, 2 },
1297        { 2, 0, 3, 3 },
1298    };
1299    const SkIRect r2[] = {
1300        { 0, 0, 1, 2 },
1301        { 2, 1, 3, 3 },
1302        { 4, 0, 5, 1 },
1303        { 6, 0, 7, 4 },
1304    };
1305
1306    static const struct {
1307        const SkIRect* fRects;
1308        int            fCount;
1309    } gRecs[] = {
1310        { r0, SK_ARRAY_COUNT(r0) },
1311        { r1, SK_ARRAY_COUNT(r1) },
1312        { r2, SK_ARRAY_COUNT(r2) },
1313    };
1314
1315    for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
1316        test_rects(gRecs[i].fRects, gRecs[i].fCount);
1317    }
1318
1319    SkRandom rand;
1320    for (i = 0; i < 10000; i++) {
1321        SkRegion rgn0, rgn1;
1322
1323        const int N = 8;
1324        SkIRect rect[N];
1325        for (int j = 0; j < N; j++) {
1326            rand_rect(&rect[j], rand);
1327        }
1328        test_rects(rect, N);
1329    }
1330}
1331
1332SkOSWindow* create_sk_window(void* hwnd) {
1333//    test();
1334    return new SampleWindow(hwnd);
1335}
1336
1337void get_preferred_size(int* x, int* y, int* width, int* height) {
1338    *x = 10;
1339    *y = 50;
1340    *width = 640;
1341    *height = 480;
1342}
1343
1344void application_init() {
1345//    setenv("ANDROID_ROOT", "../../../data", 0);
1346#ifdef SK_BUILD_FOR_MAC
1347    setenv("ANDROID_ROOT", "/android/device/data", 0);
1348#endif
1349    SkGraphics::Init();
1350    SkEvent::Init();
1351}
1352
1353void application_term() {
1354    SkEvent::Term();
1355    SkGraphics::Term();
1356}
1357