Add experimental API to draw a set of SkImages in one SkCanvas call.

The client provides a src and dst rect for each image as well as
a bitfield that indicates whether each edge of the image should be
antialiased. This per-edge AA is useful for tiled compositors.

Rather than take a full SkPaint this API only takes an alpha, a filter
quality (which is pinned to kLow), and a blend mode. This is a likely
point of future evolution.

Currently the API is only fully implemented for kSrcOver on the GPU
backend. With other blend modes or on other backends AA will be ignored
for images that do not have all four edge AA flags set.

BUG: skia:8444

Change-Id: I143998dda8ad6a25f64e18cd600392ba553030ac
Reviewed-on: https://skia-review.googlesource.com/c/159062
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Salomon 2018-10-11 10:16:33 -04:00 committed by Skia Commit-Bot
parent b27a9cf2f4
commit 0a0304c426
43 changed files with 791 additions and 289 deletions

View File

@ -574,6 +574,22 @@ void SkPipeCanvas::onDrawImageLattice(const SkImage* image, const Lattice& latti
}
}
void SkPipeCanvas::onDrawImageSet(const ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
SkPipeWriter writer(this);
writer.write32(pack_verb(SkPipeVerb::kDrawImageSet));
writer.writeInt(count);
writer.writeScalar(SkFloatToScalar(alpha));
writer.writeInt((int)filterQuality);
writer.writeInt((int)mode);
for (int i = 0; i < count; ++i) {
writer.writeImage(set[i].fImage.get());
writer.writeRect(set[i].fSrcRect);
writer.writeRect(set[i].fDstRect);
writer.writeUInt(set[i].fAAFlags);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void SkPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,

View File

@ -133,6 +133,8 @@ protected:
const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
const SkPaint*) override;
void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
SkBlendMode, const SkPaint&) override;

View File

@ -45,6 +45,7 @@ enum class SkPipeVerb : uint8_t {
kDrawImageRect, // extra == constraint | has_src_rect | has_paint
kDrawImageNine, // extra == has_paint:1
kDrawImageLattice, // extra == has_paint:1
kDrawImageSet, // extra == 0
kDrawVertices,

View File

@ -538,6 +538,23 @@ static void drawImageLattice_handler(SkPipeReader& reader, uint32_t packedVerb,
canvas->drawImageLattice(image.get(), lattice, *dst, paint);
}
static void drawImageSet_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) {
SkASSERT(SkPipeVerb::kDrawImageSet == unpack_verb(packedVerb));
int cnt = reader.readInt();
float alpha = SkScalarToFloat(reader.readScalar());
SkFilterQuality filterQuality = (SkFilterQuality)reader.readInt();
SkBlendMode mode = (SkBlendMode)reader.readInt();
SkAutoTArray<SkCanvas::ImageSetEntry> set(cnt);
for (int i = 0; i < cnt; ++i) {
set[i].fImage = reader.readImage();
reader.readRect(&set[i].fSrcRect);
reader.readRect(&set[i].fDstRect);
set[i].fAAFlags = reader.readUInt();
}
canvas->experimental_DrawImageSetV0(set.get(), cnt, alpha, filterQuality, mode);
}
static void drawVertices_handler(SkPipeReader& reader, uint32_t packedVerb, SkCanvas* canvas) {
SkASSERT(SkPipeVerb::kDrawVertices == unpack_verb(packedVerb));
SkBlendMode bmode = (SkBlendMode)unpack_verb_extra(packedVerb);
@ -735,6 +752,7 @@ const HandlerRec gPipeHandlers[] = {
HANDLER(drawImageRect),
HANDLER(drawImageNine),
HANDLER(drawImageLattice),
HANDLER(drawImageSet),
HANDLER(drawVertices),

View File

@ -1,168 +0,0 @@
/*
* Copyright 2018 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 "GrClip.h"
#include "GrContext.h"
#include "GrRenderTargetContext.h"
#include "SkGradientShader.h"
#include "SkImage_Base.h"
#include "SkSurface.h"
namespace skiagm {
class AAFlagsGM : public GM {
private:
SkString onShortName() final { return SkString("aaflags"); }
SkISize onISize() override { return SkISize::Make(1000, 1450); }
void onOnceBeforeDraw() override {
static constexpr SkScalar kW = SkIntToScalar(kTileW * kM);
static constexpr SkScalar kH = SkIntToScalar(kTileH * kN);
auto surf = SkSurface::MakeRaster(
SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
surf->getCanvas()->clear(SK_ColorLTGRAY);
static constexpr SkScalar kStripeW = 10;
static constexpr SkScalar kStripeSpacing = 30;
SkPaint paint;
static constexpr SkPoint pts1[] = {{0.f, 0.f}, {kW, kH}};
static constexpr SkColor kColors1[] = {SK_ColorCYAN, SK_ColorBLACK};
auto grad =
SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkShader::kClamp_TileMode);
paint.setShader(std::move(grad));
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(kStripeW);
SkPoint stripePts[] = {{-kW - kStripeW, -kStripeW}, {kStripeW, kH + kStripeW}};
while (stripePts[0].fX <= kW) {
surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
stripePts[0].fX += kStripeSpacing;
stripePts[1].fX += kStripeSpacing;
}
static constexpr SkPoint pts2[] = {{0.f, kH}, {kW, 0.f}};
static constexpr SkColor kColors2[] = {SK_ColorMAGENTA, SK_ColorBLACK};
grad = SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkShader::kClamp_TileMode);
paint.setShader(std::move(grad));
paint.setBlendMode(SkBlendMode::kMultiply);
stripePts[0] = {-kW - kStripeW, kH + kStripeW};
stripePts[1] = {kStripeW, -kStripeW};
while (stripePts[0].fX <= kW) {
surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
stripePts[0].fX += kStripeSpacing;
stripePts[1].fX += kStripeSpacing;
}
auto img = surf->makeImageSnapshot();
for (int y = 0; y < kN; ++y) {
for (int x = 0; x < kM; ++x) {
fImage[x][y] =
img->makeSubset(SkIRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH));
}
}
}
void onDraw(SkCanvas* canvas) override {
GrContext* ctx = canvas->getGrContext();
if (!ctx) {
DrawGpuOnlyMessage(canvas);
return;
}
GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
SkASSERT(rtc);
SkScalar d = SkVector{kM * kTileW, kN * kTileH}.length();
SkMatrix matrices[4];
// rotation
matrices[0].setRotate(30);
matrices[0].postTranslate(d / 3, 0);
// perespective
SkPoint src[4];
SkRect::MakeWH(kM * kTileW, kN * kTileH).toQuad(src);
SkPoint dst[4] = {{0, 0},
{kM * kTileW + 10.f, -5.f},
{kM * kTileW - 28.f, kN * kTileH + 40.f},
{45.f, kN * kTileH - 25.f}};
matrices[1].setPolyToPoly(src, dst, 4);
matrices[1].postTranslate(d, 50.f);
// skew
matrices[2].setRotate(-60.f);
matrices[2].postSkew(0.5f, -1.35f);
matrices[2].postScale(0.6f, 1.05f);
matrices[2].postTranslate(d, 2.5f * d);
// perspective + mirror in x.
dst[1] = {0, 0};
dst[0] = {3.f / 4.f * kM * kTileW, 0};
dst[3] = {2.f / 3.f * kM * kTileW, 1 / 4.f * kN * kTileH};
dst[2] = {1.f / 3.f * kM * kTileW, 1 / 4.f * kN * kTileH - 25.f};
matrices[3].setPolyToPoly(src, dst, 4);
matrices[3].postTranslate(100.f, d);
for (size_t m = 0; m < SK_ARRAY_COUNT(matrices); ++m) {
// Draw grid of green "lines" at interior tile boundaries.
static constexpr SkScalar kLineOutset = 10.f;
static constexpr SkScalar kLineHalfW = 4.f;
auto color = GrColor4f(0.f, 1.f, 0.f, 1.f);
for (int x = 1; x < kM; ++x) {
GrPaint paint;
paint.setColor4f(color);
SkRect lineRect =
SkRect::MakeLTRB(x * kTileW - kLineHalfW, -kLineOutset,
x * kTileW + kLineHalfW, kN * kTileH + kLineOutset);
rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kYes, matrices[m], lineRect);
}
for (int y = 1; y < kN; ++y) {
GrPaint paint;
paint.setColor4f(color);
SkRect lineRect =
SkRect::MakeLTRB(-kLineOutset, y * kTileH - kLineHalfW,
kTileW * kM + kLineOutset, y * kTileH + kLineHalfW);
rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kYes, matrices[m], lineRect);
}
static constexpr GrColor kColor = GrColor_WHITE;
for (int x = 0; x < kM; ++x) {
for (int y = 0; y < kN; ++y) {
auto proxy = as_IB(fImage[x][y])
->asTextureProxyRef(ctx, GrSamplerState::ClampBilerp(),
nullptr, nullptr, nullptr);
if (!proxy) {
continue;
}
auto srcR = proxy->getBoundsRect();
auto dstR = SkRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH);
GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
if (x == 0) {
aaFlags |= GrQuadAAFlags::kLeft;
}
if (x == kM - 1) {
aaFlags |= GrQuadAAFlags::kRight;
}
if (y == 0) {
aaFlags |= GrQuadAAFlags::kTop;
}
if (y == kN - 1) {
aaFlags |= GrQuadAAFlags::kBottom;
}
rtc->drawTexture(GrNoClip(), proxy, GrSamplerState::Filter::kBilerp, kColor,
srcR, dstR, aaFlags, SkCanvas::kFast_SrcRectConstraint,
matrices[m], nullptr, nullptr);
}
}
}
}
static constexpr int kM = 4;
static constexpr int kN = 4;
static constexpr SkScalar kTileW = 100;
static constexpr SkScalar kTileH = 100;
sk_sp<SkImage> fImage[kM][kN];
};
DEF_GM(return new AAFlagsGM();)
} // namespace skiagm

167
gm/drawimageset.cpp Normal file
View File

@ -0,0 +1,167 @@
/*
* Copyright 2018 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 "SkGradientShader.h"
#include "SkSurface.h"
namespace skiagm {
class DrawImageSetGM : public GM {
private:
SkString onShortName() final { return SkString("draw_image_set"); }
SkISize onISize() override { return SkISize::Make(1000, 725); }
void onOnceBeforeDraw() override {
static constexpr SkScalar kW = SkIntToScalar(kTileW * kM);
static constexpr SkScalar kH = SkIntToScalar(kTileH * kN);
auto surf = SkSurface::MakeRaster(
SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
surf->getCanvas()->clear(SK_ColorLTGRAY);
static constexpr SkScalar kStripeW = 10;
static constexpr SkScalar kStripeSpacing = 30;
SkPaint paint;
static constexpr SkPoint pts1[] = {{0.f, 0.f}, {kW, kH}};
static constexpr SkColor kColors1[] = {SK_ColorCYAN, SK_ColorBLACK};
auto grad =
SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkShader::kClamp_TileMode);
paint.setShader(std::move(grad));
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(kStripeW);
SkPoint stripePts[] = {{-kW - kStripeW, -kStripeW}, {kStripeW, kH + kStripeW}};
while (stripePts[0].fX <= kW) {
surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
stripePts[0].fX += kStripeSpacing;
stripePts[1].fX += kStripeSpacing;
}
static constexpr SkPoint pts2[] = {{0.f, kH}, {kW, 0.f}};
static constexpr SkColor kColors2[] = {SK_ColorMAGENTA, SK_ColorBLACK};
grad = SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkShader::kClamp_TileMode);
paint.setShader(std::move(grad));
paint.setBlendMode(SkBlendMode::kMultiply);
stripePts[0] = {-kW - kStripeW, kH + kStripeW};
stripePts[1] = {kStripeW, -kStripeW};
while (stripePts[0].fX <= kW) {
surf->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, 2, stripePts, paint);
stripePts[0].fX += kStripeSpacing;
stripePts[1].fX += kStripeSpacing;
}
auto img = surf->makeImageSnapshot();
for (int y = 0; y < kN; ++y) {
for (int x = 0; x < kM; ++x) {
fImage[x][y] =
img->makeSubset(SkIRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH));
}
}
}
void onDraw(SkCanvas* canvas) override {
SkScalar d = SkVector{kM * kTileW, kN * kTileH}.length();
SkMatrix matrices[4];
// rotation
matrices[0].setRotate(30);
matrices[0].postTranslate(d / 3, 0);
// perespective
SkPoint src[4];
SkRect::MakeWH(kM * kTileW, kN * kTileH).toQuad(src);
SkPoint dst[4] = {{0, 0},
{kM * kTileW + 10.f, -5.f},
{kM * kTileW - 28.f, kN * kTileH + 40.f},
{45.f, kN * kTileH - 25.f}};
SkAssertResult(matrices[1].setPolyToPoly(src, dst, 4));
matrices[1].postTranslate(d, 50.f);
// skew
matrices[2].setRotate(-60.f);
matrices[2].postSkew(0.5f, -1.15f);
matrices[2].postScale(0.6f, 1.05f);
matrices[2].postTranslate(d, 2.6f * d);
// perspective + mirror in x.
dst[1] = {-.25 * kM * kTileW, 0};
dst[0] = {5.f / 4.f * kM * kTileW, 0};
dst[3] = {2.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH};
dst[2] = {1.f / 3.f * kM * kTileW, 1 / 2.f * kN * kTileH - 0.1f * kTileH};
SkAssertResult(matrices[3].setPolyToPoly(src, dst, 4));
matrices[3].postTranslate(100.f, d);
SkCanvas::ImageSetEntry set[kM * kN];
for (int x = 0; x < kM; ++x) {
for (int y = 0; y < kN; ++y) {
set[y * kM + x].fAAFlags = SkCanvas::kNone_QuadAAFlags;
if (x == 0) {
set[y * kM + x].fAAFlags |= SkCanvas::kLeft_QuadAAFlag;
}
if (x == kM - 1) {
set[y * kM + x].fAAFlags |= SkCanvas::kRight_QuadAAFlag;
}
if (y == 0) {
set[y * kM + x].fAAFlags |= SkCanvas::kTop_QuadAAFlag;
}
if (y == kN - 1) {
set[y * kM + x].fAAFlags |= SkCanvas::kBottom_QuadAAFlag;
}
set[y * kM + x].fSrcRect = SkRect::MakeWH(kTileW, kTileH);
set[y * kM + x].fDstRect = SkRect::MakeXYWH(x * kTileW, y * kTileH, kTileW, kTileH);
set[y * kM + x].fImage = fImage[x][y];
}
}
for (auto fm : {kNone_SkFilterQuality, kLow_SkFilterQuality}) {
for (size_t m = 0; m < SK_ARRAY_COUNT(matrices); ++m) {
// Draw grid of red lines at interior tile boundaries.
static constexpr SkScalar kLineOutset = 10.f;
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(SK_ColorRED);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(0.f);
for (int x = 1; x < kM; ++x) {
SkPoint pts[] = {{x * kTileW, 0}, {x * kTileW, kN * kTileH}};
matrices[m].mapPoints(pts, 2);
SkVector v = pts[1] - pts[0];
v.setLength(v.length() + kLineOutset);
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
}
for (int y = 1; y < kN; ++y) {
SkPoint pts[] = {{0, y * kTileH}, {kTileW * kM, y * kTileH}};
matrices[m].mapPoints(pts, 2);
SkVector v = pts[1] - pts[0];
v.setLength(v.length() + kLineOutset);
canvas->drawLine(pts[1] - v, pts[0] + v, paint);
}
canvas->save();
canvas->concat(matrices[m]);
canvas->experimental_DrawImageSetV0(set, kM * kN, 1.f, fm, SkBlendMode::kSrcOver);
canvas->restore();
}
// A more exotic case with an unusual blend mode, all aa flags set, and alpha, and
// subsets the image
SkCanvas::ImageSetEntry entry;
entry.fSrcRect = SkRect::MakeWH(kTileW, kTileH).makeInset(kTileW / 4.f, kTileH / 4.f);
entry.fDstRect = SkRect::MakeWH(2 * kTileW, 2 * kTileH).makeOffset(d / 4, 2 * d);
entry.fImage = fImage[0][0];
entry.fAAFlags = SkCanvas::kAll_QuadAAFlags;
canvas->save();
canvas->rotate(3.f);
canvas->experimental_DrawImageSetV0(&entry, 1, 0.7f, fm, SkBlendMode::kLuminosity);
canvas->restore();
canvas->translate(2 * d, 0);
}
}
static constexpr int kM = 4;
static constexpr int kN = 4;
static constexpr SkScalar kTileW = 50;
static constexpr SkScalar kTileH = 50;
sk_sp<SkImage> fImage[kM][kN];
};
DEF_GM(return new DrawImageSetGM();)
} // namespace skiagm

View File

@ -10,7 +10,6 @@ gm_sources = [
"$_gm/3dgm.cpp",
"$_gm/aaa.cpp",
"$_gm/aaclip.cpp",
"$_gm/aaflags.cpp",
"$_gm/aarectmodes.cpp",
"$_gm/aaxfermodes.cpp",
"$_gm/addarc.cpp",
@ -120,6 +119,7 @@ gm_sources = [
"$_gm/drawatlascolor.cpp",
"$_gm/drawbitmaprect.cpp",
"$_gm/drawlooper.cpp",
"$_gm/drawimageset.cpp",
"$_gm/drawminibitmaprect.cpp",
"$_gm/drawregion.cpp",
"$_gm/drawregionmodes.cpp",

View File

@ -1820,6 +1820,37 @@ public:
void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
const SkPaint* paint = nullptr);
/**
* Controls anti-aliasing of each edge of images in an image-set.
*/
enum QuadAAFlags : unsigned {
kLeft_QuadAAFlag = 0b0001,
kTop_QuadAAFlag = 0b0010,
kRight_QuadAAFlag = 0b0100,
kBottom_QuadAAFlag = 0b1000,
kNone_QuadAAFlags = 0b0000,
kAll_QuadAAFlags = 0b1111,
};
/** This is used by the experimental API below. */
struct ImageSetEntry {
sk_sp<const SkImage> fImage;
SkRect fSrcRect;
SkRect fDstRect;
unsigned fAAFlags; // QuadAAFlags
};
/**
* This is an experimental API for the SkiaRenderer Chromium project. The signature will
* surely evolve if this is not removed. It currently offers no performance advantage over
* drawing images independently, though may in the future. The antialiasing flags are intended
* to allow control over each edge's AA status, to allow perfect seaming for tile sets. The
* current implementation only antialiases if all edges are flagged, however.
*/
void experimental_DrawImageSetV0(const ImageSetEntry* imageSet, int cnt, float alpha,
SkFilterQuality, SkBlendMode);
/** Draws text, with origin at (x, y), using clip, SkMatrix, and SkPaint paint.
text meaning depends on SkPaint::TextEncoding; by default, text is encoded as
@ -2446,6 +2477,9 @@ protected:
virtual void onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
const SkPaint* paint);
virtual void onDrawImageSet(const ImageSetEntry imageSet[], int count, float alpha,
SkFilterQuality, SkBlendMode);
virtual void onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy,
const SkPaint* paint);
virtual void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,

View File

@ -58,6 +58,16 @@ protected:
void onDrawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice,
const SkRect& dst, const SkPaint* paint) override = 0;
#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
// This is under active development for Chrome and not used in Android. Hold off on adding
// implementations in Android's SkCanvas subclasses until this stabilizes.
void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override {};
#else
void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override = 0;
#endif
void onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy,
const SkPaint* paint) override = 0;
void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,

View File

@ -47,6 +47,8 @@ public:
SrcRectConstraint) override;
void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override;
void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override;
void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
SrcRectConstraint) override;

View File

@ -11,6 +11,7 @@
#include <chrono>
#include "GrSharedEnums.h"
#include "GrTypes.h"
#include "SkCanvas.h"
#include "SkImageInfo.h"
#include "SkImageInfoPriv.h"
#include "SkRefCnt.h"
@ -287,30 +288,24 @@ enum class GrAllowMixedSamples : bool { kNo = false, kYes = true };
GrAAType GrChooseAAType(GrAA, GrFSAAType, GrAllowMixedSamples, const GrCaps&);
/**
* Controls anti-aliasing of a quad on a per-edge basis. Currently only used by GrTextureOp.
* This will be moved to public API and renamed when this functionality is exposed.
*/
enum class GrQuadAAFlags : unsigned {
kLeft = 0b0001,
kTop = 0b0010,
kRight = 0b0100,
kBottom = 0b1000,
enum class GrQuadAAFlags {
kLeft = SkCanvas::kLeft_QuadAAFlag,
kTop = SkCanvas::kTop_QuadAAFlag,
kRight = SkCanvas::kRight_QuadAAFlag,
kBottom = SkCanvas::kBottom_QuadAAFlag,
kNone = 0b0000,
kAll = 0b1111,
kTopLeft = kTop | kLeft,
kTopRight = kTop | kRight,
kBottomRight = kBottom | kRight,
kBottomLeft = kBottom | kLeft,
kNone = SkCanvas::kNone_QuadAAFlags,
kAll = SkCanvas::kAll_QuadAAFlags
};
GR_MAKE_BITFIELD_CLASS_OPS(GrQuadAAFlags)
static inline GrQuadAAFlags SkToGrQuadAAFlags(unsigned flags) {
return static_cast<GrQuadAAFlags>(flags);
}
/**
* Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars,
* but should be applicable to other shader languages.)
* Types of shader-language-specific boxed variables we can create.
*/
enum GrSLType {
kVoid_GrSLType,

View File

@ -63,10 +63,11 @@ protected:
const SkPaint*, SrcRectConstraint) override;
void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&,
const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&,
const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override;
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,

View File

@ -71,6 +71,8 @@ protected:
const SkPaint*) override {}
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&,
const SkPaint*) override {}
void onDrawImageSet(const SkCanvas::ImageSetEntry[], int, float, SkFilterQuality,
SkBlendMode) override {}
void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&,
const SkPaint*) override {}
void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode,

View File

@ -88,6 +88,8 @@ protected:
const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&,
const SkPaint*) override;
void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
SkBlendMode, const SkPaint&) override;
void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],

View File

@ -1796,6 +1796,15 @@ void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, co
}
}
void SkCanvas::experimental_DrawImageSetV0(const ImageSetEntry* imageSet, int cnt, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
TRACE_EVENT0("skia", TRACE_FUNC);
RETURN_ON_NULL(imageSet);
RETURN_ON_FALSE(cnt);
this->onDrawImageSet(imageSet, cnt, alpha, filterQuality, mode);
}
void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) {
TRACE_EVENT0("skia", TRACE_FUNC);
if (bitmap.drawsNothing()) {
@ -2397,6 +2406,16 @@ void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
LOOPER_END
}
void SkCanvas::onDrawImageSet(const ImageSetEntry imageSet[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
SkPaint paint;
LOOPER_BEGIN(paint, nullptr);
while (iter.next()) {
iter.fDevice->drawImageSet(imageSet, count, alpha, filterQuality, mode);
}
LOOPER_END
}
void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
const SkRect& dst, const SkPaint* paint) {
SkPaint realPaint;

View File

@ -171,6 +171,18 @@ public:
dst, MaybePaint(paint, fXformer.get()));
}
}
void onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) override {
SkAutoTArray<ImageSetEntry> xformedSet(count);
for (int i = 0; i < count; ++i) {
xformedSet[i].fImage = this->prepareImage(set[i].fImage.get());
xformedSet[i].fSrcRect = set[i].fSrcRect;
xformedSet[i].fDstRect = set[i].fDstRect;
xformedSet[i].fAAFlags = set[i].fAAFlags;
}
fTarget->experimental_DrawImageSetV0(xformedSet.get(), count, alpha, filterQuality, mode);
}
void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex,
const SkColor* colors, int count, SkBlendMode mode,
const SkRect* cull, const SkPaint* paint) override {

View File

@ -202,6 +202,22 @@ void SkBaseDevice::drawImageLattice(const SkImage* image,
}
}
void SkBaseDevice::drawImageSet(const SkCanvas::ImageSetEntry images[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
SkPaint paint;
paint.setFilterQuality(SkTPin(filterQuality, kNone_SkFilterQuality, kLow_SkFilterQuality));
paint.setAlpha(SkToUInt(SkTClamp(SkScalarRoundToInt(alpha * 255), 0, 255)));
paint.setBlendMode(mode);
for (int i = 0; i < count; ++i) {
// TODO: Handle per-edge AA. Right now this mirrors the SkiaRenderer component of Chrome
// which turns off antialiasing unless all four edges should be antialiased. This avoids
// seaming in tiled composited layers.
paint.setAntiAlias(images[i].fAAFlags == SkCanvas::kAll_QuadAAFlags);
this->drawImageRect(images[i].fImage.get(), &images[i].fSrcRect, images[i].fDstRect, paint,
SkCanvas::kFast_SrcRectConstraint);
}
}
void SkBaseDevice::drawBitmapLattice(const SkBitmap& bitmap,
const SkCanvas::Lattice& lattice, const SkRect& dst,
const SkPaint& paint) {

View File

@ -212,6 +212,8 @@ protected:
virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&,
const SkRect& dst, const SkPaint&);
virtual void drawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha,
SkFilterQuality, SkBlendMode);
virtual void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
SkBlendMode, const SkPaint&) = 0;

View File

@ -5,16 +5,17 @@
* found in the LICENSE file.
*/
#include "SkLiteDL.h"
#include <algorithm>
#include "SkCanvas.h"
#include "SkData.h"
#include "SkDrawShadowInfo.h"
#include "SkImage.h"
#include "SkImageFilter.h"
#include "SkLiteDL.h"
#include "SkMath.h"
#include "SkPicture.h"
#include "SkRegion.h"
#include "SkRSXform.h"
#include "SkRegion.h"
#include "SkTextBlob.h"
#include "SkVertices.h"
@ -46,15 +47,15 @@ static const D* pod(const T* op, size_t offset = 0) {
}
namespace {
#define TYPES(M) \
M(Flush) M(Save) M(Restore) M(SaveLayer) \
M(Concat) M(SetMatrix) M(Translate) \
M(ClipPath) M(ClipRect) M(ClipRRect) M(ClipRegion) \
M(DrawPaint) M(DrawPath) M(DrawRect) M(DrawRegion) M(DrawOval) M(DrawArc) \
M(DrawRRect) M(DrawDRRect) M(DrawAnnotation) M(DrawDrawable) M(DrawPicture) \
M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice) \
M(DrawText) M(DrawPosText) M(DrawPosTextH) \
M(DrawTextRSXform) M(DrawTextBlob) \
#define TYPES(M) \
M(Flush) M(Save) M(Restore) M(SaveLayer) \
M(Concat) M(SetMatrix) M(Translate) \
M(ClipPath) M(ClipRect) M(ClipRRect) M(ClipRegion) \
M(DrawPaint) M(DrawPath) M(DrawRect) M(DrawRegion) M(DrawOval) M(DrawArc) \
M(DrawRRect) M(DrawDRRect) M(DrawAnnotation) M(DrawDrawable) M(DrawPicture) \
M(DrawImage) M(DrawImageNine) M(DrawImageRect) M(DrawImageLattice) M(DrawImageSet) \
M(DrawText) M(DrawPosText) M(DrawPosTextH) \
M(DrawTextRSXform) M(DrawTextBlob) \
M(DrawPatch) M(DrawPoints) M(DrawVertices) M(DrawAtlas) M(DrawShadowRec)
#define M(T) T,
@ -325,7 +326,22 @@ namespace {
&paint);
}
};
struct DrawImageSet final : Op {
static const auto kType = Type::DrawImageSet;
DrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
SkFilterQuality quality, SkBlendMode xfermode)
: count(count), alpha(alpha), quality(quality), xfermode(xfermode), set(count) {
std::copy_n(set, count, this->set.get());
}
int count;
float alpha;
SkFilterQuality quality;
SkBlendMode xfermode;
SkAutoTArray<SkCanvas::ImageSetEntry> set;
void draw(SkCanvas* c, const SkMatrix&) const {
c->experimental_DrawImageSetV0(set.get(), count, alpha, quality, xfermode);
}
};
struct DrawText final : Op {
static const auto kType = Type::DrawText;
DrawText(size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint)
@ -604,6 +620,11 @@ void SkLiteDL::drawImageLattice(sk_sp<const SkImage> image, const SkCanvas::Latt
lattice.fRectTypes, fs);
}
void SkLiteDL::drawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
this->push<DrawImageSet>(0, set, count, alpha, filterQuality, mode);
}
void SkLiteDL::drawText(const void* text, size_t bytes,
SkScalar x, SkScalar y, const SkPaint& paint) {
void* pod = this->push<DrawText>(bytes, bytes, x, y, paint);

View File

@ -67,6 +67,8 @@ public:
SkCanvas::SrcRectConstraint);
void drawImageLattice(sk_sp<const SkImage>, const SkCanvas::Lattice&,
const SkRect&, const SkPaint*);
void drawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode);
void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4],
SkBlendMode, const SkPaint&);

View File

@ -159,6 +159,10 @@ void SkLiteRecorder::onDrawImageLattice(const SkImage* img,
fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, paint);
}
void SkLiteRecorder::onDrawImageSet(const ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
fDL->drawImageSet(set, count, alpha, filterQuality, mode);
}
void SkLiteRecorder::onDrawPatch(const SkPoint cubics[12],
const SkColor colors[4], const SkPoint texCoords[4],

View File

@ -67,6 +67,8 @@ public:
void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override;
void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
SrcRectConstraint) override;
void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawPatch(const SkPoint[12], const SkColor[4],
const SkPoint[4], SkBlendMode, const SkPaint&) override;

View File

@ -272,6 +272,13 @@ void SkOverdrawCanvas::onDrawImageLattice(const SkImage* image, const Lattice& l
}
}
void SkOverdrawCanvas::onDrawImageSet(const ImageSetEntry set[], int count, float alpha,
SkFilterQuality, SkBlendMode) {
for (int i = 0; i < count; ++i) {
fList[0]->onDrawRect(set[i].fDstRect, fPaint);
}
}
void SkOverdrawCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
const SkPaint*) {
fList[0]->onDrawRect(SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()), fPaint);

View File

@ -97,7 +97,8 @@ enum DrawType {
FLUSH,
LAST_DRAWTYPE_ENUM = FLUSH
DRAW_IMAGE_SET,
LAST_DRAWTYPE_ENUM = DRAW_IMAGE_SET
};
enum DrawVertexFlags {

View File

@ -355,6 +355,22 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader,
canvas->legacy_drawImageRect(image, src, dst, paint, constraint);
} break;
case DRAW_IMAGE_SET: {
int cnt = reader->readInt();
float alpha = SkScalarToFloat(reader->readScalar());
SkFilterQuality filterQuality = (SkFilterQuality)reader->readUInt();
SkBlendMode mode = (SkBlendMode)reader->readUInt();
SkAutoTArray<SkCanvas::ImageSetEntry> set(cnt);
for (int i = 0; i < cnt; ++i) {
set[i].fImage = sk_ref_sp(fPictureData->getImage(reader));
reader->readRect(&set[i].fSrcRect);
reader->readRect(&set[i].fDstRect);
set[i].fAAFlags = reader->readUInt();
}
BREAK_ON_READ_ERROR(reader);
canvas->experimental_DrawImageSetV0(set.get(), cnt, alpha, filterQuality, mode);
} break;
case DRAW_OVAL: {
const SkPaint* paint = fPictureData->getPaint(reader);
SkRect rect;

View File

@ -543,6 +543,25 @@ void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& la
this->validate(initialOffset, size);
}
void SkPictureRecord::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
// op + count + alpha + fq + mode + (image index, src rect, dst rect, aa flags) * cnt
size_t size =
4 * kUInt32Size + sizeof(SkScalar) + (2 * kUInt32Size + 2 * sizeof(SkRect)) * count;
size_t initialOffset = this->addDraw(DRAW_IMAGE_SET, &size);
this->addInt(count);
this->addScalar(SkFloatToScalar(alpha));
this->addInt((int)filterQuality);
this->addInt((int)mode);
for (int i = 0; i < count; ++i) {
this->addImage(set[i].fImage.get());
this->addRect(set[i].fSrcRect);
this->addRect(set[i].fDstRect);
this->addInt((int)set[i].fAAFlags);
}
this->validate(initialOffset, size);
}
void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
const SkPaint& paint) {
// op + paint index + length + 'length' worth of chars + x + y

View File

@ -193,6 +193,8 @@ protected:
const SkPaint*) override;
void onDrawImageLattice(const SkImage*, const SkCanvas::Lattice& lattice, const SkRect& dst,
const SkPaint*) override;
void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
SkBlendMode, const SkPaint&) override;

View File

@ -109,6 +109,7 @@ template <> void Draw::draw(const DrawImageLattice& r) {
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(DrawImageSet, experimental_DrawImageSetV0(r.set.get(), r.count, r.alpha, r.quality, r.mode));
DRAW(DrawOval, drawOval(r.oval, r.paint));
DRAW(DrawPaint, drawPaint(r.paint));
DRAW(DrawPath, drawPath(r.path, r.paint));
@ -383,6 +384,13 @@ private:
Bounds bounds(const DrawImageNine& op) const {
return this->adjustAndMap(op.dst, op.paint);
}
Bounds bounds(const DrawImageSet& op) const {
SkRect rect = SkRect::MakeEmpty();
for (int i = 0; i < op.count; ++i) {
rect.join(this->adjustAndMap(op.set[i].fDstRect, nullptr));
}
return rect;
}
Bounds bounds(const DrawPath& op) const {
return op.path.isInverseFillType() ? fCullRect
: this->adjustAndMap(op.path.getBounds(), &op.paint);

View File

@ -253,6 +253,15 @@ void SkRecorder::onDrawImageLattice(const SkImage* image, const Lattice& lattice
this->copy(lattice.fColors, flagCount), *lattice.fBounds, dst);
}
void SkRecorder::onDrawImageSet(const ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
SkAutoTArray<ImageSetEntry> setCopy(count);
for (int i = 0; i < count; ++i) {
setCopy[i] = set[i];
}
this->append<SkRecords::DrawImageSet>(std::move(setCopy), count, alpha, filterQuality, mode);
}
void SkRecorder::onDrawText(const void* text, size_t byteLength,
SkScalar x, SkScalar y, const SkPaint& paint) {
this->append<SkRecords::DrawText>(

View File

@ -116,6 +116,8 @@ public:
const SkPaint*) override;
void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst,
const SkPaint*) override;
void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
SkBlendMode, const SkPaint&) override;
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],

View File

@ -64,6 +64,7 @@ namespace SkRecords {
M(DrawImageLattice) \
M(DrawImageRect) \
M(DrawImageNine) \
M(DrawImageSet) \
M(DrawDRRect) \
M(DrawOval) \
M(DrawPaint) \
@ -265,6 +266,12 @@ RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
sk_sp<const SkImage> image;
SkIRect center;
SkRect dst);
RECORD(DrawImageSet, kDraw_Tag|kHasImage_Tag,
SkAutoTArray<SkCanvas::ImageSetEntry> set;
int count;
float alpha;
SkFilterQuality quality;
SkBlendMode mode);
RECORD(DrawOval, kDraw_Tag|kHasPaint_Tag,
SkPaint paint;
SkRect oval);

View File

@ -798,6 +798,21 @@ void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy
this->addDrawOp(clip, std::move(op));
}
void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
GrSamplerState::Filter filter, GrColor color,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform,
sk_sp<GrColorSpaceXform> colorXform) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
GrAAType aaType = this->chooseAAType(GrAA::kYes, GrAllowMixedSamples::kNo);
auto op = GrTextureOp::Make(fContext, set, cnt, filter, color, aaType, viewMatrix,
std::move(texXform), std::move(colorXform));
this->addDrawOp(clip, std::move(op));
}
void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
GrPaint&& paint,
GrAA aa,

View File

@ -139,6 +139,21 @@ public:
SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform, sk_sp<GrColorSpaceXform> colorXform);
/** Used with drawTextureSet */
struct TextureSetEntry {
sk_sp<GrTextureProxy> fProxy;
SkRect fSrcRect;
SkRect fDstRect;
GrQuadAAFlags fAAFlags;
};
/**
* Draws a set of textures with a shared filter, color, view matrix, color xform, and
* texture color xform. The textures must all have the same GrTextureType and GrConfig.
*/
void drawTextureSet(const GrClip&, const TextureSetEntry[], int cnt, GrSamplerState::Filter,
GrColor, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> texXform,
sk_sp<GrColorSpaceXform> colorXform);
/**
* Draw a roundrect using a paint.
*

View File

@ -1446,6 +1446,61 @@ void SkGpuDevice::drawBitmapLattice(const SkBitmap& bitmap,
this->drawProducerLattice(&maker, std::move(iter), dst, paint);
}
void SkGpuDevice::drawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
SkASSERT(count > 0);
if (mode != SkBlendMode::kSrcOver) {
INHERITED::drawImageSet(set, count, alpha, filterQuality, mode);
return;
}
GrSamplerState sampler;
sampler.setFilterMode(kNone_SkFilterQuality == filterQuality ? GrSamplerState::Filter::kNearest
: GrSamplerState::Filter::kBilerp);
SkAutoTArray<GrRenderTargetContext::TextureSetEntry> textures(count);
GrColor color = GrColorPackA4(SkToUInt(SkTClamp(SkScalarRoundToInt(alpha * 255), 0, 255)));
// We accumulate compatible proxies until we find an an incompatible one or reach the end and
// issue the accumulated 'n' draws starting at 'base'.
int base = 0, n = 0;
auto draw = [&] {
if (n > 0) {
auto textureXform = GrColorSpaceXform::Make(
set[base].fImage->colorSpace(), set[base].fImage->alphaType(),
fRenderTargetContext->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType);
fRenderTargetContext->drawTextureSet(this->clip(), textures.get() + base, n,
sampler.filter(), color, this->ctm(),
std::move(textureXform), nullptr);
}
};
for (int i = 0; i < count; ++i) {
textures[i].fProxy =
as_IB(set[i].fImage.get())
->asTextureProxyRef(fContext.get(), GrSamplerState::ClampBilerp(), nullptr,
nullptr, nullptr);
textures[i].fSrcRect = set[i].fSrcRect;
textures[i].fDstRect = set[i].fDstRect;
textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags);
// If we failed to make a proxy or our proxy can't be grouped with the previous proxies then
// draw the accumulated set and reset.
if (!textures[i].fProxy) {
draw();
base = i + 1;
n = 0;
} else if (n > 0 &&
(textures[i].fProxy->textureType() != textures[base].fProxy->textureType() ||
textures[i].fProxy->config() != textures[base].fProxy->config() ||
set[i].fImage->alphaType() != set[base].fImage->alphaType() ||
!SkColorSpace::Equals(set[i].fImage->colorSpace(),
set[base].fImage->colorSpace()))) {
draw();
base = i;
n = 1;
} else {
++n;
}
}
draw();
}
static bool init_vertices_paint(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo,
const SkPaint& skPaint, const SkMatrix& matrix, SkBlendMode bmode,
bool hasTexs, bool hasColors, GrPaint* grPaint) {

View File

@ -105,6 +105,8 @@ public:
const SkRect& dst, const SkPaint&) override;
void drawBitmapLattice(const SkBitmap&, const SkCanvas::Lattice&,
const SkRect& dst, const SkPaint&) override;
void drawImageSet(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void drawSpecial(SkSpecialImage*, int left, int top, const SkPaint& paint,
SkImage*, const SkMatrix&) override;

View File

@ -6,7 +6,7 @@
*/
#include "GrTextureOp.h"
#include <new>
#include "GrAppliedClip.h"
#include "GrCaps.h"
#include "GrContext.h"
@ -27,13 +27,13 @@
#include "SkMatrixPriv.h"
#include "SkPoint.h"
#include "SkPoint3.h"
#include "SkRectPriv.h"
#include "SkTo.h"
#include "glsl/GrGLSLColorSpaceXformHelper.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLVarying.h"
#include "glsl/GrGLSLVertexGeoBuilder.h"
#include <new>
namespace {
@ -271,8 +271,6 @@ private:
// output.
static void compute_quad_edges_and_outset_vertices(GrQuadAAFlags aaFlags, Sk4f* x, Sk4f* y, Sk4f* a,
Sk4f* b, Sk4f* c, bool outsetCorners) {
SkASSERT(GrQuadAAFlags::kNone != aaFlags);
static constexpr auto fma = SkNx_fma<4, float>;
// These rotate the points/edge values either clockwise or counterclockwise assuming tri strip
// order.
@ -594,34 +592,56 @@ public:
std::move(proxy), filter, color, srcRect, dstRect, aaType, aaFlags, constraint,
viewMatrix, std::move(textureColorSpaceXform), std::move(paintColorSpaceXform));
}
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
const GrRenderTargetContext::TextureSetEntry set[],
int cnt, GrSamplerState::Filter filter, GrColor color,
GrAAType aaType, const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
sk_sp<GrColorSpaceXform> paintColorSpaceXform) {
size_t size = sizeof(TextureOp) + sizeof(Proxy) * (cnt - 1);
GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
void* mem = pool->allocate(size);
return std::unique_ptr<GrDrawOp>(new (mem) TextureOp(
set, cnt, filter, color, aaType, viewMatrix, std::move(textureColorSpaceXform),
std::move(paintColorSpaceXform)));
}
~TextureOp() override {
if (fFinalized) {
fProxy->completedRead();
} else {
fProxy->unref();
for (unsigned p = 0; p < fProxyCnt; ++p) {
if (fFinalized) {
fProxies[p].fProxy->completedRead();
} else {
fProxies[p].fProxy->unref();
}
}
}
const char* name() const override { return "TextureOp"; }
void visitProxies(const VisitProxyFunc& func) const override { func(fProxy); }
void visitProxies(const VisitProxyFunc& func) const override {
for (unsigned p = 0; p < fProxyCnt; ++p) {
func(fProxies[p].fProxy);
}
}
SkString dumpInfo() const override {
SkString str;
str.appendf("# draws: %d\n", fDraws.count());
str.appendf("Proxy ID: %d, Filter: %d\n", fProxy->uniqueID().asUInt(),
static_cast<int>(fFilter));
for (int i = 0; i < fDraws.count(); ++i) {
const Draw& draw = fDraws[i];
str.appendf(
"%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
"Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
i, draw.color(), draw.srcRect().fLeft, draw.srcRect().fTop,
draw.srcRect().fRight, draw.srcRect().fBottom, draw.quad().point(0).fX,
draw.quad().point(0).fY, draw.quad().point(1).fX, draw.quad().point(1).fY,
draw.quad().point(2).fX, draw.quad().point(2).fY, draw.quad().point(3).fX,
draw.quad().point(3).fY);
str.appendf("# draws: %d\n", fQuads.count());
int q = 0;
for (unsigned p = 0; p < fProxyCnt; ++p) {
str.appendf("Proxy ID: %d, Filter: %d\n", fProxies[p].fProxy->uniqueID().asUInt(),
static_cast<int>(fFilter));
for (int i = 0; i < fProxies[p].fQuadCnt; ++i, ++q) {
const Quad& quad = fQuads[q];
str.appendf(
"%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
"Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
i, quad.color(), quad.srcRect().fLeft, quad.srcRect().fTop,
quad.srcRect().fRight, quad.srcRect().fBottom, quad.quad().point(0).fX,
quad.quad().point(0).fY, quad.quad().point(1).fX, quad.quad().point(1).fY,
quad.quad().point(2).fX, quad.quad().point(2).fY, quad.quad().point(3).fX,
quad.quad().point(3).fY);
}
}
str += INHERITED::dumpInfo();
return str;
@ -630,8 +650,10 @@ public:
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
SkASSERT(!fFinalized);
fFinalized = true;
fProxy->addPendingRead();
fProxy->unref();
for (unsigned p = 0; p < fProxyCnt; ++p) {
fProxies[p].fProxy->addPendingRead();
fProxies[p].fProxy->unref();
}
return RequiresDstTexture::kNo;
}
@ -653,7 +675,6 @@ private:
: INHERITED(ClassID())
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fPaintColorSpaceXform(std::move(paintColorSpaceXform))
, fProxy(proxy.release())
, fFilter(filter)
, fAAType(static_cast<unsigned>(aaType))
, fFinalized(0) {
@ -673,11 +694,11 @@ private:
SK_ABORT("Should not use mixed sample AA");
break;
}
fPerspective = viewMatrix.hasPerspective();
fPerspective = static_cast<unsigned>(viewMatrix.hasPerspective());
auto quad = GrPerspQuad(dstRect, viewMatrix);
auto bounds = quad.bounds();
// We expect our caller to have already caught this optimization.
SkASSERT(!srcRect.contains(fProxy->getWorstCaseBoundsRect()) ||
SkASSERT(!srcRect.contains(proxy->getWorstCaseBoundsRect()) ||
constraint == SkCanvas::kFast_SrcRectConstraint);
if (viewMatrix.rectStaysRect()) {
// Disable filtering when there is no scaling or fractional translation.
@ -707,48 +728,107 @@ private:
this->aaType() != GrAAType::kCoverage) {
constraint = SkCanvas::kFast_SrcRectConstraint;
}
const auto& draw = fDraws.emplace_back(srcRect, quad, aaFlags, constraint, color);
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
fDomain = static_cast<bool>(draw.domain());
const auto& draw = fQuads.emplace_back(srcRect, quad, aaFlags, constraint, color);
fProxyCnt = 1;
fProxies[0] = {proxy.release(), 1};
this->setBounds(bounds, HasAABloat(this->aaType() == GrAAType::kCoverage), IsZeroArea::kNo);
fDomain = static_cast<unsigned>(draw.domain());
}
TextureOp(const GrRenderTargetContext::TextureSetEntry set[], int cnt,
GrSamplerState::Filter filter, GrColor color, GrAAType aaType,
const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> textureColorSpaceXform,
sk_sp<GrColorSpaceXform> paintColorSpaceXform)
: INHERITED(ClassID())
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fPaintColorSpaceXform(std::move(paintColorSpaceXform))
, fFilter(filter)
, fAAType(static_cast<unsigned>(aaType))
, fFinalized(0) {
fQuads.reserve(cnt);
fProxyCnt = SkToUInt(cnt);
SkRect bounds = SkRectPriv::MakeLargestInverted();
bool aa = false;
for (unsigned p = 0; p < fProxyCnt; ++p) {
fProxies[p].fProxy = SkRef(set[p].fProxy.get());
fProxies[p].fQuadCnt = 1;
SkASSERT(fProxies[p].fProxy->textureType() == fProxies[0].fProxy->textureType());
SkASSERT(fProxies[p].fProxy->config() == fProxies[0].fProxy->config());
auto quad = GrPerspQuad(set[p].fDstRect, viewMatrix);
bounds.joinPossiblyEmptyRect(quad.bounds());
GrQuadAAFlags aaFlags = set[p].fAAFlags;
switch (aaType) {
case GrAAType::kNone:
aaFlags = GrQuadAAFlags::kNone;
break;
case GrAAType::kCoverage:
break;
case GrAAType::kMSAA:
aaFlags = GrQuadAAFlags::kAll;
break;
case GrAAType::kMixedSamples:
SK_ABORT("Should not use mixed sample AA");
break;
}
aa = aa || (set[p].fAAFlags != GrQuadAAFlags::kNone);
fQuads.emplace_back(set[p].fSrcRect, quad, aaFlags, SkCanvas::kFast_SrcRectConstraint,
color);
}
if (!aa) {
fAAType = static_cast<unsigned>(GrAAType::kNone);
}
this->setBounds(bounds, HasAABloat(this->aaType() == GrAAType::kCoverage), IsZeroArea::kNo);
fPerspective = static_cast<unsigned>(viewMatrix.hasPerspective());
fDomain = static_cast<unsigned>(false);
}
template <typename Pos, Domain D, GrAA AA>
void tess(void* v, const GrGeometryProcessor* gp) const {
void tess(void* v, const GrGeometryProcessor* gp, const GrTextureProxy* proxy, int start,
int cnt) const {
TRACE_EVENT0("skia", TRACE_FUNC);
using Vertex = TextureGeometryProcessor::Vertex<Pos, D, AA>;
SkASSERT(gp->debugOnly_vertexStride() == sizeof(Vertex));
auto vertices = static_cast<Vertex*>(v);
auto origin = fProxy->origin();
const auto* texture = fProxy->peekTexture();
auto origin = proxy->origin();
const auto* texture = proxy->peekTexture();
float iw = 1.f / texture->width();
float ih = 1.f / texture->height();
for (const auto& draw : fDraws) {
tessellate_quad<Vertex>(draw.quad(), draw.aaFlags(), draw.srcRect(), draw.color(),
origin, fFilter, vertices, iw, ih, draw.domain());
for (int i = start; i < start + cnt; ++i) {
const auto q = fQuads[i];
tessellate_quad<Vertex>(q.quad(), q.aaFlags(), q.srcRect(), q.color(), origin, fFilter,
vertices, iw, ih, q.domain());
vertices += 4;
}
}
void onPrepareDraws(Target* target) override {
TRACE_EVENT0("skia", TRACE_FUNC);
bool hasPerspective = false;
Domain domain = Domain::kNo;
int numOps = 0;
int numProxies = 0;
auto textureType = fProxies[0].fProxy->textureType();
auto config = fProxies[0].fProxy->config();
for (const auto& op : ChainRange<TextureOp>(this)) {
++numOps;
hasPerspective |= op.fPerspective;
if (op.fDomain) {
domain = Domain::kYes;
}
if (!op.fProxy->instantiate(target->resourceProvider())) {
return;
numProxies += op.fProxyCnt;
for (unsigned p = 0; p < op.fProxyCnt; ++p) {
auto* proxy = op.fProxies[p].fProxy;
if (!proxy->instantiate(target->resourceProvider())) {
return;
}
SkASSERT(proxy->config() == config);
SkASSERT(proxy->textureType() == textureType);
}
}
bool coverageAA = GrAAType::kCoverage == this->aaType();
sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
fProxy->textureType(), fProxy->config(), fFilter,
std::move(fTextureColorSpaceXform), std::move(fPaintColorSpaceXform), coverageAA,
hasPerspective, domain, *target->caps().shaderCaps());
textureType, config, fFilter, std::move(fTextureColorSpaceXform),
std::move(fPaintColorSpaceXform), coverageAA, hasPerspective, domain,
*target->caps().shaderCaps());
GrPipeline::InitArgs args;
args.fProxy = target->proxy();
args.fCaps = &target->caps();
@ -763,12 +843,12 @@ private:
// Otherwise, we use fixed dynamic state to specify the single op's proxy.
GrPipeline::DynamicStateArrays* dynamicStateArrays = nullptr;
GrPipeline::FixedDynamicState* fixedDynamicState;
if (numOps > 1) {
dynamicStateArrays = target->allocDynamicStateArrays(numOps, 1, false);
if (numProxies > 1) {
dynamicStateArrays = target->allocDynamicStateArrays(numProxies, 1, false);
fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 0);
} else {
fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 1);
fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxy;
fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxies[0].fProxy;
}
const auto* pipeline =
target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip));
@ -799,44 +879,53 @@ private:
SkASSERT(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize == gp->debugOnly_vertexStride());
GrMesh* meshes = target->allocMeshes(numOps);
int i = 0;
GrMesh* meshes = target->allocMeshes(numProxies);
int m = 0;
for (const auto& op : ChainRange<TextureOp>(this)) {
int vstart;
const GrBuffer* vbuffer;
void* vdata = target->makeVertexSpace(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize,
4 * op.fDraws.count(), &vbuffer, &vstart);
if (!vdata) {
SkDebugf("Could not allocate vertices\n");
return;
}
(op.*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get());
if (op.fDraws.count() > 1) {
meshes[i].setPrimitiveType(GrPrimitiveType::kTriangles);
sk_sp<const GrBuffer> ibuffer = target->resourceProvider()->refQuadIndexBuffer();
if (!ibuffer) {
SkDebugf("Could not allocate quad indices\n");
int q = 0;
for (unsigned p = 0; p < op.fProxyCnt; ++p) {
int quadCnt = op.fProxies[p].fQuadCnt;
auto* proxy = op.fProxies[p].fProxy;
int vstart;
const GrBuffer* vbuffer;
void* vdata = target->makeVertexSpace(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize,
4 * quadCnt, &vbuffer, &vstart);
if (!vdata) {
SkDebugf("Could not allocate vertices\n");
return;
}
meshes[i].setIndexedPatterned(ibuffer.get(), 6, 4, op.fDraws.count(),
GrResourceProvider::QuadCountOfQuadBuffer());
} else {
meshes[i].setPrimitiveType(GrPrimitiveType::kTriangleStrip);
meshes[i].setNonIndexedNonInstanced(4);
(op.*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get(), proxy, q,
quadCnt);
if (quadCnt > 1) {
meshes[m].setPrimitiveType(GrPrimitiveType::kTriangles);
sk_sp<const GrBuffer> ibuffer =
target->resourceProvider()->refQuadIndexBuffer();
if (!ibuffer) {
SkDebugf("Could not allocate quad indices\n");
return;
}
meshes[m].setIndexedPatterned(ibuffer.get(), 6, 4, quadCnt,
GrResourceProvider::QuadCountOfQuadBuffer());
} else {
meshes[m].setPrimitiveType(GrPrimitiveType::kTriangleStrip);
meshes[m].setNonIndexedNonInstanced(4);
}
meshes[m].setVertexData(vbuffer, vstart);
if (dynamicStateArrays) {
dynamicStateArrays->fPrimitiveProcessorTextures[m] = proxy;
}
++m;
q += quadCnt;
}
meshes[i].setVertexData(vbuffer, vstart);
if (dynamicStateArrays) {
dynamicStateArrays->fPrimitiveProcessorTextures[i] = op.fProxy;
}
++i;
}
target->draw(std::move(gp), pipeline, fixedDynamicState, dynamicStateArrays, meshes,
numOps);
numProxies);
}
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
TRACE_EVENT0("skia", TRACE_FUNC);
const auto* that = t->cast<TextureOp>();
if (!GrColorSpaceXform::Equals(fTextureColorSpaceXform.get(),
that->fTextureColorSpaceXform.get())) {
@ -854,17 +943,21 @@ private:
if (fFilter != that->fFilter) {
return CombineResult::kCannotCombine;
}
if (fProxy->uniqueID() != that->fProxy->uniqueID() || that->isChained()) {
auto thisProxy = fProxies[0].fProxy;
auto thatProxy = that->fProxies[0].fProxy;
if (fProxyCnt > 1 || that->fProxyCnt > 1 ||
thisProxy->uniqueID() != thatProxy->uniqueID() || that->isChained()) {
// We can't merge across different proxies (and we're disallowed from merging when
// 'that' is chained. Check if we can be chained with 'that'.
if (fProxy->config() == that->fProxy->config() &&
fProxy->textureType() == that->fProxy->textureType() &&
if (thisProxy->config() == thatProxy->config() &&
thisProxy->textureType() == thatProxy->textureType() &&
caps.dynamicStateArrayGeometryProcessorTextureSupport()) {
return CombineResult::kMayChain;
}
return CombineResult::kCannotCombine;
}
fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
fProxies[0].fQuadCnt += that->fQuads.count();
fQuads.push_back_n(that->fQuads.count(), that->fQuads.begin());
this->joinBounds(*that);
fPerspective |= that->fPerspective;
fDomain |= that->fDomain;
@ -873,9 +966,9 @@ private:
GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
class Draw {
class Quad {
public:
Draw(const SkRect& srcRect, const GrPerspQuad& quad, GrQuadAAFlags aaFlags,
Quad(const SkRect& srcRect, const GrPerspQuad& quad, GrQuadAAFlags aaFlags,
SkCanvas::SrcRectConstraint constraint, GrColor color)
: fSrcRect(srcRect)
, fQuad(quad)
@ -897,16 +990,21 @@ private:
unsigned fHasDomain : 1;
unsigned fAAFlags : 4;
};
SkSTArray<1, Draw, true> fDraws;
struct Proxy {
GrTextureProxy* fProxy;
int fQuadCnt;
};
SkSTArray<1, Quad, true> fQuads;
sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
sk_sp<GrColorSpaceXform> fPaintColorSpaceXform;
GrTextureProxy* fProxy;
GrSamplerState::Filter fFilter;
unsigned fAAType : 2;
unsigned fPerspective : 1;
unsigned fDomain : 1;
// Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called.
unsigned fFinalized : 1;
unsigned fProxyCnt : 32 - 5;
Proxy fProxies[1];
typedef GrMeshDrawOp INHERITED;
};
@ -932,6 +1030,19 @@ std::unique_ptr<GrDrawOp> Make(GrContext* context,
std::move(paintColorSpaceXform));
}
std::unique_ptr<GrDrawOp> Make(GrContext* context,
const GrRenderTargetContext::TextureSetEntry set[],
int cnt,
GrSamplerState::Filter filter,
GrColor color,
GrAAType aaType,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
sk_sp<GrColorSpaceXform> paintColorSpaceXform) {
return TextureOp::Make(context, set, cnt, filter, color, aaType, viewMatrix,
std::move(textureColorSpaceXform), std::move(paintColorSpaceXform));
}
} // namespace GrTextureOp
#if GR_TEST_UTILS

View File

@ -6,6 +6,7 @@
*/
#include "GrColor.h"
#include "GrRenderTargetContext.h"
#include "GrSamplerState.h"
#include "GrTypesPriv.h"
#include "SkCanvas.h"
@ -38,4 +39,14 @@ std::unique_ptr<GrDrawOp> Make(GrContext*,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureXform,
sk_sp<GrColorSpaceXform> paintXform);
std::unique_ptr<GrDrawOp> Make(GrContext*,
const GrRenderTargetContext::TextureSetEntry[],
int cnt,
GrSamplerState::Filter,
GrColor,
GrAAType,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureXform,
sk_sp<GrColorSpaceXform> paintXform);
}

View File

@ -257,6 +257,14 @@ void SkNWayCanvas::onDrawImageLattice(const SkImage* image, const Lattice& latti
}
}
void SkNWayCanvas::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
Iter iter(fList);
while (iter.next()) {
iter->experimental_DrawImageSetV0(set, count, alpha, filterQuality, mode);
}
}
void SkNWayCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
const SkPaint& paint) {
Iter iter(fList);

View File

@ -173,6 +173,18 @@ void SkPaintFilterCanvas::onDrawImageLattice(const SkImage* image, const Lattice
}
}
void SkPaintFilterCanvas::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count,
float alpha, SkFilterQuality filterQuality,
SkBlendMode mode) {
SkPaint paint;
paint.setBlendMode(mode);
AutoPaintFilter apf(this, kBitmap_Type, &paint);
mode = paint.getBlendMode();
if (apf.shouldDraw()) {
this->SkNWayCanvas::onDrawImageSet(set, count, alpha, filterQuality, mode);
}
}
void SkPaintFilterCanvas::onDrawVerticesObject(const SkVertices* vertices,
const SkVertices::Bone bones[], int boneCount,
SkBlendMode bmode, const SkPaint& paint) {

View File

@ -357,6 +357,11 @@ void SkDebugCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
this->addDrawCommand(new SkDrawImageNineCommand(image, center, dst, paint));
}
void SkDebugCanvas::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count, float alpha,
SkFilterQuality filterQuality, SkBlendMode mode) {
this->addDrawCommand(new SkDrawImageSetCommand(set, count, alpha, filterQuality, mode));
}
void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
}

View File

@ -158,6 +158,8 @@ protected:
const SkRect& dst, const SkPaint* paint) override;
void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
const SkPaint*, SrcRectConstraint) override;
void onDrawImageSet(const ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode) override;
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
const SkPaint*) override;
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,

View File

@ -7,12 +7,15 @@
#include "SkDrawCommand.h"
#include <algorithm>
#include "SkAutoMalloc.h"
#include "SkClipOpPriv.h"
#include "SkColorFilter.h"
#include "SkDashPathEffect.h"
#include "SkDrawable.h"
#include "SkImageFilter.h"
#include "SkJsonWriteBuffer.h"
#include "SkLatticeIter.h"
#include "SkMaskFilterBase.h"
#include "SkPaintDefaults.h"
#include "SkPathEffect.h"
@ -20,13 +23,11 @@
#include "SkPngEncoder.h"
#include "SkReadBuffer.h"
#include "SkRectPriv.h"
#include "SkTextBlobPriv.h"
#include "SkShadowFlags.h"
#include "SkTHash.h"
#include "SkTextBlobPriv.h"
#include "SkTypeface.h"
#include "SkWriteBuffer.h"
#include "SkClipOpPriv.h"
#include <SkLatticeIter.h>
#include <SkShadowFlags.h>
#define SKDEBUGCANVAS_ATTRIBUTE_COMMAND "command"
#define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE "visible"
@ -227,6 +228,7 @@ const char* SkDrawCommand::GetCommandString(OpType type) {
case kDrawImageLattice_OpType: return "DrawImageLattice";
case kDrawImageNine_OpType: return "DrawImageNine";
case kDrawImageRect_OpType: return "DrawImageRect";
case kDrawImageSet_OpType: return "DrawImageSet";
case kDrawOval_OpType: return "DrawOval";
case kDrawPaint_OpType: return "DrawPaint";
case kDrawPatch_OpType: return "DrawPatch";
@ -1552,6 +1554,22 @@ Json::Value SkDrawImageRectCommand::toJSON(UrlDataManager& urlDataManager) const
return result;
}
SkDrawImageSetCommand::SkDrawImageSetCommand(const SkCanvas::ImageSetEntry set[], int count,
float alpha, SkFilterQuality filterQuality,
SkBlendMode mode)
: INHERITED(kDrawImageSet_OpType)
, fSet(count)
, fCount(count)
, fAlpha(alpha)
, fFilterQuality(filterQuality)
, fMode(mode) {
std::copy_n(set, count, fSet.get());
}
void SkDrawImageSetCommand::execute(SkCanvas* canvas) const {
canvas->experimental_DrawImageSetV0(fSet.get(), fCount, fAlpha, fFilterQuality, fMode);
}
SkDrawImageNineCommand::SkDrawImageNineCommand(const SkImage* image, const SkIRect& center,
const SkRect& dst, const SkPaint* paint)
: INHERITED(kDrawImageNine_OpType)

View File

@ -43,6 +43,7 @@ public:
kDrawImageLattice_OpType,
kDrawImageNine_OpType,
kDrawImageRect_OpType,
kDrawImageSet_OpType,
kDrawOval_OpType,
kDrawArc_OpType,
kDrawPaint_OpType,
@ -363,6 +364,22 @@ private:
typedef SkDrawCommand INHERITED;
};
class SkDrawImageSetCommand : public SkDrawCommand {
public:
SkDrawImageSetCommand(const SkCanvas::ImageSetEntry[], int count, float alpha, SkFilterQuality,
SkBlendMode);
void execute(SkCanvas* canvas) const override;
private:
SkAutoTArray<SkCanvas::ImageSetEntry> fSet;
int fCount;
float fAlpha;
SkFilterQuality fFilterQuality;
SkBlendMode fMode;
typedef SkDrawCommand INHERITED;
};
class SkDrawOvalCommand : public SkDrawCommand {
public:
SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint);