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