check-point for image/surface work
authormike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Sun, 29 Jul 2012 20:38:16 +0000 (20:38 +0000)
committermike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Sun, 29 Jul 2012 20:38:16 +0000 (20:38 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@4823 2bbb7eff-a529-9590-31e7-b0007b416f81

gm/image.cpp [new file with mode: 0644]
gm/image.h [new file with mode: 0644]
src/image/SkImage.cpp
src/image/SkImagePriv.cpp
src/image/SkImagePriv.h
src/image/SkSurface.cpp

diff --git a/gm/image.cpp b/gm/image.cpp
new file mode 100644 (file)
index 0000000..0d6443e
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkSurface.h"
+#include "SkCanvas.h"
+
+static void drawContents(SkSurface* surface, SkColor fillC) {
+    SkSize size = SkSize::Make(surface->width(), surface->height());
+    SkAutoTUnref<SkCanvas> canvas(surface->newCanvas());
+
+    SkScalar stroke = size.fWidth / 10;
+    SkScalar radius = (size.fWidth - stroke) / 2;
+
+    SkPaint paint;
+    
+    paint.setAntiAlias(true);
+    paint.setColor(fillC);
+    canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
+    
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setStrokeWidth(stroke);
+    paint.setColor(SK_ColorBLACK);
+    canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
+}
+
+static void test_surface(SkCanvas* canvas, SkSurface* surf) {
+    drawContents(surf, SK_ColorRED);
+    SkImage* imgR = surf->newImageShapshot();
+
+    drawContents(surf, SK_ColorGREEN);
+    SkImage* imgG = surf->newImageShapshot();
+
+    drawContents(surf, SK_ColorBLUE);
+
+    imgR->draw(canvas, 0, 0, NULL);
+    imgG->draw(canvas, 0, 80, NULL);
+    surf->draw(canvas, 0, 160, NULL);
+
+    imgG->unref();
+    imgR->unref();
+}
+
+class ImageGM : public skiagm::GM {
+    void*   fBuffer;
+    SkSize  fSize;
+    enum {
+        W = 64,
+        H = 64,
+        RB = W * 4 + 8,
+    };
+public:
+    ImageGM() {
+        fBuffer = sk_malloc_throw(RB * H);
+        fSize.set(SkIntToScalar(W), SkIntToScalar(H));
+    }
+    
+    virtual ~ImageGM() {
+        sk_free(fBuffer);
+    }
+        
+    
+protected:
+    virtual SkString onShortName() {
+        return SkString("image");
+    }
+    
+    virtual SkISize onISize() {
+        return SkISize::Make(640, 480);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        SkImage::Info info;
+
+        info.fWidth = W;
+        info.fHeight = H;
+        info.fColorType = SkImage::kPMColor_ColorType;
+        info.fAlphaType = SkImage::kPremul_AlphaType;
+        SkAutoTUnref<SkSurface> surf0(SkSurface::NewRasterDirect(info, NULL, fBuffer, RB));
+        SkAutoTUnref<SkSurface> surf1(SkSurface::NewRaster(info, NULL));
+        SkAutoTUnref<SkSurface> surf2(SkSurface::NewPicture(info.fWidth, info.fHeight));
+
+        test_surface(canvas, surf0);
+        canvas->translate(80, 0);
+        test_surface(canvas, surf1);
+        canvas->translate(80, 0);
+        test_surface(canvas, surf2);
+    }
+    
+private:
+    typedef skiagm::GM INHERITED;
+};
+    
+//////////////////////////////////////////////////////////////////////////////
+
+static skiagm::GM* MyFactory(void*) { return new ImageGM; }
+static skiagm::GMRegistry reg(MyFactory);
+    
diff --git a/gm/image.h b/gm/image.h
new file mode 100644 (file)
index 0000000..25711be
--- /dev/null
@@ -0,0 +1,14 @@
+//
+//  image.h
+//  SampleApp
+//
+//  Created by Mike Reed on 7/27/12.
+//
+//
+
+#ifndef __SampleApp__image__
+#define __SampleApp__image__
+
+#include <iostream>
+
+#endif /* defined(__SampleApp__image__) */
index 4d96b9f..9cf9267 100644 (file)
@@ -1,6 +1,7 @@
 #include "SkImage.h"
 #include "SkImagePriv.h"
 #include "SkBitmap.h"
+#include "SkCanvas.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -8,7 +9,7 @@ class SkImage_Base : public SkImage {
 public:
     SkImage_Base(int width, int height) : INHERITED(width, height) {}
 
-    virtual const SkBitmap* asABitmap() { return NULL; }
+    virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) = 0;
 
 private:    
     typedef SkImage INHERITED;
@@ -63,7 +64,7 @@ public:
     SkImage_Raster(const SkImage::Info&, SkColorSpace*, SkData*, size_t rb);
     virtual ~SkImage_Raster();
 
-    virtual const SkBitmap* asABitmap() SK_OVERRIDE;
+    virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
 
     // exposed for SkSurface_Raster via SkNewImageFromPixelRef
     SkImage_Raster(const SkImage::Info&, SkPixelRef*, size_t rowBytes);
@@ -123,8 +124,44 @@ SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes
 
 SkImage_Raster::~SkImage_Raster() {}
 
-const SkBitmap* SkImage_Raster::asABitmap() {
-    return &fBitmap;
+void SkImage_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
+    canvas->drawBitmap(fBitmap, x, y, paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkPicture.h"
+
+class SkImage_Picture : public SkImage_Base {
+public:
+    SkImage_Picture(SkPicture*);
+    virtual ~SkImage_Picture();
+
+    virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
+
+private:
+    SkPicture*  fPicture;
+
+    typedef SkImage_Base INHERITED;
+};
+
+SkImage_Picture::SkImage_Picture(SkPicture* pict) : INHERITED(pict->width(), pict->height()) {
+    pict->endRecording();
+    pict->ref();
+    fPicture = pict;
+}
+
+SkImage_Picture::~SkImage_Picture() {
+    fPicture->unref();
+}
+
+void SkImage_Picture::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+                             const SkPaint* paint) {
+    SkImagePrivDrawPicture(canvas, fPicture, x, y, paint);
+}
+
+SkImage* SkNewImageFromPicture(SkPicture* pict) {
+    return SkNEW_ARGS(SkImage_Picture, (pict));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -188,9 +225,6 @@ uint32_t SkImage::NextUniqueID() {
 
 void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
                    const SkPaint* paint) {
-    const SkBitmap* bitmap = asIB(this)->asABitmap();
-    if (bitmap) {
-        canvas->drawBitmap(*bitmap, x, y, paint);
-    }
+    asIB(this)->onDraw(canvas, x, y, paint);
 }
 
index d0c56fd..ed570ca 100644 (file)
@@ -1,4 +1,6 @@
 #include "SkImagePriv.h"
+#include "SkCanvas.h"
+#include "SkPicture.h"
 
 SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info& info,
                                            bool* isOpaque) {
@@ -98,7 +100,7 @@ SkImage* SkNewImageFromBitmap(const SkBitmap& bm) {
         image = SkNewImageFromPixelRef(info, bm.pixelRef(), bm.rowBytes());
     } else {
         bm.lockPixels();
-        if (NULL == bm.getPixels()) {
+        if (bm.getPixels()) {
             image = SkImage::NewRasterCopy(info, NULL, bm.getPixels(),
                                            bm.rowBytes());
         }
@@ -107,3 +109,28 @@ SkImage* SkNewImageFromBitmap(const SkBitmap& bm) {
     return image;
 }
 
+static bool needs_layer(const SkPaint& paint) {
+    return  0xFF != paint.getAlpha() ||
+    paint.getColorFilter() ||
+    paint.getImageFilter() ||
+    SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode);
+}
+
+void SkImagePrivDrawPicture(SkCanvas* canvas, SkPicture* picture,
+                            SkScalar x, SkScalar y, const SkPaint* paint) {
+    int saveCount = canvas->getSaveCount();
+    
+    if (paint && needs_layer(*paint)) {
+        SkRect bounds;
+        bounds.set(x, y,
+                   x + SkIntToScalar(picture->width()),
+                   y + SkIntToScalar(picture->height()));
+        canvas->saveLayer(&bounds, paint);
+    } else if (x || y) {
+        canvas->save();
+    }
+    
+    canvas->drawPicture(*picture);
+    canvas->restoreToCount(saveCount);
+}
+
index 1c732c3..525ca42 100644 (file)
@@ -5,6 +5,8 @@
 #include "SkBitmap.h"
 #include "SkImage.h"
 
+class SkPicture;
+
 extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info&,
                                                   bool* isOpaque);
 
@@ -20,8 +22,13 @@ extern SkImage* SkNewImageFromPixelRef(const SkImage::Info&, SkPixelRef*,
  */
 extern SkImage* SkNewImageFromBitmap(const SkBitmap&);
 
+extern void SkImagePrivDrawPicture(SkCanvas*, SkPicture*,
+                                   SkScalar x, SkScalar y, const SkPaint*);
+extern SkImage* SkNewImageFromPicture(SkPicture*);
+
 static inline size_t SkImageMinRowBytes(const SkImage::Info& info) {
-    return info.fWidth * SkImageBytesPerPixel(info.fColorType);
+    size_t rb = info.fWidth * SkImageBytesPerPixel(info.fColorType);
+    return SkAlign4(rb);
 }
 
 #endif
index 2a9e33a..1f2c320 100644 (file)
@@ -67,11 +67,14 @@ void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
 
 ///////////////////////////////////////////////////////////////////////////////
 
-class SkSurface_Raster : public SkSurface {
+static const size_t kIgnoreRowBytesValue = (size_t)~0;
+
+class SkSurface_Raster : public SkSurface_Base {
 public:
-    static bool Valid(const SkImage::Info&, SkColorSpace*, size_t rb);
+    static bool Valid(const SkImage::Info&, SkColorSpace*, size_t rb = kIgnoreRowBytesValue);
 
     SkSurface_Raster(const SkImage::Info&, SkColorSpace*, void*, size_t rb);
+    SkSurface_Raster(const SkImage::Info&, SkColorSpace*, SkPixelRef*, size_t rb);
 
     virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
     virtual SkSurface* onNewSurface(const SkImage::Info&, SkColorSpace*) SK_OVERRIDE;
@@ -81,8 +84,9 @@ public:
 
 private:
     SkBitmap    fBitmap;
+    bool        fWeOwnThePixels;
 
-    typedef SkSurface INHERITED;
+    typedef SkSurface_Base INHERITED;
 };
 
 bool SkSurface_Raster::Valid(const SkImage::Info& info, SkColorSpace* cs,
@@ -109,6 +113,10 @@ bool SkSurface_Raster::Valid(const SkImage::Info& info, SkColorSpace* cs,
 
     // TODO: examine colorspace
 
+    if (kIgnoreRowBytesValue == rowBytes) {
+        return true;
+    }
+
     uint64_t minRB = (uint64_t)info.fWidth << shift;
     if (minRB > rowBytes) {
         return false;
@@ -132,10 +140,27 @@ SkSurface_Raster::SkSurface_Raster(const SkImage::Info& info, SkColorSpace* cs,
         : INHERITED(info.fWidth, info.fHeight) {
     bool isOpaque;
     SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
-
+    
     fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
     fBitmap.setPixels(pixels);
     fBitmap.setIsOpaque(isOpaque);
+    fWeOwnThePixels = false;
+}
+
+SkSurface_Raster::SkSurface_Raster(const SkImage::Info& info, SkColorSpace* cs,
+                                   SkPixelRef* pr, size_t rb)
+        : INHERITED(info.fWidth, info.fHeight) {
+    bool isOpaque;
+    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+    fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
+    fBitmap.setPixelRef(pr);
+    fBitmap.setIsOpaque(isOpaque);
+    fWeOwnThePixels = true;
+
+    if (!isOpaque) {
+        fBitmap.eraseColor(0);
+    }
 }
 
 SkCanvas* SkSurface_Raster::onNewCanvas() {
@@ -148,6 +173,9 @@ SkSurface* SkSurface_Raster::onNewSurface(const SkImage::Info& info,
 }
 
 SkImage* SkSurface_Raster::onNewImageShapshot() {
+    // if we don't own the pixels, we need to make a deep-copy
+    // if we do, we need to perform a copy-on-write the next time
+    // we draw to this bitmap from our canvas...
     return SkNewImageFromBitmap(fBitmap);
 }
 
@@ -158,6 +186,75 @@ void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
 
 ///////////////////////////////////////////////////////////////////////////////
 
+#include "SkPicture.h"
+
+/**
+ *  What does it mean to ask for more than one canvas from a picture?
+ *  How do we return an Image and then "continue" recording?
+ */
+class SkSurface_Picture : public SkSurface_Base {
+public:
+    SkSurface_Picture(int width, int height);
+    virtual ~SkSurface_Picture();
+    
+    virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
+    virtual SkSurface* onNewSurface(const SkImage::Info&, SkColorSpace*) SK_OVERRIDE;
+    virtual SkImage* onNewImageShapshot() SK_OVERRIDE;
+    virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
+                        const SkPaint*) SK_OVERRIDE;
+    
+private:
+    SkPicture*  fPicture;
+    SkPicture*  fRecordingPicture;
+    
+    typedef SkSurface_Base INHERITED;
+};
+
+SkSurface_Picture::SkSurface_Picture(int width, int height) : INHERITED(width, height) {
+    fPicture = NULL;
+}
+
+SkSurface_Picture::~SkSurface_Picture() {
+    SkSafeUnref(fPicture);
+}
+
+SkCanvas* SkSurface_Picture::onNewCanvas() {
+    if (!fPicture) {
+        fPicture = SkNEW(SkPicture);
+    }
+    SkCanvas* canvas = fPicture->beginRecording(this->width(), this->height());
+    canvas->ref();  // our caller will call unref()
+    return canvas;
+}
+
+SkSurface* SkSurface_Picture::onNewSurface(const SkImage::Info& info, SkColorSpace*) {
+    return SkSurface::NewPicture(info.fWidth, info.fHeight);
+}
+
+SkImage* SkSurface_Picture::onNewImageShapshot() {
+    if (fPicture) {
+        return SkNewImageFromPicture(fPicture);
+    } else {
+        SkImage::Info info;
+        info.fWidth = info.fHeight = 0;
+        info.fColorType = SkImage::kPMColor_ColorType;
+        info.fAlphaType = SkImage::kOpaque_AlphaType;
+        return SkImage::NewRasterCopy(info, NULL, NULL, 0);
+    }
+}
+
+void SkSurface_Picture::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+                               const SkPaint* paint) {
+    if (!fPicture) {
+        return;
+    }
+    SkImagePrivDrawPicture(canvas, fPicture, x, y, paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkMallocPixelRef.h"
+
 SkSurface* SkSurface::NewRasterDirect(const SkImage::Info& info,
                                       SkColorSpace* cs,
                                       void* pixels, size_t rowBytes) {
@@ -171,3 +268,33 @@ SkSurface* SkSurface::NewRasterDirect(const SkImage::Info& info,
     return SkNEW_ARGS(SkSurface_Raster, (info, cs, pixels, rowBytes));
 }
 
+SkSurface* SkSurface::NewRaster(const SkImage::Info& info, SkColorSpace* cs) {
+    if (!SkSurface_Raster::Valid(info, cs)) {
+        return NULL;
+    }
+
+    size_t kMaxTotalSize = (1 << 31) - 1;
+    size_t rowBytes = SkImageMinRowBytes(info);
+    uint64_t size64 = (uint64_t)info.fHeight * rowBytes;
+    if (size64 > kMaxTotalSize) {
+        return NULL;
+    }
+
+    size_t size = (size_t)size64;
+    void* pixels = sk_malloc_throw(size);
+    if (NULL == pixels) {
+        return NULL;
+    }
+
+    SkAutoTUnref<SkPixelRef> pr(SkNEW_ARGS(SkMallocPixelRef, (pixels, size, NULL, true)));
+    return SkNEW_ARGS(SkSurface_Raster, (info, cs, pr, rowBytes));
+}
+
+SkSurface* SkSurface::NewPicture(int width, int height) {
+    if ((width | height) < 0) {
+        return NULL;
+    }
+
+    return SkNEW_ARGS(SkSurface_Picture, (width, height));
+}
+