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