aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-08-02 08:05:56 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-02 08:05:56 -0700
commitc573a40ed5024b463e47088d307e3164a486dba5 (patch)
tree17969315cf64ce827395c4b8ad9273cc6f96886d
parent7d0e3bc785fc5aaf2ed0aa8f37a2bc85c2f82da0 (diff)
Add drawImageLattice() and drawBitmapLattice() APIs
The specified image/bitmap is divided into rects, which can be draw stretched, shrunk, or at a fixed size. Will be used by Android to draw 9patch (which are acutally N-patch) images. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1992283002 Review-Url: https://codereview.chromium.org/1992283002
-rw-r--r--bench/DrawLatticeBench.cpp59
-rw-r--r--gm/lattice.cpp147
-rw-r--r--gyp/core.gypi4
-rw-r--r--include/core/SkCanvas.h45
-rw-r--r--include/core/SkDevice.h4
-rw-r--r--include/private/SkRecords.h9
-rw-r--r--src/core/SkCanvas.cpp47
-rw-r--r--src/core/SkDevice.cpp17
-rw-r--r--src/core/SkLatticeIter.cpp230
-rw-r--r--src/core/SkLatticeIter.h49
-rw-r--r--src/core/SkNinePatchIter.cpp72
-rw-r--r--src/core/SkNinePatchIter.h41
-rw-r--r--src/core/SkPictureFlat.h3
-rw-r--r--src/core/SkPicturePlayback.cpp12
-rw-r--r--src/core/SkPictureRecord.cpp18
-rw-r--r--src/core/SkPictureRecord.h2
-rw-r--r--src/core/SkRecordDraw.cpp13
-rw-r--r--src/core/SkRecorder.cpp10
-rw-r--r--src/core/SkRecorder.h2
-rw-r--r--src/gpu/SkGpuDevice.cpp4
-rw-r--r--src/gpu/batches/GrNinePatch.cpp4
-rw-r--r--src/pdf/SkPDFCanvas.cpp17
-rw-r--r--src/pdf/SkPDFCanvas.h5
-rw-r--r--tests/PictureTest.cpp5
24 files changed, 688 insertions, 131 deletions
diff --git a/bench/DrawLatticeBench.cpp b/bench/DrawLatticeBench.cpp
new file mode 100644
index 0000000000..4c03ca1dfa
--- /dev/null
+++ b/bench/DrawLatticeBench.cpp
@@ -0,0 +1,59 @@
+/*
+* Copyright 2016 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
+
+#include "Benchmark.h"
+#include "SkCanvas.h"
+#include "SkRect.h"
+#include "SkString.h"
+
+class DrawLatticeBench : public Benchmark {
+public:
+ DrawLatticeBench(int* xDivs, int xCount, int* yDivs, int yCount, const SkISize& srcSize,
+ const SkRect& dst, const char* desc)
+ : fSrcSize(srcSize)
+ , fDst(dst)
+ {
+ fLattice.fXDivs = xDivs;
+ fLattice.fXCount = xCount;
+ fLattice.fYDivs = yDivs;
+ fLattice.fYCount = yCount;
+
+ fName = SkStringPrintf("DrawLattice_%s", desc);
+ }
+
+ const char* onGetName() override {
+ return fName.c_str();
+ }
+
+ bool isSuitableFor(Backend backend) override {
+ return kRaster_Backend == backend || kGPU_Backend == backend;
+ }
+
+ void onDelayedSetup() override {
+ fBitmap.allocN32Pixels(fSrcSize.width(), fSrcSize.height());
+ fBitmap.eraseColor(0x880000FF);
+ }
+
+ void onDraw(int loops, SkCanvas* canvas) override {
+ for (int i = 0; i < loops; i++) {
+ canvas->drawBitmapLattice(fBitmap, fLattice, fDst);
+ }
+ }
+
+private:
+ SkISize fSrcSize;
+ SkCanvas::Lattice fLattice;
+ SkRect fDst;
+ SkString fName;
+ SkBitmap fBitmap;
+
+ typedef Benchmark INHERITED;
+};
+
+static int gDivs[2] = { 250, 750, };
+DEF_BENCH(return new DrawLatticeBench(gDivs, 2, gDivs, 2, SkISize::Make(1000, 1000),
+ SkRect::MakeWH(4000.0f, 4000.0f), "StandardNine");)
diff --git a/gm/lattice.cpp b/gm/lattice.cpp
new file mode 100644
index 0000000000..63de2a66b4
--- /dev/null
+++ b/gm/lattice.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 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"
+
+static sk_sp<SkSurface> make_surface(SkCanvas* root, int N) {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
+ auto surface = root->makeSurface(info);
+ if (!surface) {
+ surface = SkSurface::MakeRaster(info);
+ }
+ return surface;
+}
+
+static sk_sp<SkImage> make_image(SkCanvas* root, int* xDivs, int* yDivs) {
+ const int kCap = 28;
+ const int kMid = 8;
+ const int kSize = 2*kCap + 3*kMid;
+
+ auto surface(make_surface(root, kSize));
+ SkCanvas* canvas = surface->getCanvas();
+
+ SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
+ const SkScalar strokeWidth = SkIntToScalar(6);
+ const SkScalar radius = SkIntToScalar(kCap) - strokeWidth/2;
+
+ xDivs[0] = yDivs[0] = kCap;
+ xDivs[1] = yDivs[1] = kCap + kMid;
+ xDivs[2] = yDivs[2] = kCap + 2 * kMid;
+ xDivs[3] = yDivs[3] = kCap + 3 * kMid;
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ paint.setColor(0xFFFFFF00);
+ canvas->drawRoundRect(r, radius, radius, paint);
+
+ r.setXYWH(SkIntToScalar(kCap), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
+ paint.setColor(0x8800FF00);
+ canvas->drawRect(r, paint);
+ r.setXYWH(SkIntToScalar(kCap + kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
+ paint.setColor(0x880000FF);
+ canvas->drawRect(r, paint);
+ r.setXYWH(SkIntToScalar(kCap + 2*kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
+ paint.setColor(0x88FF00FF);
+ canvas->drawRect(r, paint);
+
+ r.setXYWH(0, SkIntToScalar(kCap), SkIntToScalar(kSize), SkIntToScalar(kMid));
+ paint.setColor(0x8800FF00);
+ canvas->drawRect(r, paint);
+ r.setXYWH(0, SkIntToScalar(kCap + kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
+ paint.setColor(0x880000FF);
+ canvas->drawRect(r, paint);
+ r.setXYWH(0, SkIntToScalar(kCap + 2*kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
+ paint.setColor(0x88FF00FF);
+ canvas->drawRect(r, paint);
+
+ return surface->makeImageSnapshot();
+}
+
+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);
+}
+
+/**
+ * This is similar to NinePatchStretchGM, but it also tests "ninepatch" images with more
+ * than nine patches.
+ */
+class LatticeGM : public skiagm::GM {
+public:
+ LatticeGM() {}
+
+protected:
+ SkString onShortName() override {
+ return SkString("lattice");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(800, 400);
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ int xDivs[5];
+ int yDivs[5];
+ xDivs[0] = 0;
+ yDivs[0] = 0;
+
+ SkBitmap bitmap;
+ sk_sp<SkImage> image = make_image(canvas, xDivs + 1, yDivs + 1);
+ image_to_bitmap(image.get(), &bitmap);
+
+ const SkTSize<SkScalar> size[] = {
+ { 50, 50, }, // shrink in both axes
+ { 50, 200, }, // shrink in X
+ { 200, 50, }, // shrink in Y
+ { 200, 200, },
+ };
+
+ canvas->drawImage(image, 10, 10, nullptr);
+
+ SkScalar x = SkIntToScalar(100);
+ SkScalar y = SkIntToScalar(100);
+
+ SkCanvas::Lattice lattice;
+ lattice.fXCount = 4;
+ lattice.fXDivs = xDivs + 1;
+ lattice.fYCount = 4;
+ lattice.fYDivs = yDivs + 1;
+
+ for (int iy = 0; iy < 2; ++iy) {
+ for (int ix = 0; ix < 2; ++ix) {
+ int i = ix * 2 + iy;
+ SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
+ size[i].width(), size[i].height());
+ canvas->drawBitmapLattice(bitmap, lattice, r);
+ }
+ }
+
+ // Include the degenerate first div. While normally the first patch is "scalable",
+ // this will mean that the first non-degenerate patch is "fixed".
+ lattice.fXCount = 5;
+ lattice.fXDivs = xDivs;
+ lattice.fYCount = 5;
+ lattice.fYDivs = yDivs;
+
+ canvas->translate(400, 0);
+ for (int iy = 0; iy < 2; ++iy) {
+ for (int ix = 0; ix < 2; ++ix) {
+ int i = ix * 2 + iy;
+ SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
+ size[i].width(), size[i].height());
+ canvas->drawImageLattice(image.get(), lattice, r);
+ }
+ }
+ }
+
+private:
+ typedef skiagm::GM INHERITED;
+};
+DEF_GM( return new LatticeGM; )
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 35312563a2..6b1d9f4eb5 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -187,8 +187,8 @@
'<(skia_src_path)/core/SkModeColorFilter.cpp',
'<(skia_src_path)/core/SkMultiPictureDraw.cpp',
'<(skia_src_path)/core/SkNextID.h',
- '<(skia_src_path)/core/SkNinePatchIter.cpp',
- '<(skia_src_path)/core/SkNinePatchIter.h',
+ '<(skia_src_path)/core/SkLatticeIter.cpp',
+ '<(skia_src_path)/core/SkLatticeIter.h',
'<(skia_src_path)/core/SkNormalBevelSource.cpp',
'<(skia_src_path)/core/SkNormalBevelSource.h',
'<(skia_src_path)/core/SkNormalMapSource.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 3f9b034946..c3f8599db4 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -938,7 +938,7 @@ public:
SrcRectConstraint = kStrict_SrcRectConstraint);
/**
- * Draw the bitmap stretched differentially to fit into dst.
+ * Draw the bitmap stretched or shrunk differentially to fit into dst.
* center is a rect within the bitmap, and logically divides the bitmap
* into 9 sections (3x3). For example, if the middle pixel of a [5x5]
* bitmap is the "center", then the center-rect should be [2, 2, 3, 3].
@@ -954,6 +954,47 @@ public:
void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
const SkPaint* paint = NULL);
+ /**
+ * Specifies coordinates to divide a bitmap into (xCount*yCount) rects.
+ */
+ struct Lattice {
+ // An array of x-coordinates that divide the bitmap vertically.
+ // These must be unique, increasing, and in the set [0, width].
+ // Does not have ownership.
+ const int* fXDivs;
+
+ // The number of fXDivs.
+ int fXCount;
+
+ // An array of y-coordinates that divide the bitmap horizontally.
+ // These must be unique, increasing, and in the set [0, height].
+ // Does not have ownership.
+ const int* fYDivs;
+
+ // The number of fYDivs.
+ int fYCount;
+ };
+
+ /**
+ * Draw the bitmap stretched or shrunk differentially to fit into dst.
+ *
+ * Moving horizontally across the bitmap, alternating rects will be "scalable"
+ * (in the x-dimension) to fit into dst or must be left "fixed". The first rect
+ * is treated as "fixed", but it's possible to specify an empty first rect by
+ * making lattice.fXDivs[0] = 0.
+ *
+ * The scale factor for all "scalable" rects will be the same, and may be greater
+ * than or less than 1 (meaning we can stretch or shrink). If the number of
+ * "fixed" pixels is greater than the width of the dst, we will collapse all of
+ * the "scalable" regions and appropriately downscale the "fixed" regions.
+ *
+ * The same interpretation also applies to the y-dimension.
+ */
+ void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint = nullptr);
+ void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint = nullptr);
+
/** Draw the text, with origin at (x,y), using the specified paint.
The origin is interpreted based on the Align setting in the paint.
@param text The text to be drawn
@@ -1435,6 +1476,8 @@ protected:
SrcRectConstraint);
virtual void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*);
+ virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
+ const SkPaint*);
enum ClipEdgeStyle {
kHard_ClipEdgeStyle,
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index f3b484e4be..99018df182 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -197,13 +197,15 @@ protected:
const SkPaint& paint,
SkCanvas::SrcRectConstraint) = 0;
virtual void drawBitmapNine(const SkDraw&, const SkBitmap&, const SkIRect& center,
- const SkRect& dst, const SkPaint&);
+ 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&, SkCanvas::SrcRectConstraint);
virtual void drawImageNine(const SkDraw&, const SkImage*, const SkIRect& center,
const SkRect& dst, const SkPaint&);
+ virtual void drawImageLattice(const SkDraw&, const SkImage*, const SkCanvas::Lattice&,
+ const SkRect& dst, const SkPaint&);
/**
* Does not handle text decoration.
diff --git a/include/private/SkRecords.h b/include/private/SkRecords.h
index 32da3dd377..a095452d1c 100644
--- a/include/private/SkRecords.h
+++ b/include/private/SkRecords.h
@@ -55,6 +55,7 @@ namespace SkRecords {
M(ClipRegion) \
M(DrawDrawable) \
M(DrawImage) \
+ M(DrawImageLattice) \
M(DrawImageRect) \
M(DrawImageNine) \
M(DrawDRRect) \
@@ -222,6 +223,14 @@ RECORD(DrawImage, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
sk_sp<const SkImage> image;
SkScalar left;
SkScalar top);
+RECORD(DrawImageLattice, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
+ Optional<SkPaint> paint;
+ sk_sp<const SkImage> image;
+ int xCount;
+ PODArray<int> xDivs;
+ int yCount;
+ PODArray<int> yDivs;
+ SkRect dst);
RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
Optional<SkPaint> paint;
sk_sp<const SkImage> image;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a86cd37cad..648059a196 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -19,9 +19,9 @@
#include "SkImage_Base.h"
#include "SkImageFilter.h"
#include "SkImageFilterCache.h"
+#include "SkLatticeIter.h"
#include "SkMatrixUtils.h"
#include "SkMetaData.h"
-#include "SkNinePatchIter.h"
#include "SkPaintPriv.h"
#include "SkPatchUtils.h"
#include "SkPicture.h"
@@ -1985,7 +1985,7 @@ void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const
if (dst.isEmpty()) {
return;
}
- if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) {
+ if (!SkLatticeIter::Valid(image->width(), image->height(), center)) {
this->drawImageRect(image, dst, paint);
}
this->onDrawImageNine(image, center, dst, paint);
@@ -2022,12 +2022,30 @@ void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, con
if (bitmap.drawsNothing() || dst.isEmpty()) {
return;
}
- if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) {
+ if (!SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) {
this->drawBitmapRect(bitmap, dst, paint);
}
this->onDrawBitmapNine(bitmap, center, dst, paint);
}
+void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint) {
+ sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
+ this->drawImageLattice(image.get(), lattice, dst, paint);
+}
+
+void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint) {
+ RETURN_ON_NULL(image);
+ if (dst.isEmpty()) {
+ return;
+ }
+ if (!SkLatticeIter::Valid(image->width(), image->height(), lattice)) {
+ this->drawImageRect(image, dst, paint);
+ }
+ this->onDrawImageLattice(image, lattice, dst, paint);
+}
+
void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
const SkColor colors[], int count, SkXfermode::Mode mode,
const SkRect* cull, const SkPaint* paint) {
@@ -2332,6 +2350,29 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S
LOOPER_END
}
+void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
+ const SkPaint* paint) {
+ if (nullptr == paint || paint->canComputeFastBounds()) {
+ SkRect storage;
+ if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) {
+ return;
+ }
+ }
+
+ SkLazyPaint lazy;
+ if (nullptr == paint) {
+ paint = lazy.init();
+ }
+
+ LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst)
+
+ while (iter.next()) {
+ iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint());
+ }
+
+ LOOPER_END
+}
+
void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) {
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageRect()");
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 14250ab775..59408dc64a 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -12,8 +12,8 @@
#include "SkImage_Base.h"
#include "SkImageFilter.h"
#include "SkImageFilterCache.h"
+#include "SkLatticeIter.h"
#include "SkMetaData.h"
-#include "SkNinePatchIter.h"
#include "SkPatchUtils.h"
#include "SkPathMeasure.h"
#include "SkRasterClip.h"
@@ -152,6 +152,17 @@ void SkBaseDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar
}
}
+void SkBaseDevice::drawImageLattice(const SkDraw& draw, const SkImage* image,
+ const SkCanvas::Lattice& lattice, const SkRect& dst,
+ const SkPaint& paint) {
+ SkLatticeIter iter(image->width(), image->height(), lattice, dst);
+
+ SkRect srcR, dstR;
+ while (iter.next(&srcR, &dstR)) {
+ this->drawImageRect(draw, image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint);
+ }
+}
+
void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src,
const SkRect& dst, const SkPaint& paint,
SkCanvas::SrcRectConstraint constraint) {
@@ -164,7 +175,7 @@ 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);
+ SkLatticeIter iter(image->width(), image->height(), center, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
@@ -174,7 +185,7 @@ void SkBaseDevice::drawImageNine(const SkDraw& draw, const SkImage* image, const
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);
+ SkLatticeIter iter(bitmap.width(), bitmap.height(), center, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
diff --git a/src/core/SkLatticeIter.cpp b/src/core/SkLatticeIter.cpp
new file mode 100644
index 0000000000..24ab3f1cbc
--- /dev/null
+++ b/src/core/SkLatticeIter.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 "SkLatticeIter.h"
+#include "SkRect.h"
+
+/**
+ * Divs must be in increasing order with no duplicates.
+ */
+static bool valid_divs(const int* divs, int count, int len) {
+ if (count <= 0) {
+ return false;
+ }
+
+ int prev = -1;
+ for (int i = 0; i < count; i++) {
+ if (prev >= divs[i] || divs[i] > len) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool SkLatticeIter::Valid(int width, int height, const SkCanvas::Lattice& lattice) {
+ return valid_divs(lattice.fXDivs, lattice.fXCount, width) &&
+ valid_divs(lattice.fYDivs, lattice.fYCount, height);
+}
+
+/**
+ * Count the number of pixels that are in "scalable" patches.
+ */
+static int count_scalable_pixels(const int32_t* divs, int numDivs, bool firstIsScalable,
+ int length) {
+ if (0 == numDivs) {
+ return firstIsScalable ? length : 0;
+ }
+
+ int i;
+ int count;
+ if (firstIsScalable) {
+ count = divs[0];
+ i = 1;
+ } else {
+ count = 0;
+ i = 0;
+ }
+
+ for (; i < numDivs; i += 2) {
+ // Alternatively, we could use |top| and |bottom| as variable names, instead of
+ // |left| and |right|.
+ int left = divs[i];
+ int right = (i + 1 < numDivs) ? divs[i + 1] : length;
+ count += right - left;
+ }
+
+ return count;
+}
+
+/**
+ * Set points for the src and dst rects on subsequent draw calls.
+ */
+static void set_points(float* dst, float* src, const int* divs, int divCount, int srcFixed,
+ int srcScalable, float dstStart, float dstStop, bool isScalable) {
+
+ float dstLen = dstStop - dstStart;
+ int srcLen = srcFixed + srcScalable;
+ float scale;
+ if (srcFixed <= dstLen) {
+ // This is the "normal" case, where we scale the "scalable" patches and leave
+ // the other patches fixed.
+ scale = (dstLen - ((float) srcFixed)) / ((float) srcScalable);
+ } else {
+ // In this case, we eliminate the "scalable" patches and scale the "fixed" patches.
+ scale = dstLen / ((float) srcFixed);
+ }
+
+ src[0] = 0.0f;
+ dst[0] = dstStart;
+ for (int i = 0; i < divCount; i++) {
+ src[i + 1] = (float) (divs[i]);
+ float srcDelta = src[i + 1] - src[i];
+ float dstDelta;
+ if (srcFixed <= dstLen) {
+ dstDelta = isScalable ? scale * srcDelta : srcDelta;
+ } else {
+ dstDelta = isScalable ? 0.0f : scale * srcDelta;
+ }
+ dst[i + 1] = dst[i] + dstDelta;
+
+ // Alternate between "scalable" and "fixed" patches.
+ isScalable = !isScalable;
+ }
+
+ src[divCount + 1] = (float) srcLen;
+ dst[divCount + 1] = dstStop;
+}
+
+SkLatticeIter::SkLatticeIter(int srcWidth, int srcHeight, const SkCanvas::Lattice& lattice,
+ const SkRect& dst)
+{
+ const int* xDivs = lattice.fXDivs;
+ int xCount = lattice.fXCount;
+ const int* yDivs = lattice.fYDivs;
+ int yCount = lattice.fYCount;
+
+ // In the x-dimension, the first rectangle always starts at x = 0 and is "scalable".
+ // If xDiv[0] is 0, it indicates that the first rectangle is degenerate, so the
+ // first real rectangle "scalable" in the x-direction.
+ //
+ // The same interpretation applies to the y-dimension.
+ //
+ // As we move left to right across the image, alternating patches will be "fixed" or
+ // "scalable" in the x-direction. Similarly, as move top to bottom, alternating
+ // patches will be "fixed" or "scalable" in the y-direction.
+ SkASSERT(xCount > 0 && yCount > 0);
+ bool xIsScalable = (0 == xDivs[0]);
+ if (xIsScalable) {
+ // Once we've decided that the first patch is "scalable", we don't need the
+ // xDiv. It is always implied that we start at zero.
+ xDivs++;
+ xCount--;
+ }
+ bool yIsScalable = (0 == yDivs[0]);
+ if (yIsScalable) {
+ // Once we've decided that the first patch is "scalable", we don't need the
+ // yDiv. It is always implied that we start at zero.
+ yDivs++;
+ yCount--;
+ }
+
+ // We never need the final xDiv/yDiv if it is equal to the width/height. This is implied.
+ if (xCount > 0 && srcWidth == xDivs[xCount - 1]) {
+ xCount--;
+ }
+ if (yCount > 0 && srcHeight == yDivs[yCount - 1]) {
+ yCount--;
+ }
+
+ // Count "scalable" and "fixed" pixels in each dimension.
+ int xCountScalable = count_scalable_pixels(xDivs, xCount, xIsScalable, srcWidth);
+ int xCountFixed = srcWidth - xCountScalable;
+ int yCountScalable = count_scalable_pixels(yDivs, yCount, yIsScalable, srcHeight);
+ int yCountFixed = srcHeight - yCountScalable;
+
+ fSrcX.reset(xCount + 2);
+ fDstX.reset(xCount + 2);
+ set_points(fDstX.begin(), fSrcX.begin(), xDivs, xCount, xCountFixed, xCountScalable,
+ dst.fLeft, dst.fRight, xIsScalable);
+
+ fSrcY.reset(yCount + 2);
+ fDstY.reset(yCount + 2);
+ set_points(fDstY.begin(), fSrcY.begin(), yDivs, yCount, yCountFixed, yCountScalable,
+ dst.fTop, dst.fBottom, yIsScalable);
+
+ fCurrX = fCurrY = 0;
+ fDone = false;
+}
+
+bool SkLatticeIter::Valid(int width, int height, const SkIRect& center) {
+ return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center);
+}
+
+SkLatticeIter::SkLatticeIter(int w, int h, const SkIRect& c, const SkRect& dst) {
+ SkASSERT(SkIRect::MakeWH(w, h).contains(c));
+
+ fSrcX.reset(4);
+ fSrcY.reset(4);
+ fDstX.reset(4);
+ fDstY.reset(4);
+
+ 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 SkLatticeIter::next(SkRect* src, SkRect* dst) {
+ if (fDone) {
+ return false;
+ }
+
+ const int x = fCurrX;
+ const int y = fCurrY;
+ SkASSERT(x >= 0 && x < fSrcX.count() - 1);
+ SkASSERT(y >= 0 && y < fSrcY.count() - 1);
+
+ 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 (fSrcX.count() - 1 == ++fCurrX) {
+ fCurrX = 0;
+ fCurrY += 1;
+ if (fCurrY >= fSrcY.count() - 1) {
+ fDone = true;
+ }
+ }
+ return true;
+}
diff --git a/src/core/SkLatticeIter.h b/src/core/SkLatticeIter.h
new file mode 100644
index 0000000000..e2d767f1c8
--- /dev/null
+++ b/src/core/SkLatticeIter.h
@@ -0,0 +1,49 @@
+/*
+ * 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 SkLatticeIter_DEFINED
+#define SkLatticeIter_DEFINED
+
+#include "SkCanvas.h"
+#include "SkScalar.h"
+#include "SkTArray.h"
+
+struct SkIRect;
+struct SkRect;
+
+/**
+ * Disect a lattice request into an sequence of src-rect / dst-rect pairs
+ */
+class SkLatticeIter {
+public:
+
+ static bool Valid(int imageWidth, int imageHeight, const SkCanvas::Lattice& lattice);
+
+ SkLatticeIter(int imageWidth, int imageHeight, const SkCanvas::Lattice& lattice,
+ const SkRect& dst);
+
+ static bool Valid(int imageWidth, int imageHeight, const SkIRect& center);
+
+ SkLatticeIter(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:
+ SkTArray<SkScalar> fSrcX;
+ SkTArray<SkScalar> fSrcY;
+ SkTArray<SkScalar> fDstX;
+ SkTArray<SkScalar> fDstY;
+
+ int fCurrX;
+ int fCurrY;
+ bool fDone;
+};
+
+#endif
diff --git a/src/core/SkNinePatchIter.cpp b/src/core/SkNinePatchIter.cpp
deleted file mode 100644
index 1a780a0c0d..0000000000
--- a/src/core/SkNinePatchIter.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 < 3);
- SkASSERT(y >= 0 && y < 3);
-
- 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 (3 == ++fCurrX) {
- fCurrX = 0;
- fCurrY += 1;
- if (fCurrY >= 3) {
- fDone = true;
- }
- }
- return true;
-}
diff --git a/src/core/SkNinePatchIter.h b/src/core/SkNinePatchIter.h
deleted file mode 100644
index df06c1f630..0000000000
--- a/src/core/SkNinePatchIter.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 17b76817fe..c704f29e58 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -91,8 +91,9 @@ enum DrawType {
TRANSLATE_Z,
DRAW_SHADOWED_PICTURE_LIGHTS,
+ DRAW_IMAGE_LATTICE,
- LAST_DRAWTYPE_ENUM = DRAW_SHADOWED_PICTURE_LIGHTS
+ LAST_DRAWTYPE_ENUM = DRAW_IMAGE_LATTICE
};
// 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 0bce09cdf2..307e946871 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -298,6 +298,18 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
reader->readPoint(&loc);
canvas->drawImage(image, loc.fX, loc.fY, paint);
} break;
+ case DRAW_IMAGE_LATTICE: {
+ const SkPaint* paint = fPictureData->getPaint(reader);
+ const SkImage* image = fPictureData->getImage(reader);
+ SkCanvas::Lattice lattice;
+ lattice.fXCount = reader->readInt();
+ lattice.fXDivs = (const int*) reader->skip(lattice.fXCount * sizeof(int32_t));
+ lattice.fYCount = reader->readInt();
+ lattice.fYDivs = (const int*) reader->skip(lattice.fYCount * sizeof(int32_t));
+ SkRect dst;
+ reader->readRect(&dst);
+ canvas->drawImageLattice(image, lattice, dst, paint);
+ } break;
case DRAW_IMAGE_NINE: {
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 562f056c50..d85376a118 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -510,6 +510,24 @@ void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
this->validate(initialOffset, size);
}
+void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
+ const SkRect& dst, const SkPaint* paint) {
+ // xCount + xDivs + yCount+ yDivs
+ size_t latticeSize = (1 + lattice.fXCount + 1 + lattice.fYCount) * kUInt32Size;
+
+ // op + paint index + image index + lattice + dst rect
+ size_t size = 3 * kUInt32Size + latticeSize + sizeof(dst);
+ size_t initialOffset = this->addDraw(DRAW_IMAGE_LATTICE, &size);
+ this->addPaintPtr(paint);
+ this->addImage(image);
+ this->addInt(lattice.fXCount);
+ fWriter.writePad(lattice.fXDivs, lattice.fXCount * kUInt32Size);
+ this->addInt(lattice.fYCount);
+ fWriter.writePad(lattice.fYDivs, lattice.fYCount * kUInt32Size);
+ this->addRect(dst);
+ this->validate(initialOffset, size);
+}
+
void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) {
// id + paint_index + image_index + bool_for_src + constraint
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index b798234a72..637c46dbf8 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -194,6 +194,8 @@ protected:
void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
SrcRectConstraint) override;
void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
+ void onDrawImageLattice(const SkImage*, const SkCanvas::Lattice& lattice, const SkRect& dst,
+ const SkPaint*) override;
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint*, SrcRectConstraint) override;
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 8897e5fcf3..dcfc0fbf90 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -97,6 +97,16 @@ template <> void Draw::draw(const TranslateZ& r) { }
DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint));
DRAW(DrawImage, drawImage(r.image.get(), r.left, r.top, r.paint));
+
+template <> void Draw::draw(const DrawImageLattice& r) {
+ SkCanvas::Lattice lattice;
+ lattice.fXCount = r.xCount;
+ lattice.fXDivs = r.xDivs;
+ lattice.fYCount = r.yCount;
+ lattice.fYDivs = r.yDivs;
+ fCanvas->drawImageLattice(r.image.get(), lattice, r.dst, r.paint);
+}
+
DRAW(DrawImageRect, legacy_drawImageRect(r.image.get(), r.src, r.dst, r.paint, r.constraint));
DRAW(DrawImageNine, drawImageNine(r.image.get(), r.center, r.dst, r.paint));
DRAW(DrawOval, drawOval(r.oval, r.paint));
@@ -412,6 +422,9 @@ private:
return this->adjustAndMap(rect, op.paint);
}
+ Bounds bounds(const DrawImageLattice& op) const {
+ return this->adjustAndMap(op.dst, op.paint);
+ }
Bounds bounds(const DrawImageRect& op) const {
return this->adjustAndMap(op.dst, op.paint);
}
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index c822fdba87..7ffb1f4c44 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -211,6 +211,16 @@ void SkRecorder::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
APPEND(DrawImage, this->copy(paint), sk_ref_sp(image), left, top);
}
+void SkRecorder::onDrawImageLattice(const SkImage* image,
+ const Lattice& lattice,
+ const SkRect& dst,
+ const SkPaint* paint) {
+ APPEND(DrawImageLattice, this->copy(paint), sk_ref_sp(image),
+ lattice.fXCount, this->copy(lattice.fXDivs, lattice.fXCount),
+ lattice.fYCount, this->copy(lattice.fYDivs, lattice.fYCount), dst);
+}
+
+
void SkRecorder::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint constraint) {
APPEND(DrawImageRect, this->copy(paint), sk_ref_sp(image), this->copy(src), dst, constraint);
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 5282740c0c..6da3824123 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -111,6 +111,8 @@ public:
void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
SrcRectConstraint) override;
void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
+ void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
+ const SkPaint*) override;
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint*, SrcRectConstraint) override;
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index de814ab883..7271819269 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -24,8 +24,8 @@
#include "SkImageCacherator.h"
#include "SkImageFilter.h"
#include "SkImageFilterCache.h"
+#include "SkLatticeIter.h"
#include "SkMaskFilter.h"
-#include "SkNinePatchIter.h"
#include "SkPathEffect.h"
#include "SkPicture.h"
#include "SkPictureData.h"
@@ -1446,7 +1446,7 @@ void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* produc
GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I(),
&doBicubic);
if (useFallback || doBicubic || GrTextureParams::kNone_FilterMode != textureFilterMode) {
- SkNinePatchIter iter(producer->width(), producer->height(), center, dst);
+ SkLatticeIter iter(producer->width(), producer->height(), center, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
diff --git a/src/gpu/batches/GrNinePatch.cpp b/src/gpu/batches/GrNinePatch.cpp
index 62af20b2cf..cde3d266ca 100644
--- a/src/gpu/batches/GrNinePatch.cpp
+++ b/src/gpu/batches/GrNinePatch.cpp
@@ -12,7 +12,7 @@
#include "GrResourceProvider.h"
#include "GrVertexBatch.h"
#include "SkBitmap.h"
-#include "SkNinePatchIter.h"
+#include "SkLatticeIter.h"
#include "SkRect.h"
static sk_sp<GrGeometryProcessor> create_gp(bool readsCoverage) {
@@ -101,7 +101,7 @@ private:
i * kRectsPerInstance * kVertsPerRect * vertexStride;
const Patch& patch = fPatches[i];
- SkNinePatchIter iter(fImageWidth, fImageHeight, patch.fCenter, patch.fDst);
+ SkLatticeIter iter(fImageWidth, fImageHeight, patch.fCenter, patch.fDst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
diff --git a/src/pdf/SkPDFCanvas.cpp b/src/pdf/SkPDFCanvas.cpp
index f3ba66b57a..1d3138541d 100644
--- a/src/pdf/SkPDFCanvas.cpp
+++ b/src/pdf/SkPDFCanvas.cpp
@@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
-#include "SkNinePatchIter.h"
+#include "SkLatticeIter.h"
#include "SkPDFCanvas.h"
#include "SkPDFDevice.h"
@@ -35,7 +35,7 @@ void SkPDFCanvas::onDrawBitmapNine(const SkBitmap& bitmap,
const SkIRect& center,
const SkRect& dst,
const SkPaint* paint) {
- SkNinePatchIter iter(bitmap.width(), bitmap.height(), center, dst);
+ SkLatticeIter iter(bitmap.width(), bitmap.height(), center, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
this->drawBitmapRect(bitmap, srcR, dstR, paint);
@@ -46,7 +46,7 @@ void SkPDFCanvas::onDrawImageNine(const SkImage* image,
const SkIRect& center,
const SkRect& dst,
const SkPaint* paint) {
- SkNinePatchIter iter(image->width(), image->height(), center, dst);
+ SkLatticeIter iter(image->width(), image->height(), center, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
this->drawImageRect(image, srcR, dstR, paint);
@@ -84,3 +84,14 @@ void SkPDFCanvas::onDrawBitmapRect(const SkBitmap& bitmap,
SkMatrix::kFill_ScaleToFit));
this->drawBitmap(bitmap, 0, 0, paint);
}
+
+void SkPDFCanvas::onDrawImageLattice(const SkImage* image,
+ const Lattice& lattice,
+ const SkRect& dst,
+ const SkPaint* paint) {
+ SkLatticeIter iter(image->width(), image->height(), lattice, dst);
+ SkRect srcR, dstR;
+ while (iter.next(&srcR, &dstR)) {
+ this->drawImageRect(image, srcR, dstR, paint);
+ }
+}
diff --git a/src/pdf/SkPDFCanvas.h b/src/pdf/SkPDFCanvas.h
index 1c3ec715b7..76bb7e13e3 100644
--- a/src/pdf/SkPDFCanvas.h
+++ b/src/pdf/SkPDFCanvas.h
@@ -39,6 +39,11 @@ protected:
const SkPaint*,
SkCanvas::SrcRectConstraint) override;
+ void onDrawImageLattice(const SkImage*,
+ const Lattice& lattice,
+ const SkRect& dst,
+ const SkPaint*) override;
+
private:
typedef SkCanvas INHERITED;
};
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index b02491661e..8f5ebd3f3b 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -994,12 +994,17 @@ static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
const SkPaint paint;
const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
const SkIRect irect = { 2, 2, 3, 3 };
+ int divs[] = { 2, 3 };
+ SkCanvas::Lattice lattice;
+ lattice.fXCount = lattice.fYCount = 2;
+ lattice.fXDivs = lattice.fYDivs = divs;
// Don't care what these record, as long as they're legal.
canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
canvas->drawBitmapNine(bitmap, irect, rect, &paint);
canvas->drawBitmap(bitmap, 1, 1); // drawSprite
+ canvas->drawBitmapLattice(bitmap, lattice, rect, &paint);
}
static void test_draw_bitmaps(SkCanvas* canvas) {