зеркало из https://github.com/mozilla/moz-skia.git
Explicit tile bounds for SkPictureShader
The integer picture size is not granular enough to allow precise tiling in arbitrary coordinate systems. This CL adds an optional tile bounds float rect param to control the tile size and location. (this also allows tile spacing emulation for picture shaders). R=reed@google.com, robertphillips@google.com Author: fmalita@chromium.org Review URL: https://codereview.chromium.org/437393003
This commit is contained in:
Родитель
3c7edda88e
Коммит
b5f7826c51
|
@ -135,7 +135,8 @@ private:
|
|||
fPicture,
|
||||
kTileConfigs[tileMode].tmx,
|
||||
kTileConfigs[tileMode].tmy,
|
||||
&localMatrix));
|
||||
&localMatrix,
|
||||
NULL));
|
||||
paint.setShader(pictureShader.get());
|
||||
canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright 2014 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 "SkPaint.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkPictureRecorder.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
static const SkScalar kPictureSize = SK_Scalar1;
|
||||
static const SkScalar kFillSize = 100;
|
||||
static const unsigned kRowSize = 6;
|
||||
|
||||
static const struct {
|
||||
SkScalar x, y, w, h;
|
||||
SkScalar offsetX, offsetY;
|
||||
} tiles[] = {
|
||||
{ 0, 0, 1, 1, 0, 0 },
|
||||
{ 0.5f, 0.5f, 1, 1, 0, 0 },
|
||||
{ -0.5f, -0.5f, 1, 1, 0, 0 },
|
||||
|
||||
{ 0, 0, 1.5f, 1.5f, 0, 0 },
|
||||
{ 0.5f, 0.5f, 1.5f, 1.5f, 0, 0 },
|
||||
{ -0.5f, -0.5f, 1.5f, 1.5f, 0, 0 },
|
||||
|
||||
{ 0, 0, 0.5f, 0.5f, 0, 0 },
|
||||
{ -0.25f, -0.25f, 0.5f, 0.5f, 0, 0 },
|
||||
{ 0.25f, 0.25f, 0.5f, 0.5f, 0, 0 },
|
||||
|
||||
{ 0, 0, 1, 1, 0.5f, 0.5f },
|
||||
{ 0.5f, 0.5f, 1, 1, 0.5f, 0.5f },
|
||||
{ -0.5f, -0.5f, 1, 1, 0.5f, 0.5f },
|
||||
|
||||
{ 0, 0, 1.5f, 1.5f, 0.5f, 0.5f },
|
||||
{ 0.5f, 0.5f, 1.5f, 1.5f, 0.5f, 0.5f },
|
||||
{ -0.5f, -0.5f, 1.5f, 1.5f, 0.5f, 0.5f },
|
||||
|
||||
{ 0, 0, 1.5f, 1, 0, 0 },
|
||||
{ 0.5f, 0.5f, 1.5f, 1, 0, 0 },
|
||||
{ -0.5f, -0.5f, 1.5f, 1, 0, 0 },
|
||||
|
||||
{ 0, 0, 0.5f, 1, 0, 0 },
|
||||
{ -0.25f, -0.25f, 0.5f, 1, 0, 0 },
|
||||
{ 0.25f, 0.25f, 0.5f, 1, 0, 0 },
|
||||
|
||||
{ 0, 0, 1, 1.5f, 0, 0 },
|
||||
{ 0.5f, 0.5f, 1, 1.5f, 0, 0 },
|
||||
{ -0.5f, -0.5f, 1, 1.5f, 0, 0 },
|
||||
|
||||
{ 0, 0, 1, 0.5f, 0, 0 },
|
||||
{ -0.25f, -0.25f, 1, 0.5f, 0, 0 },
|
||||
{ 0.25f, 0.25f, 1, 0.5f, 0, 0 },
|
||||
};
|
||||
|
||||
class PictureShaderTileGM : public skiagm::GM {
|
||||
public:
|
||||
PictureShaderTileGM() {
|
||||
SkPictureRecorder recorder;
|
||||
SkCanvas* pictureCanvas = recorder.beginRecording(SkScalarCeilToInt(kPictureSize),
|
||||
SkScalarCeilToInt(kPictureSize),
|
||||
NULL, 0);
|
||||
drawScene(pictureCanvas, kPictureSize);
|
||||
SkAutoTUnref<SkPicture> picture(recorder.endRecording());
|
||||
|
||||
for (unsigned i = 0; i < SK_ARRAY_COUNT(tiles); ++i) {
|
||||
SkRect tile = SkRect::MakeXYWH(tiles[i].x * kPictureSize,
|
||||
tiles[i].y * kPictureSize,
|
||||
tiles[i].w * kPictureSize,
|
||||
tiles[i].h * kPictureSize);
|
||||
SkMatrix localMatrix;
|
||||
localMatrix.setTranslate(tiles[i].offsetX * kPictureSize,
|
||||
tiles[i].offsetY * kPictureSize);
|
||||
localMatrix.postScale(kFillSize / (2 * kPictureSize),
|
||||
kFillSize / (2 * kPictureSize));
|
||||
fShaders[i].reset(SkShader::CreatePictureShader(picture,
|
||||
SkShader::kRepeat_TileMode,
|
||||
SkShader::kRepeat_TileMode,
|
||||
&localMatrix,
|
||||
&tile));
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual uint32_t onGetFlags() const SK_OVERRIDE {
|
||||
return kSkipTiled_Flag;
|
||||
}
|
||||
|
||||
virtual SkString onShortName() SK_OVERRIDE {
|
||||
return SkString("pictureshadertile");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() SK_OVERRIDE {
|
||||
return SkISize::Make(800, 600);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
|
||||
canvas->clear(SK_ColorBLACK);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
|
||||
for (unsigned i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
|
||||
paint.setShader(fShaders[i]);
|
||||
|
||||
canvas->save();
|
||||
canvas->translate((i % kRowSize) * kFillSize * 1.1f,
|
||||
(i / kRowSize) * kFillSize * 1.1f);
|
||||
canvas->drawRect(SkRect::MakeWH(kFillSize, kFillSize), paint);
|
||||
canvas->restore();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void drawScene(SkCanvas* canvas, SkScalar pictureSize) {
|
||||
canvas->clear(SK_ColorWHITE);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
canvas->drawCircle(pictureSize / 4, pictureSize / 4, pictureSize / 4, paint);
|
||||
canvas->drawRect(SkRect::MakeXYWH(pictureSize / 2, pictureSize / 2,
|
||||
pictureSize / 2, pictureSize / 2), paint);
|
||||
|
||||
paint.setColor(SK_ColorRED);
|
||||
canvas->drawLine(pictureSize / 2, pictureSize * 1 / 3,
|
||||
pictureSize / 2, pictureSize * 2 / 3, paint);
|
||||
canvas->drawLine(pictureSize * 1 / 3, pictureSize / 2,
|
||||
pictureSize * 2 / 3, pictureSize / 2, paint);
|
||||
|
||||
paint.setColor(SK_ColorBLACK);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
canvas->drawRect(SkRect::MakeWH(pictureSize, pictureSize), paint);
|
||||
}
|
||||
|
||||
SkAutoTUnref<SkShader> fShaders[SK_ARRAY_COUNT(tiles)];
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
||||
DEF_GM( return SkNEW(PictureShaderTileGM); )
|
|
@ -135,6 +135,7 @@
|
|||
'../gm/perlinnoise.cpp',
|
||||
'../gm/pictureimagefilter.cpp',
|
||||
'../gm/pictureshader.cpp',
|
||||
'../gm/pictureshadertile.cpp',
|
||||
'../gm/points.cpp',
|
||||
'../gm/poly2poly.cpp',
|
||||
'../gm/polygons.cpp',
|
||||
|
|
|
@ -428,10 +428,17 @@ public:
|
|||
* FIXME: src cannot be const due to SkCanvas::drawPicture
|
||||
* @param tmx The tiling mode to use when sampling the bitmap in the x-direction.
|
||||
* @param tmy The tiling mode to use when sampling the bitmap in the y-direction.
|
||||
* @param tile The tile rectangle in picture coordinates: this represents the subset
|
||||
* (or superset) of the picture used when building a tile. It is not
|
||||
* affected by localMatrix and does not imply scaling (only translation
|
||||
* and cropping). If null, the tile rect is considered equal to the picture
|
||||
* bounds.
|
||||
* @return Returns a new shader object. Note: this function never returns null.
|
||||
*/
|
||||
static SkShader* CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy,
|
||||
const SkMatrix* localMatrix = NULL);
|
||||
static SkShader* CreatePictureShader(SkPicture* src,
|
||||
TileMode tmx, TileMode tmy,
|
||||
const SkMatrix* localMatrix,
|
||||
const SkRect* tile);
|
||||
|
||||
/**
|
||||
* Return a shader that will apply the specified localMatrix to the proxy shader.
|
||||
|
|
|
@ -19,16 +19,20 @@
|
|||
#endif
|
||||
|
||||
SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMode tmy,
|
||||
const SkMatrix* localMatrix)
|
||||
const SkMatrix* localMatrix, const SkRect* tile)
|
||||
: INHERITED(localMatrix)
|
||||
, fPicture(SkRef(picture))
|
||||
, fTmx(tmx)
|
||||
, fTmy(tmy) { }
|
||||
, fTmy(tmy) {
|
||||
fTile = tile ? *tile : SkRect::MakeWH(SkIntToScalar(picture->width()),
|
||||
SkIntToScalar(picture->height()));
|
||||
}
|
||||
|
||||
SkPictureShader::SkPictureShader(SkReadBuffer& buffer)
|
||||
: INHERITED(buffer) {
|
||||
fTmx = static_cast<SkShader::TileMode>(buffer.read32());
|
||||
fTmy = static_cast<SkShader::TileMode>(buffer.read32());
|
||||
buffer.readRect(&fTile);
|
||||
fPicture = SkPicture::CreateFromBuffer(buffer);
|
||||
}
|
||||
|
||||
|
@ -37,11 +41,12 @@ SkPictureShader::~SkPictureShader() {
|
|||
}
|
||||
|
||||
SkPictureShader* SkPictureShader::Create(const SkPicture* picture, TileMode tmx, TileMode tmy,
|
||||
const SkMatrix* localMatrix) {
|
||||
if (!picture || 0 == picture->width() || 0 == picture->height()) {
|
||||
const SkMatrix* localMatrix, const SkRect* tile) {
|
||||
if (!picture || 0 == picture->width() || 0 == picture->height()
|
||||
|| (NULL != tile && tile->isEmpty())) {
|
||||
return NULL;
|
||||
}
|
||||
return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy, localMatrix));
|
||||
return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy, localMatrix, tile));
|
||||
}
|
||||
|
||||
void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
|
||||
|
@ -49,6 +54,7 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
|
|||
|
||||
buffer.write32(fTmx);
|
||||
buffer.write32(fTmy);
|
||||
buffer.writeRect(fTile);
|
||||
fPicture->flatten(buffer);
|
||||
}
|
||||
|
||||
|
@ -68,7 +74,7 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatri
|
|||
scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
|
||||
SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
|
||||
}
|
||||
SkSize scaledSize = SkSize::Make(scale.x() * fPicture->width(), scale.y() * fPicture->height());
|
||||
SkSize scaledSize = SkSize::Make(scale.x() * fTile.width(), scale.y() * fTile.height());
|
||||
|
||||
SkISize tileSize = scaledSize.toRound();
|
||||
if (tileSize.isEmpty()) {
|
||||
|
@ -76,8 +82,8 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatri
|
|||
}
|
||||
|
||||
// The actual scale, compensating for rounding.
|
||||
SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(),
|
||||
SkIntToScalar(tileSize.height()) / fPicture->height());
|
||||
SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.width(),
|
||||
SkIntToScalar(tileSize.height()) / fTile.height());
|
||||
|
||||
SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);
|
||||
|
||||
|
@ -90,6 +96,7 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatri
|
|||
|
||||
SkCanvas canvas(bm);
|
||||
canvas.scale(tileScale.width(), tileScale.height());
|
||||
canvas.translate(fTile.x(), fTile.y());
|
||||
canvas.drawPicture(fPicture);
|
||||
|
||||
fCachedTileScale = tileScale;
|
||||
|
|
|
@ -21,7 +21,8 @@ class SkPicture;
|
|||
*/
|
||||
class SkPictureShader : public SkShader {
|
||||
public:
|
||||
static SkPictureShader* Create(const SkPicture*, TileMode, TileMode, const SkMatrix* = NULL);
|
||||
static SkPictureShader* Create(const SkPicture*, TileMode, TileMode, const SkMatrix*,
|
||||
const SkRect*);
|
||||
virtual ~SkPictureShader();
|
||||
|
||||
virtual size_t contextSize() const SK_OVERRIDE;
|
||||
|
@ -38,11 +39,12 @@ protected:
|
|||
virtual Context* onCreateContext(const ContextRec&, void* storage) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkPictureShader(const SkPicture*, TileMode, TileMode, const SkMatrix* = NULL);
|
||||
SkPictureShader(const SkPicture*, TileMode, TileMode, const SkMatrix*, const SkRect*);
|
||||
|
||||
SkShader* refBitmapShader(const SkMatrix&, const SkMatrix* localMatrix) const;
|
||||
|
||||
const SkPicture* fPicture;
|
||||
SkRect fTile;
|
||||
TileMode fTmx, fTmy;
|
||||
|
||||
mutable SkMutex fCachedBitmapShaderMutex;
|
||||
|
|
|
@ -228,8 +228,8 @@ SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMo
|
|||
}
|
||||
|
||||
SkShader* SkShader::CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy,
|
||||
const SkMatrix* localMatrix) {
|
||||
return SkPictureShader::Create(src, tmx, tmy, localMatrix);
|
||||
const SkMatrix* localMatrix, const SkRect* tile) {
|
||||
return SkPictureShader::Create(src, tmx, tmy, localMatrix, tile);
|
||||
}
|
||||
|
||||
#ifndef SK_IGNORE_TO_STRING
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
// empty picture returns NULL.
|
||||
DEF_TEST(PictureShader_empty, reporter) {
|
||||
SkShader* shader = SkShader::CreatePictureShader(NULL,
|
||||
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
|
||||
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, NULL, NULL);
|
||||
REPORTER_ASSERT(reporter, NULL == shader);
|
||||
|
||||
SkPictureRecorder factory;
|
||||
factory.beginRecording(0, 0, NULL, 0);
|
||||
SkAutoTUnref<SkPicture> picture(factory.endRecording());
|
||||
shader = SkShader::CreatePictureShader(picture.get(),
|
||||
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
|
||||
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, NULL, NULL);
|
||||
REPORTER_ASSERT(reporter, NULL == shader);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче