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