support external raster handles
authorMike Reed <reed@google.com>
Tue, 10 Jan 2017 16:58:39 +0000 (11:58 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 10 Jan 2017 17:31:58 +0000 (17:31 +0000)
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>

include/core/SkBitmapDevice.h
include/core/SkCanvas.h
include/core/SkDevice.h
include/core/SkRasterHandleAllocator.h [new file with mode: 0644]
include/utils/mac/SkCGUtils.h
samplecode/SampleBigGradient.cpp
src/core/SkBitmapDevice.cpp
src/core/SkCanvas.cpp
src/utils/mac/SkCreateCGImageRef.cpp

index 7ad4abec218cac98b544976948f9031d7a3b3a9c..776b6a0decaaa6c3e6992b16a60b765c39365b2e 100644 (file)
@@ -28,6 +28,7 @@ class SkPaint;
 class SkPath;
 class SkPixelRef;
 class SkPixmap;
+class SkRasterHandleAllocator;
 class SkRRect;
 class SkSurface;
 struct SkPoint;
@@ -54,12 +55,15 @@ public:
      *  valid for the bitmap to have no pixels associated with it. In that case,
      *  any drawing to this device will have no effect.
      */
-    SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps);
+    SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps,
+                   void* externalHandle = nullptr);
 
-    static SkBitmapDevice* Create(const SkImageInfo&, const SkSurfaceProps&);
+    static SkBitmapDevice* Create(const SkImageInfo&, const SkSurfaceProps&,
+                                  SkRasterHandleAllocator* = nullptr);
 
 protected:
     bool onShouldDisableLCD(const SkPaint&) const override;
+    void* getRasterHandle() const override { return fRasterHandle; }
 
     /** These are called inside the per-device-layer loop for each draw call.
      When these are called, we have already applied any saveLayer operations,
@@ -172,6 +176,7 @@ private:
     SkImageFilterCache* getImageFilterCache() override;
 
     SkBitmap    fBitmap;
+    void*       fRasterHandle = nullptr;
 
     void setNewSize(const SkISize&);  // Used by SkCanvas for resetForNextPicture().
 
index 63f7f780de0337626e1fd2ad16c09ee0ae50c923..704584a050e4388e0ca51610fd5a499a017de4da 100644 (file)
@@ -15,6 +15,7 @@
 #include "SkDeque.h"
 #include "SkImage.h"
 #include "SkPaint.h"
+#include "SkRasterHandleAllocator.h"
 #include "SkRefCnt.h"
 #include "SkRegion.h"
 #include "SkSurfaceProps.h"
@@ -217,6 +218,8 @@ public:
      */
     void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = NULL);
 
+    SkRasterHandleAllocator::Handle accessTopRasterHandle() const;
+
     /**
      *  If the canvas has readable pixels in its base layer (and is not recording to a picture
      *  or other non-raster target) and has direct access to its pixels (i.e. they are in
@@ -1569,6 +1572,7 @@ private:
     int         fSaveCount;         // value returned by getSaveCount()
 
     SkMetaData* fMetaData;
+    std::unique_ptr<SkRasterHandleAllocator> fAllocator;
 
     SkSurface_Base*  fSurfaceBase;
     SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; }
@@ -1599,6 +1603,7 @@ private:
     friend class SkPicturePlayback; // SaveFlagsToSaveLayerFlags
     friend class SkDeferredCanvas;  // For use of resetForNextPicture
     friend class SkOverdrawCanvas;
+    friend class SkRasterHandleAllocator;
 
     enum InitFlags {
         kDefault_InitFlags                  = 0,
@@ -1606,6 +1611,8 @@ private:
     };
     SkCanvas(const SkIRect& bounds, InitFlags);
     SkCanvas(SkBaseDevice* device, InitFlags);
+    SkCanvas(const SkBitmap&, std::unique_ptr<SkRasterHandleAllocator>,
+             SkRasterHandleAllocator::Handle);
 
     void resetForNextPicture(const SkIRect& bounds);
 
index b0aac41d0bd726549311c51dd140b212a6492f37..fa427c6a15c16ce449f2bef0bffc4c09cf84409f 100644 (file)
@@ -21,6 +21,7 @@ class SkImageFilterCache;
 struct SkIRect;
 class SkMatrix;
 class SkMetaData;
+class SkRasterHandleAllocator;
 class SkRegion;
 class SkSpecialImage;
 class GrRenderTarget;
@@ -112,6 +113,8 @@ public:
      */
     const SkIPoint& getOrigin() const { return fOrigin; }
 
+    virtual void* getRasterHandle() const { return nullptr; }
+
 protected:
     enum TileUsage {
         kPossible_TileUsage,    //!< the created device may be drawn tiled
@@ -292,15 +295,18 @@ protected:
         CreateInfo(const SkImageInfo& info,
                    TileUsage tileUsage,
                    SkPixelGeometry geo,
-                   bool preserveLCDText)
+                   bool preserveLCDText,
+                   SkRasterHandleAllocator* allocator)
             : fInfo(info)
             , fTileUsage(tileUsage)
             , fPixelGeometry(AdjustGeometry(info, tileUsage, geo, preserveLCDText))
+            , fAllocator(allocator)
         {}
 
         const SkImageInfo       fInfo;
         const TileUsage         fTileUsage;
         const SkPixelGeometry   fPixelGeometry;
+        SkRasterHandleAllocator* fAllocator = nullptr;
     };
 
     /**
diff --git a/include/core/SkRasterHandleAllocator.h b/include/core/SkRasterHandleAllocator.h
new file mode 100644 (file)
index 0000000..62796cb
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRasterHandleAllocator_DEFINED
+#define SkRasterHandleAllocator_DEFINED
+
+#include "SkImageInfo.h"
+
+class SkCanvas;
+class SkMatrix;
+
+/**
+ *  If a client wants to control the allocation of raster layers in a canvas, it should subclass
+ *  SkRasterHandleAllocator. This allocator performs two tasks:
+ *      1. controls how the memory for the pixels is allocated
+ *      2. associates a "handle" to a private object that can track the matrix/clip of the SkCanvas
+ *
+ *  This example allocates a canvas, and defers to the allocator to create the base layer.
+ *
+ *      std::unique_ptr<SkCanvas> canvas = SkRasterHandleAllocator::MakeCanvas(
+ *              SkImageInfo::Make(...),
+ *              skstd::make_unique<MySubclassRasterHandleAllocator>(...),
+ *              nullptr);
+ *
+ *  If you have already allocated the base layer (and its handle, release-proc etc.) then you
+ *  can pass those in using the last parameter to MakeCanvas().
+ *
+ *  Regardless of how the base layer is allocated, each time canvas->saveLayer() is called,
+ *  your allocator's allocHandle() will be called.
+ */
+class SK_API SkRasterHandleAllocator {
+public:
+    virtual ~SkRasterHandleAllocator() {}
+
+    // The value that is returned to clients of the canvas that has this allocator installed.
+    typedef void* Handle;
+
+    struct Rec {
+        // When the allocation goes out of scope, this proc is called to free everything associated
+        // with it: the pixels, the "handle", etc. This is passed the pixel address and fReleaseCtx.
+        void    (*fReleaseProc)(void* pixels, void* ctx);
+        void*   fReleaseCtx;    // context passed to fReleaseProc
+        void*   fPixels;        // pixels for this allocation
+        size_t  fRowBytes;      // rowbytes for these pixels
+        Handle  fHandle;        // public handle returned by SkCanvas::accessTopRasterHandle()
+    };
+
+    /**
+     *  Given a requested info, allocate the corresponding pixels/rowbytes, and whatever handle
+     *  is desired to give clients access to those pixels. The rec also contains a proc and context
+     *  which will be called when this allocation goes out of scope.
+     *
+     *  e.g.
+     *      when canvas->saveLayer() is called, the allocator will be called to allocate the pixels
+     *      for the layer. When canvas->restore() is called, the fReleaseProc will be called.
+     */
+    virtual bool allocHandle(const SkImageInfo&, Rec*) = 0;
+
+    /**
+     *  Clients access the handle for a given layer by calling SkCanvas::accessTopRasterHandle().
+     *  To allow the handle to reflect the current matrix/clip in the canvs, updateHandle() is
+     *  is called. The subclass is responsible to update the handle as it sees fit.
+     */
+    virtual void updateHandle(Handle, const SkMatrix&, const SkIRect&) = 0;
+
+    /**
+     *  This creates a canvas which will use the allocator to manage pixel allocations, including
+     *  all calls to saveLayer().
+     *
+     *  If rec is non-null, then it will be used as the base-layer of pixels/handle.
+     *  If rec is null, then the allocator will be called for the base-layer as well.
+     */
+    static std::unique_ptr<SkCanvas> MakeCanvas(std::unique_ptr<SkRasterHandleAllocator>,
+                                                const SkImageInfo&, const Rec* rec = nullptr);
+
+private:
+    friend class SkBitmapDevice;
+
+    Handle allocBitmap(const SkImageInfo&, SkBitmap*);
+};
+
+#endif
index 592f2f6e4140d55f849b0c85139bbb5ec15ba7fa..2dcbb965b4b70493f8d0d25db1c04f661657ff12 100644 (file)
 
 class SkBitmap;
 class SkData;
+class SkPixmap;
 class SkStreamRewindable;
 
+SK_API CGContextRef SkCreateCGContext(const SkPixmap&);
+
 /**
  *  Given a CGImage, allocate an SkBitmap and copy the image's pixels into it. If scaleToFit is not
  *  null, use it to determine the size of the bitmap, and scale the image to fill the bitmap.
index 8ae099051b4457f11e3301211cb9a03015c0ef26..175b728a5c72467352b3be7981537d5f600ead42 100644 (file)
@@ -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 @@ private:
 
 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
index 814019059a403361456c000b5435bd76f8d0a331..6d63ecf6207e555106ef88a4bcc2f894e344121b 100644 (file)
@@ -17,6 +17,7 @@
 #include "SkPixelRef.h"
 #include "SkPixmap.h"
 #include "SkRasterClip.h"
+#include "SkRasterHandleAllocator.h"
 #include "SkShader.h"
 #include "SkSpecialImage.h"
 #include "SkSurface.h"
@@ -79,21 +80,25 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) {
     return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType));
 }
 
-SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps)
+SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps,
+                               SkRasterHandleAllocator::Handle hndl)
     : INHERITED(bitmap.info(), surfaceProps)
     , fBitmap(bitmap)
+    , fRasterHandle(hndl)
 {
     SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr));
     fBitmap.lockPixels();
 }
 
 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
-                                       const SkSurfaceProps& surfaceProps) {
+                                       const SkSurfaceProps& surfaceProps,
+                                       SkRasterHandleAllocator* allocator) {
     SkAlphaType newAT = origInfo.alphaType();
     if (!valid_for_bitmap_device(origInfo, &newAT)) {
         return nullptr;
     }
 
+    SkRasterHandleAllocator::Handle hndl = nullptr;
     const SkImageInfo info = origInfo.makeAlphaType(newAT);
     SkBitmap bitmap;
 
@@ -101,6 +106,11 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
         if (!bitmap.setInfo(info)) {
             return nullptr;
         }
+    } else if (allocator) {
+        hndl = allocator->allocBitmap(info, &bitmap);
+        if (!hndl) {
+            return nullptr;
+        }
     } else if (info.isOpaque()) {
         // If this bitmap is opaque, we don't have any sensible default color,
         // so we just return uninitialized pixels.
@@ -116,7 +126,7 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
         }
     }
 
-    return new SkBitmapDevice(bitmap, surfaceProps);
+    return new SkBitmapDevice(bitmap, surfaceProps, hndl);
 }
 
 void SkBitmapDevice::setNewSize(const SkISize& size) {
@@ -135,7 +145,7 @@ void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
 
 SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
     const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry);
-    return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps);
+    return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps, cinfo.fAllocator);
 }
 
 const SkBitmap& SkBitmapDevice::onAccessBitmap() {
index cb76051add5d48ac5d1d091e3fd0016f155fbbfd..47160531974a2f5cef8859173fd464efda2eef40 100644 (file)
@@ -29,6 +29,7 @@
 #include "SkPicture.h"
 #include "SkRadialShadowMapShader.h"
 #include "SkRasterClip.h"
+#include "SkRasterHandleAllocator.h"
 #include "SkReadPixelsRec.h"
 #include "SkRRect.h"
 #include "SkShadowPaintFilterCanvas.h"
@@ -772,17 +773,21 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props)
     this->init(device.get(), kDefault_InitFlags);
 }
 
-SkCanvas::SkCanvas(const SkBitmap& bitmap)
+SkCanvas::SkCanvas(const SkBitmap& bitmap, std::unique_ptr<SkRasterHandleAllocator> alloc,
+                   SkRasterHandleAllocator::Handle hndl)
     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
     , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
+    , fAllocator(std::move(alloc))
     , fConservativeRasterClip(false)
 {
     inc_canvas();
 
-    sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps));
+    sk_sp<SkBaseDevice> device(new SkBitmapDevice(bitmap, fProps, hndl));
     this->init(device.get(), kDefault_InitFlags);
 }
 
+SkCanvas::SkCanvas(const SkBitmap& bitmap) : SkCanvas(bitmap, nullptr, nullptr) {}
+
 SkCanvas::~SkCanvas() {
     // free up the contents of our deque
     this->restoreToCount(1);    // restore everything but the last
@@ -1260,7 +1265,8 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
                                      (saveLayerFlags & kPreserveLCDText_SaveLayerFlag);
         const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
         const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo,
-                                                                             preserveLCDText);
+                                                                             preserveLCDText,
+                                                                             fAllocator.get());
         newDevice.reset(priorDevice->onCreateDevice(createInfo, paint));
         if (!newDevice) {
             return;
@@ -3404,3 +3410,58 @@ static_assert((int)SkRegion::kUnion_Op              == (int)kUnion_SkClipOp, "")
 static_assert((int)SkRegion::kXOR_Op                == (int)kXOR_SkClipOp, "");
 static_assert((int)SkRegion::kReverseDifference_Op  == (int)kReverseDifference_SkClipOp, "");
 static_assert((int)SkRegion::kReplace_Op            == (int)kReplace_SkClipOp, "");
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkRasterHandleAllocator::Handle SkCanvas::accessTopRasterHandle() const {
+    if (fAllocator && fMCRec->fTopLayer->fDevice) {
+        const SkBaseDevice* dev = fMCRec->fTopLayer->fDevice;
+        SkRasterHandleAllocator::Handle handle = dev->getRasterHandle();
+        SkIPoint origin = dev->getOrigin();
+        SkMatrix ctm = this->getTotalMatrix();
+        ctm.preTranslate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
+
+        SkIRect clip = fMCRec->fRasterClip.getBounds();
+        clip.offset(-origin.x(), -origin.y());
+        if (clip.intersect(0, 0, dev->width(), dev->height())) {
+            clip.setEmpty();
+        }
+
+        fAllocator->updateHandle(handle, ctm, clip);
+        return handle;
+    }
+    return nullptr;
+}
+
+static bool install(SkBitmap* bm, const SkImageInfo& info,
+                    const SkRasterHandleAllocator::Rec& rec) {
+    return bm->installPixels(info, rec.fPixels, rec.fRowBytes, nullptr,
+                             rec.fReleaseProc, rec.fReleaseCtx);
+}
+
+SkRasterHandleAllocator::Handle SkRasterHandleAllocator::allocBitmap(const SkImageInfo& info,
+                                                                     SkBitmap* bm) {
+    SkRasterHandleAllocator::Rec rec;
+    if (!this->allocHandle(info, &rec) || !install(bm, info, rec)) {
+        return nullptr;
+    }
+    return rec.fHandle;
+}
+
+std::unique_ptr<SkCanvas>
+SkRasterHandleAllocator::MakeCanvas(std::unique_ptr<SkRasterHandleAllocator> alloc,
+                                    const SkImageInfo& info, const Rec* rec) {
+    if (!alloc || !supported_for_raster_canvas(info)) {
+        return nullptr;
+    }
+
+    SkBitmap bm;
+    Handle hndl;
+
+    if (rec) {
+        hndl = install(&bm, info, *rec) ? rec->fHandle : nullptr;
+    } else {
+        hndl = alloc->allocBitmap(info, &bm);
+    }
+    return hndl ? std::unique_ptr<SkCanvas>(new SkCanvas(bm, std::move(alloc), hndl)) : nullptr;
+}
index 1b7e12bde5896af4cb62ce8fa70a0a97a2b941e4..e3735920a1d19954f9b1266d821c992e18bfd461 100644 (file)
@@ -178,6 +178,30 @@ void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+CGContextRef SkCreateCGContext(const SkPixmap& pmap) {
+    CGBitmapInfo cg_bitmap_info = 0;
+    size_t bitsPerComponent = 0;
+    switch (pmap.colorType()) {
+        case kRGBA_8888_SkColorType:
+            bitsPerComponent = 8;
+            cg_bitmap_info = ComputeCGAlphaInfo_RGBA(pmap.alphaType());
+            break;
+        case kBGRA_8888_SkColorType:
+            bitsPerComponent = 8;
+            cg_bitmap_info = ComputeCGAlphaInfo_BGRA(pmap.alphaType());
+            break;
+        default:
+            return nullptr;   // no other colortypes are supported (for now)
+    }
+
+    size_t rb = pmap.addr() ? pmap.rowBytes() : 0;
+    CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
+    CGContextRef cg = CGBitmapContextCreate(pmap.writable_addr(), pmap.width(), pmap.height(),
+                                            bitsPerComponent, rb, cs, cg_bitmap_info);
+    CFRelease(cs);
+    return cg;
+}
+
 SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
                                     CGImageRef image) {
     CGBitmapInfo cg_bitmap_info = 0;