simplify code in SkRecords.h

- use C++11 features ({} init, move constructors) to eliminate the need
     for explicit constructors
   - collapse RECORD0...RECORD8 into just one RECORD macro
   - explicitly tag record types instead of using member detectors.

Removing member detectors makes this code significantly less fragile.

This exposes a few places where we didn't really think through what to do
with SkDrawable.  I've marked them TODO for now.

BUG=skia:

Review URL: https://codereview.chromium.org/1360943003
This commit is contained in:
mtklein 2015-09-28 10:33:02 -07:00 committed by Commit bot
parent 476506d070
commit 449d9b7e2d
10 changed files with 245 additions and 290 deletions

View File

@ -24,10 +24,11 @@
#include "SkRecordDraw.h" #include "SkRecordDraw.h"
#include "SkRecorder.h" #include "SkRecorder.h"
#include "SkSVGCanvas.h" #include "SkSVGCanvas.h"
#include "SkScaledCodec.h"
#include "SkScanlineDecoder.h" #include "SkScanlineDecoder.h"
#include "SkStream.h" #include "SkStream.h"
#include "SkTLogic.h"
#include "SkXMLWriter.h" #include "SkXMLWriter.h"
#include "SkScaledCodec.h"
DEFINE_bool(multiPage, false, "For document-type backends, render the source" DEFINE_bool(multiPage, false, "For document-type backends, render the source"
" into multiple pages"); " into multiple pages");
@ -1212,8 +1213,6 @@ struct DrawsAsSingletonPictures {
SkCanvas* fCanvas; SkCanvas* fCanvas;
const SkDrawableList& fDrawables; const SkDrawableList& fDrawables;
SK_CREATE_MEMBER_DETECTOR(paint);
template <typename T> template <typename T>
void draw(const T& op, SkCanvas* canvas) { void draw(const T& op, SkCanvas* canvas) {
// We must pass SkMatrix::I() as our initial matrix. // We must pass SkMatrix::I() as our initial matrix.
@ -1223,20 +1222,20 @@ struct DrawsAsSingletonPictures {
d(op); d(op);
} }
// Most things that have paints are Draw-type ops. Create sub-pictures for each. // Draws get their own picture.
template <typename T> template <typename T>
SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) { SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
SkPictureRecorder rec; SkPictureRecorder rec;
this->draw(op, rec.beginRecording(SkRect::MakeLargest())); this->draw(op, rec.beginRecording(SkRect::MakeLargest()));
SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture()); SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture());
fCanvas->drawPicture(pic); fCanvas->drawPicture(pic);
} }
// If you don't have a paint or are a SaveLayer, you're not a Draw-type op. // We'll just issue non-draws directly.
// We cannot make subpictures out of these because they affect state. Draw them directly.
template <typename T> template <typename T>
SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { this->draw(op, fCanvas); } skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) {
void operator()(const SkRecords::SaveLayer& op) { this->draw(op, fCanvas); } this->draw(op, fCanvas);
}
}; };
// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw. // Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.

View File

@ -72,74 +72,6 @@ namespace SkRecords {
enum Type { SK_RECORD_TYPES(ENUM) }; enum Type { SK_RECORD_TYPES(ENUM) };
#undef ENUM #undef ENUM
// Macros to make it easier to define a record for a draw call with 0 args, 1 args, 2 args, etc.
// These should be clearer when you look at their use below.
#define RECORD0(T) \
struct T { \
static const Type kType = T##_Type; \
};
// Instead of requring the exact type A here, we take any type Z which implicitly casts to A.
// This lets our wrappers like ImmutableBitmap work seamlessly.
#define RECORD1(T, A, a) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z> \
T(const Z& a) : a(a) {} \
A a; \
};
#define RECORD2(T, A, a, B, b) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y> \
T(const Z& a, const Y& b) : a(a), b(b) {} \
A a; B b; \
};
#define RECORD3(T, A, a, B, b, C, c) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X> \
T(const Z& a, const Y& b, const X& c) : a(a), b(b), c(c) {} \
A a; B b; C c; \
};
#define RECORD4(T, A, a, B, b, C, c, D, d) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X, typename W> \
T(const Z& a, const Y& b, const X& c, const W& d) : a(a), b(b), c(c), d(d) {} \
A a; B b; C c; D d; \
};
#define RECORD5(T, A, a, B, b, C, c, D, d, E, e) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X, typename W, typename V> \
T(const Z& a, const Y& b, const X& c, const W& d, const V& e) \
: a(a), b(b), c(c), d(d), e(e) {} \
A a; B b; C c; D d; E e; \
};
#define RECORD8(T, A, a, B, b, C, c, D, d, E, e, F, f, G, g, H, h) \
struct T { \
static const Type kType = T##_Type; \
T() {} \
template <typename Z, typename Y, typename X, typename W, \
typename V, typename U, typename S, typename R> \
T(const Z& a, const Y& b, const X& c, const W& d, \
const V& e, const U& f, const S& g, const R& h) \
: a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {} \
A a; B b; C c; D d; E e; F f; G g; H h; \
};
#define ACT_AS_PTR(ptr) \ #define ACT_AS_PTR(ptr) \
operator T*() const { return ptr; } \ operator T*() const { return ptr; } \
T* operator->() const { return ptr; } T* operator->() const { return ptr; }
@ -149,6 +81,9 @@ class RefBox : SkNoncopyable {
public: public:
RefBox() {} RefBox() {}
RefBox(T* obj) : fObj(SkSafeRef(obj)) {} RefBox(T* obj) : fObj(SkSafeRef(obj)) {}
RefBox(RefBox&& o) : fObj(o.fObj) {
o.fObj = nullptr;
}
~RefBox() { SkSafeUnref(fObj); } ~RefBox() { SkSafeUnref(fObj); }
ACT_AS_PTR(fObj); ACT_AS_PTR(fObj);
@ -163,6 +98,9 @@ class Optional : SkNoncopyable {
public: public:
Optional() : fPtr(nullptr) {} Optional() : fPtr(nullptr) {}
Optional(T* ptr) : fPtr(ptr) {} Optional(T* ptr) : fPtr(ptr) {}
Optional(Optional&& o) : fPtr(o.fPtr) {
o.fPtr = nullptr;
}
~Optional() { if (fPtr) fPtr->~T(); } ~Optional() { if (fPtr) fPtr->~T(); }
ACT_AS_PTR(fPtr); ACT_AS_PTR(fPtr);
@ -207,7 +145,10 @@ private:
class ImmutableBitmap : SkNoncopyable { class ImmutableBitmap : SkNoncopyable {
public: public:
ImmutableBitmap() {} ImmutableBitmap() {}
explicit ImmutableBitmap(const SkBitmap& bitmap); ImmutableBitmap(const SkBitmap& bitmap);
ImmutableBitmap(ImmutableBitmap&& o) {
fBitmap.swap(o.fBitmap);
}
int width() const { return fBitmap.width(); } int width() const { return fBitmap.width(); }
int height() const { return fBitmap.height(); } int height() const { return fBitmap.height(); }
@ -223,23 +164,43 @@ private:
// Recording is a convenient time to cache these, or we can delay it to between record and playback. // Recording is a convenient time to cache these, or we can delay it to between record and playback.
struct PreCachedPath : public SkPath { struct PreCachedPath : public SkPath {
PreCachedPath() {} PreCachedPath() {}
explicit PreCachedPath(const SkPath& path); PreCachedPath(const SkPath& path);
}; };
// Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it. // Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it.
// This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader). // This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader).
struct TypedMatrix : public SkMatrix { struct TypedMatrix : public SkMatrix {
TypedMatrix() {} TypedMatrix() {}
explicit TypedMatrix(const SkMatrix& matrix); TypedMatrix(const SkMatrix& matrix);
}; };
RECORD0(NoOp); enum Tags {
kDraw_Tag = 1, // May draw something (usually named DrawFoo).
kHasImage_Tag = 2, // Contains an SkImage or SkBitmap.
kHasText_Tag = 4, // Contains text.
};
RECORD2(Restore, SkIRect, devBounds, TypedMatrix, matrix); // A macro to make it a little easier to define a struct that can be stored in SkRecord.
RECORD0(Save); #define RECORD(T, tags, ...) \
RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags); struct T { \
static const Type kType = T##_Type; \
static const int kTags = tags; \
__VA_ARGS__; \
};
RECORD1(SetMatrix, TypedMatrix, matrix); RECORD(NoOp, 0);
RECORD(Restore, 0,
SkIRect devBounds;
TypedMatrix matrix);
RECORD(Save, 0);
RECORD(SaveLayer, 0,
Optional<SkRect> bounds;
Optional<SkPaint> paint;
SkCanvas::SaveFlags flags);
RECORD(SetMatrix, 0,
TypedMatrix matrix);
struct RegionOpAndAA { struct RegionOpAndAA {
RegionOpAndAA() {} RegionOpAndAA() {}
@ -249,138 +210,157 @@ struct RegionOpAndAA {
}; };
static_assert(sizeof(RegionOpAndAA) == 4, "RegionOpAndAASize"); static_assert(sizeof(RegionOpAndAA) == 4, "RegionOpAndAASize");
RECORD3(ClipPath, SkIRect, devBounds, PreCachedPath, path, RegionOpAndAA, opAA); RECORD(ClipPath, 0,
RECORD3(ClipRRect, SkIRect, devBounds, SkRRect, rrect, RegionOpAndAA, opAA); SkIRect devBounds;
RECORD3(ClipRect, SkIRect, devBounds, SkRect, rect, RegionOpAndAA, opAA); PreCachedPath path;
RECORD3(ClipRegion, SkIRect, devBounds, SkRegion, region, SkRegion::Op, op); RegionOpAndAA opAA);
RECORD(ClipRRect, 0,
SkIRect devBounds;
SkRRect rrect;
RegionOpAndAA opAA);
RECORD(ClipRect, 0,
SkIRect devBounds;
SkRect rect;
RegionOpAndAA opAA);
RECORD(ClipRegion, 0,
SkIRect devBounds;
SkRegion region;
SkRegion::Op op);
// While not strictly required, if you have an SkPaint, it's fastest to put it first. // While not strictly required, if you have an SkPaint, it's fastest to put it first.
RECORD4(DrawBitmap, Optional<SkPaint>, paint, RECORD(DrawBitmap, kDraw_Tag|kHasImage_Tag,
ImmutableBitmap, bitmap, Optional<SkPaint> paint;
SkScalar, left, ImmutableBitmap bitmap;
SkScalar, top); SkScalar left;
RECORD4(DrawBitmapNine, Optional<SkPaint>, paint, SkScalar top);
ImmutableBitmap, bitmap, RECORD(DrawBitmapNine, kDraw_Tag|kHasImage_Tag,
SkIRect, center, Optional<SkPaint> paint;
SkRect, dst); ImmutableBitmap bitmap;
RECORD4(DrawBitmapRect, Optional<SkPaint>, paint, SkIRect center;
ImmutableBitmap, bitmap, SkRect dst);
Optional<SkRect>, src, RECORD(DrawBitmapRect, kDraw_Tag|kHasImage_Tag,
SkRect, dst); Optional<SkPaint> paint;
RECORD4(DrawBitmapRectFast, Optional<SkPaint>, paint, ImmutableBitmap bitmap;
ImmutableBitmap, bitmap, Optional<SkRect> src;
Optional<SkRect>, src, SkRect dst);
SkRect, dst); RECORD(DrawBitmapRectFast, kDraw_Tag|kHasImage_Tag,
RECORD5(DrawBitmapRectFixedSize, SkPaint, paint, Optional<SkPaint> paint;
ImmutableBitmap, bitmap, ImmutableBitmap bitmap;
SkRect, src, Optional<SkRect> src;
SkRect, dst, SkRect dst);
SkCanvas::SrcRectConstraint, constraint); RECORD(DrawBitmapRectFixedSize, kDraw_Tag|kHasImage_Tag,
RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner); SkPaint paint;
RECORD3(DrawDrawable, Optional<SkMatrix>, matrix, SkRect, worstCaseBounds, int32_t, index); ImmutableBitmap bitmap;
RECORD4(DrawImage, Optional<SkPaint>, paint, SkRect src;
RefBox<const SkImage>, image, SkRect dst;
SkScalar, left, SkCanvas::SrcRectConstraint constraint);
SkScalar, top); RECORD(DrawDRRect, kDraw_Tag,
RECORD5(DrawImageRect, Optional<SkPaint>, paint, SkPaint paint;
RefBox<const SkImage>, image, SkRRect outer;
Optional<SkRect>, src, SkRRect inner);
SkRect, dst, RECORD(DrawDrawable, kDraw_Tag,
SkCanvas::SrcRectConstraint, constraint); Optional<SkMatrix> matrix;
RECORD4(DrawImageNine, Optional<SkPaint>, paint, SkRect worstCaseBounds;
RefBox<const SkImage>, image, int32_t index);
SkIRect, center, RECORD(DrawImage, kDraw_Tag|kHasImage_Tag,
SkRect, dst); Optional<SkPaint> paint;
RECORD2(DrawOval, SkPaint, paint, SkRect, oval); RefBox<const SkImage> image;
RECORD1(DrawPaint, SkPaint, paint); SkScalar left;
RECORD2(DrawPath, SkPaint, paint, PreCachedPath, path); SkScalar top);
RECORD3(DrawPicture, Optional<SkPaint>, paint, RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag,
RefBox<const SkPicture>, picture, Optional<SkPaint> paint;
TypedMatrix, matrix); RefBox<const SkImage> image;
RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, unsigned, count, SkPoint*, pts); Optional<SkRect> src;
RECORD4(DrawPosText, SkPaint, paint, SkRect dst;
PODArray<char>, text, SkCanvas::SrcRectConstraint constraint);
size_t, byteLength, RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag,
PODArray<SkPoint>, pos); Optional<SkPaint> paint;
RECORD5(DrawPosTextH, SkPaint, paint, RefBox<const SkImage> image;
PODArray<char>, text, SkIRect center;
unsigned, byteLength, SkRect dst);
SkScalar, y, RECORD(DrawOval, kDraw_Tag,
PODArray<SkScalar>, xpos); SkPaint paint;
RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect); SkRect oval);
RECORD2(DrawRect, SkPaint, paint, SkRect, rect); RECORD(DrawPaint, kDraw_Tag,
RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top); SkPaint paint);
RECORD5(DrawText, SkPaint, paint, RECORD(DrawPath, kDraw_Tag,
PODArray<char>, text, SkPaint paint;
size_t, byteLength, PreCachedPath path);
SkScalar, x, RECORD(DrawPicture, kDraw_Tag,
SkScalar, y); Optional<SkPaint> paint;
RECORD4(DrawTextBlob, SkPaint, paint, RefBox<const SkPicture> picture;
RefBox<const SkTextBlob>, blob, TypedMatrix matrix);
SkScalar, x, RECORD(DrawPoints, kDraw_Tag,
SkScalar, y); SkPaint paint;
RECORD5(DrawTextOnPath, SkPaint, paint, SkCanvas::PointMode mode;
PODArray<char>, text, unsigned count;
size_t, byteLength, SkPoint* pts);
PreCachedPath, path, RECORD(DrawPosText, kDraw_Tag|kHasText_Tag,
TypedMatrix, matrix); SkPaint paint;
PODArray<char> text;
size_t byteLength;
PODArray<SkPoint> pos);
RECORD(DrawPosTextH, kDraw_Tag|kHasText_Tag,
SkPaint paint;
PODArray<char> text;
unsigned byteLength;
SkScalar y;
PODArray<SkScalar> xpos);
RECORD(DrawRRect, kDraw_Tag,
SkPaint paint;
SkRRect rrect);
RECORD(DrawRect, kDraw_Tag,
SkPaint paint;
SkRect rect);
RECORD(DrawSprite, kDraw_Tag|kHasImage_Tag,
Optional<SkPaint> paint;
ImmutableBitmap bitmap;
int left;
int top);
RECORD(DrawText, kDraw_Tag|kHasText_Tag,
SkPaint paint;
PODArray<char> text;
size_t byteLength;
SkScalar x;
SkScalar y);
RECORD(DrawTextBlob, kDraw_Tag|kHasText_Tag,
SkPaint paint;
RefBox<const SkTextBlob> blob;
SkScalar x;
SkScalar y);
RECORD(DrawTextOnPath, kDraw_Tag|kHasText_Tag,
SkPaint paint;
PODArray<char> text;
size_t byteLength;
PreCachedPath path;
TypedMatrix matrix);
RECORD(DrawPatch, kDraw_Tag,
SkPaint paint;
PODArray<SkPoint> cubics;
PODArray<SkColor> colors;
PODArray<SkPoint> texCoords;
RefBox<SkXfermode> xmode);
RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag,
Optional<SkPaint> paint;
RefBox<const SkImage> atlas;
PODArray<SkRSXform> xforms;
PODArray<SkRect> texs;
PODArray<SkColor> colors;
int count;
SkXfermode::Mode mode;
Optional<SkRect> cull);
RECORD(DrawVertices, kDraw_Tag,
SkPaint paint;
SkCanvas::VertexMode vmode;
int vertexCount;
PODArray<SkPoint> vertices;
PODArray<SkPoint> texs;
PODArray<SkColor> colors;
RefBox<SkXfermode> xmode;
PODArray<uint16_t> indices;
int indexCount);
RECORD5(DrawPatch, SkPaint, paint, #undef RECORD
PODArray<SkPoint>, cubics,
PODArray<SkColor>, colors,
PODArray<SkPoint>, texCoords,
RefBox<SkXfermode>, xmode);
RECORD8(DrawAtlas, Optional<SkPaint>, paint,
RefBox<const SkImage>, atlas,
PODArray<SkRSXform>, xforms,
PODArray<SkRect>, texs,
PODArray<SkColor>, colors,
int, count,
SkXfermode::Mode, mode,
Optional<SkRect>, cull);
// This guy is so ugly we just write it manually.
struct DrawVertices {
static const Type kType = DrawVertices_Type;
DrawVertices(const SkPaint& paint,
SkCanvas::VertexMode vmode,
int vertexCount,
SkPoint* vertices,
SkPoint* texs,
SkColor* colors,
SkXfermode* xmode,
uint16_t* indices,
int indexCount)
: paint(paint)
, vmode(vmode)
, vertexCount(vertexCount)
, vertices(vertices)
, texs(texs)
, colors(colors)
, xmode(SkSafeRef(xmode))
, indices(indices)
, indexCount(indexCount) {}
SkPaint paint;
SkCanvas::VertexMode vmode;
int vertexCount;
PODArray<SkPoint> vertices;
PODArray<SkPoint> texs;
PODArray<SkColor> colors;
SkAutoTUnref<SkXfermode> xmode;
PODArray<uint16_t> indices;
int indexCount;
};
#undef RECORD0
#undef RECORD1
#undef RECORD2
#undef RECORD3
#undef RECORD4
#undef RECORD5
#undef RECORD8
} // namespace SkRecords } // namespace SkRecords

View File

@ -220,35 +220,7 @@ template <typename D, typename S> using same_cv_t = typename same_cv<D, S>::type
} // namespace sknonstd } // namespace sknonstd
/** Use as a return type to enable a function only when cond_type::value is true, // Just a pithier wrapper for enable_if_t.
* like C++14's std::enable_if_t. E.g. (N.B. this is a dumb example.) #define SK_WHEN(condition, T) skstd::enable_if_t<!!(condition), T>
* SK_WHEN(true_type, int) f(void* ptr) { return 1; }
* SK_WHEN(!true_type, int) f(void* ptr) { return 2; }
*/
#define SK_WHEN(cond_prefix, T) skstd::enable_if_t<cond_prefix::value, T>
// See http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector
#define SK_CREATE_MEMBER_DETECTOR(member) \
template <typename T> \
class HasMember_##member { \
struct Fallback { int member; }; \
struct Derived : T, Fallback {}; \
template <typename U, U> struct Check; \
template <typename U> static uint8_t func(Check<int Fallback::*, &U::member>*); \
template <typename U> static uint16_t func(...); \
public: \
typedef HasMember_##member type; \
static const bool value = sizeof(func<Derived>(NULL)) == sizeof(uint16_t); \
}
// Same sort of thing as SK_CREATE_MEMBER_DETECTOR, but checks for the existence of a nested type.
#define SK_CREATE_TYPE_DETECTOR(type) \
template <typename T> \
class HasType_##type { \
template <typename U> static uint8_t func(typename U::type*); \
template <typename U> static uint16_t func(...); \
public: \
static const bool value = sizeof(func<T>(NULL)) == sizeof(uint8_t); \
}
#endif #endif

View File

@ -70,7 +70,7 @@ SkMiniRecorder::~SkMiniRecorder() {
#define TRY_TO_STORE(Type, ...) \ #define TRY_TO_STORE(Type, ...) \
if (fState != State::kEmpty) { return false; } \ if (fState != State::kEmpty) { return false; } \
fState = State::k##Type; \ fState = State::k##Type; \
new (fBuffer.get()) Type(__VA_ARGS__); \ new (fBuffer.get()) Type{__VA_ARGS__}; \
return true return true
bool SkMiniRecorder::drawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst, bool SkMiniRecorder::drawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,

View File

@ -16,28 +16,18 @@
struct SkTextHunter { struct SkTextHunter {
// Most ops never have text. Some always do. Subpictures know themeselves. // Most ops never have text. Some always do. Subpictures know themeselves.
template <typename T> bool operator()(const T&) { return false; }
bool operator()(const SkRecords::DrawPosText&) { return true; }
bool operator()(const SkRecords::DrawPosTextH&) { return true; }
bool operator()(const SkRecords::DrawText&) { return true; }
bool operator()(const SkRecords::DrawTextBlob&) { return true; }
bool operator()(const SkRecords::DrawTextOnPath&) { return true; }
bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); } bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
bool operator()(const SkRecords::DrawDrawable&) { /*TODO*/ return false; }
template <typename T>
SK_WHEN(T::kTags & SkRecords::kHasText_Tag, bool) operator()(const T&) { return true; }
template <typename T>
SK_WHEN(!(T::kTags & SkRecords::kHasText_Tag), bool) operator()(const T&) { return false; }
}; };
// N.B. This name is slightly historical: hunting season is now open for SkImages too. // N.B. This name is slightly historical: hunting season is now open for SkImages too.
struct SkBitmapHunter { struct SkBitmapHunter {
// Helpers. These let us detect the presence of struct members with particular names.
SK_CREATE_MEMBER_DETECTOR(bitmap);
SK_CREATE_MEMBER_DETECTOR(image);
SK_CREATE_MEMBER_DETECTOR(paint);
template <typename T>
struct HasMember_bitmap_or_image {
static const bool value = HasMember_bitmap<T>::value || HasMember_image<T>::value;
};
// Some ops have a paint, some have an optional paint. Either way, get back a pointer. // Some ops have a paint, some have an optional paint. Either way, get back a pointer.
static const SkPaint* AsPtr(const SkPaint& p) { return &p; } static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; } static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
@ -48,26 +38,42 @@ struct SkBitmapHunter {
// If the op has a paint and the paint has a bitmap, return true. // If the op has a paint and the paint has a bitmap, return true.
// Otherwise, return false. // Otherwise, return false.
bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); } bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
bool operator()(const SkRecords::DrawDrawable&) { /*TODO*/ return false; }
template <typename T> template <typename T>
bool operator()(const T& r) { return CheckBitmap(r); } bool operator()(const T& op) { return CheckBitmap(op); }
// If the op has a bitmap, of course we're going to play back bitmaps. // If the op is tagged as having an image, return true.
template <typename T> template <typename T>
static SK_WHEN(HasMember_bitmap_or_image<T>, bool) CheckBitmap(const T&) { static SK_WHEN(T::kTags & SkRecords::kHasImage_Tag, bool) CheckBitmap(const T&) {
return true; return true;
} }
// If not, look for one in its paint (if it has a paint). // If not, look for one in its paint (if it has a paint).
template <typename T> template <typename T>
static SK_WHEN(!HasMember_bitmap_or_image<T>, bool) CheckBitmap(const T& r) { static SK_WHEN(!(T::kTags & SkRecords::kHasImage_Tag), bool) CheckBitmap(const T& op) {
return CheckPaint(r); return CheckPaint(op);
} }
// If we have a paint, dig down into the effects looking for a bitmap. // Most draws-type ops have paints.
template <typename T> template <typename T>
static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) { static SK_WHEN(T::kTags & SkRecords::kDraw_Tag, bool) CheckPaint(const T& op) {
const SkPaint* paint = AsPtr(r.paint); return PaintHasBitmap(AsPtr(op.paint));
}
// SaveLayers also have a paint to check.
static bool CheckPaint(const SkRecords::SaveLayer& op) {
return PaintHasBitmap(AsPtr(op.paint));
}
// Shouldn't be any non-Draw non-SaveLayer ops with paints.
template <typename T>
static SK_WHEN(!(T::kTags & SkRecords::kDraw_Tag), bool) CheckPaint(const T&) {
return false;
}
private:
static bool PaintHasBitmap(const SkPaint* paint) {
if (paint) { if (paint) {
const SkShader* shader = paint->getShader(); const SkShader* shader = paint->getShader();
if (shader && shader->isABitmap()) { if (shader && shader->isABitmap()) {
@ -76,16 +82,10 @@ struct SkBitmapHunter {
} }
return false; return false;
} }
// If we don't have a paint, that non-paint has no bitmap.
template <typename T>
static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
}; };
// TODO: might be nicer to have operator() return an int (the number of slow paths) ? // TODO: might be nicer to have operator() return an int (the number of slow paths) ?
struct SkPathCounter { struct SkPathCounter {
SK_CREATE_MEMBER_DETECTOR(paint);
// Some ops have a paint, some have an optional paint. Either way, get back a pointer. // Some ops have a paint, some have an optional paint. Either way, get back a pointer.
static const SkPaint* AsPtr(const SkPaint& p) { return &p; } static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; } static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
@ -96,6 +96,7 @@ struct SkPathCounter {
void operator()(const SkRecords::DrawPicture& op) { void operator()(const SkRecords::DrawPicture& op) {
fNumSlowPathsAndDashEffects += op.picture->numSlowPaths(); fNumSlowPathsAndDashEffects += op.picture->numSlowPaths();
} }
void operator()(const SkRecords::DrawDrawable&) { /* TODO */ }
void checkPaint(const SkPaint* paint) { void checkPaint(const SkPaint* paint) {
if (paint && paint->getPathEffect()) { if (paint && paint->getPathEffect()) {
@ -134,13 +135,17 @@ struct SkPathCounter {
} }
} }
template <typename T> void operator()(const SkRecords::SaveLayer& op) {
SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
this->checkPaint(AsPtr(op.paint)); this->checkPaint(AsPtr(op.paint));
} }
template <typename T> template <typename T>
SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ } SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
this->checkPaint(AsPtr(op.paint));
}
template <typename T>
SK_WHEN(!(T::kTags & SkRecords::kDraw_Tag), void) operator()(const T& op) { /* do nothing */ }
int fNumSlowPathsAndDashEffects; int fNumSlowPathsAndDashEffects;
}; };

View File

@ -134,13 +134,13 @@ private:
}; };
template <typename T> template <typename T>
SK_WHEN(skstd::is_empty<T>, T*) allocCommand() { SK_WHEN(skstd::is_empty<T>::value, T*) allocCommand() {
static T singleton = {}; static T singleton = {};
return &singleton; return &singleton;
} }
template <typename T> template <typename T>
SK_WHEN(!skstd::is_empty<T>, T*) allocCommand() { return this->alloc<T>(); } SK_WHEN(!skstd::is_empty<T>::value, T*) allocCommand() { return this->alloc<T>(); }
void grow(); void grow();

View File

@ -116,7 +116,7 @@ DRAW(DrawTextBlob, drawTextBlob(r.blob, r.x, r.y, r.paint));
DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint)); DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, &r.matrix, r.paint));
DRAW(DrawAtlas, drawAtlas(r.atlas, r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint)); DRAW(DrawAtlas, drawAtlas(r.atlas, r.xforms, r.texs, r.colors, r.count, r.mode, r.cull, r.paint));
DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors, DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
r.xmode.get(), r.indices, r.indexCount, r.paint)); r.xmode, r.indices, r.indexCount, r.paint));
#undef DRAW #undef DRAW
template <> void Draw::draw(const DrawDrawable& r) { template <> void Draw::draw(const DrawDrawable& r) {

View File

@ -41,7 +41,6 @@ private:
// Matches any command that draws, and stores its paint. // Matches any command that draws, and stores its paint.
class IsDraw { class IsDraw {
SK_CREATE_MEMBER_DETECTOR(paint);
public: public:
IsDraw() : fPaint(nullptr) {} IsDraw() : fPaint(nullptr) {}
@ -49,19 +48,19 @@ public:
type* get() { return fPaint; } type* get() { return fPaint; }
template <typename T> template <typename T>
SK_WHEN(HasMember_paint<T>, bool) operator()(T* draw) { SK_WHEN(T::kTags & kDraw_Tag, bool) operator()(T* draw) {
fPaint = AsPtr(draw->paint); fPaint = AsPtr(draw->paint);
return true; return true;
} }
template <typename T> bool operator()(DrawDrawable*) {
SK_WHEN(!HasMember_paint<T>, bool) operator()(T*) { static_assert(DrawDrawable::kTags & kDraw_Tag, "");
fPaint = nullptr; fPaint = nullptr;
return false; return true;
} }
// SaveLayer has an SkPaint named paint, but it's not a draw. template <typename T>
bool operator()(SaveLayer*) { SK_WHEN(!(T::kTags & kDraw_Tag), bool) operator()(T* draw) {
fPaint = nullptr; fPaint = nullptr;
return false; return false;
} }

View File

@ -70,7 +70,7 @@ void SkRecorder::forgetRecord() {
if (fMiniRecorder) { \ if (fMiniRecorder) { \
this->flushMiniRecorder(); \ this->flushMiniRecorder(); \
} \ } \
new (fRecord->append<SkRecords::T>()) SkRecords::T(__VA_ARGS__) new (fRecord->append<SkRecords::T>()) SkRecords::T{__VA_ARGS__}
#define TRY_MINIRECORDER(method, ...) \ #define TRY_MINIRECORDER(method, ...) \
if (fMiniRecorder && fMiniRecorder->method(__VA_ARGS__)) { return; } if (fMiniRecorder && fMiniRecorder->method(__VA_ARGS__)) { return; }

View File

@ -51,7 +51,7 @@ struct Stretch {
} }
}; };
#define APPEND(record, type, ...) new (record.append<type>()) type(__VA_ARGS__) #define APPEND(record, type, ...) new (record.append<type>()) type{__VA_ARGS__}
// Basic tests for the low-level SkRecord code. // Basic tests for the low-level SkRecord code.
DEF_TEST(Record, r) { DEF_TEST(Record, r) {