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:
parent
476506d070
commit
449d9b7e2d
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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; }
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user