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

This reverts commit 8d5b41b553.

Bug: skia:8444
Change-Id: I29b52c6fe9475c6113ec954b7918cf591111846c
Reviewed-on: https://skia-review.googlesource.com/c/161627
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-10-12 11:42:02 -04:00 committed by Skia Commit-Bot
parent 11422c63d3
commit d7065e72da
44 changed files with 853 additions and 289 deletions

View File

@ -4957,6 +4957,67 @@ void draw(SkCanvas* canvas) {
#Subtopic Lattice ##
# ------------------------------------------------------------------------------
#Enum QuadAAFlags
#Line # don't use this ##
#Private
##
#NoExample
##
##
# ------------------------------------------------------------------------------
#Struct ImageSetEntry
#Line # don't use this ##
#Private
##
#Member SkImage* fImage
#Line # image to draw ##
##
#Member SkRect fSrcRect
#Line # image src rectangle ##
##
#Member SkRect fDstRect
#Line # local space rectangle ##
##
#Member unsigned fAAFlags
#Line # antialiasing flags ##
##
#NoExample
##
##
# ------------------------------------------------------------------------------
#Method void experimental_DrawImageSetV0(const ImageSetEntry imageSet[], int cnt, float alpha,
SkFilterQuality quality, SkBlendMode mode);
#Private
##
#In Draw_Image
#In Draw
#Line # draws a set a of images (don't call this) ##
Draws a set of images. Do not use this method.
#Param imageSet images ##
#Param cnt number of images ##
#Param alpha alpha ##
#Param quality filter quality ##
#Param mode blend mode ##
#NoExample
##
##
#Subtopic Draw_Image ##
# ------------------------------------------------------------------------------

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 quality, SkBlendMode mode);
/** 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,62 @@ 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 ||
!fContext->contextPriv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
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);