aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/utils
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-29 21:00:39 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-29 21:00:39 +0000
commitfe7b1ed30a75cecfe80d1ba4d1f60295e99aeef0 (patch)
tree05dd1397127c756a562bd54cbfccbb1f35d99e67 /src/utils
parent417bc1382ee527077d96414552b52050335b3350 (diff)
add SkPictureUtils::GatherPixelRefs()
Review URL: https://codereview.appspot.com/6845106 git-svn-id: http://skia.googlecode.com/svn/trunk@6615 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/SkPictureUtils.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp
new file mode 100644
index 0000000000..16cf11d2e0
--- /dev/null
+++ b/src/utils/SkPictureUtils.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPictureUtils.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkDevice.h"
+#include "SkPixelRef.h"
+#include "SkShader.h"
+
+class PixelRefSet {
+public:
+ PixelRefSet(SkTDArray<SkPixelRef*>* array) : fArray(array) {}
+
+ // This does a linear search on existing pixelrefs, so if this list gets big
+ // we should use a more complex sorted/hashy thing.
+ //
+ void add(SkPixelRef* pr) {
+ uint32_t genID = pr->getGenerationID();
+ if (fGenID.find(genID) < 0) {
+ *fArray->append() = pr;
+ *fGenID.append() = genID;
+// SkDebugf("--- adding [%d] %x %d\n", fArray->count() - 1, pr, genID);
+ } else {
+// SkDebugf("--- already have %x %d\n", pr, genID);
+ }
+ }
+
+private:
+ SkTDArray<SkPixelRef*>* fArray;
+ SkTDArray<uint32_t> fGenID;
+};
+
+static void not_supported() {
+ SkASSERT(!"this method should never be called");
+}
+
+static void nothing_to_do() {}
+
+/**
+ * This device will route all bitmaps (primitives and in shaders) to its PRSet.
+ * It should never actually draw anything, so there need not be any pixels
+ * behind its device-bitmap.
+ */
+class GatherPixelRefDevice : public SkDevice {
+private:
+ PixelRefSet* fPRSet;
+
+ void addBitmap(const SkBitmap& bm) {
+ fPRSet->add(bm.pixelRef());
+ }
+
+ void addBitmapFromPaint(const SkPaint& paint) {
+ SkShader* shader = paint.getShader();
+ if (shader) {
+ SkBitmap bm;
+ if (shader->asABitmap(&bm, NULL, NULL)) {
+ fPRSet->add(bm.pixelRef());
+ }
+ }
+ }
+
+public:
+ GatherPixelRefDevice(const SkBitmap& bm, PixelRefSet* prset) : SkDevice(bm) {
+ fPRSet = prset;
+ }
+
+ virtual void clear(SkColor color) SK_OVERRIDE {
+ nothing_to_do();
+ }
+ virtual void writePixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888 config8888) SK_OVERRIDE {
+ not_supported();
+ }
+
+ virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
+ const SkPoint[], const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawRect(const SkDraw&, const SkRect& r,
+ const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawPath(const SkDraw&, const SkPath& path,
+ const SkPaint& paint, const SkMatrix* prePathMatrix,
+ bool pathIsMutable) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
+ const SkIRect* srcRectOrNull,
+ const SkMatrix&, const SkPaint&) SK_OVERRIDE {
+ this->addBitmap(bitmap);
+ }
+ virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap,
+ const SkRect* srcOrNull, const SkRect& dst,
+ const SkPaint&) SK_OVERRIDE {
+ this->addBitmap(bitmap);
+ }
+ virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
+ int x, int y, const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmap(bitmap);
+ }
+ virtual void drawText(const SkDraw&, const void* text, size_t len,
+ SkScalar x, SkScalar y,
+ const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawPosText(const SkDraw&, const void* text, size_t len,
+ const SkScalar pos[], SkScalar constY,
+ int, const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
+ const SkPoint verts[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) SK_OVERRIDE {
+ this->addBitmapFromPaint(paint);
+ }
+ virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
+ const SkPaint&) SK_OVERRIDE {
+ nothing_to_do();
+ }
+
+protected:
+ virtual bool onReadPixels(const SkBitmap& bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888) SK_OVERRIDE {
+ not_supported();
+ return false;
+ }
+};
+
+class NoSaveLayerCanvas : public SkCanvas {
+public:
+ NoSaveLayerCanvas(SkDevice* device) : INHERITED(device) {}
+
+ // turn saveLayer() into save() for speed, should not affect correctness.
+ virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags flags) SK_OVERRIDE {
+
+ // Like SkPictureRecord, we don't want to create layers, but we do need
+ // to respect the save and (possibly) its rect-clip.
+
+ int count = this->INHERITED::save(flags);
+ if (bounds) {
+ this->INHERITED::clipRectBounds(bounds, flags, NULL);
+ }
+ return count;
+ }
+
+ // disable aa for speed
+ virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
+ bool doAA) SK_OVERRIDE {
+ return this->INHERITED::clipRect(rect, op, false);
+ }
+
+ // for speed, just respect the bounds, and disable AA. May give us a few
+ // false positives and negatives.
+ virtual bool clipPath(const SkPath& path, SkRegion::Op op,
+ bool doAA) SK_OVERRIDE {
+ return this->INHERITED::clipRect(path.getBounds(), op, false);
+ }
+
+private:
+ typedef SkCanvas INHERITED;
+};
+
+SkData* SkPictureUtils::GatherPixelRefs(SkPicture* pict, const SkRect& area) {
+ if (NULL == pict) {
+ return NULL;
+ }
+
+ // this test also handles if either area or pict's width/height are empty
+ if (!SkRect::Intersects(area,
+ SkRect::MakeWH(SkIntToScalar(pict->width()),
+ SkIntToScalar(pict->height())))) {
+ return NULL;
+ }
+
+ SkTDArray<SkPixelRef*> array;
+ PixelRefSet prset(&array);
+
+ SkBitmap emptyBitmap;
+ emptyBitmap.setConfig(SkBitmap::kARGB_8888_Config, pict->width(), pict->height());
+ // note: we do not set any pixels (shouldn't need to)
+
+ GatherPixelRefDevice device(emptyBitmap, &prset);
+ NoSaveLayerCanvas canvas(&device);
+
+ canvas.clipRect(area, SkRegion::kIntersect_Op, false);
+ canvas.drawPicture(*pict);
+
+ SkData* data = NULL;
+ int count = array.count();
+ if (count > 0) {
+ data = SkData::NewFromMalloc(array.detach(), count * sizeof(SkPixelRef*));
+ }
+ return data;
+}
+