aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2015-06-25 12:32:03 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-06-25 12:32:03 -0700
commit4c21dc5ddf3b482293ed34eead876d8d61a662c3 (patch)
tree390454c66e28c94a8a59b8d5ca881ef4b94e9fe2 /src/core
parentb4022965a280dd1ed64d6103dd29e2189abe6e00 (diff)
add drawImageNine
this also exposes nine-patch drawing directly to devices, and creates a shared iterator for unrolling a nine-patch into single rect->rect draws. BUG=skia: Review URL: https://codereview.chromium.org/1211583003
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkCanvas.cpp123
-rw-r--r--src/core/SkDevice.cpp21
-rw-r--r--src/core/SkNinePatchIter.cpp72
-rw-r--r--src/core/SkNinePatchIter.h42
-rw-r--r--src/core/SkPictureFlat.h3
-rw-r--r--src/core/SkPicturePlayback.cpp7
-rw-r--r--src/core/SkPictureRecord.cpp17
-rw-r--r--src/core/SkPictureRecord.h2
-rw-r--r--src/core/SkRecordDraw.cpp4
-rw-r--r--src/core/SkRecorder.cpp5
-rw-r--r--src/core/SkRecorder.h2
-rw-r--r--src/core/SkRecords.h5
12 files changed, 237 insertions, 66 deletions
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index d7c62e8e11..88339ff4f3 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -16,6 +16,7 @@
#include "SkErrorInternals.h"
#include "SkImage.h"
#include "SkMetaData.h"
+#include "SkNinePatchIter.h"
#include "SkPathOps.h"
#include "SkPatchUtils.h"
#include "SkPicture.h"
@@ -1771,8 +1772,19 @@ void SkCanvas::drawImageRect(const SkImage* image, const SkRect* src, const SkRe
this->onDrawImageRect(image, src, dst, paint);
}
+void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) {
+ if (dst.isEmpty()) {
+ return;
+ }
+ if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
+ this->drawImageRect(image, NULL, dst, paint);
+ }
+ this->onDrawImageNine(image, center, dst, paint);
+}
+
void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
- if (bitmap.empty()) {
+ if (bitmap.drawsNothing()) {
return;
}
this->onDrawBitmap(bitmap, dx, dy, paint);
@@ -1780,7 +1792,7 @@ void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, cons
void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
const SkPaint* paint, DrawBitmapRectFlags flags) {
- if (bitmap.empty()) {
+ if (bitmap.drawsNothing() || dst.isEmpty()) {
return;
}
this->onDrawBitmapRect(bitmap, src, dst, paint, flags);
@@ -1788,14 +1800,17 @@ void SkCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, c
void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
const SkPaint* paint) {
- if (bitmap.empty()) {
+ if (bitmap.drawsNothing() || dst.isEmpty()) {
return;
}
+ if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
+ this->drawBitmapRectToRect(bitmap, NULL, dst, paint);
+ }
this->onDrawBitmapNine(bitmap, center, dst, paint);
}
void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
- if (bitmap.empty()) {
+ if (bitmap.drawsNothing()) {
return;
}
this->onDrawSprite(bitmap, left, top, paint);
@@ -2116,15 +2131,13 @@ void SkCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const
this->internalDrawBitmapRect(bitmap, src, dst, paint, flags);
}
-void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
- const SkIRect& center, const SkRect& dst,
- const SkPaint* paint) {
- if (bitmap.drawsNothing()) {
- return;
- }
+void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) {
+ TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
+
+ SkRect storage;
+ const SkRect* bounds = &dst;
if (NULL == paint || paint->canComputeFastBounds()) {
- SkRect storage;
- const SkRect* bounds = &dst;
if (paint) {
bounds = &paint->computeFastBounds(dst, &storage);
}
@@ -2132,58 +2145,19 @@ void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
return;
}
}
-
- const int32_t w = bitmap.width();
- const int32_t h = bitmap.height();
-
- SkIRect c = center;
- // pin center to the bounds of the bitmap
- c.fLeft = SkMax32(0, center.fLeft);
- c.fTop = SkMax32(0, center.fTop);
- c.fRight = SkPin32(center.fRight, c.fLeft, w);
- c.fBottom = SkPin32(center.fBottom, c.fTop, h);
-
- const SkScalar srcX[4] = {
- 0, SkIntToScalar(c.fLeft), SkIntToScalar(c.fRight), SkIntToScalar(w)
- };
- const SkScalar srcY[4] = {
- 0, SkIntToScalar(c.fTop), SkIntToScalar(c.fBottom), SkIntToScalar(h)
- };
- SkScalar dstX[4] = {
- dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
- dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
- };
- SkScalar dstY[4] = {
- dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
- dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
- };
-
- if (dstX[1] > dstX[2]) {
- dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
- dstX[2] = dstX[1];
- }
-
- if (dstY[1] > dstY[2]) {
- dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
- dstY[2] = dstY[1];
+
+ SkLazyPaint lazy;
+ if (NULL == paint) {
+ paint = lazy.init();
}
-
- for (int y = 0; y < 3; y++) {
- SkRect s, d;
-
- s.fTop = srcY[y];
- s.fBottom = srcY[y+1];
- d.fTop = dstY[y];
- d.fBottom = dstY[y+1];
- for (int x = 0; x < 3; x++) {
- s.fLeft = srcX[x];
- s.fRight = srcX[x+1];
- d.fLeft = dstX[x];
- d.fRight = dstX[x+1];
- this->internalDrawBitmapRect(bitmap, &s, d, paint,
- kNone_DrawBitmapRectFlag);
- }
+
+ LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
+
+ while (iter.next()) {
+ iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
}
+
+ LOOPER_END
}
void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
@@ -2191,8 +2165,29 @@ void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, c
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawBitmapNine()");
SkDEBUGCODE(bitmap.validate();)
- // Need a device entry-point, so gpu can use a mesh
- this->internalDrawBitmapNine(bitmap, center, dst, paint);
+ SkRect storage;
+ const SkRect* bounds = &dst;
+ if (NULL == paint || paint->canComputeFastBounds()) {
+ if (paint) {
+ bounds = &paint->computeFastBounds(dst, &storage);
+ }
+ if (this->quickReject(*bounds)) {
+ return;
+ }
+ }
+
+ SkLazyPaint lazy;
+ if (NULL == paint) {
+ paint = lazy.init();
+ }
+
+ LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
+
+ while (iter.next()) {
+ iter.fDevice->drawBitmapNine(iter, bitmap, center, dst, looper.paint());
+ }
+
+ LOOPER_END
}
class SkDeviceFilteredPaint {
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 8f7f50c863..90161b4eb3 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -11,6 +11,7 @@
#include "SkDrawFilter.h"
#include "SkImage_Base.h"
#include "SkMetaData.h"
+#include "SkNinePatchIter.h"
#include "SkPatchUtils.h"
#include "SkPathMeasure.h"
#include "SkRasterClip.h"
@@ -161,6 +162,26 @@ void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const
}
}
+void SkBaseDevice::drawImageNine(const SkDraw& draw, const SkImage* image, const SkIRect& center,
+ const SkRect& dst, const SkPaint& paint) {
+ SkNinePatchIter iter(image->width(), image->height(), center, dst);
+
+ SkRect srcR, dstR;
+ while (iter.next(&srcR, &dstR)) {
+ this->drawImageRect(draw, image, &srcR, dstR, paint);
+ }
+}
+
+void SkBaseDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint& paint) {
+ SkNinePatchIter iter(bitmap.width(), bitmap.height(), center, dst);
+
+ SkRect srcR, dstR;
+ while (iter.next(&srcR, &dstR)) {
+ this->drawBitmapRect(draw, bitmap, &srcR, dstR, paint, SkCanvas::kNone_DrawBitmapRectFlag);
+ }
+}
+
void SkBaseDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count,
SkXfermode::Mode mode, const SkPaint& paint) {
diff --git a/src/core/SkNinePatchIter.cpp b/src/core/SkNinePatchIter.cpp
new file mode 100644
index 0000000000..c6bd16dcdb
--- /dev/null
+++ b/src/core/SkNinePatchIter.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkNinePatchIter.h"
+#include "SkRect.h"
+
+bool SkNinePatchIter::Valid(int width, int height, const SkIRect& center) {
+ return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center);
+}
+
+SkNinePatchIter::SkNinePatchIter(int w, int h, const SkIRect& c, const SkRect& dst) {
+ SkASSERT(SkIRect::MakeWH(w, h).contains(c));
+
+ fSrcX[0] = 0;
+ fSrcX[1] = SkIntToScalar(c.fLeft);
+ fSrcX[2] = SkIntToScalar(c.fRight);
+ fSrcX[3] = SkIntToScalar(w);
+
+ fSrcY[0] = 0;
+ fSrcY[1] = SkIntToScalar(c.fTop);
+ fSrcY[2] = SkIntToScalar(c.fBottom);
+ fSrcY[3] = SkIntToScalar(h);
+
+ fDstX[0] = dst.fLeft;
+ fDstX[1] = dst.fLeft + SkIntToScalar(c.fLeft);
+ fDstX[2] = dst.fRight - SkIntToScalar(w - c.fRight);
+ fDstX[3] = dst.fRight;
+
+ fDstY[0] = dst.fTop;
+ fDstY[1] = dst.fTop + SkIntToScalar(c.fTop);
+ fDstY[2] = dst.fBottom - SkIntToScalar(h - c.fBottom);
+ fDstY[3] = dst.fBottom;
+
+ if (fDstX[1] > fDstX[2]) {
+ fDstX[1] = fDstX[0] + (fDstX[3] - fDstX[0]) * c.fLeft / (w - c.width());
+ fDstX[2] = fDstX[1];
+ }
+
+ if (fDstY[1] > fDstY[2]) {
+ fDstY[1] = fDstY[0] + (fDstY[3] - fDstY[0]) * c.fTop / (h - c.height());
+ fDstY[2] = fDstY[1];
+ }
+
+ fCurrX = fCurrY = 0;
+ fDone = false;
+}
+
+bool SkNinePatchIter::next(SkRect* src, SkRect* dst) {
+ if (fDone) {
+ return false;
+ }
+
+ const int x = fCurrX;
+ const int y = fCurrY;
+ SkASSERT(x >= 0 && x < 4);
+ SkASSERT(y >= 0 && y < 4);
+
+ src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]);
+ dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]);
+ if (4 == ++fCurrX) {
+ fCurrX = 0;
+ fCurrY += 1;
+ if (fCurrY >= 4) {
+ fDone = true;
+ }
+ }
+ return true;
+}
diff --git a/src/core/SkNinePatchIter.h b/src/core/SkNinePatchIter.h
new file mode 100644
index 0000000000..2d7e9a8b19
--- /dev/null
+++ b/src/core/SkNinePatchIter.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkNinePatchIter_DEFINED
+#define SkNinePatchIter_DEFINED
+
+#include "SkScalar.h"
+
+struct SkIRect;
+struct SkRect;
+
+/**
+ * Disect a ninepatch request into an sequence of src-rect / dst-rect pairs
+ */
+class SkNinePatchIter {
+public:
+ static bool Valid(int imageWidth, int imageHeight, const SkIRect& center);
+
+ SkNinePatchIter(int imageWidth, int imageHeight, const SkIRect& center, const SkRect& dst);
+
+ /**
+ * While it returns true, use src/dst to draw the image/bitmap
+ */
+ bool next(SkRect* src, SkRect* dst);
+
+private:
+ SkScalar fSrcX[4];
+ SkScalar fSrcY[4];
+ SkScalar fDstX[4];
+ SkScalar fDstY[4];
+
+ int fCurrX;
+ int fCurrY;
+ bool fDone;
+};
+
+#endif
+
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 07411002ae..d421c47603 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -72,8 +72,9 @@ enum DrawType {
DRAW_IMAGE,
DRAW_IMAGE_RECT,
DRAW_ATLAS,
+ DRAW_IMAGE_NINE,
- LAST_DRAWTYPE_ENUM = DRAW_ATLAS
+ LAST_DRAWTYPE_ENUM = DRAW_IMAGE_NINE
};
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index a1bb1ba293..1cf1a1bfb4 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -242,6 +242,13 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
const SkPoint& loc = reader->skipT<SkPoint>();
canvas->drawImage(image, loc.fX, loc.fY, paint);
} break;
+ case DRAW_IMAGE_NINE: {
+ const SkPaint* paint = fPictureData->getPaint(reader);
+ const SkImage* image = fPictureData->getImage(reader);
+ const SkIRect& center = reader->skipT<SkIRect>();
+ const SkRect& dst = reader->skipT<SkRect>();
+ canvas->drawImageNine(image, center, dst, paint);
+ } break;
case DRAW_IMAGE_RECT: {
const SkPaint* paint = fPictureData->getPaint(reader);
const SkImage* image = fPictureData->getImage(reader);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 0fbf98089a..5f85b47aac 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -101,6 +101,7 @@ static inline size_t get_paint_offset(DrawType op, size_t opSize) {
1, // DRAW_IMAGE - right after op code
1, // DRAW_IMAGE_RECT - right after op code
1, // DRAW_ATLAS - right after op code
+ 1, // DRAW_IMAGE_NINE - right after op code
};
SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
@@ -584,7 +585,7 @@ void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
const SkPaint* paint) {
- // id + paint_index + bitmap_index + bool_for_src
+ // id + paint_index + image_index + bool_for_src
size_t size = 4 * kUInt32Size;
if (src) {
size += sizeof(*src); // + rect
@@ -601,6 +602,20 @@ void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, c
this->validate(initialOffset, size);
}
+void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) {
+ // id + paint_index + image_index + center + dst
+ size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
+
+ size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
+ SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_NINE, size) == fWriter.bytesWritten());
+ this->addPaintPtr(paint);
+ this->addImage(img);
+ this->addIRect(center);
+ this->addRect(dst);
+ this->validate(initialOffset, size);
+}
+
void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
const SkRect& dst, const SkPaint* paint) {
// op + paint index + bitmap id + center + dst rect
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index cee5ea35f5..e2d5f7d1df 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -188,6 +188,8 @@ protected:
void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint*) override;
+ void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+ const SkPaint*) override;
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override;
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 944443c8ee..af71624474 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -97,6 +97,7 @@ DRAW(DrawBitmapRectToRectBleed,
DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint));
DRAW(DrawImage, drawImage(r.image, r.left, r.top, r.paint));
DRAW(DrawImageRect, drawImageRect(r.image, r.src, r.dst, r.paint));
+DRAW(DrawImageNine, drawImageNine(r.image, r.center, r.dst, r.paint));
DRAW(DrawOval, drawOval(r.oval, r.paint));
DRAW(DrawPaint, drawPaint(r.paint));
DRAW(DrawPath, drawPath(r.path, r.paint));
@@ -413,6 +414,9 @@ private:
Bounds bounds(const DrawImageRect& op) const {
return this->adjustAndMap(op.dst, op.paint);
}
+ Bounds bounds(const DrawImageNine& op) const {
+ return this->adjustAndMap(op.dst, op.paint);
+ }
Bounds bounds(const DrawBitmapRectToRect& op) const {
return this->adjustAndMap(op.dst, op.paint);
}
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 812fd9d49c..c27405575c 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -222,6 +222,11 @@ void SkRecorder::onDrawImageRect(const SkImage* image, const SkRect* src,
APPEND(DrawImageRect, this->copy(paint), image, this->copy(src), dst);
}
+void SkRecorder::onDrawImageNine(const SkImage* image, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint) {
+ APPEND(DrawImageNine, this->copy(paint), image, center, dst);
+}
+
void SkRecorder::onDrawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
APPEND(DrawSprite, this->copy(paint), delay_copy(bitmap), left, top);
}
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 53c658fa6f..3809ae239d 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -100,6 +100,8 @@ public:
void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint*) override;
+ void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+ const SkPaint*) override;
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
void onDrawSprite(const SkBitmap&, int left, int top, const SkPaint*) override;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 381f91438b..8e778bf7a2 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -44,6 +44,7 @@ namespace SkRecords {
M(DrawDrawable) \
M(DrawImage) \
M(DrawImageRect) \
+ M(DrawImageNine) \
M(DrawDRRect) \
M(DrawOval) \
M(DrawPaint) \
@@ -288,6 +289,10 @@ RECORD4(DrawImageRect, Optional<SkPaint>, paint,
RefBox<const SkImage>, image,
Optional<SkRect>, src,
SkRect, dst);
+RECORD4(DrawImageNine, Optional<SkPaint>, paint,
+ RefBox<const SkImage>, image,
+ SkIRect, center,
+ SkRect, dst);
RECORD2(DrawOval, SkPaint, paint, SkRect, oval);
RECORD1(DrawPaint, SkPaint, paint);
RECORD2(DrawPath, SkPaint, paint, PreCachedPath, path);