support external raster handles

draft CL for chrome: https://codereview.chromium.org/2618323005/

BUG=skia:

Change-Id: I5dbcd700818776a9f62f1e10723d2efcc248dc44
Reviewed-on: https://skia-review.googlesource.com/6406
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/samplecode/SampleBigGradient.cpp b/samplecode/SampleBigGradient.cpp
index 8ae0990..175b728 100644
--- a/samplecode/SampleBigGradient.cpp
+++ b/samplecode/SampleBigGradient.cpp
@@ -9,6 +9,7 @@
 #include "SkView.h"
 #include "SkCanvas.h"
 #include "SkGradientShader.h"
+#include "SkMakeUnique.h"
 
 static sk_sp<SkShader> make_grad(SkScalar w, SkScalar h) {
     SkColor colors[] = { 0xFF000000, 0xFF333333 };
@@ -45,3 +46,149 @@
 
 static SkView* MyFactory() { return new BigGradientView; }
 static SkViewRegister reg(MyFactory);
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_BUILD_FOR_MAC
+
+#include "SkCGUtils.h"
+#include "SkRasterHandleAllocator.h"
+
+class GraphicsPort {
+protected:
+    SkCanvas* fCanvas;
+
+public:
+    GraphicsPort(SkCanvas* canvas) : fCanvas(canvas) {}
+    virtual ~GraphicsPort() {}
+
+    void save() { fCanvas->save(); }
+    void saveLayer(const SkRect& bounds, SkAlpha alpha) {
+        fCanvas->saveLayerAlpha(&bounds, alpha);
+    }
+    void restore() { fCanvas->restore(); }
+
+    void translate(float x, float y) { fCanvas->translate(x, y); }
+    void scale(float s) { fCanvas->scale(s, s); }
+
+    void drawOval(const SkRect& r, SkColor c) {
+        SkPaint p;
+        p.setColor(c);
+        fCanvas->drawOval(r, p);
+    }
+
+    virtual void drawRect(const SkRect& r, SkColor c) {
+        SkPaint p;
+        p.setColor(c);
+        fCanvas->drawRect(r, p);
+    }
+};
+
+class CGGraphicsPort : public GraphicsPort {
+public:
+    CGGraphicsPort(SkCanvas* canvas) : GraphicsPort(canvas) {}
+
+    void drawRect(const SkRect& r, SkColor c) override {
+        CGContextRef cg = (CGContextRef)fCanvas->accessTopRasterHandle();
+        
+        CGColorRef color = CGColorCreateGenericRGB(SkColorGetR(c)/255.f,
+                                                   SkColorGetG(c)/255.f,
+                                                   SkColorGetB(c)/255.f,
+                                                   SkColorGetA(c)/255.f);
+
+        CGContextSetFillColorWithColor(cg, color);
+        CGContextFillRect(cg, CGRectMake(r.x(), r.y(), r.width(), r.height()));
+    }
+};
+
+static CGAffineTransform matrix_to_transform(CGContextRef cg, const SkMatrix& ctm) {
+    SkMatrix matrix;
+    matrix.setScale(1, -1);
+    matrix.postTranslate(0, SkIntToScalar(CGBitmapContextGetHeight(cg)));
+    matrix.preConcat(ctm);
+
+    return CGAffineTransformMake(matrix[SkMatrix::kMScaleX],
+                                 matrix[SkMatrix::kMSkewY],
+                                 matrix[SkMatrix::kMSkewX],
+                                 matrix[SkMatrix::kMScaleY],
+                                 matrix[SkMatrix::kMTransX],
+                                 matrix[SkMatrix::kMTransY]);
+}
+
+class Allocator_CG : public SkRasterHandleAllocator {
+public:
+    Allocator_CG() {}
+    
+    bool allocHandle(const SkImageInfo& info, Rec* rec) override {
+        // let CG allocate the pixels
+        CGContextRef cg = SkCreateCGContext(SkPixmap(info, nullptr, 0));
+        if (!cg) {
+            return false;
+        }
+        rec->fReleaseProc = [](void* pixels, void* ctx){ CGContextRelease((CGContextRef)ctx); };
+        rec->fReleaseCtx = cg;
+        rec->fPixels = CGBitmapContextGetData(cg);
+        rec->fRowBytes = CGBitmapContextGetBytesPerRow(cg);
+        rec->fHandle = cg;
+        CGContextSaveGState(cg);    // balanced each time updateContext is called
+        return true;
+    }
+
+    void updateHandle(Handle hndl, const SkMatrix& ctm, const SkIRect& clip) override {
+        CGContextRef cg = (CGContextRef)hndl;
+        
+        CGContextRestoreGState(cg);
+        CGContextSaveGState(cg);
+        CGContextClearRect(cg, CGRectMake(clip.x(), clip.y(), clip.width(), clip.height()));
+        CGContextConcatCTM(cg, matrix_to_transform(cg, ctm));
+    }
+};
+
+class RasterAllocatorSample : public SampleView {
+public:
+    RasterAllocatorSample() {}
+
+protected:
+    bool onQuery(SkEvent* evt) override {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "raster-allocator");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    void doDraw(GraphicsPort* port) {
+        port->drawRect({0, 0, 256, 256}, SK_ColorRED);
+        port->save();
+        port->translate(30, 30);
+        port->drawRect({0, 0, 30, 30}, SK_ColorBLUE);
+        port->drawOval({10, 10, 20, 20}, SK_ColorWHITE);
+        port->restore();
+        
+        port->saveLayer({50, 50, 100, 100}, 0x80);
+        port->drawRect({55, 55, 95, 95}, SK_ColorGREEN);
+        port->restore();
+    }
+
+    void onDrawContent(SkCanvas* canvas) override {
+        GraphicsPort skp(canvas);
+        doDraw(&skp);
+
+        const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
+        std::unique_ptr<SkCanvas> c2 =
+            SkRasterHandleAllocator::MakeCanvas(skstd::make_unique<Allocator_CG>(), info);
+        CGGraphicsPort cgp(c2.get());
+        doDraw(&cgp);
+
+        SkPixmap pm;
+        c2->peekPixels(&pm);
+        SkBitmap bm;
+        bm.installPixels(pm);
+        canvas->drawBitmap(bm, 280, 0, nullptr);
+    }
+
+private:
+    typedef SampleView INHERITED;
+};
+DEF_SAMPLE( return new RasterAllocatorSample; )
+#endif