/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkRecords_DEFINED #define SkRecords_DEFINED #include "SkData.h" #include "SkCanvas.h" #include "SkDrawable.h" #include "SkDrawShadowInfo.h" #include "SkImage.h" #include "SkImageFilter.h" #include "SkMatrix.h" #include "SkPath.h" #include "SkPicture.h" #include "SkRect.h" #include "SkRegion.h" #include "SkRRect.h" #include "SkRSXform.h" #include "SkString.h" #include "SkTextBlob.h" #include "SkVertices.h" namespace SkRecords { // A list of all the types of canvas calls we can record. // Each of these is reified into a struct below. // // (We're using the macro-of-macro trick here to do several different things with the same list.) // // We leave this SK_RECORD_TYPES macro defined for use by code that wants to operate on SkRecords // types polymorphically. (See SkRecord::Record::{visit,mutate} for an example.) // // Order doesn't technically matter here, but the compiler can generally generate better code if // you keep them semantically grouped, especially the Draws. It's also nice to leave NoOp at 0. #define SK_RECORD_TYPES(M) \ M(NoOp) \ M(Flush) \ M(Restore) \ M(Save) \ M(SaveLayer) \ M(SaveBehind) \ M(SetMatrix) \ M(Translate) \ M(Concat) \ M(ClipPath) \ M(ClipRRect) \ M(ClipRect) \ M(ClipRegion) \ M(DrawArc) \ M(DrawDrawable) \ M(DrawImage) \ M(DrawImageLattice) \ M(DrawImageRect) \ M(DrawImageNine) \ M(DrawImageSet) \ M(DrawDRRect) \ M(DrawOval) \ M(DrawPaint) \ M(DrawPath) \ M(DrawPatch) \ M(DrawPicture) \ M(DrawPoints) \ M(DrawRRect) \ M(DrawRect) \ M(DrawEdgeAARect) \ M(DrawRegion) \ M(DrawTextBlob) \ M(DrawAtlas) \ M(DrawVertices) \ M(DrawShadowRec) \ M(DrawAnnotation) // Defines SkRecords::Type, an enum of all record types. #define ENUM(T) T##_Type, enum Type { SK_RECORD_TYPES(ENUM) }; #undef ENUM #define ACT_AS_PTR(ptr) \ operator T*() const { return ptr; } \ T* operator->() const { return ptr; } // An Optional doesn't own the pointer's memory, but may need to destroy non-POD data. template <typename T> class Optional : SkNoncopyable { public: Optional() : fPtr(nullptr) {} Optional(T* ptr) : fPtr(ptr) {} Optional(Optional&& o) : fPtr(o.fPtr) { o.fPtr = nullptr; } ~Optional() { if (fPtr) fPtr->~T(); } ACT_AS_PTR(fPtr) private: T* fPtr; }; // Like Optional, but ptr must not be NULL. template <typename T> class Adopted : SkNoncopyable { public: Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); } Adopted(Adopted* source) { // Transfer ownership from source to this. fPtr = source->fPtr; source->fPtr = NULL; } ~Adopted() { if (fPtr) fPtr->~T(); } ACT_AS_PTR(fPtr) private: T* fPtr; }; // PODArray doesn't own the pointer's memory, and we assume the data is POD. template <typename T> class PODArray { public: PODArray() {} PODArray(T* ptr) : fPtr(ptr) {} // Default copy and assign. ACT_AS_PTR(fPtr) private: T* fPtr; }; #undef ACT_AS_PTR // SkPath::getBounds() isn't thread safe unless we precache the bounds in a singlethreaded context. // SkPath::cheapComputeDirection() is similar. // Recording is a convenient time to cache these, or we can delay it to between record and playback. struct PreCachedPath : public SkPath { PreCachedPath() {} PreCachedPath(const SkPath& path); }; // 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). struct TypedMatrix : public SkMatrix { TypedMatrix() {} TypedMatrix(const SkMatrix& matrix); }; enum Tags { kDraw_Tag = 1, // May draw something (usually named DrawFoo). kHasImage_Tag = 2, // Contains an SkImage or SkBitmap. kHasText_Tag = 4, // Contains text. kHasPaint_Tag = 8, // May have an SkPaint field, at least optionally. kDrawWithPaint_Tag = kDraw_Tag | kHasPaint_Tag, }; // A macro to make it a little easier to define a struct that can be stored in SkRecord. #define RECORD(T, tags, ...) \ struct T { \ static const Type kType = T##_Type; \ static const int kTags = tags; \ __VA_ARGS__; \ }; RECORD(NoOp, 0); RECORD(Flush, 0); RECORD(Restore, 0, TypedMatrix matrix); RECORD(Save, 0); RECORD(SaveLayer, kHasPaint_Tag, Optional<SkRect> bounds; Optional<SkPaint> paint; sk_sp<const SkImageFilter> backdrop; sk_sp<const SkImage> clipMask; Optional<SkMatrix> clipMatrix; SkCanvas::SaveLayerFlags saveLayerFlags); RECORD(SaveBehind, 0, Optional<SkRect> subset); RECORD(SetMatrix, 0, TypedMatrix matrix); RECORD(Concat, 0, TypedMatrix matrix); RECORD(Translate, 0, SkScalar dx; SkScalar dy); struct ClipOpAndAA { ClipOpAndAA() {} ClipOpAndAA(SkClipOp op, bool aa) : fOp(static_cast<unsigned>(op)), fAA(aa) {} SkClipOp op() const { return static_cast<SkClipOp>(fOp); } bool aa() const { return fAA != 0; } private: unsigned fOp : 31; // This really only needs to be 3, but there's no win today to do so. unsigned fAA : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. }; static_assert(sizeof(ClipOpAndAA) == 4, "ClipOpAndAASize"); RECORD(ClipPath, 0, PreCachedPath path; ClipOpAndAA opAA); RECORD(ClipRRect, 0, SkRRect rrect; ClipOpAndAA opAA); RECORD(ClipRect, 0, SkRect rect; ClipOpAndAA opAA); RECORD(ClipRegion, 0, SkRegion region; SkClipOp op); // While not strictly required, if you have an SkPaint, it's fastest to put it first. RECORD(DrawArc, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect oval; SkScalar startAngle; SkScalar sweepAngle; unsigned useCenter); RECORD(DrawDRRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRRect outer; SkRRect inner); RECORD(DrawDrawable, kDraw_Tag, Optional<SkMatrix> matrix; SkRect worstCaseBounds; int32_t index); RECORD(DrawImage, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional<SkPaint> paint; sk_sp<const SkImage> image; SkScalar left; SkScalar top); RECORD(DrawImageLattice, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional<SkPaint> paint; sk_sp<const SkImage> image; int xCount; PODArray<int> xDivs; int yCount; PODArray<int> yDivs; int flagCount; PODArray<SkCanvas::Lattice::RectType> flags; PODArray<SkColor> colors; SkIRect src; SkRect dst); RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional<SkPaint> paint; sk_sp<const SkImage> image; Optional<SkRect> src; SkRect dst; SkCanvas::SrcRectConstraint constraint); RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional<SkPaint> paint; sk_sp<const SkImage> image; SkIRect center; SkRect dst); RECORD(DrawImageSet, kDraw_Tag|kHasImage_Tag, SkAutoTArray<SkCanvas::ImageSetEntry> set; int count; SkFilterQuality quality; SkBlendMode mode); RECORD(DrawOval, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect oval); RECORD(DrawPaint, kDraw_Tag|kHasPaint_Tag, SkPaint paint); RECORD(DrawPath, kDraw_Tag|kHasPaint_Tag, SkPaint paint; PreCachedPath path); RECORD(DrawPicture, kDraw_Tag|kHasPaint_Tag, Optional<SkPaint> paint; sk_sp<const SkPicture> picture; TypedMatrix matrix); RECORD(DrawPoints, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkCanvas::PointMode mode; unsigned count; SkPoint* pts); RECORD(DrawRRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRRect rrect); RECORD(DrawRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect rect); RECORD(DrawEdgeAARect, kDraw_Tag, SkRect rect; SkCanvas::QuadAAFlags aa; SkColor color; SkBlendMode mode); RECORD(DrawRegion, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRegion region); RECORD(DrawTextBlob, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; sk_sp<const SkTextBlob> blob; SkScalar x; SkScalar y); RECORD(DrawPatch, kDraw_Tag|kHasPaint_Tag, SkPaint paint; PODArray<SkPoint> cubics; PODArray<SkColor> colors; PODArray<SkPoint> texCoords; SkBlendMode bmode); RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional<SkPaint> paint; sk_sp<const SkImage> atlas; PODArray<SkRSXform> xforms; PODArray<SkRect> texs; PODArray<SkColor> colors; int count; SkBlendMode mode; Optional<SkRect> cull); RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag, SkPaint paint; sk_sp<SkVertices> vertices; PODArray<SkVertices::Bone> bones; int boneCount; SkBlendMode bmode); RECORD(DrawShadowRec, kDraw_Tag, PreCachedPath path; SkDrawShadowRec rec); RECORD(DrawAnnotation, 0, // TODO: kDraw_Tag, skia:5548 SkRect rect; SkString key; sk_sp<SkData> value); #undef RECORD } // namespace SkRecords #endif//SkRecords_DEFINED