SampleApp.cpp revision 820e80ad6390e120d4991a5280d0452ec87beaeb
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SampleApp.h"
9
10#include "SkData.h"
11#include "SkCanvas.h"
12#include "SkDevice.h"
13#include "SkGpuDevice.h"
14#include "SkGraphics.h"
15#include "SkImageEncoder.h"
16#include "SkPaint.h"
17#include "SkPicture.h"
18#include "SkStream.h"
19#include "SkTime.h"
20#include "SkWindow.h"
21
22#include "SampleCode.h"
23#include "GrContext.h"
24#include "SkTypeface.h"
25
26#include "GrGLInterface.h"
27#include "GrRenderTarget.h"
28
29#include "SkPDFDevice.h"
30#include "SkPDFDocument.h"
31#include "SkStream.h"
32
33#define TEST_GPIPE
34
35#ifdef  TEST_GPIPE
36#define PIPE_FILEx
37#ifdef  PIPE_FILE
38#define FILE_PATH "/path/to/drawing.data"
39#endif
40
41#define PIPE_NETx
42#ifdef  PIPE_NET
43#include "SkSockets.h"
44SkTCPServer gServer;
45#endif
46
47#define DEBUGGERx
48#ifdef  DEBUGGER
49extern SkView* create_debugger(const char* data, size_t size);
50extern bool is_debugger(SkView* view);
51SkTDArray<char> gTempDataStore;
52#endif
53
54#endif
55
56#define USE_ARROWS_FOR_ZOOM true
57//#define DEFAULT_TO_GPU
58
59extern SkView* create_overview(int, const SkViewFactory[]);
60extern bool is_overview(SkView* view);
61extern SkView* create_transition(SkView*, SkView*, int);
62extern bool is_transition(SkView* view);
63
64
65#define ANIMATING_EVENTTYPE "nextSample"
66#define ANIMATING_DELAY     750
67
68#ifdef SK_DEBUG
69    #define FPS_REPEAT_MULTIPLIER   1
70#else
71    #define FPS_REPEAT_MULTIPLIER   10
72#endif
73#define FPS_REPEAT_COUNT    (10 * FPS_REPEAT_MULTIPLIER)
74
75static SampleWindow* gSampleWindow;
76
77///////////////
78class SampleWindow::DefaultDeviceManager : public SampleWindow::DeviceManager {
79public:
80
81    DefaultDeviceManager() {
82        fGrRenderTarget = NULL;
83        fGrContext = NULL;
84        fGL = NULL;
85    }
86
87    virtual ~DefaultDeviceManager() {
88        SkSafeUnref(fGrRenderTarget);
89        SkSafeUnref(fGrContext);
90        SkSafeUnref(fGL);
91    }
92
93    virtual void init(SampleWindow* win) {
94        win->attachGL();
95        if (NULL == fGrContext) {
96            fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
97        }
98        if (NULL == fGL) {
99            fGL = GrGLDefaultInterface();
100        }
101        if (NULL == fGrContext || NULL == fGL) {
102            SkDebugf("Failed to setup 3D");
103            win->detachGL();
104        }
105    }
106
107    virtual bool supportsDeviceType(SampleWindow::DeviceType dType) {
108        switch (dType) {
109            case kRaster_DeviceType:
110            case kPicture_DeviceType: // fallthru
111                return true;
112            case kGPU_DeviceType:
113                return NULL != fGrContext && NULL != fGrRenderTarget;
114            default:
115                return false;
116        }
117    }
118
119    virtual bool prepareCanvas(SampleWindow::DeviceType dType,
120                               SkCanvas* canvas,
121                               SampleWindow* win) {
122        if (kGPU_DeviceType == dType) {
123            if (fGrContext) {
124                canvas->setDevice(new SkGpuDevice(fGrContext,
125                                                fGrRenderTarget))->unref();
126            } else {
127                return false;
128            }
129        }
130        return true;
131    }
132
133    virtual void publishCanvas(SampleWindow::DeviceType dType,
134                               SkCanvas* canvas,
135                               SampleWindow* win) {
136        if (fGrContext) {
137            // in case we have queued drawing calls
138            fGrContext->flush();
139            if (dType != kGPU_DeviceType) {
140                // need to send the raster bits to the (gpu) window
141                fGrContext->setRenderTarget(fGrRenderTarget);
142                const SkBitmap& bm = win->getBitmap();
143                fGrContext->writePixels(0, 0, bm.width(), bm.height(),
144                                        kRGBA_8888_GrPixelConfig, bm.getPixels(),
145                                        bm.rowBytes());
146            }
147        }
148        win->presentGL();
149    }
150
151    virtual void windowSizeChanged(SampleWindow* win) {
152        if (fGrContext) {
153            win->attachGL();
154
155            GrPlatformSurfaceDesc desc;
156            desc.reset();
157            desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
158            desc.fWidth = SkScalarRound(win->width());
159            desc.fHeight = SkScalarRound(win->height());
160            desc.fConfig = kRGBA_8888_GrPixelConfig;
161            GR_GL_GetIntegerv(fGL, GR_GL_STENCIL_BITS, &desc.fStencilBits);
162            GR_GL_GetIntegerv(fGL, GR_GL_SAMPLES, &desc.fSampleCnt);
163            GrGLint buffer;
164            GR_GL_GetIntegerv(fGL, GR_GL_FRAMEBUFFER_BINDING, &buffer);
165            desc.fPlatformRenderTarget = buffer;
166
167            SkSafeUnref(fGrRenderTarget);
168            fGrRenderTarget = static_cast<GrRenderTarget*>(
169                                            fGrContext->createPlatformSurface(desc));
170        }
171    }
172
173    virtual GrContext* getGrContext() {
174        return fGrContext;
175    }
176private:
177    GrContext* fGrContext;
178    const GrGLInterface* fGL;
179    GrRenderTarget* fGrRenderTarget;
180};
181
182///////////////
183static const char view_inval_msg[] = "view-inval-msg";
184
185void SampleWindow::postInvalDelay() {
186    (new SkEvent(view_inval_msg, this->getSinkID()))->postDelay(1);
187}
188
189static bool isInvalEvent(const SkEvent& evt) {
190    return evt.isType(view_inval_msg);
191}
192//////////////////
193
194SkViewRegister* SkViewRegister::gHead;
195SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
196    static bool gOnce;
197    if (!gOnce) {
198        gHead = NULL;
199        gOnce = true;
200    }
201
202    fChain = gHead;
203    gHead = this;
204}
205
206#if 0
207#include <CoreFoundation/CoreFoundation.h>
208#include <CoreFoundation/CFURLAccess.h>
209
210static void testpdf() {
211    CFStringRef path = CFStringCreateWithCString(NULL, "/test.pdf",
212                                                 kCFStringEncodingUTF8);
213    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path,
214                                              kCFURLPOSIXPathStyle,
215                                              false);
216    CFRelease(path);
217    CGRect box = CGRectMake(0, 0, 8*72, 10*72);
218    CGContextRef cg = CGPDFContextCreateWithURL(url, &box, NULL);
219    CFRelease(url);
220
221    CGContextBeginPage(cg, &box);
222    CGRect r = CGRectMake(10, 10, 40 + 0.5, 50 + 0.5);
223    CGContextFillEllipseInRect(cg, r);
224    CGContextEndPage(cg);
225    CGContextRelease(cg);
226
227    if (false) {
228        SkBitmap bm;
229        bm.setConfig(SkBitmap::kA8_Config, 64, 64);
230        bm.allocPixels();
231        bm.eraseColor(0);
232
233        SkCanvas canvas(bm);
234
235    }
236}
237#endif
238
239//////////////////////////////////////////////////////////////////////////////
240
241enum FlipAxisEnum {
242    kFlipAxis_X = (1 << 0),
243    kFlipAxis_Y = (1 << 1)
244};
245
246#include "SkDrawFilter.h"
247
248class FlagsDrawFilter : public SkDrawFilter {
249public:
250    FlagsDrawFilter(SkOSMenu::TriState lcd, SkOSMenu::TriState aa, SkOSMenu::TriState filter,
251                    SkOSMenu::TriState hinting) :
252        fLCDState(lcd), fAAState(aa), fFilterState(filter), fHintingState(hinting) {}
253
254    virtual void filter(SkPaint* paint, Type t) {
255        if (kText_Type == t && SkOSMenu::kMixedState != fLCDState) {
256            paint->setLCDRenderText(SkOSMenu::kOnState == fLCDState);
257        }
258        if (SkOSMenu::kMixedState != fAAState) {
259            paint->setAntiAlias(SkOSMenu::kOnState == fAAState);
260        }
261        if (SkOSMenu::kMixedState != fFilterState) {
262            paint->setFilterBitmap(SkOSMenu::kOnState == fFilterState);
263        }
264        if (SkOSMenu::kMixedState != fHintingState) {
265            paint->setHinting(SkOSMenu::kOnState == fHintingState ?
266                              SkPaint::kNormal_Hinting :
267                              SkPaint::kSlight_Hinting);
268        }
269    }
270
271private:
272    SkOSMenu::TriState  fLCDState;
273    SkOSMenu::TriState  fAAState;
274    SkOSMenu::TriState  fFilterState;
275    SkOSMenu::TriState  fHintingState;
276};
277
278//////////////////////////////////////////////////////////////////////////////
279
280#define MAX_ZOOM_LEVEL  8
281#define MIN_ZOOM_LEVEL  -8
282
283static const char gCharEvtName[] = "SampleCode_Char_Event";
284static const char gKeyEvtName[] = "SampleCode_Key_Event";
285static const char gTitleEvtName[] = "SampleCode_Title_Event";
286static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
287static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
288
289bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
290    if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
291        if (outUni) {
292            *outUni = evt.getFast32();
293        }
294        return true;
295    }
296    return false;
297}
298
299bool SampleCode::KeyQ(const SkEvent& evt, SkKey* outKey) {
300    if (evt.isType(gKeyEvtName, sizeof(gKeyEvtName) - 1)) {
301        if (outKey) {
302            *outKey = (SkKey)evt.getFast32();
303        }
304        return true;
305    }
306    return false;
307}
308
309bool SampleCode::TitleQ(const SkEvent& evt) {
310    return evt.isType(gTitleEvtName, sizeof(gTitleEvtName) - 1);
311}
312
313void SampleCode::TitleR(SkEvent* evt, const char title[]) {
314    SkASSERT(evt && TitleQ(*evt));
315    evt->setString(gTitleEvtName, title);
316}
317
318bool SampleCode::RequestTitle(SkView* view, SkString* title) {
319    SkEvent evt(gTitleEvtName);
320    if (view->doQuery(&evt)) {
321        title->set(evt.findString(gTitleEvtName));
322        return true;
323    }
324    return false;
325}
326
327bool SampleCode::PrefSizeQ(const SkEvent& evt) {
328    return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
329}
330
331void SampleCode::PrefSizeR(SkEvent* evt, SkScalar width, SkScalar height) {
332    SkASSERT(evt && PrefSizeQ(*evt));
333    SkScalar size[2];
334    size[0] = width;
335    size[1] = height;
336    evt->setScalars(gPrefSizeEvtName, 2, size);
337}
338
339bool SampleCode::FastTextQ(const SkEvent& evt) {
340    return evt.isType(gFastTextEvtName, sizeof(gFastTextEvtName) - 1);
341}
342
343///////////////////////////////////////////////////////////////////////////////
344
345static SkMSec gAnimTime;
346static SkMSec gAnimTimePrev;
347
348SkMSec SampleCode::GetAnimTime() { return gAnimTime; }
349SkMSec SampleCode::GetAnimTimeDelta() { return gAnimTime - gAnimTimePrev; }
350SkScalar SampleCode::GetAnimSecondsDelta() {
351    return SkDoubleToScalar(GetAnimTimeDelta() / 1000.0);
352}
353
354SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
355    // since gAnimTime can be up to 32 bits, we can't convert it to a float
356    // or we'll lose the low bits. Hence we use doubles for the intermediate
357    // calculations
358    double seconds = (double)gAnimTime / 1000.0;
359    double value = SkScalarToDouble(speed) * seconds;
360    if (period) {
361        value = ::fmod(value, SkScalarToDouble(period));
362    }
363    return SkDoubleToScalar(value);
364}
365
366GrContext* SampleCode::GetGr() {
367    return gSampleWindow ? gSampleWindow->getGrContext() : NULL;
368}
369
370//////////////////////////////////////////////////////////////////////////////
371
372static SkView* curr_view(SkWindow* wind) {
373    SkView::F2BIter iter(wind);
374    return iter.next();
375}
376
377void SampleWindow::setZoomCenter(float x, float y)
378{
379    fZoomCenterX = SkFloatToScalar(x);
380    fZoomCenterY = SkFloatToScalar(y);
381}
382
383bool SampleWindow::zoomIn()
384{
385    // Arbitrarily decided
386    if (fFatBitsScale == 25) return false;
387    fFatBitsScale++;
388    this->inval(NULL);
389    return true;
390}
391
392bool SampleWindow::zoomOut()
393{
394    if (fFatBitsScale == 1) return false;
395    fFatBitsScale--;
396    this->inval(NULL);
397    return true;
398}
399
400void SampleWindow::updatePointer(int x, int y)
401{
402    fMouseX = x;
403    fMouseY = y;
404    if (fShowZoomer) {
405        this->inval(NULL);
406    }
407}
408
409static inline SampleWindow::DeviceType cycle_devicetype(SampleWindow::DeviceType ct) {
410    static const SampleWindow::DeviceType gCT[] = {
411        SampleWindow::kPicture_DeviceType,
412        SampleWindow::kGPU_DeviceType,
413        SampleWindow::kRaster_DeviceType
414    };
415    return gCT[ct];
416}
417
418SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* devManager) : INHERITED(hwnd) {
419    gSampleWindow = this;
420
421#ifdef  PIPE_FILE
422    //Clear existing file or create file if it doesn't exist
423    FILE* f = fopen(FILE_PATH, "wb");
424    fclose(f);
425#endif
426
427    fPicture = NULL;
428
429#ifdef DEFAULT_TO_GPU
430    fDeviceType = kGPU_DeviceType;
431#else
432    fDeviceType = kRaster_DeviceType;
433#endif
434    fUseClip = false;
435    fNClip = false;
436    fRepeatDrawing = false;
437    fAnimating = false;
438    fRotate = false;
439    fPerspAnim = false;
440    fPerspAnimTime = 0;
441    fScale = false;
442    fRequestGrabImage = false;
443    fUsePipe = false;
444    fMeasureFPS = false;
445    fLCDState = SkOSMenu::kMixedState;
446    fAAState = SkOSMenu::kMixedState;
447    fFilterState = SkOSMenu::kMixedState;
448    fHintingState = SkOSMenu::kMixedState;
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    fMagnify = false;
461    fDebugger = false;
462
463    fSaveToPdf = false;
464    fPdfCanvas = NULL;
465
466    fTransitionNext = 6;
467    fTransitionPrev = 2;
468
469    int sinkID = this->getSinkID();
470    fAppMenu.setTitle("Global Settings");
471    int itemID;
472
473    itemID =fAppMenu.appendList("Device Type", "Device Type", sinkID, 0,
474                                "Raster", "Picture", "OpenGL", NULL);
475    fAppMenu.assignKeyEquivalentToItem(itemID, 'd');
476    itemID = fAppMenu.appendTriState("AA", "AA", sinkID, fAAState);
477    fAppMenu.assignKeyEquivalentToItem(itemID, 'b');
478    itemID = fAppMenu.appendTriState("LCD", "LCD", sinkID, fLCDState);
479    fAppMenu.assignKeyEquivalentToItem(itemID, 'l');
480    itemID = fAppMenu.appendTriState("Filter", "Filter", sinkID, fFilterState);
481    fAppMenu.assignKeyEquivalentToItem(itemID, 'n');
482    itemID = fAppMenu.appendTriState("Hinting", "Hinting", sinkID, fHintingState);
483    fAppMenu.assignKeyEquivalentToItem(itemID, 'h');
484    fUsePipeMenuItemID = fAppMenu.appendSwitch("Pipe", "Pipe" , sinkID, fUsePipe);
485    fAppMenu.assignKeyEquivalentToItem(fUsePipeMenuItemID, 'p');
486#ifdef DEBUGGER
487    itemID = fAppMenu.appendSwitch("Debugger", "Debugger", sinkID, fDebugger);
488    fAppMenu.assignKeyEquivalentToItem(itemID, 'q');
489#endif
490    itemID = fAppMenu.appendSwitch("Slide Show", "Slide Show" , sinkID, false);
491    fAppMenu.assignKeyEquivalentToItem(itemID, 'a');
492    itemID = fAppMenu.appendSwitch("Clip", "Clip" , sinkID, fUseClip);
493    fAppMenu.assignKeyEquivalentToItem(itemID, 'c');
494    itemID = fAppMenu.appendSwitch("Flip X", "Flip X" , sinkID, false);
495    fAppMenu.assignKeyEquivalentToItem(itemID, 'x');
496    itemID = fAppMenu.appendSwitch("Flip Y", "Flip Y" , sinkID, false);
497    fAppMenu.assignKeyEquivalentToItem(itemID, 'y');
498    itemID = fAppMenu.appendSwitch("Zoomer", "Zoomer" , sinkID, fShowZoomer);
499    fAppMenu.assignKeyEquivalentToItem(itemID, 'z');
500    itemID = fAppMenu.appendSwitch("Magnify", "Magnify" , sinkID, fMagnify);
501    fAppMenu.assignKeyEquivalentToItem(itemID, 'm');
502    itemID =fAppMenu.appendList("Transition-Next", "Transition-Next", sinkID,
503                                fTransitionNext, "Up", "Up and Right", "Right",
504                                "Down and Right", "Down", "Down and Left",
505                                "Left", "Up and Left", NULL);
506    fAppMenu.assignKeyEquivalentToItem(itemID, 'j');
507    itemID =fAppMenu.appendList("Transition-Prev", "Transition-Prev", sinkID,
508                                fTransitionPrev, "Up", "Up and Right", "Right",
509                                "Down and Right", "Down", "Down and Left",
510                                "Left", "Up and Left", NULL);
511    fAppMenu.assignKeyEquivalentToItem(itemID, 'k');
512    itemID = fAppMenu.appendAction("Save to PDF", sinkID);
513    fAppMenu.assignKeyEquivalentToItem(itemID, 'e');
514
515    this->addMenu(&fAppMenu);
516    this->addMenu(&fSlideMenu);
517
518//    this->setConfig(SkBitmap::kRGB_565_Config);
519    this->setConfig(SkBitmap::kARGB_8888_Config);
520    this->setVisibleP(true);
521    this->setClipToBounds(false);
522
523    {
524        const SkViewRegister* reg = SkViewRegister::Head();
525        while (reg) {
526            *fSamples.append() = reg->factory();
527            reg = reg->next();
528        }
529    }
530    fCurrIndex = 0;
531    if (argc > 1) {
532        int i, count = fSamples.count();
533        for (i = 0; i < count; i++) {
534            SkString title = getSampleTitle(i);
535            if (title.equals(argv[1])) {
536                fCurrIndex = i;
537                break;
538            }
539        }
540        if (i == count) {
541            fprintf(stderr, "Unknown sample \"%s\"\n", argv[1]);
542        }
543    }
544    this->loadView(fSamples[fCurrIndex]());
545
546    fPDFData = NULL;
547
548    if (NULL == devManager) {
549        fDevManager = new DefaultDeviceManager();
550    } else {
551        devManager->ref();
552        fDevManager = devManager;
553    }
554    fDevManager->init(this);
555
556    // If another constructor set our dimensions, ensure that our
557    // onSizeChange gets called.
558    if (this->height() && this->width()) {
559        this->onSizeChange();
560    }
561}
562
563SampleWindow::~SampleWindow() {
564    delete fPicture;
565    delete fPdfCanvas;
566    fTypeface->unref();
567
568    SkSafeUnref(fDevManager);
569}
570
571static SkBitmap capture_bitmap(SkCanvas* canvas) {
572    SkBitmap bm;
573    const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
574    src.copyTo(&bm, src.config());
575    return bm;
576}
577
578static bool bitmap_diff(SkCanvas* canvas, const SkBitmap& orig,
579                        SkBitmap* diff) {
580    const SkBitmap& src = canvas->getDevice()->accessBitmap(false);
581
582    SkAutoLockPixels alp0(src);
583    SkAutoLockPixels alp1(orig);
584    for (int y = 0; y < src.height(); y++) {
585        const void* srcP = src.getAddr(0, y);
586        const void* origP = orig.getAddr(0, y);
587        size_t bytes = src.width() * src.bytesPerPixel();
588        if (memcmp(srcP, origP, bytes)) {
589            SkDebugf("---------- difference on line %d\n", y);
590            return true;
591        }
592    }
593    return false;
594}
595
596static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
597{
598    SkColor desiredColor = paint.getColor();
599    paint.setColor(SK_ColorWHITE);
600    const char* c_str = string.c_str();
601    size_t size = string.size();
602    SkRect bounds;
603    paint.measureText(c_str, size, &bounds);
604    bounds.offset(left, top);
605    SkScalar inset = SkIntToScalar(-2);
606    bounds.inset(inset, inset);
607    canvas->drawRect(bounds, paint);
608    if (desiredColor != SK_ColorBLACK) {
609        paint.setColor(SK_ColorBLACK);
610        canvas->drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
611    }
612    paint.setColor(desiredColor);
613    canvas->drawText(c_str, size, left, top, paint);
614}
615
616#define XCLIP_N  8
617#define YCLIP_N  8
618
619void SampleWindow::draw(SkCanvas* canvas) {
620    if (!fDevManager->prepareCanvas(fDeviceType, canvas, this)) {
621        return;
622    }
623    // update the animation time
624    if (!gAnimTimePrev && !gAnimTime) {
625        // first time make delta be 0
626        gAnimTime = SkTime::GetMSecs();
627        gAnimTimePrev = gAnimTime;
628    } else {
629        gAnimTimePrev = gAnimTime;
630        gAnimTime = SkTime::GetMSecs();
631    }
632
633    SkScalar cx = fZoomCenterX;
634    SkScalar cy = fZoomCenterY;
635
636    if (fZoomLevel) {
637        SkMatrix m;
638        SkPoint center;
639        m = canvas->getTotalMatrix();//.invert(&m);
640        m.mapXY(cx, cy, &center);
641        cx = center.fX;
642        cy = center.fY;
643
644        m.setTranslate(-cx, -cy);
645        m.postScale(fZoomScale, fZoomScale);
646        m.postTranslate(cx, cy);
647
648        canvas->concat(m);
649    }
650
651    if (fFlipAxis) {
652        SkMatrix m;
653        m.setTranslate(cx, cy);
654        if (fFlipAxis & kFlipAxis_X) {
655            m.preScale(-SK_Scalar1, SK_Scalar1);
656        }
657        if (fFlipAxis & kFlipAxis_Y) {
658            m.preScale(SK_Scalar1, -SK_Scalar1);
659        }
660        m.preTranslate(-cx, -cy);
661        canvas->concat(m);
662    }
663
664    // Apply any gesture matrix
665    if (true) {
666        const SkMatrix& localM = fGesture.localM();
667        if (localM.getType() & SkMatrix::kScale_Mask) {
668            canvas->setExternalMatrix(&localM);
669        }
670        canvas->concat(localM);
671        canvas->concat(fGesture.globalM());
672
673        if (fGesture.isActive()) {
674            this->inval(NULL);
675        }
676    }
677
678    if (fNClip) {
679        this->INHERITED::draw(canvas);
680        SkBitmap orig = capture_bitmap(canvas);
681
682        const SkScalar w = this->width();
683        const SkScalar h = this->height();
684        const SkScalar cw = w / XCLIP_N;
685        const SkScalar ch = h / YCLIP_N;
686        for (int y = 0; y < YCLIP_N; y++) {
687            SkRect r;
688            r.fTop = y * ch;
689            r.fBottom = (y + 1) * ch;
690            if (y == YCLIP_N - 1) {
691                r.fBottom = h;
692            }
693            for (int x = 0; x < XCLIP_N; x++) {
694                SkAutoCanvasRestore acr(canvas, true);
695                r.fLeft = x * cw;
696                r.fRight = (x + 1) * cw;
697                if (x == XCLIP_N - 1) {
698                    r.fRight = w;
699                }
700                canvas->clipRect(r);
701                this->INHERITED::draw(canvas);
702            }
703        }
704
705        SkBitmap diff;
706        if (bitmap_diff(canvas, orig, &diff)) {
707        }
708    } else {
709        this->INHERITED::draw(canvas);
710    }
711    if (fShowZoomer && !fSaveToPdf) {
712        showZoomer(canvas);
713    }
714    if (fMagnify && !fSaveToPdf) {
715        magnify(canvas);
716    }
717
718    // do this last
719    fDevManager->publishCanvas(fDeviceType, canvas, this);
720}
721
722static float clipW = 200;
723static float clipH = 200;
724void SampleWindow::magnify(SkCanvas* canvas) {
725    SkRect r;
726    int count = canvas->save();
727
728    SkMatrix m = canvas->getTotalMatrix();
729    m.invert(&m);
730    SkPoint offset, center;
731    SkScalar mouseX = fMouseX * SK_Scalar1;
732    SkScalar mouseY = fMouseY * SK_Scalar1;
733    m.mapXY(mouseX - clipW/2, mouseY - clipH/2, &offset);
734    m.mapXY(mouseX, mouseY, &center);
735
736    r.set(0, 0, clipW * m.getScaleX(), clipH * m.getScaleX());
737    r.offset(offset.fX, offset.fY);
738
739    SkPaint paint;
740    paint.setColor(0xFF66AAEE);
741    paint.setStyle(SkPaint::kStroke_Style);
742    paint.setStrokeWidth(10.f * m.getScaleX());
743    //lense offset
744    //canvas->translate(0, -250);
745    canvas->drawRect(r, paint);
746    canvas->clipRect(r);
747
748    m = canvas->getTotalMatrix();
749    m.setTranslate(-center.fX, -center.fY);
750    m.postScale(0.5f * fFatBitsScale, 0.5f * fFatBitsScale);
751    m.postTranslate(center.fX, center.fY);
752    canvas->concat(m);
753
754    this->INHERITED::draw(canvas);
755
756    canvas->restoreToCount(count);
757}
758
759void SampleWindow::showZoomer(SkCanvas* canvas) {
760        int count = canvas->save();
761        canvas->resetMatrix();
762        // Ensure the mouse position is on screen.
763        int width = SkScalarRound(this->width());
764        int height = SkScalarRound(this->height());
765        if (fMouseX >= width) fMouseX = width - 1;
766        else if (fMouseX < 0) fMouseX = 0;
767        if (fMouseY >= height) fMouseY = height - 1;
768        else if (fMouseY < 0) fMouseY = 0;
769
770        SkBitmap bitmap = capture_bitmap(canvas);
771        bitmap.lockPixels();
772
773        // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
774        int zoomedWidth = (width >> 1) | 1;
775        int zoomedHeight = (height >> 1) | 1;
776        SkIRect src;
777        src.set(0, 0, zoomedWidth / fFatBitsScale, zoomedHeight / fFatBitsScale);
778        src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
779        SkRect dest;
780        dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
781        dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
782        SkPaint paint;
783        // Clear the background behind our zoomed in view
784        paint.setColor(SK_ColorWHITE);
785        canvas->drawRect(dest, paint);
786        canvas->drawBitmapRect(bitmap, &src, dest);
787        paint.setColor(SK_ColorBLACK);
788        paint.setStyle(SkPaint::kStroke_Style);
789        // Draw a border around the pixel in the middle
790        SkRect originalPixel;
791        originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
792        SkMatrix matrix;
793        SkRect scalarSrc;
794        scalarSrc.set(src);
795        SkColor color = bitmap.getColor(fMouseX, fMouseY);
796        if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
797            SkRect pixel;
798            matrix.mapRect(&pixel, originalPixel);
799            // TODO Perhaps measure the values and make the outline white if it's "dark"
800            if (color == SK_ColorBLACK) {
801                paint.setColor(SK_ColorWHITE);
802            }
803            canvas->drawRect(pixel, paint);
804        }
805        paint.setColor(SK_ColorBLACK);
806        // Draw a border around the destination rectangle
807        canvas->drawRect(dest, paint);
808        paint.setStyle(SkPaint::kStrokeAndFill_Style);
809        // Identify the pixel and its color on screen
810        paint.setTypeface(fTypeface);
811        paint.setAntiAlias(true);
812        SkScalar lineHeight = paint.getFontMetrics(NULL);
813        SkString string;
814        string.appendf("(%i, %i)", fMouseX, fMouseY);
815        SkScalar left = dest.fLeft + SkIntToScalar(3);
816        SkScalar i = SK_Scalar1;
817        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
818        // Alpha
819        i += SK_Scalar1;
820        string.reset();
821        string.appendf("A: %X", SkColorGetA(color));
822        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
823        // Red
824        i += SK_Scalar1;
825        string.reset();
826        string.appendf("R: %X", SkColorGetR(color));
827        paint.setColor(SK_ColorRED);
828        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
829        // Green
830        i += SK_Scalar1;
831        string.reset();
832        string.appendf("G: %X", SkColorGetG(color));
833        paint.setColor(SK_ColorGREEN);
834        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
835        // Blue
836        i += SK_Scalar1;
837        string.reset();
838        string.appendf("B: %X", SkColorGetB(color));
839        paint.setColor(SK_ColorBLUE);
840        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
841        canvas->restoreToCount(count);
842}
843
844void SampleWindow::onDraw(SkCanvas* canvas) {
845    if (fRepeatDrawing) {
846        this->inval(NULL);
847    }
848}
849
850#include "SkColorPriv.h"
851
852static void reverseRedAndBlue(const SkBitmap& bm) {
853    SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
854    uint8_t* p = (uint8_t*)bm.getPixels();
855    uint8_t* stop = p + bm.getSize();
856    while (p < stop) {
857        // swap red/blue (to go from ARGB(int) to RGBA(memory) and premultiply
858        unsigned scale = SkAlpha255To256(p[3]);
859        unsigned r = p[2];
860        unsigned b = p[0];
861        p[0] = SkAlphaMul(r, scale);
862        p[1] = SkAlphaMul(p[1], scale);
863        p[2] = SkAlphaMul(b, scale);
864        p += 4;
865    }
866}
867
868void SampleWindow::saveToPdf()
869{
870    fSaveToPdf = true;
871    this->inval(NULL);
872}
873
874SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
875    if (fSaveToPdf) {
876        const SkBitmap& bmp = canvas->getDevice()->accessBitmap(false);
877        SkISize size = SkISize::Make(bmp.width(), bmp.height());
878        SkPDFDevice* pdfDevice = new SkPDFDevice(size, size,
879                canvas->getTotalMatrix());
880        fPdfCanvas = new SkCanvas(pdfDevice);
881        pdfDevice->unref();
882        canvas = fPdfCanvas;
883    } else {
884        switch (fDeviceType) {
885            case kRaster_DeviceType:
886            case kGPU_DeviceType:
887                canvas = this->INHERITED::beforeChildren(canvas);
888                break;
889            case kPicture_DeviceType:
890                fPicture = new SkPicture;
891                canvas = fPicture->beginRecording(9999, 9999);
892                break;
893        }
894    }
895
896    if (fUseClip) {
897        canvas->drawColor(0xFFFF88FF);
898        canvas->clipPath(fClipPath, SkRegion::kIntersect_Op, true);
899    }
900
901    return canvas;
902}
903
904static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
905                      const SkRegion& rgn) {
906    SkCanvas    canvas(bm);
907    SkRegion    inval(rgn);
908
909    inval.translate(r.fLeft, r.fTop);
910    canvas.clipRegion(inval);
911    canvas.drawColor(0xFFFF8080);
912}
913#include "SkData.h"
914void SampleWindow::afterChildren(SkCanvas* orig) {
915    if (fSaveToPdf) {
916        fSaveToPdf = false;
917        if (fShowZoomer) {
918            showZoomer(fPdfCanvas);
919        }
920        SkString name;
921        name.printf("%s.pdf", this->getTitle());
922        SkPDFDocument doc;
923        SkPDFDevice* device = static_cast<SkPDFDevice*>(fPdfCanvas->getDevice());
924        doc.appendPage(device);
925#ifdef ANDROID
926        name.prepend("/sdcard/");
927#endif
928
929#ifdef SK_BUILD_FOR_IOS
930        SkDynamicMemoryWStream mstream;
931        doc.emitPDF(&mstream);
932        fPDFData = mstream.copyToData();
933#endif
934        SkFILEWStream stream(name.c_str());
935        if (stream.isValid()) {
936            doc.emitPDF(&stream);
937            const char* desc = "File saved from Skia SampleApp";
938            this->onPDFSaved(this->getTitle(), desc, name.c_str());
939        }
940
941        delete fPdfCanvas;
942        fPdfCanvas = NULL;
943
944        // We took over the draw calls in order to create the PDF, so we need
945        // to redraw.
946        this->inval(NULL);
947        return;
948    }
949
950    if (fRequestGrabImage) {
951        fRequestGrabImage = false;
952
953        SkDevice* device = orig->getDevice();
954        SkBitmap bmp;
955        if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) {
956            static int gSampleGrabCounter;
957            SkString name;
958            name.printf("sample_grab_%d", gSampleGrabCounter++);
959            SkImageEncoder::EncodeFile(name.c_str(), bmp,
960                                       SkImageEncoder::kPNG_Type, 100);
961        }
962    }
963
964    if (kPicture_DeviceType == fDeviceType) {
965        if (true) {
966            SkPicture* pict = new SkPicture(*fPicture);
967            fPicture->unref();
968            orig->drawPicture(*pict);
969            pict->unref();
970        } else if (true) {
971            SkDynamicMemoryWStream ostream;
972            fPicture->serialize(&ostream);
973            fPicture->unref();
974
975            SkAutoDataUnref data(ostream.copyToData());
976            SkMemoryStream istream(data.data(), data.size());
977            SkPicture pict(&istream);
978            orig->drawPicture(pict);
979        } else {
980            fPicture->draw(orig);
981            fPicture->unref();
982        }
983        fPicture = NULL;
984    }
985
986    // Do this after presentGL and other finishing, rather than in afterChild
987    if (fMeasureFPS && fMeasureFPS_Time) {
988        fMeasureFPS_Time = SkTime::GetMSecs() - fMeasureFPS_Time;
989        this->updateTitle();
990        this->postInvalDelay();
991    }
992
993    //    if ((fScrollTestX | fScrollTestY) != 0)
994    if (false) {
995        const SkBitmap& bm = orig->getDevice()->accessBitmap(true);
996        int dx = fScrollTestX * 7;
997        int dy = fScrollTestY * 7;
998        SkIRect r;
999        SkRegion inval;
1000
1001        r.set(50, 50, 50+100, 50+100);
1002        bm.scrollRect(&r, dx, dy, &inval);
1003        paint_rgn(bm, r, inval);
1004    }
1005#ifdef DEBUGGER
1006    SkView* curr = curr_view(this);
1007    if (fDebugger && !is_debugger(curr) && !is_transition(curr) && !is_overview(curr)) {
1008        //Stop Pipe when fDebugger is active
1009        fUsePipe = false;
1010        (void)SampleView::SetUsePipe(curr, false);
1011        fAppMenu.getItemByID(fUsePipeMenuItemID)->setBool(fUsePipe);
1012        this->onUpdateMenu(&fAppMenu);
1013
1014        //Reset any transformations
1015        fGesture.stop();
1016        fGesture.reset();
1017
1018        this->loadView(create_debugger(gTempDataStore.begin(),
1019                                       gTempDataStore.count()));
1020    }
1021#endif
1022}
1023
1024void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
1025    if (fScale) {
1026        SkScalar scale = SK_Scalar1 * 7 / 10;
1027        SkScalar cx = this->width() / 2;
1028        SkScalar cy = this->height() / 2;
1029        canvas->translate(cx, cy);
1030        canvas->scale(scale, scale);
1031        canvas->translate(-cx, -cy);
1032    }
1033    if (fRotate) {
1034        SkScalar cx = this->width() / 2;
1035        SkScalar cy = this->height() / 2;
1036        canvas->translate(cx, cy);
1037        canvas->rotate(SkIntToScalar(30));
1038        canvas->translate(-cx, -cy);
1039    }
1040    if (fPerspAnim) {
1041        fPerspAnimTime += SampleCode::GetAnimSecondsDelta();
1042
1043        static const SkScalar gAnimPeriod = 10 * SK_Scalar1;
1044        static const SkScalar gAnimMag = SK_Scalar1 / 1000;
1045        SkScalar t = SkScalarMod(fPerspAnimTime, gAnimPeriod);
1046        if (SkScalarFloorToInt(SkScalarDiv(fPerspAnimTime, gAnimPeriod)) & 0x1) {
1047            t = gAnimPeriod - t;
1048        }
1049        t = 2 * t - gAnimPeriod;
1050        t = SkScalarMul(SkScalarDiv(t, gAnimPeriod), gAnimMag);
1051        SkMatrix m;
1052        m.reset();
1053        m.setPerspY(t);
1054        canvas->concat(m);
1055    }
1056
1057    canvas->setDrawFilter(new FlagsDrawFilter(fLCDState, fAAState,
1058                                       fFilterState, fHintingState))->unref();
1059
1060    if (fMeasureFPS) {
1061        fMeasureFPS_Time = 0;   // 0 means the child is not aware of repeat-draw
1062        if (SampleView::SetRepeatDraw(child, FPS_REPEAT_COUNT)) {
1063            fMeasureFPS_Time = SkTime::GetMSecs();
1064        }
1065    } else {
1066        (void)SampleView::SetRepeatDraw(child, 1);
1067    }
1068    if (fPerspAnim) {
1069        this->inval(NULL);
1070    }
1071    //(void)SampleView::SetUsePipe(child, fUsePipe);
1072}
1073
1074void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
1075    canvas->setDrawFilter(NULL);
1076}
1077
1078static SkBitmap::Config gConfigCycle[] = {
1079    SkBitmap::kNo_Config,           // none -> none
1080    SkBitmap::kNo_Config,           // a1 -> none
1081    SkBitmap::kNo_Config,           // a8 -> none
1082    SkBitmap::kNo_Config,           // index8 -> none
1083    SkBitmap::kARGB_4444_Config,    // 565 -> 4444
1084    SkBitmap::kARGB_8888_Config,    // 4444 -> 8888
1085    SkBitmap::kRGB_565_Config       // 8888 -> 565
1086};
1087
1088static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
1089    return gConfigCycle[c];
1090}
1091
1092void SampleWindow::changeZoomLevel(float delta) {
1093    fZoomLevel += SkFloatToScalar(delta);
1094    if (fZoomLevel > 0) {
1095        fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL);
1096        fZoomScale = fZoomLevel + SK_Scalar1;
1097    } else if (fZoomLevel < 0) {
1098        fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL);
1099        fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel);
1100    } else {
1101        fZoomScale = SK_Scalar1;
1102    }
1103
1104    this->updateTitle();
1105
1106    this->inval(NULL);
1107}
1108
1109bool SampleWindow::previousSample() {
1110    fCurrIndex = (fCurrIndex - 1 + fSamples.count()) % fSamples.count();
1111    this->loadView(create_transition(curr_view(this), fSamples[fCurrIndex](),
1112                                     fTransitionPrev));
1113    return true;
1114}
1115
1116bool SampleWindow::nextSample() {
1117    fCurrIndex = (fCurrIndex + 1) % fSamples.count();
1118    this->loadView(create_transition(curr_view(this), fSamples[fCurrIndex](),
1119                                     fTransitionNext));
1120    return true;
1121}
1122
1123bool SampleWindow::goToSample(int i) {
1124    fCurrIndex = (i) % fSamples.count();
1125    this->loadView(create_transition(curr_view(this),fSamples[fCurrIndex](), 6));
1126    return true;
1127}
1128
1129SkString SampleWindow::getSampleTitle(int i) {
1130    SkView* view = fSamples[i]();
1131    SkString title;
1132    SampleCode::RequestTitle(view, &title);
1133    view->unref();
1134    return title;
1135}
1136
1137int SampleWindow::sampleCount() {
1138    return fSamples.count();
1139}
1140
1141void SampleWindow::showOverview() {
1142    this->loadView(create_transition(curr_view(this),
1143                                     create_overview(fSamples.count(), fSamples.begin()),
1144                                     4));
1145}
1146
1147void SampleWindow::postAnimatingEvent() {
1148    if (fAnimating) {
1149        (new SkEvent(ANIMATING_EVENTTYPE, this->getSinkID()))->postDelay(ANIMATING_DELAY);
1150    }
1151}
1152bool SampleWindow::onEvent(const SkEvent& evt) {
1153    if (evt.isType(ANIMATING_EVENTTYPE)) {
1154        if (fAnimating) {
1155            this->nextSample();
1156            this->postAnimatingEvent();
1157        }
1158        return true;
1159    }
1160    if (evt.isType("replace-transition-view")) {
1161        this->loadView((SkView*)SkEventSink::FindSink(evt.getFast32()));
1162        return true;
1163    }
1164    if (evt.isType("set-curr-index")) {
1165        this->goToSample(evt.getFast32());
1166        return true;
1167    }
1168    if (isInvalEvent(evt)) {
1169        this->inval(NULL);
1170        return true;
1171    }
1172    int selected = -1;
1173    if (SkOSMenu::FindListIndex(evt, "Device Type", &selected)) {
1174        this->setDeviceType((DeviceType)selected);
1175        return true;
1176    }
1177    if (SkOSMenu::FindSwitchState(evt, "Pipe", &fUsePipe)) {
1178#ifdef PIPE_NET
1179        if (!fUsePipe)
1180            gServer.disconnectAll();
1181#endif
1182        (void)SampleView::SetUsePipe(curr_view(this), fUsePipe);
1183        this->updateTitle();
1184        this->inval(NULL);
1185        return true;
1186    }
1187    if (SkOSMenu::FindSwitchState(evt, "Slide Show", NULL)) {
1188        this->toggleSlideshow();
1189        return true;
1190    }
1191    if (SkOSMenu::FindTriState(evt, "AA", &fAAState) ||
1192        SkOSMenu::FindTriState(evt, "LCD", &fLCDState) ||
1193        SkOSMenu::FindTriState(evt, "Filter", &fFilterState) ||
1194        SkOSMenu::FindTriState(evt, "Hinting", &fHintingState) ||
1195        SkOSMenu::FindSwitchState(evt, "Clip", &fUseClip) ||
1196        SkOSMenu::FindSwitchState(evt, "Zoomer", &fShowZoomer) ||
1197        SkOSMenu::FindSwitchState(evt, "Magnify", &fMagnify) ||
1198        SkOSMenu::FindListIndex(evt, "Transition-Next", &fTransitionNext) ||
1199        SkOSMenu::FindListIndex(evt, "Transition-Prev", &fTransitionPrev)) {
1200        this->inval(NULL);
1201        this->updateTitle();
1202        return true;
1203    }
1204    if (SkOSMenu::FindSwitchState(evt, "Flip X", NULL)) {
1205        fFlipAxis ^= kFlipAxis_X;
1206        this->updateTitle();
1207        this->inval(NULL);
1208        return true;
1209    }
1210    if (SkOSMenu::FindSwitchState(evt, "Flip Y", NULL)) {
1211        fFlipAxis ^= kFlipAxis_Y;
1212        this->updateTitle();
1213        this->inval(NULL);
1214        return true;
1215    }
1216    if (SkOSMenu::FindAction(evt,"Save to PDF")) {
1217        this->saveToPdf();
1218        return true;
1219    }
1220#ifdef DEBUGGER
1221    if (SkOSMenu::FindSwitchState(evt, "Debugger", &fDebugger)) {
1222        if (fDebugger) {
1223            fUsePipe = true;
1224            (void)SampleView::SetUsePipe(curr_view(this), true);
1225        } else {
1226            this->loadView(fSamples[fCurrIndex]());
1227        }
1228        this->inval(NULL);
1229        return true;
1230    }
1231#endif
1232    return this->INHERITED::onEvent(evt);
1233}
1234
1235bool SampleWindow::onQuery(SkEvent* query) {
1236    if (query->isType("get-slide-count")) {
1237        query->setFast32(fSamples.count());
1238        return true;
1239    }
1240    if (query->isType("get-slide-title")) {
1241        SkView* view = fSamples[query->getFast32()]();
1242        SkEvent evt(gTitleEvtName);
1243        if (view->doQuery(&evt)) {
1244            query->setString("title", evt.findString(gTitleEvtName));
1245        }
1246        SkSafeUnref(view);
1247        return true;
1248    }
1249    if (query->isType("use-fast-text")) {
1250        SkEvent evt(gFastTextEvtName);
1251        return curr_view(this)->doQuery(&evt);
1252    }
1253    if (query->isType("ignore-window-bitmap")) {
1254        query->setFast32(this->getGrContext() != NULL);
1255        return true;
1256    }
1257    return this->INHERITED::onQuery(query);
1258}
1259
1260static void cleanup_for_filename(SkString* name) {
1261    char* str = name->writable_str();
1262    for (size_t i = 0; i < name->size(); i++) {
1263        switch (str[i]) {
1264            case ':': str[i] = '-'; break;
1265            case '/': str[i] = '-'; break;
1266            case ' ': str[i] = '_'; break;
1267            default: break;
1268        }
1269    }
1270}
1271
1272bool SampleWindow::onHandleChar(SkUnichar uni) {
1273    {
1274        SkView* view = curr_view(this);
1275        if (view) {
1276            SkEvent evt(gCharEvtName);
1277            evt.setFast32(uni);
1278            if (view->doQuery(&evt)) {
1279                return true;
1280            }
1281        }
1282    }
1283
1284    int dx = 0xFF;
1285    int dy = 0xFF;
1286
1287    switch (uni) {
1288        case '5': dx =  0; dy =  0; break;
1289        case '8': dx =  0; dy = -1; break;
1290        case '6': dx =  1; dy =  0; break;
1291        case '2': dx =  0; dy =  1; break;
1292        case '4': dx = -1; dy =  0; break;
1293        case '7': dx = -1; dy = -1; break;
1294        case '9': dx =  1; dy = -1; break;
1295        case '3': dx =  1; dy =  1; break;
1296        case '1': dx = -1; dy =  1; break;
1297
1298        default:
1299            break;
1300    }
1301
1302    if (0xFF != dx && 0xFF != dy) {
1303        if ((dx | dy) == 0) {
1304            fScrollTestX = fScrollTestY = 0;
1305        } else {
1306            fScrollTestX += dx;
1307            fScrollTestY += dy;
1308        }
1309        this->inval(NULL);
1310        return true;
1311    }
1312
1313    switch (uni) {
1314        case 'd':
1315            SkGraphics::SetFontCacheUsed(0);
1316            return true;
1317        case 'f':
1318            // only
1319            fMeasureFPS = !fMeasureFPS;
1320            this->updateTitle();
1321            this->inval(NULL);
1322            break;
1323        case 'g':
1324            fRequestGrabImage = true;
1325            this->inval(NULL);
1326            break;
1327        case 'i':
1328            this->zoomIn();
1329            break;
1330        case 'o':
1331            this->zoomOut();
1332            break;
1333        case 'r':
1334            fRotate = !fRotate;
1335            this->inval(NULL);
1336            this->updateTitle();
1337            return true;
1338        case 'k':
1339            fPerspAnim = !fPerspAnim;
1340            this->inval(NULL);
1341            this->updateTitle();
1342            return true;
1343        case 's':
1344            fScale = !fScale;
1345            this->inval(NULL);
1346            this->updateTitle();
1347            return true;
1348        default:
1349            break;
1350    }
1351
1352    if (fAppMenu.handleKeyEquivalent(uni)|| fSlideMenu.handleKeyEquivalent(uni)) {
1353        this->onUpdateMenu(&fAppMenu);
1354        this->onUpdateMenu(&fSlideMenu);
1355        return true;
1356    }
1357    return this->INHERITED::onHandleChar(uni);
1358}
1359
1360void SampleWindow::setDeviceType(DeviceType type) {
1361    if (type != fDeviceType && fDevManager->supportsDeviceType(fDeviceType))
1362        fDeviceType = type;
1363    this->updateTitle();
1364    this->inval(NULL);
1365}
1366
1367void SampleWindow::toggleSlideshow() {
1368    fAnimating = !fAnimating;
1369    this->postAnimatingEvent();
1370    this->updateTitle();
1371}
1372
1373void SampleWindow::toggleRendering() {
1374    DeviceType origDevType = fDeviceType;
1375    do {
1376        fDeviceType = cycle_devicetype(fDeviceType);
1377    } while (origDevType != fDeviceType &&
1378             !fDevManager->supportsDeviceType(fDeviceType));
1379    this->updateTitle();
1380    this->inval(NULL);
1381}
1382
1383#include "SkDumpCanvas.h"
1384
1385bool SampleWindow::onHandleKey(SkKey key) {
1386    {
1387        SkView* view = curr_view(this);
1388        if (view) {
1389            SkEvent evt(gKeyEvtName);
1390            evt.setFast32(key);
1391            if (view->doQuery(&evt)) {
1392                return true;
1393            }
1394        }
1395    }
1396    switch (key) {
1397        case kRight_SkKey:
1398            if (this->nextSample()) {
1399                return true;
1400            }
1401            break;
1402        case kLeft_SkKey:
1403            toggleRendering();
1404            return true;
1405        case kUp_SkKey:
1406            if (USE_ARROWS_FOR_ZOOM) {
1407                this->changeZoomLevel(1.f);
1408            } else {
1409                fNClip = !fNClip;
1410                this->inval(NULL);
1411                this->updateTitle();
1412            }
1413            return true;
1414        case kDown_SkKey:
1415            if (USE_ARROWS_FOR_ZOOM) {
1416                this->changeZoomLevel(-1.f);
1417            } else {
1418                this->setConfig(cycle_configs(this->getBitmap().config()));
1419                this->updateTitle();
1420            }
1421            return true;
1422        case kOK_SkKey:
1423            if (false) {
1424                SkDebugfDumper dumper;
1425                SkDumpCanvas dc(&dumper);
1426                this->draw(&dc);
1427            } else {
1428                fRepeatDrawing = !fRepeatDrawing;
1429                if (fRepeatDrawing) {
1430                    this->inval(NULL);
1431                }
1432            }
1433            return true;
1434        case kBack_SkKey:
1435            this->showOverview();
1436            return true;
1437        default:
1438            break;
1439    }
1440    return this->INHERITED::onHandleKey(key);
1441}
1442
1443///////////////////////////////////////////////////////////////////////////////
1444
1445static const char gGestureClickType[] = "GestureClickType";
1446
1447bool SampleWindow::onDispatchClick(int x, int y, Click::State state,
1448        void* owner) {
1449    if (Click::kMoved_State == state) {
1450        updatePointer(x, y);
1451    }
1452    int w = SkScalarRound(this->width());
1453    int h = SkScalarRound(this->height());
1454
1455    // check for the resize-box
1456    if (w - x < 16 && h - y < 16) {
1457        return false;   // let the OS handle the click
1458    }
1459    else if (fMagnify) {
1460        //it's only necessary to update the drawing if there's a click
1461        this->inval(NULL);
1462        return false; //prevent dragging while magnify is enabled
1463    }
1464    else {
1465        return this->INHERITED::onDispatchClick(x, y, state, owner);
1466    }
1467}
1468
1469class GestureClick : public SkView::Click {
1470public:
1471    GestureClick(SkView* target) : SkView::Click(target) {
1472        this->setType(gGestureClickType);
1473    }
1474
1475    static bool IsGesture(Click* click) {
1476        return click->isType(gGestureClickType);
1477    }
1478};
1479
1480SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
1481    return new GestureClick(this);
1482}
1483
1484bool SampleWindow::onClick(Click* click) {
1485    if (GestureClick::IsGesture(click)) {
1486        float x = SkScalarToFloat(click->fCurr.fX);
1487        float y = SkScalarToFloat(click->fCurr.fY);
1488
1489        switch (click->fState) {
1490            case SkView::Click::kDown_State:
1491                fGesture.touchBegin(click->fOwner, x, y);
1492                break;
1493            case SkView::Click::kMoved_State:
1494                fGesture.touchMoved(click->fOwner, x, y);
1495                this->inval(NULL);
1496                break;
1497            case SkView::Click::kUp_State:
1498                fGesture.touchEnd(click->fOwner);
1499                this->inval(NULL);
1500                break;
1501        }
1502        return true;
1503    }
1504    return false;
1505}
1506
1507///////////////////////////////////////////////////////////////////////////////
1508
1509void SampleWindow::loadView(SkView* view) {
1510    SkView::F2BIter iter(this);
1511    SkView* prev = iter.next();
1512    if (prev) {
1513        prev->detachFromParent();
1514    }
1515
1516    view->setVisibleP(true);
1517    view->setClipToBounds(false);
1518    this->attachChildToFront(view)->unref();
1519    view->setSize(this->width(), this->height());
1520
1521    //repopulate the slide menu when a view is loaded
1522    fSlideMenu.reset();
1523#ifdef DEBUGGER
1524    if (!is_debugger(view) && !is_overview(view) && !is_transition(view) && fDebugger) {
1525        //Force Pipe to be on if using debugger
1526        fUsePipe = true;
1527    }
1528#endif
1529    (void)SampleView::SetUsePipe(view, fUsePipe);
1530    if (SampleView::IsSampleView(view))
1531        ((SampleView*)view)->requestMenu(&fSlideMenu);
1532    this->onUpdateMenu(&fSlideMenu);
1533    this->updateTitle();
1534}
1535
1536static const char* gConfigNames[] = {
1537    "unknown config",
1538    "A1",
1539    "A8",
1540    "Index8",
1541    "565",
1542    "4444",
1543    "8888"
1544};
1545
1546static const char* configToString(SkBitmap::Config c) {
1547    return gConfigNames[c];
1548}
1549
1550static const char* gDeviceTypePrefix[] = {
1551    "raster: ",
1552    "picture: ",
1553    "opengl: "
1554};
1555
1556static const char* trystate_str(SkOSMenu::TriState state,
1557                                const char trueStr[], const char falseStr[]) {
1558    if (SkOSMenu::kOnState == state) {
1559        return trueStr;
1560    } else if (SkOSMenu::kOffState == state) {
1561        return falseStr;
1562    }
1563    return NULL;
1564}
1565
1566void SampleWindow::updateTitle() {
1567    SkString title;
1568
1569    SkView::F2BIter iter(this);
1570    SkView* view = iter.next();
1571    SkEvent evt(gTitleEvtName);
1572    if (view->doQuery(&evt)) {
1573        title.set(evt.findString(gTitleEvtName));
1574    }
1575    if (title.size() == 0) {
1576        title.set("<unknown>");
1577    }
1578
1579    title.prepend(gDeviceTypePrefix[fDeviceType]);
1580
1581    title.prepend(" ");
1582    title.prepend(configToString(this->getBitmap().config()));
1583
1584    if (fAnimating) {
1585        title.prepend("<A> ");
1586    }
1587    if (fScale) {
1588        title.prepend("<S> ");
1589    }
1590    if (fRotate) {
1591        title.prepend("<R> ");
1592    }
1593    if (fNClip) {
1594        title.prepend("<C> ");
1595    }
1596    if (fPerspAnim) {
1597        title.prepend("<K> ");
1598    }
1599
1600    title.prepend(trystate_str(fLCDState, "LCD ", "lcd "));
1601    title.prepend(trystate_str(fAAState, "AA ", "aa "));
1602    title.prepend(trystate_str(fFilterState, "H ", "h "));
1603    title.prepend(fFlipAxis & kFlipAxis_X ? "X " : NULL);
1604    title.prepend(fFlipAxis & kFlipAxis_Y ? "Y " : NULL);
1605
1606    if (fZoomLevel) {
1607        title.prependf("{%.2f} ", SkScalarToFloat(fZoomLevel));
1608    }
1609
1610    if (fMeasureFPS) {
1611        title.appendf(" %6.1f ms", fMeasureFPS_Time / (float)FPS_REPEAT_MULTIPLIER);
1612    }
1613    if (fUsePipe && SampleView::IsSampleView(view)) {
1614        title.prepend("<P> ");
1615    }
1616    if (SampleView::IsSampleView(view)) {
1617        title.prepend("! ");
1618    }
1619
1620    this->setTitle(title.c_str());
1621}
1622
1623void SampleWindow::onSizeChange() {
1624    this->INHERITED::onSizeChange();
1625
1626    SkView::F2BIter iter(this);
1627    SkView* view = iter.next();
1628    view->setSize(this->width(), this->height());
1629
1630    // rebuild our clippath
1631    {
1632        const SkScalar W = this->width();
1633        const SkScalar H = this->height();
1634
1635        fClipPath.reset();
1636#if 0
1637        for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) {
1638            SkRect r;
1639            r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30));
1640            for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0))
1641                fClipPath.addRect(r);
1642        }
1643#else
1644        SkRect r;
1645        r.set(0, 0, W, H);
1646        fClipPath.addRect(r, SkPath::kCCW_Direction);
1647        r.set(W/4, H/4, W*3/4, H*3/4);
1648        fClipPath.addRect(r, SkPath::kCW_Direction);
1649#endif
1650    }
1651
1652    fZoomCenterX = SkScalarHalf(this->width());
1653    fZoomCenterY = SkScalarHalf(this->height());
1654
1655#ifdef ANDROID
1656    // FIXME: The first draw after a size change does not work on Android, so
1657    // we post an invalidate.
1658    this->postInvalDelay();
1659#endif
1660    this->updateTitle();    // to refresh our config
1661    fDevManager->windowSizeChanged(this);
1662}
1663
1664///////////////////////////////////////////////////////////////////////////////
1665
1666static const char is_sample_view_tag[] = "sample-is-sample-view";
1667static const char repeat_count_tag[] = "sample-set-repeat-count";
1668static const char set_use_pipe_tag[] = "sample-set-use-pipe";
1669
1670bool SampleView::IsSampleView(SkView* view) {
1671    SkEvent evt(is_sample_view_tag);
1672    return view->doQuery(&evt);
1673}
1674
1675bool SampleView::SetRepeatDraw(SkView* view, int count) {
1676    SkEvent evt(repeat_count_tag);
1677    evt.setFast32(count);
1678    return view->doEvent(evt);
1679}
1680
1681bool SampleView::SetUsePipe(SkView* view, bool pred) {
1682    SkEvent evt(set_use_pipe_tag);
1683    evt.setFast32(pred);
1684    return view->doEvent(evt);
1685}
1686
1687bool SampleView::onEvent(const SkEvent& evt) {
1688    if (evt.isType(repeat_count_tag)) {
1689        fRepeatCount = evt.getFast32();
1690        return true;
1691    }
1692    if (evt.isType(set_use_pipe_tag)) {
1693        fUsePipe = !!evt.getFast32();
1694        return true;
1695    }
1696    return this->INHERITED::onEvent(evt);
1697}
1698
1699bool SampleView::onQuery(SkEvent* evt) {
1700    if (evt->isType(is_sample_view_tag)) {
1701        return true;
1702    }
1703    return this->INHERITED::onQuery(evt);
1704}
1705
1706#ifdef TEST_GPIPE
1707    #include "SkGPipe.h"
1708
1709class SimplePC : public SkGPipeController {
1710public:
1711    SimplePC(SkCanvas* target);
1712    ~SimplePC();
1713
1714    /**
1715     * User this method to halt/restart pipe
1716     */
1717    void setWriteToPipe(bool writeToPipe) { fWriteToPipe = writeToPipe; }
1718    virtual void* requestBlock(size_t minRequest, size_t* actual);
1719    virtual void notifyWritten(size_t bytes);
1720
1721private:
1722    SkGPipeReader   fReader;
1723    void*           fBlock;
1724    size_t          fBlockSize;
1725    size_t          fBytesWritten;
1726    int             fAtomsWritten;
1727    SkGPipeReader::Status   fStatus;
1728    bool            fWriteToPipe;
1729
1730    size_t        fTotalWritten;
1731};
1732
1733SimplePC::SimplePC(SkCanvas* target) : fReader(target) {
1734    fBlock = NULL;
1735    fBlockSize = fBytesWritten = 0;
1736    fStatus = SkGPipeReader::kDone_Status;
1737    fTotalWritten = 0;
1738    fAtomsWritten = 0;
1739    fWriteToPipe = true;
1740}
1741
1742SimplePC::~SimplePC() {
1743//    SkASSERT(SkGPipeReader::kDone_Status == fStatus);
1744    if (fTotalWritten) {
1745        if (fWriteToPipe) {
1746            SkDebugf("--- %d bytes %d atoms, status %d\n", fTotalWritten,
1747                     fAtomsWritten, fStatus);
1748#ifdef  PIPE_FILE
1749            //File is open in append mode
1750            FILE* f = fopen(FILE_PATH, "ab");
1751            SkASSERT(f != NULL);
1752            fwrite((const char*)fBlock + fBytesWritten, 1, bytes, f);
1753            fclose(f);
1754#endif
1755#ifdef PIPE_NET
1756            if (fAtomsWritten > 1 && fTotalWritten > 4) { //ignore done
1757                gServer.acceptConnections();
1758                gServer.writePacket(fBlock, fTotalWritten);
1759            }
1760#endif
1761#ifdef  DEBUGGER
1762            gTempDataStore.reset();
1763            gTempDataStore.append(fTotalWritten, (const char*)fBlock);
1764#endif
1765        }
1766    }
1767    sk_free(fBlock);
1768}
1769
1770void* SimplePC::requestBlock(size_t minRequest, size_t* actual) {
1771    sk_free(fBlock);
1772
1773    fBlockSize = minRequest * 4;
1774    fBlock = sk_malloc_throw(fBlockSize);
1775    fBytesWritten = 0;
1776    *actual = fBlockSize;
1777    return fBlock;
1778}
1779
1780void SimplePC::notifyWritten(size_t bytes) {
1781    SkASSERT(fBytesWritten + bytes <= fBlockSize);
1782    fStatus = fReader.playback((const char*)fBlock + fBytesWritten, bytes);
1783    SkASSERT(SkGPipeReader::kError_Status != fStatus);
1784    fBytesWritten += bytes;
1785    fTotalWritten += bytes;
1786
1787    fAtomsWritten += 1;
1788}
1789
1790#endif
1791
1792void SampleView::draw(SkCanvas* canvas) {
1793#ifdef TEST_GPIPE
1794    if (fUsePipe) {
1795        SkGPipeWriter writer;
1796        SimplePC controller(canvas);
1797        uint32_t flags = SkGPipeWriter::kCrossProcess_Flag;
1798        canvas = writer.startRecording(&controller, flags);
1799        //Must draw before controller goes out of scope and sends data
1800        this->INHERITED::draw(canvas);
1801        //explicitly end recording to ensure writer is flushed before the memory
1802        //is freed in the deconstructor of the controller
1803        writer.endRecording();
1804        controller.setWriteToPipe(fUsePipe);
1805    }
1806    else
1807        this->INHERITED::draw(canvas);
1808#else
1809    this->INHERITED::draw(canvas);
1810#endif
1811}
1812void SampleView::onDraw(SkCanvas* canvas) {
1813    this->onDrawBackground(canvas);
1814
1815    for (int i = 0; i < fRepeatCount; i++) {
1816        SkAutoCanvasRestore acr(canvas, true);
1817        this->onDrawContent(canvas);
1818    }
1819}
1820
1821void SampleView::onDrawBackground(SkCanvas* canvas) {
1822    canvas->drawColor(fBGColor);
1823}
1824
1825///////////////////////////////////////////////////////////////////////////////
1826
1827template <typename T> void SkTBSort(T array[], int count) {
1828    for (int i = 1; i < count - 1; i++) {
1829        bool didSwap = false;
1830        for (int j = count - 1; j > i; --j) {
1831            if (array[j] < array[j-1]) {
1832                T tmp(array[j-1]);
1833                array[j-1] = array[j];
1834                array[j] = tmp;
1835                didSwap = true;
1836            }
1837        }
1838        if (!didSwap) {
1839            break;
1840        }
1841    }
1842
1843    for (int k = 0; k < count - 1; k++) {
1844        SkASSERT(!(array[k+1] < array[k]));
1845    }
1846}
1847
1848#include "SkRandom.h"
1849
1850static void rand_rect(SkIRect* rect, SkRandom& rand) {
1851    int bits = 8;
1852    int shift = 32 - bits;
1853    rect->set(rand.nextU() >> shift, rand.nextU() >> shift,
1854              rand.nextU() >> shift, rand.nextU() >> shift);
1855    rect->sort();
1856}
1857
1858static void dumpRect(const SkIRect& r) {
1859    SkDebugf(" { %d, %d, %d, %d },\n",
1860             r.fLeft, r.fTop,
1861             r.fRight, r.fBottom);
1862}
1863
1864static void test_rects(const SkIRect rect[], int count) {
1865    SkRegion rgn0, rgn1;
1866
1867    for (int i = 0; i < count; i++) {
1868        rgn0.op(rect[i], SkRegion::kUnion_Op);
1869     //   dumpRect(rect[i]);
1870    }
1871    rgn1.setRects(rect, count);
1872
1873    if (rgn0 != rgn1) {
1874        SkDebugf("\n");
1875        for (int i = 0; i < count; i++) {
1876            dumpRect(rect[i]);
1877        }
1878        SkDebugf("\n");
1879    }
1880}
1881
1882static void test() {
1883    size_t i;
1884
1885    const SkIRect r0[] = {
1886        { 0, 0, 1, 1 },
1887        { 2, 2, 3, 3 },
1888    };
1889    const SkIRect r1[] = {
1890        { 0, 0, 1, 3 },
1891        { 1, 1, 2, 2 },
1892        { 2, 0, 3, 3 },
1893    };
1894    const SkIRect r2[] = {
1895        { 0, 0, 1, 2 },
1896        { 2, 1, 3, 3 },
1897        { 4, 0, 5, 1 },
1898        { 6, 0, 7, 4 },
1899    };
1900
1901    static const struct {
1902        const SkIRect* fRects;
1903        int            fCount;
1904    } gRecs[] = {
1905        { r0, SK_ARRAY_COUNT(r0) },
1906        { r1, SK_ARRAY_COUNT(r1) },
1907        { r2, SK_ARRAY_COUNT(r2) },
1908    };
1909
1910    for (i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
1911        test_rects(gRecs[i].fRects, gRecs[i].fCount);
1912    }
1913
1914    SkRandom rand;
1915    for (i = 0; i < 10000; i++) {
1916        SkRegion rgn0, rgn1;
1917
1918        const int N = 8;
1919        SkIRect rect[N];
1920        for (int j = 0; j < N; j++) {
1921            rand_rect(&rect[j], rand);
1922        }
1923        test_rects(rect, N);
1924    }
1925}
1926
1927SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
1928//    test();
1929    return new SampleWindow(hwnd, argc, argv, NULL);
1930}
1931
1932void get_preferred_size(int* x, int* y, int* width, int* height) {
1933    *x = 10;
1934    *y = 50;
1935    *width = 640;
1936    *height = 480;
1937}
1938
1939void application_init() {
1940//    setenv("ANDROID_ROOT", "../../../data", 0);
1941#ifdef SK_BUILD_FOR_MAC
1942    setenv("ANDROID_ROOT", "/android/device/data", 0);
1943#endif
1944    SkGraphics::Init();
1945    SkEvent::Init();
1946}
1947
1948void application_term() {
1949    SkEvent::Term();
1950    SkGraphics::Term();
1951}
1952