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