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
This commit is contained in:
reed 2015-06-25 12:32:03 -07:00 committed by Commit bot
parent b4022965a2
commit 4c21dc5ddf
21 changed files with 349 additions and 95 deletions

View File

@ -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);
}

View File

@ -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',

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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,
void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
const SkPaint* paint) {
if (bitmap.drawsNothing()) {
return;
}
if (NULL == paint || paint->canComputeFastBounds()) {
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawImageNine()");
SkRect storage;
const SkRect* bounds = &dst;
if (NULL == paint || paint->canComputeFastBounds()) {
if (paint) {
bounds = &paint->computeFastBounds(dst, &storage);
}
@ -2133,57 +2146,18 @@ void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
}
}
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];
SkLazyPaint lazy;
if (NULL == paint) {
paint = lazy.init();
}
if (dstY[1] > dstY[2]) {
dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
dstY[2] = dstY[1];
LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds)
while (iter.next()) {
iter.fDevice->drawImageNine(iter, image, center, dst, looper.paint());
}
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_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 {

View File

@ -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) {

View File

@ -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;
}

View File

@ -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

View File

@ -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*

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -46,6 +46,7 @@ enum DrawOps {
kDrawDRRect_DrawOp,
kDrawImage_DrawOp,
kDrawImageRect_DrawOp,
kDrawImageNine_DrawOp,
kDrawOval_DrawOp,
kDrawPaint_DrawOp,
kDrawPatch_DrawOp,

View File

@ -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,

View File

@ -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) {

View File

@ -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) {