add SkCanvas::drawAtlas

BUG=skia:

Review URL: https://codereview.chromium.org/1181913003
This commit is contained in:
reed 2015-06-24 10:29:17 -07:00 committed by Commit bot
parent 52d4deb128
commit 71c3c760a8
24 changed files with 732 additions and 8 deletions

103
gm/drawatlas.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
* 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 "gm.h"
#include "SkCanvas.h"
#include "SkRSXform.h"
#include "SkSurface.h"
class DrawAtlasGM : public skiagm::GM {
static SkImage* MakeAtlas(SkCanvas* caller, const SkRect& target) {
SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
SkAutoTUnref<SkSurface> surface(caller->newSurface(info));
if (NULL == surface) {
surface.reset(SkSurface::NewRaster(info));
}
SkCanvas* canvas = surface->getCanvas();
// draw red everywhere, but we don't expect to see it in the draw, testing the notion
// that drawAtlas draws a subset-region of the atlas.
canvas->clear(SK_ColorRED);
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kClear_Mode);
SkRect r(target);
r.inset(-1, -1);
// zero out a place (with a 1-pixel border) to land our drawing.
canvas->drawRect(r, paint);
paint.setXfermode(NULL);
paint.setColor(SK_ColorBLUE);
paint.setAntiAlias(true);
canvas->drawOval(target, paint);
return surface->newImageSnapshot();
}
SkAutoTUnref<SkImage> fAtlas;
public:
DrawAtlasGM() {}
protected:
SkString onShortName() override {
return SkString("draw-atlas");
}
SkISize onISize() override {
return SkISize::Make(640, 480);
}
void onDraw(SkCanvas* canvas) override {
const SkRect target = { 50, 50, 80, 90 };
if (NULL == fAtlas) {
fAtlas.reset(MakeAtlas(canvas, target));
}
const struct {
SkScalar fScale;
SkScalar fDegrees;
SkScalar fTx;
SkScalar fTy;
void apply(SkRSXform* xform) const {
const SkScalar rad = SkDegreesToRadians(fDegrees);
xform->fSCos = fScale * SkScalarCos(rad);
xform->fSSin = fScale * SkScalarSin(rad);
xform->fTx = fTx;
xform->fTy = fTy;
}
} rec[] = {
{ 1, 0, 10, 10 }, // just translate
{ 2, 0, 110, 10 }, // scale + translate
{ 1, 30, 210, 10 }, // rotate + translate
{ 2, -30, 310, 30 }, // scale + rotate + translate
};
const int N = SK_ARRAY_COUNT(rec);
SkRSXform xform[N];
SkRect tex[N];
SkColor colors[N];
for (int i = 0; i < N; ++i) {
rec[i].apply(&xform[i]);
tex[i] = target;
colors[i] = 0x80FF0000 + (i * 40 * 256);
}
SkPaint paint;
paint.setFilterQuality(kLow_SkFilterQuality);
paint.setAntiAlias(true);
canvas->drawAtlas(fAtlas, xform, tex, N, NULL, &paint);
canvas->translate(0, 100);
canvas->drawAtlas(fAtlas, xform, tex, colors, N, SkXfermode::kSrcIn_Mode, NULL, &paint);
}
private:
typedef GM INHERITED;
};
DEF_GM( return new DrawAtlasGM; )

View File

@ -8,6 +8,8 @@
#include "gm.h"
#include "SkCanvas.h"
#include "SkBlurImageFilter.h"
#include "SkRSXform.h"
#include "SkSurface.h"
static void make_bm(SkBitmap* bm) {
bm->allocN32Pixels(100, 100);
@ -93,7 +95,5 @@ protected:
private:
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM( return new SpriteBitmapGM; )

View File

@ -45,6 +45,7 @@
'../samplecode/SampleAnimBlur.cpp',
'../samplecode/SampleApp.cpp',
'../samplecode/SampleArc.cpp',
'../samplecode/SampleAtlas.cpp',
'../samplecode/SampleBigBlur.cpp',
'../samplecode/SampleBigGradient.cpp',
'../samplecode/SampleBitmapRect.cpp',

View File

@ -28,6 +28,7 @@ class SkImage;
class SkMetaData;
class SkPicture;
class SkRRect;
struct SkRSXform;
class SkSurface;
class SkSurface_Base;
class SkTextBlob;
@ -1023,6 +1024,32 @@ public:
void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
/**
* Draw a set of sprites from the atlas. Each is specified by a tex rectangle in the
* coordinate space of the atlas, and a corresponding xform which transforms the tex rectangle
* into a quad.
*
* xform maps [0, 0, tex.width, tex.height] -> quad
*
* The color array is optional. When specified, each color modulates the pixels in its
* corresponding quad (via the specified SkXfermode::Mode).
*
* The cullRect is optional. When specified, it must be a conservative bounds of all of the
* resulting transformed quads, allowing the canvas to skip drawing if the cullRect does not
* intersect the current clip.
*
* The paint is optional. If specified, its antialiasing, alpha, color-filter, image-filter
* and xfermode are used to affect each of the quads.
*/
void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
const SkColor colors[], int count, SkXfermode::Mode, const SkRect* cullRect,
const SkPaint* paint);
void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count,
const SkRect* cullRect, const SkPaint* paint) {
this->drawAtlas(atlas, xform, tex, NULL, count, SkXfermode::kDst_Mode, cullRect, paint);
}
/**
* Draw the contents of this drawable into the canvas. If the canvas is async
* (e.g. it is recording into a picture) then the drawable will be referenced instead,
@ -1197,6 +1224,9 @@ protected:
virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkXfermode*,
const uint16_t indices[], int indexCount, const SkPaint&);
virtual void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*);
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*);

View File

@ -245,6 +245,11 @@ protected:
// default implementation calls drawVertices
virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
// default implementation calls drawPath
virtual void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[],
const SkColor[], int count, SkXfermode::Mode, const SkPaint&);
/** The SkDevice passed will be an SkDevice which was returned by a call to
onCreateDevice on this device with kNeverTile_TileExpectation.
*/

View File

@ -12,6 +12,7 @@
#include "SkRect.h"
struct SkRSXform;
class SkString;
/** \class SkMatrix
@ -244,6 +245,9 @@ public:
/** Set the matrix to rotate by the specified sine and cosine values.
*/
void setSinCos(SkScalar sinValue, SkScalar cosValue);
SkMatrix& setRSXform(const SkRSXform&);
/** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
The pivot point is the coordinate that should remain unchanged by the
specified transformation.

49
include/core/SkRSXform.h Normal file
View File

@ -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 SkRSXform_DEFINED
#define SkRSXform_DEFINED
#include "SkScalar.h"
/**
* A compressed form of a rotation+scale matrix.
*
* [ fSCos -fSSin fTx ]
* [ fSSin fSCos fTy ]
* [ 0 0 1 ]
*/
struct SkRSXform {
SkScalar fSCos;
SkScalar fSSin;
SkScalar fTx;
SkScalar fTy;
bool rectStaysRect() const {
return 0 == fSCos || 0 == fSSin;
}
void setIdentity() {
fSCos = 1;
fSSin = fTx = fTy = 0;
}
void set(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) {
fSCos = scos;
fSSin = ssin;
fTx = tx;
fTy = ty;
}
void toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const;
void toQuad(const SkSize& size, SkPoint quad[4]) const {
this->toQuad(size.width(), size.height(), quad);
}
};
#endif

View File

@ -186,6 +186,8 @@ protected:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
SkXfermode::Mode, const SkRect* cullRect, const SkPaint*) override;
void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;

234
samplecode/SampleAtlas.cpp Normal file
View File

@ -0,0 +1,234 @@
/*
* 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 "SampleCode.h"
#include "SkAnimTimer.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkDrawable.h"
#include "SkPath.h"
#include "SkRandom.h"
#include "SkRSXform.h"
#include "SkSurface.h"
static SkImage* make_atlas(int atlasSize, int cellSize) {
SkImageInfo info = SkImageInfo::MakeN32Premul(atlasSize, atlasSize);
SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
SkCanvas* canvas = surface->getCanvas();
SkPaint paint;
paint.setAntiAlias(true);
SkRandom rand;
const SkScalar half = cellSize * SK_ScalarHalf;
const char* s = "01234567890!@#$%^&*=+<>?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
paint.setTextSize(28);
paint.setTextAlign(SkPaint::kCenter_Align);
int i = 0;
for (int y = 0; y < atlasSize; y += cellSize) {
for (int x = 0; x < atlasSize; x += cellSize) {
paint.setColor(rand.nextU());
paint.setAlpha(0xFF);
int index = i % strlen(s);
canvas->drawText(&s[index], 1, x + half, y + half + half/2, paint);
i += 1;
}
}
return surface->newImageSnapshot();
}
class DrawAtlasDrawable : public SkDrawable {
enum {
kMaxScale = 2,
kCellSize = 32,
kAtlasSize = 512,
};
struct Rec {
SkPoint fCenter;
SkVector fVelocity;
SkScalar fScale;
SkScalar fDScale;
SkScalar fRadian;
SkScalar fDRadian;
SkScalar fAlpha;
SkScalar fDAlpha;
void advance(const SkRect& bounds) {
fCenter += fVelocity;
if (fCenter.fX > bounds.right()) {
SkASSERT(fVelocity.fX > 0);
fVelocity.fX = -fVelocity.fX;
} else if (fCenter.fX < bounds.left()) {
SkASSERT(fVelocity.fX < 0);
fVelocity.fX = -fVelocity.fX;
}
if (fCenter.fY > bounds.bottom()) {
SkASSERT(fVelocity.fY > 0);
fVelocity.fY = -fVelocity.fY;
} else if (fCenter.fY < bounds.top()) {
SkASSERT(fVelocity.fY < 0);
fVelocity.fY = -fVelocity.fY;
}
fScale += fDScale;
if (fScale > 2 || fScale < SK_Scalar1/2) {
fDScale = -fDScale;
}
fRadian += fDRadian;
fRadian = SkScalarMod(fRadian, 2 * SK_ScalarPI);
fAlpha += fDAlpha;
if (fAlpha > 1) {
fAlpha = 1;
fDAlpha = -fDAlpha;
} else if (fAlpha < 0) {
fAlpha = 0;
fDAlpha = -fDAlpha;
}
}
SkRSXform asRSXform() const {
SkMatrix m;
m.setTranslate(-8, -8);
m.postScale(fScale, fScale);
m.postRotate(SkRadiansToDegrees(fRadian));
m.postTranslate(fCenter.fX, fCenter.fY);
SkRSXform x;
x.fSCos = m.getScaleX();
x.fSSin = m.getSkewY();
x.fTx = m.getTranslateX();
x.fTy = m.getTranslateY();
return x;
}
};
enum {
N = 256,
};
SkAutoTUnref<SkImage> fAtlas;
Rec fRec[N];
SkRect fTex[N];
SkRect fBounds;
bool fUseColors;
public:
DrawAtlasDrawable(const SkRect& r) : fBounds(r), fUseColors(false) {
SkRandom rand;
fAtlas.reset(make_atlas(kAtlasSize, kCellSize));
const SkScalar kMaxSpeed = 5;
const SkScalar cell = SkIntToScalar(kCellSize);
int i = 0;
for (int y = 0; y < kAtlasSize; y += kCellSize) {
for (int x = 0; x < kAtlasSize; x += kCellSize) {
const SkScalar sx = SkIntToScalar(x);
const SkScalar sy = SkIntToScalar(y);
fTex[i].setXYWH(sx, sy, cell, cell);
fRec[i].fCenter.set(sx + cell/2, sy + 3*cell/4);
fRec[i].fVelocity.fX = rand.nextSScalar1() * kMaxSpeed;
fRec[i].fVelocity.fY = rand.nextSScalar1() * kMaxSpeed;
fRec[i].fScale = 1;
fRec[i].fDScale = rand.nextSScalar1() / 4;
fRec[i].fRadian = 0;
fRec[i].fDRadian = rand.nextSScalar1() / 8;
fRec[i].fAlpha = rand.nextUScalar1();
fRec[i].fDAlpha = rand.nextSScalar1() / 10;
i += 1;
}
}
}
void toggleUseColors() {
fUseColors = !fUseColors;
}
protected:
void onDraw(SkCanvas* canvas) override {
SkRSXform xform[N];
SkColor colors[N];
for (int i = 0; i < N; ++i) {
fRec[i].advance(fBounds);
xform[i] = fRec[i].asRSXform();
if (fUseColors) {
colors[i] = SkColorSetARGB((int)(fRec[i].fAlpha * 0xFF), 0xFF, 0xFF, 0xFF);
}
}
SkPaint paint;
paint.setFilterQuality(kLow_SkFilterQuality);
const SkRect cull = this->getBounds();
const SkColor* colorsPtr = fUseColors ? colors : NULL;
canvas->drawAtlas(fAtlas, xform, fTex, colorsPtr, N, SkXfermode::kModulate_Mode,
&cull, &paint);
}
SkRect onGetBounds() override {
const SkScalar border = kMaxScale * kCellSize;
SkRect r = fBounds;
r.outset(border, border);
return r;
}
private:
typedef SkDrawable INHERITED;
};
class DrawAtlasView : public SampleView {
DrawAtlasDrawable* fDrawable;
public:
DrawAtlasView() {
fDrawable = new DrawAtlasDrawable(SkRect::MakeWH(640, 480));
}
~DrawAtlasView() override {
fDrawable->unref();
}
protected:
bool onQuery(SkEvent* evt) override {
if (SampleCode::TitleQ(*evt)) {
SampleCode::TitleR(evt, "DrawAtlas");
return true;
}
SkUnichar uni;
if (SampleCode::CharQ(*evt, &uni)) {
switch (uni) {
case 'C': fDrawable->toggleUseColors(); this->inval(NULL); return true;
default: break;
}
}
return this->INHERITED::onQuery(evt);
}
void onDrawContent(SkCanvas* canvas) override {
canvas->drawDrawable(fDrawable);
this->inval(NULL);
}
#if 0
// TODO: switch over to use this for our animation
bool onAnimate(const SkAnimTimer& timer) override {
SkScalar angle = SkDoubleToScalar(fmod(timer.secs() * 360 / 24, 360));
fAnimatingDrawable->setSweep(angle);
return true;
}
#endif
private:
typedef SampleView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() { return new DrawAtlasView; }
static SkViewRegister reg(MyFactory);

View File

@ -1801,6 +1801,18 @@ void SkCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPai
this->onDrawSprite(bitmap, left, top, 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) {
if (count <= 0) {
return;
}
SkASSERT(atlas);
SkASSERT(xform);
SkASSERT(tex);
this->onDrawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
}
//////////////////////////////////////////////////////////////////////////////
// These are the virtual drawing methods
//////////////////////////////////////////////////////////////////////////////
@ -2449,6 +2461,25 @@ void SkCanvas::onDrawDrawable(SkDrawable* dr) {
dr->draw(this);
}
void SkCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
const SkColor colors[], int count, SkXfermode::Mode mode,
const SkRect* cull, const SkPaint* paint) {
if (cull && this->quickReject(*cull)) {
return;
}
SkPaint pnt;
if (paint) {
pnt = *paint;
}
LOOPER_BEGIN(pnt, SkDrawFilter::kPath_Type, NULL)
while (iter.next()) {
iter.fDevice->drawAtlas(iter, atlas, xform, tex, colors, count, mode, pnt);
}
LOOPER_END
}
//////////////////////////////////////////////////////////////////////////////
// These methods are NOT virtual, and therefore must call back into virtual
// methods, rather than actually drawing themselves.

View File

@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
#include "SkColorFilter.h"
#include "SkDevice.h"
#include "SkDraw.h"
#include "SkDrawFilter.h"
@ -13,6 +14,7 @@
#include "SkPatchUtils.h"
#include "SkPathMeasure.h"
#include "SkRasterClip.h"
#include "SkRSXform.h"
#include "SkShader.h"
#include "SkTextBlob.h"
#include "SkTextToPathIter.h"
@ -159,6 +161,37 @@ void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const
}
}
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) {
SkPath path;
path.setIsVolatile(true);
for (int i = 0; i < count; ++i) {
SkPoint quad[4];
xform[i].toQuad(tex[i].width(), tex[i].height(), quad);
SkMatrix localM;
localM.setRSXform(xform[i]);
localM.preTranslate(-tex[i].left(), -tex[i].top());
SkPaint pnt(paint);
pnt.setShader(atlas->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
&localM))->unref();
if (colors && colors[i] != SK_ColorWHITE) {
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(colors[i], mode));
pnt.setColorFilter(cf);
}
path.rewind();
path.addPoly(quad, 4, true);
path.setConvexity(SkPath::kConvex_Convexity);
this->drawPath(draw, path, pnt, NULL, true);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
#ifdef SK_DEBUG
SkASSERT(info.width() > 0 && info.height() > 0);

View File

@ -7,6 +7,7 @@
#include "SkMatrix.h"
#include "SkFloatBits.h"
#include "SkRSXform.h"
#include "SkString.h"
#include "SkNx.h"
@ -440,6 +441,22 @@ void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, SkScalar px, SkScalar py)
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
SkMatrix& SkMatrix::setRSXform(const SkRSXform& xform) {
fMat[kMScaleX] = xform.fSCos;
fMat[kMSkewX] = -xform.fSSin;
fMat[kMTransX] = xform.fTx;
fMat[kMSkewY] = xform.fSSin;
fMat[kMScaleY] = xform.fSCos;
fMat[kMTransY] = xform.fTy;
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = 1;
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
return *this;
}
void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
fMat[kMScaleX] = cosV;
fMat[kMSkewX] = -sinV;
@ -1823,3 +1840,15 @@ bool SkDecomposeUpper2x2(const SkMatrix& matrix,
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void SkRSXform::toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const {
quad[0].set(0, 0);
quad[1].set(width, 0);
quad[2].set(width, height);
quad[3].set(0, height);
SkMatrix m;
m.setRSXform(*this).mapPoints(quad, quad, 4);
}

View File

@ -71,8 +71,9 @@ enum DrawType {
DRAW_TEXT_BLOB,
DRAW_IMAGE,
DRAW_IMAGE_RECT,
DRAW_ATLAS,
LAST_DRAWTYPE_ENUM = DRAW_IMAGE_RECT
LAST_DRAWTYPE_ENUM = DRAW_ATLAS
};
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
@ -85,6 +86,11 @@ enum DrawVertexFlags {
DRAW_VERTICES_HAS_XFER = 0x08,
};
enum DrawAtlasFlags {
DRAW_ATLAS_HAS_COLORS = 1 << 0,
DRAW_ATLAS_HAS_CULL = 1 << 1,
};
///////////////////////////////////////////////////////////////////////////////
// clipparams are packed in 5 bits
// doAA:1 | regionOp:4

View File

@ -11,6 +11,7 @@
#include "SkPicturePlayback.h"
#include "SkPictureRecord.h"
#include "SkReader32.h"
#include "SkRSXform.h"
#include "SkTextBlob.h"
#include "SkTDArray.h"
#include "SkTypes.h"
@ -156,6 +157,25 @@ void SkPicturePlayback::handleOp(SkReader32* reader,
canvas->concat(matrix);
break;
}
case DRAW_ATLAS: {
const SkPaint* paint = fPictureData->getPaint(reader);
const SkImage* atlas = fPictureData->getImage(reader);
const uint32_t flags = reader->readU32();
const int count = reader->readU32();
const SkRSXform* xform = (const SkRSXform*)reader->skip(count * sizeof(SkRSXform));
const SkRect* tex = (const SkRect*)reader->skip(count * sizeof(SkRect));
const SkColor* colors = NULL;
SkXfermode::Mode mode = SkXfermode::kDst_Mode;
if (flags & DRAW_ATLAS_HAS_COLORS) {
colors = (const SkColor*)reader->skip(count * sizeof(SkColor));
mode = (SkXfermode::Mode)reader->readU32();
}
const SkRect* cull = NULL;
if (flags & DRAW_ATLAS_HAS_CULL) {
cull = (const SkRect*)reader->skip(sizeof(SkRect));
}
canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
} break;
case DRAW_BITMAP: {
const SkPaint* paint = fPictureData->getPaint(reader);
const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));

View File

@ -11,6 +11,7 @@
#include "SkPatchUtils.h"
#include "SkPixelRef.h"
#include "SkRRect.h"
#include "SkRSXform.h"
#include "SkTextBlob.h"
#include "SkTSearch.h"
@ -99,6 +100,7 @@ static inline size_t get_paint_offset(DrawType op, size_t opSize) {
1, // DRAW_TEXT_BLOB- right after op code
1, // DRAW_IMAGE - right after op code
1, // DRAW_IMAGE_RECT - right after op code
1, // DRAW_ATLAS - right after op code
};
SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
@ -834,6 +836,42 @@ void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors
this->validate(initialOffset, size);
}
void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
const SkColor colors[], int count, SkXfermode::Mode mode,
const SkRect* cull, const SkPaint* paint) {
// [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
uint32_t flags = 0;
if (colors) {
flags |= DRAW_ATLAS_HAS_COLORS;
size += count * sizeof(SkColor);
size += sizeof(uint32_t); // xfermode::mode
}
if (cull) {
flags |= DRAW_ATLAS_HAS_CULL;
size += sizeof(SkRect);
}
size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
SkASSERT(initialOffset+get_paint_offset(DRAW_ATLAS, size) == fWriter.bytesWritten());
this->addPaintPtr(paint);
this->addImage(atlas);
this->addInt(flags);
this->addInt(count);
fWriter.write(xform, count * sizeof(SkRSXform));
fWriter.write(tex, count * sizeof(SkRect));
// write optional parameters
if (colors) {
fWriter.write(colors, count * sizeof(SkColor));
this->addInt(mode);
}
if (cull) {
fWriter.write(cull, sizeof(SkRect));
}
this->validate(initialOffset, size);
}
///////////////////////////////////////////////////////////////////////////////
SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {

View File

@ -173,6 +173,8 @@ protected:
virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
SkXfermode::Mode, const SkRect*, const SkPaint*) override;
void onDrawPaint(const SkPaint&) override;
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;

View File

@ -111,6 +111,7 @@ DRAW(DrawSprite, drawSprite(r.bitmap.shallowCopy(), r.left, r.top, r.paint));
DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint));
DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint));
DRAW(DrawAtlas, drawAtlas(r.atlas, r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
r.xmode.get(), r.indices, r.indexCount, r.paint));
#undef DRAW
@ -452,6 +453,14 @@ private:
return this->adjustAndMap(dst, &op.paint);
}
Bounds bounds(const DrawAtlas& op) const {
if (op.cull) {
return this->adjustAndMap(*op.cull, op.paint);
} else {
return fCurrentClipBounds;
}
}
Bounds bounds(const DrawPicture& op) const {
SkRect dst = op.picture->cullRect();
op.matrix.mapRect(&dst);

View File

@ -299,6 +299,19 @@ void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
xmode);
}
void SkRecorder::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
const SkColor colors[], int count, SkXfermode::Mode mode,
const SkRect* cull, const SkPaint* paint) {
APPEND(DrawAtlas, this->copy(paint),
atlas,
this->copy(xform, count),
this->copy(tex, count),
this->copy(colors, count),
count,
mode,
this->copy(cull));
}
void SkRecorder::willSave() {
APPEND(Save);
}

View File

@ -108,6 +108,8 @@ public:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override;
void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override;
void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override;

View File

@ -12,6 +12,7 @@
#include "SkDrawable.h"
#include "SkPathPriv.h"
#include "SkPicture.h"
#include "SkRSXform.h"
#include "SkTextBlob.h"
namespace SkRecords {
@ -58,6 +59,7 @@ namespace SkRecords {
M(DrawRect) \
M(DrawSprite) \
M(DrawTextBlob) \
M(DrawAtlas) \
M(DrawVertices)
// Defines SkRecords::Type, an enum of all record types.
@ -121,6 +123,15 @@ struct T { \
A a; B b; C c; D d; E e; \
};
#define RECORD8(T, A, a, B, b, C, c, D, d, E, e, F, f, G, g, H, h) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X, typename W, typename V, typename U, typename S, typename R> \
T(Z a, Y b, X c, W d, V e, U f, S g, R h) : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {} \
A a; B b; C c; D d; E e; F f; G g; H h; \
};
#define ACT_AS_PTR(ptr) \
operator T*() const { return ptr; } \
T* operator->() const { return ptr; }
@ -317,6 +328,15 @@ RECORD5(DrawPatch, SkPaint, paint,
PODArray<SkPoint>, texCoords,
RefBox<SkXfermode>, xmode);
RECORD8(DrawAtlas, Optional<SkPaint>, paint,
RefBox<const SkImage>, atlas,
PODArray<SkRSXform>, xforms,
PODArray<SkRect>, texs,
PODArray<SkColor>, colors,
int, count,
SkXfermode::Mode, mode,
Optional<SkRect>, cull);
// This guy is so ugly we just write it manually.
struct DrawVertices {
static const Type kType = DrawVertices_Type;
@ -357,6 +377,7 @@ struct DrawVertices {
#undef RECORD3
#undef RECORD4
#undef RECORD5
#undef RECORD8
} // namespace SkRecords

View File

@ -39,6 +39,7 @@ enum DrawOps {
kClipRect_DrawOp,
kClipRRect_DrawOp,
kConcat_DrawOp,
kDrawAtlas_DrawOp,
kDrawBitmap_DrawOp,
kDrawBitmapNine_DrawOp,
kDrawBitmapRectToRect_DrawOp,
@ -144,6 +145,11 @@ enum {
kDrawVertices_HasIndices_DrawOpFlag = 1 << 2,
kDrawVertices_HasXfermode_DrawOpFlag = 1 << 3,
};
enum {
kDrawAtlas_HasPaint_DrawOpFlag = 1 << 0,
kDrawAtlas_HasColors_DrawOpFlag = 1 << 1,
kDrawAtlas_HasCull_DrawOpFlag = 1 << 2,
};
// These are shared between drawbitmap and drawimage
enum {
kDrawBitmap_HasPaint_DrawOpFlag = 1 << 0,

View File

@ -20,11 +20,12 @@
#include "SkDrawLooper.h"
#include "SkImageFilter.h"
#include "SkMaskFilter.h"
#include "SkReadBuffer.h"
#include "SkPatchUtils.h"
#include "SkPathEffect.h"
#include "SkRasterizer.h"
#include "SkReadBuffer.h"
#include "SkRRect.h"
#include "SkRSXform.h"
#include "SkShader.h"
#include "SkTextBlob.h"
#include "SkTypeface.h"
@ -479,6 +480,33 @@ static void drawVertices_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
}
}
static void drawAtlas_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32, SkGPipeState* state) {
unsigned flags = DrawOp_unpackFlags(op32);
const SkPaint* paint = NULL;
if (flags & kDrawAtlas_HasPaint_DrawOpFlag) {
paint = &state->paint();
}
const int slot = reader->readU32();
const SkImage* atlas = state->getImage(slot);
const int count = reader->readU32();
SkXfermode::Mode mode = (SkXfermode::Mode)reader->readU32();
const SkRSXform* xform = skip<SkRSXform>(reader, count);
const SkRect* tex = skip<SkRect>(reader, count);
const SkColor* colors = NULL;
if (flags & kDrawAtlas_HasColors_DrawOpFlag) {
colors = skip<SkColor>(reader, count);
}
const SkRect* cull = NULL;
if (flags & kDrawAtlas_HasCull_DrawOpFlag) {
cull = skip<SkRect>(reader, 1);
}
if (state->shouldDraw()) {
canvas->drawAtlas(atlas, xform, tex, colors, count, mode, cull, paint);
}
}
///////////////////////////////////////////////////////////////////////////////
static void drawText_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@ -831,6 +859,7 @@ static const ReadProc gReadTable[] = {
clipRect_rp,
clipRRect_rp,
concat_rp,
drawAtlas_rp,
drawBitmap_rp,
drawBitmapNine_rp,
drawBitmapRect_rp,

View File

@ -16,6 +16,7 @@
#include "SkGPipePriv.h"
#include "SkImageFilter.h"
#include "SkMaskFilter.h"
#include "SkRSXform.h"
#include "SkWriteBuffer.h"
#include "SkPaint.h"
#include "SkPatchUtils.h"
@ -287,6 +288,8 @@ protected:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override;
void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
@ -1096,6 +1099,48 @@ void SkGPipeCanvas::onDrawVertices(VertexMode vmode, int vertexCount,
}
}
void SkGPipeCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
const SkColor colors[], int count, SkXfermode::Mode mode,
const SkRect* cull, const SkPaint* paint) {
NOTIFY_SETUP(this);
unsigned flags = 0; // packs with the op, so needs no extra space
if (paint) {
flags |= kDrawAtlas_HasPaint_DrawOpFlag;
this->writePaint(*paint);
}
size_t size = 4; // image-slot
size += 4; // count
size += 4; // mode
size += count * sizeof(SkRSXform); // xform
size += count * sizeof(SkRect); // tex
if (colors) {
flags |= kDrawAtlas_HasColors_DrawOpFlag;
size += count * sizeof(SkColor); // colors
}
if (cull) {
flags |= kDrawAtlas_HasCull_DrawOpFlag;
size += sizeof(SkRect); // cull
}
if (this->needOpBytes(size)) {
this->writeOp(kDrawAtlas_DrawOp, flags, 0);
int32_t slot = fImageHeap->insert(atlas);
fWriter.write32(slot);
fWriter.write32(count);
fWriter.write32(mode);
fWriter.write(xform, count * sizeof(SkRSXform));
fWriter.write(tex, count * sizeof(SkRect));
if (colors) {
fWriter.write(colors, count * sizeof(SkColor));
}
if (cull) {
fWriter.writeRect(*cull);
}
}
}
void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) {

View File

@ -251,6 +251,10 @@ protected:
const SkPoint texCoords[4], SkXfermode* xmode,
const SkPaint& paint) override
{SkASSERT(0);}
void drawAtlas(const SkDraw&, const SkImage* atlas, const SkRSXform[], const SkRect[],
const SkColor[], int count, SkXfermode::Mode, const SkPaint&) override
{SkASSERT(0);}
void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
const SkPaint&) override
{SkASSERT(0);}
@ -356,8 +360,7 @@ bool SkDeferredDevice::hasPendingCommands() {
return fPipeController.hasPendingCommands();
}
void SkDeferredDevice::aboutToDraw()
{
void SkDeferredDevice::aboutToDraw() {
if (fNotificationClient) {
fNotificationClient->prepareForDraw();
}
@ -989,6 +992,15 @@ void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor color
this->recordedDrawCommand();
}
void SkDeferredCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[],
const SkRect tex[], const SkColor colors[], int count,
SkXfermode::Mode mode, const SkRect* cullRect,
const SkPaint* paint) {
AutoImmediateDrawIfNeeded autoDraw(*this, paint);
this->drawingCanvas()->drawAtlas(atlas, xform, tex, colors, count, mode, cullRect, paint);
this->recordedDrawCommand();
}
SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
this->drawingCanvas()->setDrawFilter(filter);
this->INHERITED::setDrawFilter(filter);