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