aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/ninepatchstretch.cpp69
-rw-r--r--gyp/core.gypi1
-rw-r--r--include/core/SkCanvas.h22
-rw-r--r--include/core/SkDevice.h4
-rw-r--r--include/utils/SkDeferredCanvas.h2
-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
-rw-r--r--src/pipe/SkGPipePriv.h1
-rw-r--r--src/pipe/SkGPipeRead.cpp14
-rw-r--r--src/pipe/SkGPipeWrite.cpp12
-rw-r--r--src/utils/SkDeferredCanvas.cpp16
21 files changed, 349 insertions, 95 deletions
diff --git a/gm/ninepatchstretch.cpp b/gm/ninepatchstretch.cpp
index 5031480aa5..267c41587b 100644
--- a/gm/ninepatchstretch.cpp
+++ b/gm/ninepatchstretch.cpp
@@ -6,15 +6,24 @@
*/
#include "gm.h"
+#include "SkSurface.h"
-static void make_bitmap(SkBitmap* bitmap, SkIRect* center) {
+static SkSurface* make_surface(SkCanvas* root, int N) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
+ SkSurface* surface = root->newSurface(info);
+ if (!surface) {
+ surface = SkSurface::NewRaster(info);
+ }
+ return surface;
+}
+
+static SkImage* make_image(SkCanvas* root, SkIRect* center) {
const int kFixed = 28;
const int kStretchy = 8;
const int kSize = 2*kFixed + kStretchy;
- bitmap->allocN32Pixels(kSize, kSize);
- SkCanvas canvas(*bitmap);
- canvas.clear(SK_ColorTRANSPARENT);
+ SkAutoTUnref<SkSurface> surface(make_surface(root, kSize));
+ SkCanvas* canvas = surface->getCanvas();
SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
const SkScalar strokeWidth = SkIntToScalar(6);
@@ -26,39 +35,48 @@ static void make_bitmap(SkBitmap* bitmap, SkIRect* center) {
paint.setAntiAlias(true);
paint.setColor(0xFFFF0000);
- canvas.drawRoundRect(r, radius, radius, paint);
+ canvas->drawRoundRect(r, radius, radius, paint);
r.setXYWH(SkIntToScalar(kFixed), 0, SkIntToScalar(kStretchy), SkIntToScalar(kSize));
paint.setColor(0x8800FF00);
- canvas.drawRect(r, paint);
+ canvas->drawRect(r, paint);
r.setXYWH(0, SkIntToScalar(kFixed), SkIntToScalar(kSize), SkIntToScalar(kStretchy));
paint.setColor(0x880000FF);
- canvas.drawRect(r, paint);
+ canvas->drawRect(r, paint);
+
+ return surface->newImageSnapshot();
}
-namespace skiagm {
+static void image_to_bitmap(const SkImage* image, SkBitmap* bm) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height());
+ bm->allocPixels(info);
+ image->readPixels(info, bm->getPixels(), bm->rowBytes(), 0, 0);
+}
-class NinePatchStretchGM : public GM {
+class NinePatchStretchGM : public skiagm::GM {
public:
- SkBitmap fBM;
+ SkAutoTUnref<SkImage> fImage;
+ SkBitmap fBitmap;
+ SkIRect fCenter;
NinePatchStretchGM() {}
protected:
- virtual SkString onShortName() {
+ SkString onShortName() override {
return SkString("ninepatch-stretch");
}
- virtual SkISize onISize() {
- return SkISize::Make(400, 400);
+ SkISize onISize() override {
+ return SkISize::Make(760, 400);
}
- virtual void onDraw(SkCanvas* canvas) {
- SkBitmap bm;
- SkIRect center;
- make_bitmap(&bm, &center);
+ void onDraw(SkCanvas* canvas) override {
+ if (NULL == fBitmap.pixelRef()) {
+ fImage.reset(make_image(canvas, &fCenter));
+ image_to_bitmap(fImage, &fBitmap);
+ }
// amount of bm that should not be stretched (unless we have to)
- const SkScalar fixed = SkIntToScalar(bm.width() - center.width());
+ const SkScalar fixed = SkIntToScalar(fBitmap.width() - fCenter.width());
const SkTSize<SkScalar> size[] = {
{ fixed * 4 / 5, fixed * 4 / 5 }, // shrink in both axes
@@ -67,7 +85,7 @@ protected:
{ fixed * 4, fixed * 4 }
};
- canvas->drawBitmap(bm, SkIntToScalar(10), SkIntToScalar(10), NULL);
+ canvas->drawBitmap(fBitmap, 10, 10, NULL);
SkScalar x = SkIntToScalar(100);
SkScalar y = SkIntToScalar(100);
@@ -80,18 +98,15 @@ protected:
int i = ix * 2 + iy;
SkRect r = SkRect::MakeXYWH(x + ix * fixed, y + iy * fixed,
size[i].width(), size[i].height());
- canvas->drawBitmapNine(bm, center, r, &paint);
+ canvas->drawBitmapNine(fBitmap, fCenter, r, &paint);
+ canvas->drawImageNine(fImage, fCenter, r.makeOffset(360, 0), &paint);
+
}
}
}
private:
- typedef GM INHERITED;
+ typedef skiagm::GM INHERITED;
};
+DEF_GM( return new NinePatchStretchGM; )
-//////////////////////////////////////////////////////////////////////////////
-
-static GM* MyFactory(void*) { return new NinePatchStretchGM; }
-static GMRegistry reg(MyFactory);
-
-}
diff --git a/gyp/core.gypi b/gyp/core.gypi
index c41ba187eb..4da1685c10 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -134,6 +134,7 @@
'<(skia_src_path)/core/SkMipMap.cpp',
'<(skia_src_path)/core/SkMiniRecorder.cpp',
'<(skia_src_path)/core/SkMultiPictureDraw.cpp',
+ '<(skia_src_path)/core/SkNinePatchIter.cpp',
'<(skia_src_path)/core/SkPackBits.cpp',
'<(skia_src_path)/core/SkPaint.cpp',
'<(skia_src_path)/core/SkPaintPriv.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 7bdb6d219c..7bff02a6a9 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -792,6 +792,23 @@ public:
void drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
const SkPaint* paint = NULL);
+ /**
+ * Draw the image stretched differentially to fit into dst.
+ * center is a rect within the image, and logically divides the image
+ * into 9 sections (3x3). For example, if the middle pixel of a [5x5]
+ * image is the "center", then the center-rect should be [2, 2, 3, 3].
+ *
+ * If the dst is >= the image size, then...
+ * - The 4 corners are not stretched at all.
+ * - The sides are stretched in only one axis.
+ * - The center is stretched in both axes.
+ * Else, for each axis where dst < image,
+ * - The corners shrink proportionally
+ * - The sides (along the shrink axis) and center are not drawn
+ */
+ void drawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint = NULL);
+
/** Draw the specified bitmap, with its top/left corner at (x,y), using the
specified paint, transformed by the current matrix. Note: if the paint
contains a maskfilter that generates a mask which extends beyond the
@@ -1230,6 +1247,9 @@ protected:
virtual void onDrawPath(const SkPath&, const SkPaint&);
virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*);
+ virtual void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+ const SkPaint*);
+
virtual void onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*);
virtual void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
DrawBitmapRectFlags);
@@ -1347,8 +1367,6 @@ private:
void internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
const SkRect& dst, const SkPaint* paint,
DrawBitmapRectFlags flags);
- void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
- const SkRect& dst, const SkPaint* paint);
void internalDrawPaint(const SkPaint& paint);
void internalSaveLayer(const SkRect* bounds, const SkPaint*, SaveFlags, SaveLayerStrategy);
void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*, bool isBitmapDevice);
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 2db685a96e..6b00c104fc 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -220,10 +220,14 @@ protected:
const SkRect* srcOrNull, const SkRect& dst,
const SkPaint& paint,
SkCanvas::DrawBitmapRectFlags flags) = 0;
+ virtual void drawBitmapNine(const SkDraw&, const SkBitmap&, const SkIRect& center,
+ const SkRect& dst, const SkPaint&);
virtual void drawImage(const SkDraw&, const SkImage*, SkScalar x, SkScalar y, const SkPaint&);
virtual void drawImageRect(const SkDraw&, const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint&);
+ virtual void drawImageNine(const SkDraw&, const SkImage*, const SkIRect& center,
+ const SkRect& dst, const SkPaint&);
/**
* Does not handle text decoration.
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
index 4ace35f22f..1f5b12a417 100644
--- a/include/utils/SkDeferredCanvas.h
+++ b/include/utils/SkDeferredCanvas.h
@@ -178,6 +178,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/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);
diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h
index 2f246e452c..614853dd92 100644
--- a/src/pipe/SkGPipePriv.h
+++ b/src/pipe/SkGPipePriv.h
@@ -46,6 +46,7 @@ enum DrawOps {
kDrawDRRect_DrawOp,
kDrawImage_DrawOp,
kDrawImageRect_DrawOp,
+ kDrawImageNine_DrawOp,
kDrawOval_DrawOp,
kDrawPaint_DrawOp,
kDrawPatch_DrawOp,
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 8d3048d76f..48e0c0641b 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -695,6 +695,19 @@ static void drawImageRect_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32
}
}
+static void drawImageNine_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
+ SkGPipeState* state) {
+ unsigned slot = DrawOp_unpackData(op32);
+ unsigned flags = DrawOp_unpackFlags(op32);
+ bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag);
+ const SkIRect* center = skip<SkIRect>(reader);
+ const SkRect* dst = skip<SkRect>(reader);
+ const SkImage* image = state->getImage(slot);
+ if (state->shouldDraw()) {
+ canvas->drawImageNine(image, *center, *dst, hasPaint ? &state->paint() : NULL);
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
static void drawPicture_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -866,6 +879,7 @@ static const ReadProc gReadTable[] = {
drawDRRect_rp,
drawImage_rp,
drawImageRect_rp,
+ drawImageNine_rp,
drawOval_rp,
drawPaint_rp,
drawPatch_rp,
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index f2aaaae216..4dbb5b536c 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -280,6 +280,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;
@@ -883,6 +885,16 @@ void SkGPipeCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, con
}
}
+void SkGPipeCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) {
+ NOTIFY_SETUP(this);
+ size_t opBytesNeeded = sizeof(SkIRect) + sizeof(SkRect); // center + dst
+ if (this->commonDrawImage(image, kDrawImageNine_DrawOp, 0, opBytesNeeded, paint)) {
+ fWriter.writeIRect(center);
+ fWriter.writeRect(dst);
+ }
+}
+
void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
const SkPaint& paint) {
if (byteLength) {
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index ccf0b012b1..8e34235848 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -229,6 +229,9 @@ protected:
void drawImageRect(const SkDraw&, const SkImage*, const SkRect*, const SkRect&,
const SkPaint&) override
{SkASSERT(0);}
+ void drawImageNine(const SkDraw&, const SkImage*, const SkIRect&, const SkRect&,
+ const SkPaint&) override
+ {SkASSERT(0);}
void drawText(const SkDraw&, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) override
{SkASSERT(0);}
@@ -903,6 +906,19 @@ void SkDeferredCanvas::onDrawImageRect(const SkImage* image, const SkRect* src,
this->recordedDrawCommand();
}
+void SkDeferredCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint) {
+ if (fDeferredDrawing &&
+ this->isFullFrame(&dst, paint) &&
+ isPaintOpaque(paint, image)) {
+ this->getDeferredDevice()->skipPendingCommands();
+ }
+
+ AutoImmediateDrawIfNeeded autoDraw(*this, image, paint);
+ this->drawingCanvas()->drawImageNine(image, center, dst, paint);
+ this->recordedDrawCommand();
+}
+
void SkDeferredCanvas::onDrawBitmapNine(const SkBitmap& bitmap,
const SkIRect& center, const SkRect& dst,
const SkPaint* paint) {