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