merge with changes for GPU backend



git-svn-id: http://skia.googlecode.com/svn/trunk@637 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index 3c7be4c..1eaa46d 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -44,8 +44,10 @@
     this->INHERITED::endSession();
 }
 
-bool SkBitmapProcShader::asABitmap(SkBitmap* texture, SkMatrix* texM,
-                                   TileMode xy[]) {
+SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture, 
+                                                   SkMatrix* texM, 
+                                                   TileMode xy[],
+                                                   SkScalar* twoPointRadialParams) {
     if (texture) {
         *texture = fRawBitmap;
     }
@@ -56,7 +58,7 @@
         xy[0] = (TileMode)fState.fTileModeX;
         xy[1] = (TileMode)fState.fTileModeY;
     }
-    return true;
+    return kDefault_BitmapType;
 }
 
 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) {
@@ -82,7 +84,7 @@
 
     fState.fOrigBitmap = fRawBitmap;
     fState.fOrigBitmap.lockPixels();
-    if (!fState.fOrigBitmap.readyToDraw()) {
+    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
         fState.fOrigBitmap.unlockPixels();
         return false;
     }
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index 09d53af..88598fc 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -32,7 +32,8 @@
     virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
     virtual void beginSession();
     virtual void endSession();
-    virtual bool asABitmap(SkBitmap*, SkMatrix*, TileMode*);
+    virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*, 
+                                 SkScalar* twoPointRadialParams);
 
     static bool CanDo(const SkBitmap&, TileMode tx, TileMode ty);
 
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index 905ab6b..88b9491 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -40,6 +40,32 @@
 
 //////////////////////////////////////////////////////////////////////////////////////
 
+static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
+							const SkIRect& clip, SkPMColor srcColor) {
+	U8CPU alpha = SkGetPackedA32(srcColor);
+	unsigned flags = SkBlitRow::kSrcPixelAlpha_Flag32;
+	if (alpha != 255) {
+		flags |= SkBlitRow::kGlobalAlpha_Flag32;
+	}
+	SkBlitRow::Proc32 proc = SkBlitRow::Factory32(flags);
+
+    int x = clip.fLeft;
+    int y = clip.fTop;
+    int width = clip.width();
+    int height = clip.height();
+	
+    SkPMColor*		 dstRow = device.getAddr32(x, y);
+    const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr(x, y));
+
+    do {
+		proc(dstRow, srcRow, width, alpha);
+        dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
+        srcRow = (const SkPMColor*)((const char*)srcRow + mask.fRowBytes);
+    } while (--height != 0);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
 SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
         : INHERITED(device) {
     uint32_t color = paint.getColor();
@@ -156,6 +182,9 @@
     if (mask.fFormat == SkMask::kBW_Format) {
         SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
         return;
+    } else if (SkMask::kARGB32_Format == mask.fFormat) {
+		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
+		return;
     }
 
     int x = clip.fLeft;
@@ -188,7 +217,10 @@
     if (mask.fFormat == SkMask::kBW_Format) {
         SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
         return;
-    }
+    } else if (SkMask::kARGB32_Format == mask.fFormat) {
+		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
+		return;
+	}
 
     int x = clip.fLeft;
     int y = clip.fTop;
@@ -306,6 +338,8 @@
         SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
 
         SkARGB32_BlitBW(fDevice, mask, clip, black);
+    } else if (SkMask::kARGB32_Format == mask.fFormat) {
+		SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
     } else {
 #if defined(SK_SUPPORT_LCDTEXT)
         const bool      lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 5a855bb..0e36c91 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -74,6 +74,9 @@
     const SkMatrix*     fMatrix;
 	SkPaint*			fPaint;	// may be null (in the future)
     int16_t             fX, fY; // relative to base matrix/clip
+    // optional, related to canvas' external matrix
+    const SkMatrix*     fMVMatrix;
+    const SkMatrix*     fExtMatrix;
 
 	DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
             : fNext(NULL) {
@@ -132,8 +135,18 @@
             SkASSERT(deviceR.contains(fClip.getBounds()));
         }
 #endif
+        // default is to assume no external matrix
+        fMVMatrix = NULL;
+        fExtMatrix = NULL;
     }
-    
+
+    // can only be called after calling updateMC()
+    void updateExternalMatrix(const SkMatrix& extM, const SkMatrix& extI) {
+        fMVMatrixStorage.setConcat(extI, *fMatrix);
+        fMVMatrix = &fMVMatrixStorage;
+        fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas)
+    }
+
     void translateClip() {
         if (fX | fY) {
             fClip.translate(fX, fY);
@@ -141,7 +154,7 @@
     }
 
 private:
-    SkMatrix    fMatrixStorage;
+    SkMatrix    fMatrixStorage, fMVMatrixStorage;
 };
 
 /*  This is the record we keep for each save/restore level in the stack.
@@ -240,16 +253,17 @@
             fLayerX = rec->fX;
             fLayerY = rec->fY;
             fPaint  = rec->fPaint;
-            SkDEBUGCODE(this->validate(fDevice->width(), fDevice->height());)
+            fMVMatrix = rec->fMVMatrix;
+            fExtMatrix = rec->fExtMatrix;
+            SkDEBUGCODE(this->validate();)
 
             fCurrLayer = rec->fNext;
             if (fBounder) {
                 fBounder->setClip(fClip);
             }
-
             // fCurrLayer may be NULL now
 
-            fCanvas->prepareForDeviceDraw(fDevice);
+            fCanvas->prepareForDeviceDraw(fDevice, *fMatrix, *fClip);
             return true;
         }
         return false;
@@ -401,6 +415,8 @@
     fMCRec->fTopLayer = fMCRec->fLayer;
     fMCRec->fNext = NULL;
 
+    fUseExternalMatrix = false;
+
     return this->setDevice(device);
 }
 
@@ -427,7 +443,7 @@
         : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
     inc_canvas();
 
-    SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
+    SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
     fDeviceFactory = device->getDeviceFactory();
     this->init(device)->unref();
 }
@@ -527,8 +543,8 @@
     return device;
 }
 
-SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
-    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
+SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap, bool forLayer) {
+    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (this, bitmap, forLayer)));
     device->unref();
     return device;
 }
@@ -546,8 +562,9 @@
 bool SkCanvas::setViewport(int width, int height) {
     if ((getDevice()->getDeviceCapabilities() & SkDevice::kGL_Capability) == 0)
         return false;
-    this->setDevice(createDevice(SkBitmap::kARGB_8888_Config, width, height,
-                                 false, false))->unref();
+
+    this->setDevice(this->createDevice(SkBitmap::kARGB_8888_Config, width, height,
+                                       false, false))->unref();
     return true;
 }
 
@@ -559,21 +576,30 @@
         
         if (NULL == layer->fNext) {   // only one layer
             layer->updateMC(totalMatrix, totalClip, NULL);
+            if (fUseExternalMatrix) {
+                layer->updateExternalMatrix(fExternalMatrix,
+                                            fExternalInverse);
+            }
         } else {
             SkRegion clip;
             clip = totalClip;  // make a copy
             do {
                 layer->updateMC(totalMatrix, clip, &clip);
+                if (fUseExternalMatrix) {
+                    layer->updateExternalMatrix(fExternalMatrix,
+                                                fExternalInverse);
+                }
             } while ((layer = layer->fNext) != NULL);
         }
         fDeviceCMDirty = false;
     }
 }
 
-void SkCanvas::prepareForDeviceDraw(SkDevice* device) {
+void SkCanvas::prepareForDeviceDraw(SkDevice* device, const SkMatrix& matrix,
+                                    const SkRegion& clip) {
     SkASSERT(device);
     if (fLastDeviceToGainFocus != device) {
-        device->gainFocus(this);
+        device->gainFocus(this, matrix, clip);
         fLastDeviceToGainFocus = device;
     }
 }
@@ -651,6 +677,9 @@
 
     SkIRect         ir;
     const SkIRect&  clipBounds = this->getTotalClip().getBounds();
+    if (clipBounds.isEmpty()) {
+        return count;
+    }
 
     if (NULL != bounds) {
         SkRect r;
@@ -760,7 +789,7 @@
             bitmap.width() > 32767 || bitmap.height() > 32767;
 }
 
-void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
+void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
                                 const SkMatrix& matrix, const SkPaint* paint) {
     if (reject_bitmap(bitmap)) {
         return;
@@ -768,9 +797,9 @@
 
     if (NULL == paint) {
         SkPaint tmpPaint;
-        this->commonDrawBitmap(bitmap, matrix, tmpPaint);
+        this->commonDrawBitmap(bitmap, srcRect, matrix, tmpPaint);
     } else {
-        this->commonDrawBitmap(bitmap, matrix, *paint);
+        this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
     }
 }
 
@@ -1023,13 +1052,30 @@
     return *fMCRec->fRegion;
 }
 
-///////////////////////////////////////////////////////////////////////////////
+void SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
+    if (NULL == matrix || matrix->isIdentity()) {
+        if (fUseExternalMatrix) {
+            fDeviceCMDirty = true;
+        }
+        fUseExternalMatrix = false;
+    } else {
+        fUseExternalMatrix = true;
+        fDeviceCMDirty = true;  // |= (fExternalMatrix != *matrix)
+        
+        fExternalMatrix = *matrix;
+        matrix->invert(&fExternalInverse);
+    }
+    
+    static bool gUseExt;
+    if (gUseExt != fUseExternalMatrix && false) {
+        gUseExt = fUseExternalMatrix;
+        printf("---- fUseExternalMatrix = %d\n", fUseExternalMatrix);
+    }
+}
 
-SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width,
-                                 int height, bool isOpaque, bool isForLayer) {
-
-    return fDeviceFactory->newDevice(config, width, height, isOpaque,
-                                     isForLayer);
+SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, int height,
+                                 bool isOpaque, bool forLayer) {
+    return fDeviceFactory->newDevice(this, config, width, height, isOpaque, forLayer);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1116,7 +1162,7 @@
         
     SkMatrix matrix;
     matrix.setTranslate(x, y);
-    this->internalDrawBitmap(bitmap, matrix, paint);
+    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
 }
 
 void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
@@ -1130,15 +1176,7 @@
         return;
     }
     
-    SkBitmap        tmp;    // storage if we need a subset of bitmap
     const SkBitmap* bitmapPtr = &bitmap;
-
-    if (NULL != src) {
-        if (!bitmap.extractSubset(&tmp, *src)) {
-            return;     // extraction failed
-        }
-        bitmapPtr = &tmp;
-    }
     
     SkMatrix matrix;
     SkRect tmpSrc;
@@ -1159,23 +1197,32 @@
                    SkIntToScalar(bitmap.height()));
     }
     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
-    this->internalDrawBitmap(*bitmapPtr, matrix, paint);
+
+    // ensure that src is "valid" before we pass it to our internal routines
+    // and to SkDevice. i.e. sure it is contained inside the original bitmap.
+    SkIRect tmpISrc;
+    if (src) {
+        tmpISrc.set(0, 0, bitmap.width(), bitmap.height());
+        tmpISrc.intersect(*src);
+        src = &tmpISrc;
+    }
+    this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
 }
 
 void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
                                 const SkPaint* paint) {
     SkDEBUGCODE(bitmap.validate();)
-    this->internalDrawBitmap(bitmap, matrix, paint);
+    this->internalDrawBitmap(bitmap, NULL, matrix, paint);
 }
 
-void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
-                                const SkPaint& paint) {
+void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
+                                const SkMatrix& matrix, const SkPaint& paint) {
     SkDEBUGCODE(bitmap.validate();)
 
     ITER_BEGIN(paint, SkDrawFilter::kBitmap_Type)
 
     while (iter.next()) {
-        iter.fDevice->drawBitmap(iter, bitmap, matrix, paint);
+        iter.fDevice->drawBitmap(iter, bitmap, srcRect, matrix, paint);
     }
 
     ITER_END
diff --git a/src/core/SkChunkAlloc.cpp b/src/core/SkChunkAlloc.cpp
index 90a0c2a..e0c03a8 100644
--- a/src/core/SkChunkAlloc.cpp
+++ b/src/core/SkChunkAlloc.cpp
@@ -49,6 +49,11 @@
         }
         return block;
     }
+
+    bool contains(const void* addr) const {
+        const char* ptr = reinterpret_cast<const char*>(addr);
+        return ptr >= (const char*)(this + 1) && ptr < fFreePtr;
+    }
 };
 
 SkChunkAlloc::SkChunkAlloc(size_t minSize)
@@ -139,3 +144,14 @@
     return bytes;
 }
 
+bool SkChunkAlloc::contains(const void* addr) const {
+    const Block* block = fBlock;
+    while (block) {
+        if (block->contains(addr)) {
+            return true;
+        }
+        block = block->fNext;
+    }
+    return false;
+}
+
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 12efaac..8df0e41 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -4,9 +4,20 @@
 
 SkDeviceFactory::~SkDeviceFactory() {}
 
-SkDevice::SkDevice() {}
+SkDevice::SkDevice(SkCanvas* canvas) : fCanvas(canvas) {}
 
-SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {}
+SkDevice::SkDevice(SkCanvas* canvas, const SkBitmap& bitmap, bool isForLayer)
+        : fCanvas(canvas), fBitmap(bitmap) {
+    // auto-allocate if we're for offscreen drawing
+    if (isForLayer) {
+        if (NULL == fBitmap.getPixels() && NULL == fBitmap.pixelRef()) {
+            fBitmap.allocPixels();   
+            if (!fBitmap.isOpaque()) {
+                fBitmap.eraseColor(0);
+            }
+        }
+    }
+}
 
 void SkDevice::lockPixels() {
     fBitmap.lockPixels();
@@ -47,6 +58,39 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+bool SkDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
+    const SkBitmap& src = this->accessBitmap(false);
+
+    SkIRect bounds;
+    bounds.set(0, 0, src.width(), src.height());
+    if (!bounds.intersect(srcRect)) {
+        return false;
+    }
+
+    SkBitmap subset;
+    if (!src.extractSubset(&subset, bounds)) {
+        return false;
+    }
+
+    SkBitmap tmp;
+    if (!subset.copyTo(&tmp, SkBitmap::kARGB_8888_Config)) {
+        return false;
+    }
+
+    tmp.swap(*bitmap);
+    return true;
+}
+
+void SkDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
+    SkPaint paint;
+    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+
+    SkCanvas canvas(this);
+    canvas.drawSprite(bitmap, x, y, &paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
     draw.drawPaint(paint);
 }
@@ -62,13 +106,24 @@
 }
 
 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
-                            const SkPaint& paint) {
-    draw.drawPath(path, paint);
+                        const SkPaint& paint, const SkMatrix* prePathMatrix,
+                        bool pathIsMutable) {
+    draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
 }
 
 void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
-                              const SkMatrix& matrix, const SkPaint& paint) {
-    draw.drawBitmap(bitmap, matrix, paint);
+                          const SkIRect* srcRect,
+                          const SkMatrix& matrix, const SkPaint& paint) {
+    SkBitmap        tmp;    // storage if we need a subset of bitmap
+    const SkBitmap* bitmapPtr = &bitmap;
+    
+    if (srcRect) {
+        if (!bitmap.extractSubset(&tmp, *srcRect)) {
+            return;     // extraction failed
+        }
+        bitmapPtr = &tmp;
+    }
+    draw.drawBitmap(*bitmapPtr, matrix, paint);
 }
 
 void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
@@ -109,16 +164,15 @@
     draw.drawSprite(device->accessBitmap(false), x, y, paint);
 }
 
-SkDevice* SkRasterDeviceFactory::newDevice(SkBitmap::Config config, int width,
+///////////////////////////////////////////////////////////////////////////////
+
+SkDevice* SkRasterDeviceFactory::newDevice(SkCanvas* canvas,
+                                           SkBitmap::Config config, int width,
                                            int height, bool isOpaque,
                                            bool isForLayer) {
     SkBitmap bitmap;
     bitmap.setConfig(config, width, height);
     bitmap.setIsOpaque(isOpaque);
 
-    bitmap.allocPixels();
-    if (!bitmap.isOpaque())
-        bitmap.eraseARGB(0, 0, 0, 0);
-
-    return SkNEW_ARGS(SkDevice, (bitmap));
+    return SkNEW_ARGS(SkDevice, (canvas, bitmap, isForLayer));
 }
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index eff2b32..a117ab7 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -143,6 +143,10 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+SkDraw::SkDraw() {
+    sk_bzero(this, sizeof(*this));
+}
+
 SkDraw::SkDraw(const SkDraw& src) {
     memcpy(this, &src, sizeof(*this));
 }
@@ -276,7 +280,7 @@
 }
 
 void SkDraw::drawPaint(const SkPaint& paint) const {
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
 
     if (fClip->isEmpty()) {
         return;
@@ -540,7 +544,8 @@
 #define MAX_DEV_PTS     32
 
 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
-                        const SkPoint pts[], const SkPaint& paint) const {
+                        const SkPoint pts[], const SkPaint& paint,
+                        bool forceUseDevice) const {
     // if we're in lines mode, force count to be even
     if (SkCanvas::kLines_PointMode == mode) {
         count &= ~(size_t)1;
@@ -563,7 +568,7 @@
     }
 
     SkASSERT(pts != NULL);
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
     
      // nothing to draw
     if (fClip->isEmpty() ||
@@ -572,7 +577,7 @@
     }
 
     PtProcRec rec;
-    if (rec.init(mode, paint, fMatrix, fClip)) {
+    if (!forceUseDevice && rec.init(mode, paint, fMatrix, fClip)) {
         SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
 
         SkPoint             devPts[MAX_DEV_PTS];
@@ -614,7 +619,12 @@
                         preMatrix.setTranslate(pts[i].fX, pts[i].fY);
                         // pass true for the last point, since we can modify
                         // then path then
-                        this->drawPath(path, paint, &preMatrix, (count-1) == i);
+                        if (fDevice) {
+                            fDevice->drawPath(*this, path, paint, &preMatrix,
+                                              (count-1) == i);
+                        } else {
+                            this->drawPath(path, paint, &preMatrix, (count-1) == i);
+                        }
                     }
                 } else {
                     SkRect  r;
@@ -624,7 +634,11 @@
                         r.fTop = pts[i].fY - radius;
                         r.fRight = r.fLeft + width;
                         r.fBottom = r.fTop + width;
-                        this->drawRect(r, paint);
+                        if (fDevice) {
+                            fDevice->drawRect(*this, r, paint);
+                        } else {
+                            this->drawRect(r, paint);
+                        }
                     }
                 }
                 break;
@@ -639,7 +653,11 @@
                 for (size_t i = 0; i < count; i += inc) {
                     path.moveTo(pts[i]);
                     path.lineTo(pts[i+1]);
-                    this->drawPath(path, p, NULL, true);
+                    if (fDevice) {
+                        fDevice->drawPath(*this, path, p, NULL, true);
+                    } else {
+                        this->drawPath(path, p, NULL, true);
+                    }
                     path.rewind();
                 }
                 break;
@@ -657,7 +675,7 @@
 }
 
 void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
 
     // nothing to draw
     if (fClip->isEmpty() ||
@@ -799,7 +817,7 @@
 
 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint,
                       const SkMatrix* prePathMatrix, bool pathIsMutable) const {
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
 
     // nothing to draw
     if (fClip->isEmpty() ||
@@ -846,7 +864,8 @@
     // can we approximate a thin (but not hairline) stroke with an alpha-modulated
     // hairline? Only if the matrix scales evenly in X and Y, and the device-width is
     // less than a pixel
-    if (paint.getStyle() == SkPaint::kStroke_Style && paint.getXfermode() == NULL) {
+    if (paint.isAntiAlias() &&
+        paint.getStyle() == SkPaint::kStroke_Style && paint.getXfermode() == NULL) {
         SkScalar width = paint.getStrokeWidth();
         if (width > 0 && map_radius(*matrix, &width)) {
             int scale = (int)SkScalarMul(width, 256);
@@ -1024,7 +1043,7 @@
 
 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
                         const SkPaint& paint) const {
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
 
     // nothing to draw
     if (fClip->isEmpty() ||
@@ -1116,7 +1135,7 @@
 
 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
                         const SkPaint& paint) const {
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
     
     // nothing to draw
     if (fClip->isEmpty() ||
@@ -1207,7 +1226,7 @@
 void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
                               SkScalar x, SkScalar y,
                               const SkPaint& paint) const {
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
 
     SkTextToPathIter iter(text, byteLength, paint, true, true);
 
@@ -1220,7 +1239,12 @@
 
     while ((iterPath = iter.next(&xpos)) != NULL) {
         matrix.postTranslate(xpos - prevXPos, 0);
-        this->drawPath(*iterPath, iter.getPaint(), &matrix, false);
+        const SkPaint& pnt = iter.getPaint();
+        if (fDevice) {
+            fDevice->drawPath(*this, *iterPath, pnt, &matrix, false);
+        } else {
+            this->drawPath(*iterPath, pnt, &matrix, false);
+        }
         prevXPos = xpos;
     }
 }
@@ -1275,7 +1299,10 @@
 //////////////////////////////////////////////////////////////////////////////
 
 static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
-								   const SkGlyph& glyph, int left, int top) {
+                                   SkFixed fx, SkFixed fy,
+                                   const SkGlyph& glyph) {
+    int left = SkFixedFloor(fx);
+    int top = SkFixedFloor(fy);
     SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
 	SkASSERT(state.fClip->isRect());
 	SkASSERT(NULL == state.fBounder);
@@ -1316,7 +1343,10 @@
 }
 
 static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state,
-								  const SkGlyph& glyph, int left, int top) {
+                                  SkFixed fx, SkFixed fy,
+								  const SkGlyph& glyph) {
+    int left = SkFixedFloor(fx);
+    int top = SkFixedFloor(fy);
     SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
 	SkASSERT(!state.fClip->isRect());
 	SkASSERT(NULL == state.fBounder);
@@ -1350,7 +1380,10 @@
 }
 
 static void D1G_Bounder(const SkDraw1Glyph& state,
-						const SkGlyph& glyph, int left, int top) {
+                        SkFixed fx, SkFixed fy,
+						const SkGlyph& glyph) {
+    int left = SkFixedFloor(fx);
+    int top = SkFixedFloor(fy);
     SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
 
     SkMask  mask;
@@ -1435,7 +1468,7 @@
                       SkScalar x, SkScalar y, const SkPaint& paint) const {
     SkASSERT(byteLength == 0 || text != NULL);
 
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
 
     // nothing to draw
     if (text == NULL || byteLength == 0 ||
@@ -1470,14 +1503,25 @@
 
     SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
 
-    SkAutoGlyphCache    autoCache(paint, fMatrix);
+    const SkMatrix* matrix = fMatrix;
+    SkFixed finalFYMask = ~0xFFFF;  // trunc fy;
+    if (fProcs && fProcs->fD1GProc) {
+        // only support the fMVMatrix (for now) for the GPU case, which also
+        // sets the fD1GProc
+        if (fMVMatrix) {
+            matrix = fMVMatrix;
+            finalFYMask = ~0;  // don't truncate
+        }
+    }
+
+    SkAutoGlyphCache    autoCache(paint, matrix);
     SkGlyphCache*       cache = autoCache.getCache();
-    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+    SkAutoBlitterChoose blitter(*fBitmap, *matrix, paint);
     
     // transform our starting point
     {
         SkPoint loc;
-        fMatrix->mapXY(x, y, &loc);
+        matrix->mapXY(x, y, &loc);
         x = loc.fX;
         y = loc.fY;
     }
@@ -1503,30 +1547,33 @@
     SkFixed fy = SkScalarToFixed(y);
     const char* stop = text + byteLength;
 
+    SkFixed fxMask = ~0;
+    SkFixed fyMask = ~0;
     if (paint.isSubpixelText()) {
-        RoundBaseline roundBaseline = computeRoundBaseline(*fMatrix);
+        RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
         if (kRound_Y_Baseline == roundBaseline) {
-            fy = (fy + 0x8000) & ~0xFFFF;
+            fyMask = 0;
+//            fy = (fy + 0x8000) & ~0xFFFF;
         } else if (kRound_X_Baseline == roundBaseline) {
-            fx = (fx + 0x8000) & ~0xFFFF;
+            fxMask = 0;
         }
-    } else {
-        // apply the bias here, so we don't have to add 1/2 in the loop
-        fx += SK_Fixed1/2;
-        fy += SK_Fixed1/2;
     }
+    // apply the bias here, so we don't have to add 1/2 in the loop
+    fx += SK_FixedHalf;
+    fy += SK_FixedHalf;
+    fy &= finalFYMask;
 
     SkAutoKern          autokern;
 	SkDraw1Glyph        d1g;
 	SkDraw1Glyph::Proc  proc = d1g.init(this, blitter.get(), cache);
 
     while (text < stop) {
-        const SkGlyph& glyph  = glyphCacheProc(cache, &text, fx, fy);
+        const SkGlyph& glyph  = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
 
         fx += autokern.adjust(glyph);
 
         if (glyph.fWidth) {
-			proc(d1g, glyph, SkFixedFloor(fx), SkFixedFloor(fy));
+			proc(d1g, fx, fy, glyph);
         }
         fx += glyph.fAdvanceX;
         fy += glyph.fAdvanceY;
@@ -1636,7 +1683,7 @@
     SkASSERT(byteLength == 0 || text != NULL);
     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
 
-    SkDEBUGCODE(this->validate(fBitmap->width(), fBitmap->height());)
+    SkDEBUGCODE(this->validate();)
 
     // nothing to draw
     if (text == NULL || byteLength == 0 ||
@@ -1652,39 +1699,52 @@
         return;
     }
 
+    const SkMatrix* matrix = fMatrix;
+    if (fProcs && fProcs->fD1GProc) {
+        // only support the fMVMatrix (for now) for the GPU case, which also
+        // sets the fD1GProc
+        if (fMVMatrix) {
+            matrix = fMVMatrix;
+        }
+    }
+    
     SkDrawCacheProc     glyphCacheProc = paint.getDrawCacheProc();
-    SkAutoGlyphCache    autoCache(paint, fMatrix);
+    SkAutoGlyphCache    autoCache(paint, matrix);
     SkGlyphCache*       cache = autoCache.getCache();
-    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+    SkAutoBlitterChoose blitter(*fBitmap, *matrix, paint);
     
     const char*        stop = text + byteLength;
     AlignProc          alignProc = pick_align_proc(paint.getTextAlign());
 	SkDraw1Glyph	   d1g;
 	SkDraw1Glyph::Proc  proc = d1g.init(this, blitter.get(), cache);
-    TextMapState       tms(*fMatrix, constY);
+    TextMapState       tms(*matrix, constY);
     TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
 
     if (paint.isSubpixelText()) {
         // maybe we should skip the rounding if linearText is set
-        RoundBaseline roundBaseline = computeRoundBaseline(*fMatrix);
+        RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
 
         if (SkPaint::kLeft_Align == paint.getTextAlign()) {
             while (text < stop) {
+                
                 tmsProc(tms, pos);
                 
                 SkFixed fx = SkScalarToFixed(tms.fLoc.fX);
                 SkFixed fy = SkScalarToFixed(tms.fLoc.fY);
+                SkFixed fxMask = ~0;
+                SkFixed fyMask = ~0;
 
                 if (kRound_Y_Baseline == roundBaseline) {
-                    fy = (fy + 0x8000) & ~0xFFFF;
+                    fyMask = 0;
                 } else if (kRound_X_Baseline == roundBaseline) {
-                    fx = (fx + 0x8000) & ~0xFFFF;
+                    fxMask = 0;
                 }
                 
-                const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy);
+                const SkGlyph& glyph = glyphCacheProc(cache, &text,
+                                                      fx & fxMask, fy & fyMask);
                 
                 if (glyph.fWidth) {
-                    proc(d1g, glyph, SkFixedFloor(fx), SkFixedFloor(fy));
+                    proc(d1g, fx, fy, glyph);
                 }
                 pos += scalarsPerPosition;
             }
@@ -1697,6 +1757,8 @@
                     SkDEBUGCODE(SkFixed prevAdvY = glyph->fAdvanceY;)
 
                     SkFixed fx, fy;
+                    SkFixed fxMask = ~0;
+                    SkFixed fyMask = ~0;
                     tmsProc(tms, pos);
                     
                     {
@@ -1706,19 +1768,19 @@
                         fy = fixedLoc.fY;
 
                         if (kRound_Y_Baseline == roundBaseline) {
-                            fy = (fy + 0x8000) & ~0xFFFF;
+                            fyMask = 0;
                         } else if (kRound_X_Baseline == roundBaseline) {
-                            fx = (fx + 0x8000) & ~0xFFFF;
+                            fxMask = 0;
                         }
                     }
                     
                     // have to call again, now that we've been "aligned"
-                    glyph = &glyphCacheProc(cache, &text, fx, fy);
+                    glyph = &glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
                     // the assumption is that the advance hasn't changed
                     SkASSERT(prevAdvX == glyph->fAdvanceX);
                     SkASSERT(prevAdvY == glyph->fAdvanceY);
                     
-                    proc(d1g, *glyph, SkFixedFloor(fx), SkFixedFloor(fy));
+                    proc(d1g, fx, fy, *glyph);
                 }
                 pos += scalarsPerPosition;
             }
@@ -1734,8 +1796,8 @@
                 SkIPoint fixedLoc;
                 alignProc(tms.fLoc, glyph, &fixedLoc);
                 
-                proc(d1g, glyph,
-                     SkFixedRound(fixedLoc.fX), SkFixedRound(fixedLoc.fY));
+                proc(d1g, fixedLoc.fX + SK_FixedHalf,
+                     fixedLoc.fY + SK_FixedHalf, glyph);
             }
             pos += scalarsPerPosition;
         }
@@ -1863,7 +1925,11 @@
             m.postConcat(*matrix);
         }
         morphpath(&tmp, *iterPath, meas, m);
-        this->drawPath(tmp, iter.getPaint());
+        if (fDevice) {
+            fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true);
+        } else {
+            this->drawPath(tmp, iter.getPaint(), NULL, true);
+        }
     }
 }
 
@@ -2232,7 +2298,7 @@
 
 #ifdef SK_DEBUG
 
-void SkDraw::validate(int width, int height) const {
+void SkDraw::validate() const {
     SkASSERT(fBitmap != NULL);
     SkASSERT(fMatrix != NULL);
     SkASSERT(fClip != NULL);
@@ -2240,8 +2306,11 @@
     const SkIRect&  cr = fClip->getBounds();
     SkIRect         br;
 
-    br.set(0, 0, width, height);
+    br.set(0, 0, fBitmap->width(), fBitmap->height());
     SkASSERT(cr.isEmpty() || br.contains(cr));
+
+    // assert that both are null, or both are not-null
+    SkASSERT(!fMVMatrix == !fExtMatrix);
 }
 
 #endif
diff --git a/src/core/SkDrawProcs.h b/src/core/SkDrawProcs.h
index d64c088..7d69465 100644
--- a/src/core/SkDrawProcs.h
+++ b/src/core/SkDrawProcs.h
@@ -13,7 +13,9 @@
 	SkGlyphCache*	fCache;
 	SkIRect			fClipBounds;
 	
-	typedef void (*Proc)(const SkDraw1Glyph&, const SkGlyph&, int x, int y);
+    // The fixed x,y have been pre-rounded (i.e. 1/2 has already been added),
+    // so the impls need just trunc down to an int
+	typedef void (*Proc)(const SkDraw1Glyph&, SkFixed x, SkFixed y, const SkGlyph&);
 	
 	Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache);
 };
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index c744dfe..199ac14 100644
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -96,22 +96,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef SK_DEBUG
-class AutoCheckForNull {
-public:
-    AutoCheckForNull(const SkTDArray<SkGlyph*>& array) : fArray(array) {
-        for (int i = 0; i < array.count(); i++)
-            SkASSERT(array[i]);
-    }
-    ~AutoCheckForNull() {
-        const SkTDArray<SkGlyph*>& array = fArray;
-        for (int i = 0; i < array.count(); i++) {
-            SkASSERT(array[i]);
-        }
-    }
-private:
-    const SkTDArray<SkGlyph*>& fArray;
-};
-#define VALIDATE()  AutoCheckForNull acfn(fGlyphArray)
+#define VALIDATE()  AutoValidate av(this)
 #else
 #define VALIDATE()
 #endif
@@ -288,9 +273,7 @@
 
     glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph),
                                         SkChunkAlloc::kThrow_AllocFailType);
-    glyph->fID = id;
-    glyph->fImage = NULL;
-    glyph->fPath = NULL;
+    glyph->init(id);
     *fGlyphArray.insert(hi) = glyph;
     
     if (kJustAdvance_MetricsType == mtype) {
@@ -519,6 +502,9 @@
     cache = SkNEW_ARGS(SkGlyphCache, (desc));
 
 FOUND_IT:
+
+    AutoValidate av(cache);
+
     if (proc(cache, context)) {   // stay detached
         if (insideMutex) {
             SkASSERT(globals.fTotalMemoryUsed >= cache->fMemoryUsed);
@@ -549,6 +535,7 @@
     SkAutoMutexAcquire    ac(globals.fMutex);
 
     globals.validate();
+    cache->validate();
 
     // if we have a fixed budget for our cache, do a purge here
     {
@@ -664,3 +651,19 @@
     return bytesFreed;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+#ifdef SK_DEBUG
+
+void SkGlyphCache::validate() const {
+    int count = fGlyphArray.count();
+    for (int i = 0; i < count; i++) {
+        const SkGlyph* glyph = fGlyphArray[i];
+        SkASSERT(glyph);
+        SkASSERT(fGlyphAlloc.contains(glyph));
+        if (glyph->fImage) {
+            SkASSERT(fImageAlloc.contains(glyph->fImage));
+        }
+    }
+}
+
+#endif
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index cc81ed6..16330f8 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -91,7 +91,9 @@
     const SkPaint::FontMetrics& getFontMetricsY() const {
         return fFontMetricsY;
     }
-    
+
+    const SkDescriptor& getDescriptor() const { return *fDesc; }
+
     /*  AuxProc/Data allow a client to associate data with this cache entry.
         Multiple clients can use this, as their data is keyed with a function
         pointer. In addition to serving as a key, the function pointer is called
@@ -154,6 +156,31 @@
     */
     static bool SetCacheUsed(size_t bytesUsed);
 
+#ifdef SK_DEBUG
+    void validate() const;
+#else
+    void validate() const {}
+#endif
+
+    class AutoValidate : SkNoncopyable {
+    public:
+        AutoValidate(const SkGlyphCache* cache) : fCache(cache) {
+            if (fCache) {
+                fCache->validate();
+            }
+        }
+        ~AutoValidate() {
+            if (fCache) {
+                fCache->validate();
+            }
+        }
+        void forget() {
+            fCache = NULL;
+        }
+    private:
+        const SkGlyphCache* fCache;
+    };
+        
 private:
     SkGlyphCache(const SkDescriptor*);
     ~SkGlyphCache();
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index e85c6ec..f2d1708 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -1595,8 +1595,10 @@
 }
 
 uint32_t SkMatrix::unflatten(const void* buffer) {
-    memcpy(fMat, buffer, 9 * sizeof(SkScalar));
-    this->setTypeMask(kUnknown_Mask);
+    if (buffer) {
+        memcpy(fMat, buffer, 9 * sizeof(SkScalar));
+        this->setTypeMask(kUnknown_Mask);
+    }
     return 9 * sizeof(SkScalar);
 }
 
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 88d924b..d4c5b83 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1209,6 +1209,11 @@
     return h;
 }
 
+static SkScalar sk_relax(SkScalar x) {
+    int n = sk_float_round2int(x * 1024);
+    return n / 1024.0f;
+}
+
 void SkScalerContext::MakeRec(const SkPaint& paint,
                               const SkMatrix* deviceMatrix, Rec* rec)
 {
@@ -1222,10 +1227,10 @@
 
     if (deviceMatrix)
     {
-        rec->fPost2x2[0][0] = deviceMatrix->getScaleX();
-        rec->fPost2x2[0][1] = deviceMatrix->getSkewX();
-        rec->fPost2x2[1][0] = deviceMatrix->getSkewY();
-        rec->fPost2x2[1][1] = deviceMatrix->getScaleY();
+        rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX());
+        rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX());
+        rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY());
+        rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY());
     }
     else
     {
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index b149be9..983f1ad 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -344,7 +344,9 @@
         }
     }
 
-    glyph->fMaskFormat = fRec.fMaskFormat;
+	if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
+		glyph->fMaskFormat = fRec.fMaskFormat;
+	}
 
     if (fMaskFilter) {
         SkMask      src, dst;
@@ -668,9 +670,14 @@
     }
 };
 
+extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
+
 SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc)
 {
-    SkScalerContext* c = SkFontHost::CreateScalerContext(desc);
+	SkScalerContext* c = NULL;  //SkCreateColorScalerContext(desc);
+	if (NULL == c) {
+		c = SkFontHost::CreateScalerContext(desc);
+	}
     if (NULL == c) {
         c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
     }
diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp
index 34dc32e..7b3a024 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -17,6 +17,7 @@
 
 #include "SkShader.h"
 #include "SkPaint.h"
+#include "SkMallocPixelRef.h"
 
 SkShader::SkShader() : fLocalMatrix(NULL) {
     SkDEBUGCODE(fInSession = false;)
@@ -195,8 +196,9 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-bool SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) {
-    return false;
+SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, 
+                                         TileMode*, SkScalar*) {
+    return kNone_BitmapType;
 }
 
 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
@@ -209,9 +211,28 @@
 #include "SkColorShader.h"
 #include "SkUtils.h"
 
+SkColorShader::SkColorShader() {
+    fFlags = 0;
+    fInheritColor = true;
+    fAsABitmapPixelRef = NULL;
+}
+
+SkColorShader::SkColorShader(SkColor c) {
+    fFlags = 0;
+    fColor = c;
+    fInheritColor = false;
+    fAsABitmapPixelRef = NULL;
+}
+
+SkColorShader::~SkColorShader() {
+    SkSafeUnref(fAsABitmapPixelRef);
+}
+
 SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) {
     fFlags = 0; // computed in setContext
-    fInheritColor = b.readU8(); 
+    fAsABitmapPixelRef = NULL;
+
+    fInheritColor = b.readU8();
     if (fInheritColor) {
         return;
     }
@@ -285,3 +306,28 @@
     memset(alpha, SkGetPackedA32(fPMColor), count);
 }
 
+// if we had a asAColor method, that would be more efficient...
+SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
+                                              TileMode modes[], 
+                                              SkScalar* twoPointRadialParams) {
+    // we cache the pixelref, since its generateID is used in the texture cache
+    if (NULL == fAsABitmapPixelRef) {
+        SkPMColor* storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor));
+        *storage = fPMColor;
+        fAsABitmapPixelRef = new SkMallocPixelRef(storage, sizeof(SkPMColor),
+                                                  NULL);
+    }
+        
+    if (bitmap) {
+        bitmap->setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
+        bitmap->setPixelRef(fAsABitmapPixelRef);
+    }
+    if (matrix) {
+        matrix->reset();
+    }
+    if (modes) {
+        modes[0] = modes[1] = SkShader::kRepeat_TileMode;
+    }
+    return kDefault_BitmapType;
+}
+
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index 1fb25a6..c35400b 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -633,6 +633,10 @@
 
     if (fDoFill) {
         dst->addPath(src);
+    } else {
+        if (src.countPoints() == 2) {
+            dst->setIsConvex(true);
+        }
     }
 }
 
diff --git a/src/core/SkTextFormatParams.h b/src/core/SkTextFormatParams.h
new file mode 100644
index 0000000..3306270
--- /dev/null
+++ b/src/core/SkTextFormatParams.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkTextFormatParams_DEFINES
+#define SkTextFormatParams_DEFINES
+
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+// Fraction of the text size to lower a strike through line below the baseline.
+#define kStdStrikeThru_Offset       (-SK_Scalar1 * 6 / 21)
+// Fraction of the text size to lower a underline below the baseline.
+#define kStdUnderline_Offset        (SK_Scalar1 / 9)
+// Fraction of the text size to use for a strike through or under-line.
+#define kStdUnderline_Thickness     (SK_Scalar1 / 18)
+
+// The fraction of text size to embolden fake bold text scales with text size.
+// At 9 points or below, the stroke width is increased by text size / 24.
+// At 36 points and above, it is increased by text size / 32.  In between,
+// it is interpolated between those values.
+static const SkScalar kStdFakeBoldInterpKeys[] = {
+    SkIntToScalar(9),
+    SkIntToScalar(36)
+};
+static const SkScalar kStdFakeBoldInterpValues[] = {
+    SK_Scalar1/24,
+    SK_Scalar1/32
+};
+SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kStdFakeBoldInterpKeys) ==
+                  SK_ARRAY_COUNT(kStdFakeBoldInterpValues),
+                  mismatched_array_size);
+static const int kStdFakeBoldInterpLength =
+    SK_ARRAY_COUNT(kStdFakeBoldInterpKeys);
+
+#endif  //SkTextFormatParams_DEFINES
diff --git a/src/core/SkUtils.cpp b/src/core/SkUtils.cpp
index a88233f..9fb85c2 100644
--- a/src/core/SkUtils.cpp
+++ b/src/core/SkUtils.cpp
@@ -124,7 +124,7 @@
     }
 }
 
-#ifndef ANDROID
+#if !defined(ANDROID) || defined(SK_BUILD_FOR_ANDROID_NDK)
 static void sk_memset16_stub(uint16_t dst[], uint16_t value, int count)
 {
     SkMemset16Proc proc = SkMemset16GetPlatformProc();
diff --git a/src/core/core_files.mk b/src/core/core_files.mk
index af7b876..235fa76 100644
--- a/src/core/core_files.mk
+++ b/src/core/core_files.mk
@@ -72,6 +72,7 @@
     SkRect.cpp \
     SkRefCnt.cpp \
     SkRegion.cpp \
+    SkRegion_rects.cpp \
     SkRegion_path.cpp \
     SkScalar.cpp \
     SkScalerContext.cpp \
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index cc65413..9aefd0a 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -118,16 +118,23 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-SkDevice* SkPDFDeviceFactory::newDevice(SkBitmap::Config config,
-                                        int width, int height,
-                                        bool isOpaque, bool isForLayer) {
+SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
+                                        int width, int height, bool isOpaque,
+                                        bool /*isForLayer*/) {
     return SkNEW_ARGS(SkPDFDevice, (width, height));
 }
 
+static inline SkBitmap makeABitmap(int width, int height) {
+    SkBitmap bitmap;
+    bitmap.setConfig(SkBitmap::kNo_Config, width, height);
+    return bitmap;
+}
+
 SkPDFDevice::SkPDFDevice(int width, int height)
     : fWidth(width),
       fHeight(height),
-      fGraphicStackIndex(0) {
+      fGraphicStackIndex(0),
+      SkDevice(NULL, makeABitmap(width, height), false) {
     fGraphicStack[0].fColor = SK_ColorBLACK;
     fGraphicStack[0].fTextSize = SK_ScalarNaN;  // This has no default value.
     fGraphicStack[0].fTextScaleX = SK_Scalar1;
@@ -271,7 +278,10 @@
 }
 
 void SkPDFDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap,
+                             const SkIRect* srcRect,
                              const SkMatrix& matrix, const SkPaint& paint) {
+    // TODO: respect srcRect if present
+
     SkMatrix transform = matrix;
     transform.postConcat(fGraphicStack[fGraphicStackIndex].fTransform);
     internalDrawBitmap(transform, bitmap, paint);
diff --git a/src/pdf/pdf_files.mk b/src/pdf/pdf_files.mk
index 8d721eb..149e802 100644
--- a/src/pdf/pdf_files.mk
+++ b/src/pdf/pdf_files.mk
@@ -8,4 +8,4 @@
     SkPDFImage.cpp \
     SkPDFPage.cpp \
     SkPDFStream.cpp \
-    SkPDFTypes.cpp \
+    SkPDFTypes.cpp
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index c643c82..d462d01 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -18,14 +18,6 @@
     return fProxy->getViewport(size);
 }
 
-bool SkProxyCanvas::setViewport(int x, int y) {
-    return fProxy->setViewport(x, y);
-}
-
-SkDevice* SkProxyCanvas::setBitmapDevice(const SkBitmap& bitmap) {
-    return fProxy->setBitmapDevice(bitmap);
-}
-
 int SkProxyCanvas::save(SaveFlags flags) {
     return fProxy->save(flags);
 }
@@ -163,8 +155,8 @@
     return fProxy->setDrawFilter(filter);
 }
 
-SkDevice* SkProxyCanvas::createDevice(SkBitmap::Config config, int width,
-                                int height, bool isOpaque, bool isForLayer) {
+SkDevice* SkProxyCanvas::createDevice(SkBitmap::Config config, int width, int height,
+                                      bool isOpaque, bool isForLayer) {
     return fProxy->createDevice(config, width, height, isOpaque, isForLayer);
 }
 
diff --git a/src/utils/mac/SkCreateCGImageRef.cpp b/src/utils/mac/SkCreateCGImageRef.cpp
index 5c96e21..2169bc0 100644
--- a/src/utils/mac/SkCreateCGImageRef.cpp
+++ b/src/utils/mac/SkCreateCGImageRef.cpp
@@ -26,22 +26,19 @@
             *bitsPerComponent = 8;
 #if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 0, 8, 16) \
  || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(0, 24, 16, 8)
-            *info = kCGBitmapByteOrder32Big |
-                    kCGImageAlphaPremultipliedLast;
+            *info = kCGBitmapByteOrder32Big;
 #elif defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) \
    || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
             // Matches the CGBitmapInfo that Apple recommends for best
             // performance, used by google chrome.
-            *info = kCGBitmapByteOrder32Host |
-                    kCGImageAlphaPremultipliedFirst;
+            *info = kCGBitmapByteOrder32Little;
 #else
 // ...add more formats as required...
 #warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \
             This will probably not work.
             // Legacy behavior. Perhaps turn this into an error at some
             // point.
-            *info = kCGBitmapByteOrder32Big |
-                    kCGImageAlphaPremultipliedLast;
+            *info = kCGBitmapByteOrder32Big;
 #endif
             break;
 #if 0
@@ -59,6 +56,10 @@
             return NULL;
     }
 
+    if (!bm.isOpaque()) {
+        *info |= kCGImageAlphaPremultipliedLast;
+    }
+
     SkBitmap* copy;
     if (upscaleTo32) {
         copy = new SkBitmap;
@@ -93,7 +94,7 @@
     CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
 															 SkBitmap_ReleaseInfo);
 
-    CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+    CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
     CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
                                    bitmap->bytesPerPixel() * 8,
                                    bitmap->rowBytes(), space, info, dataRef,
@@ -103,4 +104,23 @@
     return ref;
 }
 
+void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
+    CGImageRef img = SkCreateCGImageRef(bm);
+
+    if (img) {
+        CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
+        
+        CGContextSaveGState(cg);
+        CGContextTranslateCTM(cg, x, r.size.height + y);
+        CGContextScaleCTM(cg, 1, -1);
+        
+        CGContextDrawImage(cg, r, img);
+        
+        CGContextRestoreGState(cg);
+        
+        CGImageRelease(img);
+    }
+}
+
+
 
diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp
index eb07e2a..6828a95 100644
--- a/src/utils/mac/SkOSWindow_Mac.cpp
+++ b/src/utils/mac/SkOSWindow_Mac.cpp
@@ -2,6 +2,8 @@
 
 #if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS)
 
+#include <AGL/agl.h>
+
 #include <Carbon/Carbon.h>
 #include "SkCGUtils.h"
 
@@ -82,7 +84,7 @@
     pos->offset = 0;
 }
 
-SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd)
+SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd), fAGLCtx(NULL)
 {
 	OSStatus    result;
     WindowRef   wr = (WindowRef)hWnd;
@@ -450,5 +452,79 @@
 	}
 }
 
+AGLContext create_gl(WindowRef wref, bool offscreen)
+{
+    GLint major, minor;
+    AGLContext ctx;
+    
+    aglGetVersion(&major, &minor);
+    SkDebugf("---- agl version %d %d\n", major, minor);
+    
+    const GLint pixelAttrs[] = {
+        AGL_RGBA,
+        AGL_STENCIL_SIZE, 8,
+        AGL_SAMPLE_BUFFERS_ARB, 1,
+		AGL_MULTISAMPLE,
+		AGL_SAMPLES_ARB, 2,        
+		(offscreen ? AGL_OFFSCREEN : AGL_ACCELERATED),
+        (offscreen ? AGL_NONE : AGL_DOUBLEBUFFER),
+        AGL_NONE
+    };
+    AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs);
+    //AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
+    SkDebugf("----- agl format %p\n", format);
+    ctx = aglCreateContext(format, NULL);
+    SkDebugf("----- agl context %p\n", ctx);
+    aglDestroyPixelFormat(format);
+
+    static const GLint interval = 1;
+    aglSetInteger(ctx, AGL_SWAP_INTERVAL, &interval);
+    aglSetCurrentContext(ctx);
+    return ctx;
+}
+
+bool SkOSWindow::attachGL(const SkBitmap* offscreen)
+{
+    if (NULL == fAGLCtx) {
+        fAGLCtx = create_gl((WindowRef)fHWND, NULL != offscreen);
+        if (NULL == fAGLCtx) {
+            return false;
+        }
+    }
+
+    GLboolean success = true;
+
+    if (offscreen) {
+        success = aglSetOffScreen((AGLContext)fAGLCtx,
+                                    offscreen->width(),
+                                    offscreen->height(),
+                                    offscreen->rowBytes(),
+                                    offscreen->getPixels());
+    } else {
+        success = aglSetWindowRef((AGLContext)fAGLCtx, (WindowRef)fHWND);
+    }
+
+    GLenum err = aglGetError();
+    if (err) {
+        SkDebugf("---- setoffscreen %d %d %s [%d %d]\n", success, err,
+                 aglErrorString(err), offscreen->width(), offscreen->height());
+    }
+    
+    if (success) {
+        glClearColor(0, 0, 0, 0);
+        glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+    }
+    return success;
+}
+
+void SkOSWindow::detachGL() {
+    aglSetWindowRef((AGLContext)fAGLCtx, NULL);
+}
+
+void SkOSWindow::presentGL() {
+    aglSwapBuffers((AGLContext)fAGLCtx);
+    glFlush();
+}
+
 #endif
 
diff --git a/src/utils/win/SkOSWindow_Win.cpp b/src/utils/win/SkOSWindow_Win.cpp
index 376c3bd..26993be 100644
--- a/src/utils/win/SkOSWindow_Win.cpp
+++ b/src/utils/win/SkOSWindow_Win.cpp
@@ -1,213 +1,569 @@
-#include "SkTypes.h"

-

-#if defined(SK_BUILD_FOR_WIN)

-

-#include "SkWindow.h"

-#include "SkCanvas.h"

-#include "SkOSMenu.h"

-#include "SkTime.h"

-

-#include "SkGraphics.h"

-

-static SkOSWindow* gCurrOSWin;

-

-SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd) {

-}

-

-static SkKey winToskKey(WPARAM vk) {

-	static const struct {

-		WPARAM	fVK;

-		SkKey	fKey;

-	} gPair[] = {

-		{ VK_BACK,	kBack_SkKey },

-		{ VK_CLEAR,	kBack_SkKey },

-		{ VK_RETURN, kOK_SkKey },

-		{ VK_UP,	 kUp_SkKey },

-		{ VK_DOWN,	 kDown_SkKey },

-		{ VK_LEFT,	 kLeft_SkKey },

-		{ VK_RIGHT,	 kRight_SkKey }

-	};

-	for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {

-		if (gPair[i].fVK == vk) {

-			return gPair[i].fKey;

-		}

-	}

-	return kNONE_SkKey;

-}

-

-bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {

-	switch (message) {

-		case WM_KEYDOWN: {

-			SkKey key = winToskKey(wParam);

-			if (kNONE_SkKey != key) {

-				this->handleKey(key);

-				return true;

-			}

-		} break;

-		case WM_KEYUP: {

-			SkKey key = winToskKey(wParam);

-			if (kNONE_SkKey != key) {

-				this->handleKeyUp(key);

-				return true;

-			}

-		} break;

-		case WM_UNICHAR:

-			this->handleChar(lParam);

-			return true;

-		case WM_SIZE:

-			this->resize(lParam & 0xFFFF, lParam >> 16);

-			break;

-		case WM_PAINT: {

-			PAINTSTRUCT ps;

-			HDC hdc = BeginPaint(hWnd, &ps);

-			this->doPaint(hdc);

-			EndPaint(hWnd, &ps);

-			return true;

-		} break;

-	}

-	return false;

-}

-

-void SkOSWindow::doPaint(void* ctx) {

-	this->update(NULL);

-

-	HDC hdc = (HDC)ctx;

-    const SkBitmap& bitmap = this->getBitmap();

-

-	BITMAPINFO bmi;

-	memset(&bmi, 0, sizeof(bmi));

-	bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);

-	bmi.bmiHeader.biWidth       = bitmap.width();

-	bmi.bmiHeader.biHeight      = -bitmap.height(); // top-down image 

-	bmi.bmiHeader.biPlanes      = 1;

-	bmi.bmiHeader.biBitCount    = 32;

-	bmi.bmiHeader.biCompression = BI_RGB;

-	bmi.bmiHeader.biSizeImage   = 0;

-

-	// 

-	// Do the SetDIBitsToDevice. 

-	// 

-	bitmap.lockPixels();

-	int iRet = SetDIBitsToDevice(hdc,

-		0, 0,

-		bitmap.width(), bitmap.height(),

-		0, 0,

-		0, bitmap.height(),

-		bitmap.getPixels(),

-		&bmi,

-		DIB_RGB_COLORS);

-	bitmap.unlockPixels();

-}

-

-#if 0

-void SkOSWindow::updateSize()

-{

-	RECT	r;

-	GetWindowRect((HWND)this->getHWND(), &r);

-	this->resize(r.right - r.left, r.bottom - r.top);

-}

-#endif

-

-void SkOSWindow::onHandleInval(const SkIRect& r) {

-	RECT rect;

-	rect.left = r.fLeft;

-	rect.top = r.fTop;

-	rect.right = r.fRight;

-	rect.bottom = r.fBottom;

-	InvalidateRect((HWND)this->getHWND(), &rect, false);

-}

-

-void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)

-{

-}

-

-

-enum {

-	SK_MacReturnKey		= 36,

-	SK_MacDeleteKey		= 51,

-	SK_MacEndKey		= 119,

-	SK_MacLeftKey		= 123,

-	SK_MacRightKey		= 124,

-	SK_MacDownKey		= 125,

-	SK_MacUpKey			= 126,

-    

-    SK_Mac0Key          = 0x52,

-    SK_Mac1Key          = 0x53,

-    SK_Mac2Key          = 0x54,

-    SK_Mac3Key          = 0x55,

-    SK_Mac4Key          = 0x56,

-    SK_Mac5Key          = 0x57,

-    SK_Mac6Key          = 0x58,

-    SK_Mac7Key          = 0x59,

-    SK_Mac8Key          = 0x5b,

-    SK_Mac9Key          = 0x5c

-};

-	

-static SkKey raw2key(uint32_t raw)

-{

-	static const struct {

-		uint32_t  fRaw;

-		SkKey   fKey;

-	} gKeys[] = {

-		{ SK_MacUpKey,		kUp_SkKey		},

-		{ SK_MacDownKey,	kDown_SkKey		},

-		{ SK_MacLeftKey,	kLeft_SkKey		},

-		{ SK_MacRightKey,   kRight_SkKey	},

-		{ SK_MacReturnKey,  kOK_SkKey		},

-		{ SK_MacDeleteKey,  kBack_SkKey		},

-		{ SK_MacEndKey,		kEnd_SkKey		},

-        { SK_Mac0Key,       k0_SkKey        },

-        { SK_Mac1Key,       k1_SkKey        },

-        { SK_Mac2Key,       k2_SkKey        },

-        { SK_Mac3Key,       k3_SkKey        },

-        { SK_Mac4Key,       k4_SkKey        },

-        { SK_Mac5Key,       k5_SkKey        },

-        { SK_Mac6Key,       k6_SkKey        },

-        { SK_Mac7Key,       k7_SkKey        },

-        { SK_Mac8Key,       k8_SkKey        },

-        { SK_Mac9Key,       k9_SkKey        }

-	};

-	

-	for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)

-		if (gKeys[i].fRaw == raw)

-			return gKeys[i].fKey;

-	return kNONE_SkKey;

-}

-

-///////////////////////////////////////////////////////////////////////////////////////

-

-void SkEvent::SignalNonEmptyQueue()

-{

-//	post_skmacevent();

-//	SkDebugf("signal nonempty\n");

-}

-

-//static void sk_timer_proc(TMTask* rec)

-//{

-//	SkEvent::ServiceQueueTimer();

-//	SkDebugf("timer task fired\n");

-//}

-

-void SkEvent::SignalQueueTimer(SkMSec delay)

-{

-#if 0

-	if (gTMTaskPtr)

-	{

-		RemoveTimeTask((QElem*)gTMTaskPtr);

-		DisposeTimerUPP(gTMTaskPtr->tmAddr);

-		gTMTaskPtr = nil;

-	}

-	if (delay)

-	{

-		gTMTaskPtr = &gTMTaskRec;

-		memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));

-		gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);

-		OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);

-//		SkDebugf("installtimetask of %d returned %d\n", delay, err);

-		PrimeTimeTask((QElem*)gTMTaskPtr, delay);

-	}

-#endif

-}

-

-#endif

-

+#include "SkTypes.h"
+
+#if defined(SK_BUILD_FOR_WIN)
+
+#include <GL/glew.h>
+#include <GL/wglew.h>
+#include <GL/gl.h>
+#include <d3d9.h>
+#include <WindowsX.h>
+#include "SkWindow.h"
+#include "SkCanvas.h"
+#include "SkOSMenu.h"
+#include "SkTime.h"
+#include "SkUtils.h"
+
+#include "SkGraphics.h"
+
+#define INVALIDATE_DELAY_MS 200
+
+static SkOSWindow* gCurrOSWin;
+static HWND gEventTarget;
+
+#define WM_EVENT_CALLBACK (WM_USER+0)
+
+void post_skwinevent()
+{
+    PostMessage(gEventTarget, WM_EVENT_CALLBACK, 0, 0);
+}
+
+SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd), 
+                                     fHGLRC(NULL),
+                                     fGLAttached(false),
+                                     fD3D9Device(NULL),
+                                     fD3D9Attached(FALSE) {
+    gEventTarget = (HWND)hWnd;
+}
+
+SkOSWindow::~SkOSWindow() {
+    if (NULL != fD3D9Device) {
+        ((IDirect3DDevice9*)fD3D9Device)->Release();
+    }
+    if (NULL != fHGLRC) {
+        wglDeleteContext((HGLRC)fHGLRC);
+    }
+}
+
+static SkKey winToskKey(WPARAM vk) {
+	static const struct {
+		WPARAM	fVK;
+		SkKey	fKey;
+	} gPair[] = {
+		{ VK_BACK,	kBack_SkKey },
+		{ VK_CLEAR,	kBack_SkKey },
+		{ VK_RETURN, kOK_SkKey },
+		{ VK_UP,	 kUp_SkKey },
+		{ VK_DOWN,	 kDown_SkKey },
+		{ VK_LEFT,	 kLeft_SkKey },
+		{ VK_RIGHT,	 kRight_SkKey }
+	};
+	for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
+		if (gPair[i].fVK == vk) {
+			return gPair[i].fKey;
+		}
+	}
+	return kNONE_SkKey;
+}
+
+bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+	switch (message) {
+		case WM_KEYDOWN: {
+			SkKey key = winToskKey(wParam);
+			if (kNONE_SkKey != key) {
+				this->handleKey(key);
+				return true;
+			}
+		} break;
+		case WM_KEYUP: {
+			SkKey key = winToskKey(wParam);
+			if (kNONE_SkKey != key) {
+				this->handleKeyUp(key);
+				return true;
+			}
+		} break;
+		case WM_UNICHAR:
+			this->handleChar(wParam);
+            return true; 
+        case WM_CHAR: {
+            this->handleChar(SkUTF8_ToUnichar((char*)&wParam));
+            return true;
+        } break;
+		case WM_SIZE:
+			this->resize(lParam & 0xFFFF, lParam >> 16);
+			break;
+		case WM_PAINT: {
+			PAINTSTRUCT ps;
+			HDC hdc = BeginPaint(hWnd, &ps);
+			this->doPaint(hdc);
+			EndPaint(hWnd, &ps);
+			return true;
+            } break;
+
+        case WM_TIMER: {
+            RECT* rect = (RECT*)wParam;
+            InvalidateRect(hWnd, rect, FALSE);
+            KillTimer(hWnd, (UINT_PTR)rect);
+            delete rect;
+            return true;
+        } break;
+    
+        case WM_LBUTTONDOWN: 
+            this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kDown_State);
+            return true;
+                    
+        case WM_MOUSEMOVE:
+            this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kMoved_State);
+            return true;
+
+        case WM_LBUTTONUP:
+            this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kUp_State);
+            return true;
+
+        case WM_EVENT_CALLBACK:
+            if (SkEvent::ProcessEvent()) {
+                post_skwinevent();
+            }
+            return true;
+	}
+	return false;
+}
+
+void SkOSWindow::doPaint(void* ctx) {
+	this->update(NULL);
+
+    if (!fGLAttached && !fD3D9Attached)
+    {
+	    HDC hdc = (HDC)ctx;
+        const SkBitmap& bitmap = this->getBitmap();
+
+	    BITMAPINFO bmi;
+	    memset(&bmi, 0, sizeof(bmi));
+	    bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
+	    bmi.bmiHeader.biWidth       = bitmap.width();
+	    bmi.bmiHeader.biHeight      = -bitmap.height(); // top-down image 
+	    bmi.bmiHeader.biPlanes      = 1;
+	    bmi.bmiHeader.biBitCount    = 32;
+	    bmi.bmiHeader.biCompression = BI_RGB;
+	    bmi.bmiHeader.biSizeImage   = 0;
+
+	    // 
+	    // Do the SetDIBitsToDevice. 
+	    // 
+	    bitmap.lockPixels();
+	    int iRet = SetDIBitsToDevice(hdc,
+		    0, 0,
+		    bitmap.width(), bitmap.height(),
+		    0, 0,
+		    0, bitmap.height(),
+		    bitmap.getPixels(),
+		    &bmi,
+		    DIB_RGB_COLORS);
+	    bitmap.unlockPixels();
+    }
+}
+
+#if 0
+void SkOSWindow::updateSize()
+{
+	RECT	r;
+	GetWindowRect((HWND)this->getHWND(), &r);
+	this->resize(r.right - r.left, r.bottom - r.top);
+}
+#endif
+
+void SkOSWindow::onHandleInval(const SkIRect& r) {
+	RECT* rect = new RECT;
+	rect->left    = r.fLeft;
+	rect->top     = r.fTop;
+	rect->right   = r.fRight;
+	rect->bottom  = r.fBottom;
+    SetTimer((HWND)fHWND, (UINT_PTR)rect, INVALIDATE_DELAY_MS, NULL);
+}
+
+void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
+{
+}
+
+void SkOSWindow::onSetTitle(const char title[]){
+    SetWindowTextA((HWND)fHWND, title);
+}
+
+enum {
+	SK_MacReturnKey		= 36,
+	SK_MacDeleteKey		= 51,
+	SK_MacEndKey		= 119,
+	SK_MacLeftKey		= 123,
+	SK_MacRightKey		= 124,
+	SK_MacDownKey		= 125,
+	SK_MacUpKey			= 126,
+    
+    SK_Mac0Key          = 0x52,
+    SK_Mac1Key          = 0x53,
+    SK_Mac2Key          = 0x54,
+    SK_Mac3Key          = 0x55,
+    SK_Mac4Key          = 0x56,
+    SK_Mac5Key          = 0x57,
+    SK_Mac6Key          = 0x58,
+    SK_Mac7Key          = 0x59,
+    SK_Mac8Key          = 0x5b,
+    SK_Mac9Key          = 0x5c
+};
+	
+static SkKey raw2key(uint32_t raw)
+{
+	static const struct {
+		uint32_t  fRaw;
+		SkKey   fKey;
+	} gKeys[] = {
+		{ SK_MacUpKey,		kUp_SkKey		},
+		{ SK_MacDownKey,	kDown_SkKey		},
+		{ SK_MacLeftKey,	kLeft_SkKey		},
+		{ SK_MacRightKey,   kRight_SkKey	},
+		{ SK_MacReturnKey,  kOK_SkKey		},
+		{ SK_MacDeleteKey,  kBack_SkKey		},
+		{ SK_MacEndKey,		kEnd_SkKey		},
+        { SK_Mac0Key,       k0_SkKey        },
+        { SK_Mac1Key,       k1_SkKey        },
+        { SK_Mac2Key,       k2_SkKey        },
+        { SK_Mac3Key,       k3_SkKey        },
+        { SK_Mac4Key,       k4_SkKey        },
+        { SK_Mac5Key,       k5_SkKey        },
+        { SK_Mac6Key,       k6_SkKey        },
+        { SK_Mac7Key,       k7_SkKey        },
+        { SK_Mac8Key,       k8_SkKey        },
+        { SK_Mac9Key,       k9_SkKey        }
+	};
+	
+	for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
+		if (gKeys[i].fRaw == raw)
+			return gKeys[i].fKey;
+	return kNONE_SkKey;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void SkEvent::SignalNonEmptyQueue()
+{
+	post_skwinevent();
+	//SkDebugf("signal nonempty\n");
+}
+
+static UINT_PTR gTimer;
+
+VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+	SkEvent::ServiceQueueTimer();
+	//SkDebugf("timer task fired\n");
+}
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+	if (gTimer)
+	{
+        KillTimer(NULL, gTimer);
+	    gTimer = NULL;
+    }
+	if (delay)
+	{     
+        gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
+        //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
+	}
+}
+
+static HWND create_dummy()
+{
+	HMODULE module = GetModuleHandle(NULL);
+	HWND dummy;
+	RECT windowRect;
+	windowRect.left = 0;
+	windowRect.right = 8;
+	windowRect.top = 0;
+	windowRect.bottom = 8;
+
+	WNDCLASS wc;
+
+	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+	wc.lpfnWndProc = (WNDPROC) DefWindowProc;
+	wc.cbClsExtra = 0;
+	wc.cbWndExtra = 0;
+	wc.hInstance = module;
+	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
+	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+	wc.hbrBackground = NULL;
+	wc.lpszMenuName = NULL;
+	wc.lpszClassName = L"DummyWindow";
+
+	if(!RegisterClass(&wc))
+	{
+		return 0;
+	}
+
+	DWORD style, exStyle;
+	exStyle = WS_EX_CLIENTEDGE;
+	style = WS_SYSMENU;
+
+	AdjustWindowRectEx(&windowRect, style, false, exStyle);
+
+	if(!(dummy = CreateWindowEx(exStyle,
+		L"DummyWindow",
+		L"Dummy Window",
+		WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
+		0, 0,
+		windowRect.right-windowRect.left,
+		windowRect.bottom-windowRect.top,
+		NULL, NULL,
+		module,
+		NULL)))
+	{
+		UnregisterClass(L"Dummy Window", module);
+		return NULL;
+	}
+	ShowWindow(dummy, SW_HIDE);
+
+	return dummy;
+}
+
+void kill_dummy(HWND dummy) {
+    DestroyWindow(dummy);
+    HMODULE module = GetModuleHandle(NULL);
+    UnregisterClass(L"Dummy Window", module);
+}
+
+HGLRC create_gl(HWND hwnd) {
+    HDC hdc;    
+    HDC prevHDC;
+    HGLRC prevGLRC, glrc;
+    PIXELFORMATDESCRIPTOR pfd;
+
+    static bool glewInitialized;
+ 
+    prevGLRC = wglGetCurrentContext();
+    prevHDC  = wglGetCurrentDC();
+
+    int format = 0;
+
+    // glew must be initialized after a context has been created and made current
+    // and we need glew already be initialized to get wglChoosePixelFormatEXT :(
+    // Even worse: SetPixelFormat needs to be called before the context is created
+    // But SetPixelFormat is only allowed to succeed once per-window. So we need to
+    // create a dummy window for glew in order for it to call wglGetProcAddress() to 
+    // get wglChoosePixelFormatARB(). This is a Windows problem, not a glew problem.
+    if (!glewInitialized) {
+        ZeroMemory(&pfd, sizeof(pfd));
+        pfd.nSize = sizeof(pfd);
+        pfd.nVersion = 1;
+        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+        pfd.iPixelType = PFD_TYPE_RGBA;
+        pfd.cColorBits  = 32;
+        pfd.cDepthBits  = 0;
+        pfd.cStencilBits = 8;
+        pfd.iLayerType = PFD_MAIN_PLANE;
+        HWND dummy = create_dummy();
+        SkASSERT(NULL != dummy);
+        hdc = GetDC(dummy);
+        format = ChoosePixelFormat(hdc, &pfd);
+        SetPixelFormat(hdc, format, &pfd);
+        glrc = wglCreateContext(hdc);
+        SkASSERT(glrc);
+        wglMakeCurrent(hdc, glrc);
+
+        GLenum err;
+        err = glewInit();
+        SkASSERT(GLEW_OK == err);
+        SkASSERT(GLEW_EXT_bgra);
+        SkASSERT(GLEW_EXT_framebuffer_object);
+        SkASSERT(WGLEW_ARB_pixel_format);
+        glewInitialized = true;
+        wglMakeCurrent(hdc, NULL);
+        wglDeleteContext(glrc);
+        glrc = 0;
+        kill_dummy(dummy);
+    }
+    
+    hdc = GetDC(hwnd);
+    format = 0;
+
+    GLint iattrs[] = {
+        WGL_DRAW_TO_WINDOW_ARB, TRUE,
+        WGL_DOUBLE_BUFFER_ARB, TRUE,
+        WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
+        WGL_SUPPORT_OPENGL_ARB, TRUE,
+        WGL_COLOR_BITS_ARB, 24,
+        WGL_STENCIL_BITS_ARB, 8,
+        WGL_SAMPLE_BUFFERS_ARB, TRUE,
+        WGL_SAMPLES_ARB, 0,
+        0,0
+    };
+    for (int samples = 16; samples > 1; --samples) {
+        iattrs[15] = samples;
+        GLfloat fattrs[] = {0,0};
+        GLuint num;
+        int formats[64];
+        wglChoosePixelFormatARB(hdc, iattrs, fattrs, 64, formats, &num);
+        num = min(num,64);
+        for (GLuint i = 0; i < num; ++i) {            
+            DescribePixelFormat(hdc, formats[i], sizeof(pfd), &pfd);
+            if (SetPixelFormat(hdc, formats[i], &pfd)) {
+                format = formats[i];
+                break;
+            }
+        }
+    }
+    if (0 == format) {
+        iattrs[12] = iattrs[13] = 0;
+        GLfloat fattrs[] = {0,0};
+        GLuint num;
+        wglChoosePixelFormatARB(hdc, iattrs, fattrs, 1, &format, &num);
+        DescribePixelFormat(hdc, format, sizeof(pfd), &pfd);
+        BOOL set = SetPixelFormat(hdc, format, &pfd);
+        SkASSERT(TRUE == set);
+    }
+    
+    glrc = wglCreateContext(hdc);
+    SkASSERT(glrc);    
+
+    wglMakeCurrent(prevHDC, prevGLRC);
+    return glrc;
+}
+
+bool SkOSWindow::attachGL(const SkBitmap* offscreen) {
+    if (offscreen) {
+        printf("windows doesn't support rendering to SkBitmap");
+    }
+    if (NULL == fHGLRC) {
+        fHGLRC = create_gl((HWND)fHWND);
+        if (NULL == fHGLRC) {
+            return false;
+        }
+    }
+    if (wglMakeCurrent(GetDC((HWND)fHWND), (HGLRC)fHGLRC)) {
+        glClearColor(0, 0, 0, 0);
+        glClear(GL_COLOR_BUFFER_BIT);
+        fGLAttached = true;
+        return true;
+    }
+    return false;
+}
+
+void SkOSWindow::detachGL() {
+    wglMakeCurrent(GetDC((HWND)fHWND), 0);
+    fGLAttached = false;
+}
+
+void SkOSWindow::presentGL() {
+    glFlush();
+    SwapBuffers(GetDC((HWND)fHWND));
+    glClearColor(0,0,0,0);
+    glClearStencil(0);
+    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+}
+
+IDirect3DDevice9* create_d3d9_device(HWND hwnd) {
+    HRESULT hr;
+
+    IDirect3D9* d3d9;
+    d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+    if (NULL == d3d9) {
+        return NULL;
+    }
+    D3DDEVTYPE devType = D3DDEVTYPE_HAL;
+    //D3DDEVTYPE devType = D3DDEVTYPE_REF;
+    DWORD qLevels;
+    DWORD qLevelsDepth;
+    D3DMULTISAMPLE_TYPE type;
+    for (type = D3DMULTISAMPLE_16_SAMPLES; 
+         type >= D3DMULTISAMPLE_NONMASKABLE; --(*(DWORD*)&type)) {
+        hr = d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, 
+                                              devType, D3DFMT_D24S8, TRUE,
+                                              type, &qLevels);
+        qLevels = (hr == D3D_OK) ? qLevels : 0;
+        hr = d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, 
+                                              devType, D3DFMT_A8R8G8B8, TRUE,
+                                              type, &qLevelsDepth);
+        qLevelsDepth = (hr == D3D_OK) ? qLevelsDepth : 0;
+        qLevels = min(qLevels,qLevelsDepth);
+        if (qLevels > 0) {
+            break;
+        }
+    }
+    qLevels = 0;
+    IDirect3DDevice9* d3d9Device;
+    D3DPRESENT_PARAMETERS pres;
+    memset(&pres, 0, sizeof(pres));
+    pres.EnableAutoDepthStencil = TRUE;
+    pres.AutoDepthStencilFormat = D3DFMT_D24S8;
+    pres.BackBufferCount = 2;
+    pres.BackBufferFormat = D3DFMT_A8R8G8B8;
+    pres.BackBufferHeight = 0;
+    pres.BackBufferWidth = 0;
+    if (qLevels > 0) {
+        pres.MultiSampleType = type;
+        pres.MultiSampleQuality = qLevels-1;
+    } else {
+        pres.MultiSampleType = D3DMULTISAMPLE_NONE;
+        pres.MultiSampleQuality = 0;
+    }
+    pres.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    pres.Windowed = TRUE;
+    pres.hDeviceWindow = hwnd;
+    pres.PresentationInterval = 1;
+    pres.Flags = 0;
+    hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT,
+                            devType,
+                            hwnd, 
+                            D3DCREATE_HARDWARE_VERTEXPROCESSING, 
+                            &pres, 
+                            &d3d9Device);    
+    D3DERR_INVALIDCALL;
+    if (SUCCEEDED(hr)) {
+        d3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
+        return d3d9Device;
+    }
+    return NULL;
+}
+
+// This needs some improvement. D3D doesn't have the same notion of attach/detach
+// as GL. However, just allowing GDI to write to the window after creating the 
+// D3D device seems to work. 
+// We need to handle resizing. On XP and earlier Reset() will trash all our textures
+// so we would need to inform the SkGpu/caches or just recreate them. On Vista+ we
+// could use an IDirect3DDevice9Ex and call ResetEx() to resize without trashing
+// everything. Currently we do nothing and the D3D9 image gets stretched/compressed
+// when resized.
+
+bool SkOSWindow::attachD3D9() {
+    if (NULL == fD3D9Device) {
+        fD3D9Device = (void*) create_d3d9_device((HWND)fHWND);
+    }
+    if (NULL != fD3D9Device) {
+        ((IDirect3DDevice9*)fD3D9Device)->BeginScene();
+        fD3D9Attached = true;
+    }
+    return fD3D9Attached;
+}
+
+void SkOSWindow::detachD3D9() {
+    if (NULL != fD3D9Device) {
+        ((IDirect3DDevice9*)fD3D9Device)->EndScene();
+    }
+    fD3D9Attached = false;
+}
+
+void SkOSWindow::presentD3D9() {
+    if (NULL != fD3D9Device) {
+        HRESULT hr;
+        hr = ((IDirect3DDevice9*)fD3D9Device)->EndScene();
+        SkASSERT(SUCCEEDED(hr));
+        hr = ((IDirect3DDevice9*)d3d9Device())->Present(NULL, NULL, NULL, NULL);
+        SkASSERT(SUCCEEDED(hr));
+        hr = ((IDirect3DDevice9*)fD3D9Device)->Clear(0,NULL,D3DCLEAR_TARGET | 
+                                                     D3DCLEAR_STENCIL, 0x0, 0, 
+                                                     0);
+        SkASSERT(SUCCEEDED(hr));
+        hr = ((IDirect3DDevice9*)fD3D9Device)->BeginScene();
+        SkASSERT(SUCCEEDED(hr));
+    }
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/views/SkEvent.cpp b/src/views/SkEvent.cpp
index 67549b4..ec4a7b4 100644
--- a/src/views/SkEvent.cpp
+++ b/src/views/SkEvent.cpp
@@ -536,6 +536,21 @@
     SkEvent::SignalQueueTimer(time);
 }
 
+int SkEvent::CountEventsOnQueue() {
+    SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+    globals.fEventMutex.acquire();
+    
+    int count = 0;
+    const SkEvent* evt = globals.fEventQHead;
+    while (evt) {
+        count += 1;
+        evt = evt->fNextEvent;
+    }
+    globals.fEventMutex.release();
+
+    return count;
+}
+
 ////////////////////////////////////////////////////////////////
 
 void SkEvent::Init()
diff --git a/src/views/SkMetaData.cpp b/src/views/SkMetaData.cpp
index c366bd3..c871efb 100644
--- a/src/views/SkMetaData.cpp
+++ b/src/views/SkMetaData.cpp
@@ -89,6 +89,10 @@
     (void)this->set(name, &value, sizeof(bool), kBool_Type, 1);
 }
 
+void SkMetaData::setData(const char name[], const void* data, size_t byteCount) {
+    (void)this->set(name, data, sizeof(char), kData_Type, byteCount);
+}
+
 void* SkMetaData::set(const char name[], const void* data, size_t dataSize, Type type, int count)
 {
     SkASSERT(name);
@@ -129,6 +133,9 @@
     case kBool_Type:
         rec->fData.fBool = *(const bool*)rec->data();
         break;
+    case kData_Type:
+        rec->fData.fPtr = rec->data();
+        break;
     default:
         SkASSERT(!"bad type");
         break;
@@ -213,6 +220,18 @@
     return false;
 }
 
+const void* SkMetaData::findData(const char name[], size_t* length) const {
+    const Rec* rec = this->find(name, kData_Type);
+    if (rec) {
+        SkASSERT(rec->fDataLen == sizeof(char));
+        if (length) {
+            *length = rec->fDataCount;
+        }
+        return rec->data();
+    }
+    return NULL;
+}
+
 const SkMetaData::Rec* SkMetaData::find(const char name[], Type type) const
 {
     const Rec* rec = fRec;
@@ -272,6 +291,10 @@
     return this->remove(name, kBool_Type);
 }
 
+bool SkMetaData::removeData(const char name[]) {
+    return this->remove(name, kData_Type);
+}
+
 ///////////////////////////////////////////////////////////////////////////////////
 
 SkMetaData::Iter::Iter(const SkMetaData& metadata)
diff --git a/src/views/SkTextBox.cpp b/src/views/SkTextBox.cpp
index df7de98..0e31ac6 100644
--- a/src/views/SkTextBox.cpp
+++ b/src/views/SkTextBox.cpp
@@ -16,7 +16,7 @@
 */
 
 #include "SkTextBox.h"
-#include "../src/core/SkGlyphCache.h"
+#include "../core/SkGlyphCache.h"
 #include "SkUtils.h"
 #include "SkAutoKern.h"
 
diff --git a/src/views/SkView.cpp b/src/views/SkView.cpp
index 652eb85..7969d3d 100644
--- a/src/views/SkView.cpp
+++ b/src/views/SkView.cpp
@@ -49,6 +49,10 @@
 	this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
 }
 
+void SkView::setClipToBounds(bool pred) {
+    this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
+}
+
 void SkView::setSize(SkScalar width, SkScalar height)
 {
 	width = SkMaxScalar(0, width);
@@ -87,12 +91,16 @@
 	{
 		SkRect	r;
 		r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
-		if (canvas->quickReject(r, SkCanvas::kBW_EdgeType))
-			return;
+		if (this->isClipToBounds() &&
+            canvas->quickReject(r, SkCanvas::kBW_EdgeType)) {
+                return;
+        }
 
 		SkAutoCanvasRestore	as(canvas, true);
 
-		canvas->clipRect(r);
+        if (this->isClipToBounds()) {
+            canvas->clipRect(r);
+        }
 		canvas->translate(fLoc.fX, fLoc.fY);
 
         if (fParent) {
@@ -119,37 +127,36 @@
 	}
 }
 
-void SkView::inval(SkRect* rect)
-{
-	if (!this->isVisible())
-		return;
-
-	SkRect	bounds;
-
-	this->getLocalBounds(&bounds);
-	if (rect && !bounds.intersect(*rect))
-		return;
-
-	rect = &bounds;
+void SkView::inval(SkRect* rect) {
 	SkView*	view = this;
+    SkRect storage;
 
-	for (;;)
-	{
-		if (view->handleInval(bounds))
-			break;
+	for (;;) {
+        if (!view->isVisible()) {
+            return;
+        }
+        if (view->isClipToBounds()) {
+            SkRect bounds;
+            view->getLocalBounds(&bounds);
+            if (rect && !bounds.intersect(*rect)) {
+                return;
+            }
+            storage = bounds;
+            rect = &storage;
+        }
+        if (view->handleInval(rect)) {
+            return;
+        }
 
-		SkRect	parentR;
 		SkView* parent = view->fParent;
+        if (parent == NULL) {
+            return;
+        }
 
-		if (parent == NULL || !parent->isVisible())
-			break;
-
-		bounds.offset(view->fLoc.fX, view->fLoc.fY);
-		parent->getLocalBounds(&parentR);
-		if (!bounds.intersect(parentR))
-			return;
-
-		view = parent;
+        if (rect) {
+            rect->offset(view->fLoc.fX, view->fLoc.fY);
+        }
+        view = parent;
 	}
 }
 
@@ -456,7 +463,7 @@
 	return false;
 }
 
-bool SkView::handleInval(const SkRect& r) {
+bool SkView::handleInval(const SkRect*) {
 	return false;
 }
 
diff --git a/src/views/SkWindow.cpp b/src/views/SkWindow.cpp
index b63b81a..dbc1eea 100644
--- a/src/views/SkWindow.cpp
+++ b/src/views/SkWindow.cpp
@@ -1,5 +1,6 @@
 #include "SkWindow.h"
 #include "SkCanvas.h"
+#include "SkDevice.h"
 #include "SkOSMenu.h"
 #include "SkSystemEventTypes.h"
 #include "SkTime.h"
@@ -48,6 +49,8 @@
 #else
 	fConfig = SkBitmap::kARGB_8888_Config;
 #endif
+
+    fMatrix.reset();
 }
 
 SkWindow::~SkWindow()
@@ -57,6 +60,25 @@
 	fMenus.deleteAll();
 }
 
+void SkWindow::setMatrix(const SkMatrix& matrix) {
+    if (fMatrix != matrix) {
+        fMatrix = matrix;
+        this->inval(NULL);
+    }
+}
+
+void SkWindow::preConcat(const SkMatrix& matrix) {
+    SkMatrix m;
+    m.setConcat(fMatrix, matrix);
+    this->setMatrix(m);
+}
+
+void SkWindow::postConcat(const SkMatrix& matrix) {
+    SkMatrix m;
+    m.setConcat(matrix, fMatrix);
+    this->setMatrix(m);
+}
+
 void SkWindow::setConfig(SkBitmap::Config config)
 {
 	this->resize(fBitmap.width(), fBitmap.height(), config);
@@ -72,6 +94,7 @@
 		fConfig = config;
 		fBitmap.setConfig(config, width, height);
 		fBitmap.allocPixels();
+        fBitmap.setIsOpaque(true);
 
 		this->setSize(SkIntToScalar(width), SkIntToScalar(height));
 		this->inval(NULL);
@@ -88,25 +111,31 @@
 	fBitmap.eraseRGB(r, g, b);
 }
 
-bool SkWindow::handleInval(const SkRect& r)
+bool SkWindow::handleInval(const SkRect* localR)
 {
 	SkIRect	ir;
 
-	r.round(&ir);
+    if (localR) {
+        SkRect devR;
+        SkMatrix inverse;
+        if (!fMatrix.invert(&inverse)) {
+            return false;
+        }
+        fMatrix.mapRect(&devR, *localR);
+        devR.round(&ir);
+    } else {
+        ir.set(0, 0, this->width(), this->height());
+    }
 	fDirtyRgn.op(ir, SkRegion::kUnion_Op);
 
-#ifdef SK_BUILD_FOR_WIN32xxxx
-	if (!fWaitingOnInval)
-	{
-		fWaitingOnInval = true;
-		(new SkEvent(SK_EventDelayInval))->post(this->getSinkID(), 10);
-	}
-#else
 	this->onHandleInval(ir);
-#endif
 	return true;
 }
 
+void SkWindow::forceInvalAll() {
+    fDirtyRgn.setRect(0, 0, this->width(), this->height());
+}
+
 #if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
 	#include <windows.h>
 	#include <gx.h>
@@ -117,7 +146,7 @@
 extern bool gEnableControlledThrow;
 #endif
 
-bool SkWindow::update(SkIRect* updateArea)
+bool SkWindow::update(SkIRect* updateArea, SkCanvas* canvas)
 {
 	if (!fDirtyRgn.isEmpty())
 	{
@@ -134,37 +163,49 @@
 		bm.setPixels(buffer);
 #endif
 
-		SkCanvas	canvas(bm);
+		SkCanvas	rasterCanvas;
+        SkDevice*   device;
 
-		canvas.clipRegion(fDirtyRgn);
+        if (NULL == canvas) {
+            canvas = &rasterCanvas;
+            device = new SkDevice(canvas, bm, false);
+            canvas->setDevice(device)->unref();
+        } else {
+            canvas->setBitmapDevice(bm);
+        }
+
+		canvas->clipRegion(fDirtyRgn);
 		if (updateArea)
 			*updateArea = fDirtyRgn.getBounds();
 
+        SkAutoCanvasRestore acr(canvas, true);
+        canvas->concat(fMatrix);
+
 		// empty this now, so we can correctly record any inval calls that
 		// might be made during the draw call.
 		fDirtyRgn.setEmpty();
 
 #ifdef TEST_BOUNDER
 		test_bounder	b(bm);
-		canvas.setBounder(&b);
+		canvas->setBounder(&b);
 #endif
 #ifdef SK_SIMULATE_FAILED_MALLOC
 		gEnableControlledThrow = true;
 #endif
 #ifdef SK_BUILD_FOR_WIN32
-		try {
-			this->draw(&canvas);
-		}
-		catch (...) {
-		}
+		//try {
+			this->draw(canvas);
+		//}
+		//catch (...) {
+		//}
 #else
-		this->draw(&canvas);
+		this->draw(canvas);
 #endif
 #ifdef SK_SIMULATE_FAILED_MALLOC
 		gEnableControlledThrow = false;
 #endif
 #ifdef TEST_BOUNDER
-		canvas.setBounder(NULL);
+		canvas->setBounder(NULL);
 #endif
 
 #if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)