/* * 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 "SkCanvas.h" #include "SkDrawable.h" #include "SkImageFilter.h" #include "SkMatrix.h" #include "SkPath.h" #include "SkPicture.h" #include "SkRect.h" #include "SkRRect.h" #include "SkRSXform.h" #include "SkTextBlob.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(Restore) \ M(Save) \ M(SaveLayer) \ M(SetMatrix) \ M(Concat) \ M(ClipPath) \ M(ClipRRect) \ M(ClipRect) \ M(ClipRegion) \ M(DrawBitmap) \ M(DrawBitmapNine) \ M(DrawBitmapRect) \ M(DrawBitmapRectFast) \ M(DrawBitmapRectFixedSize) \ M(DrawDrawable) \ M(DrawImage) \ M(DrawImageRect) \ M(DrawImageNine) \ M(DrawDRRect) \ M(DrawOval) \ M(DrawPaint) \ M(DrawPath) \ M(DrawPatch) \ M(DrawPicture) \ M(DrawPoints) \ M(DrawPosText) \ M(DrawPosTextH) \ M(DrawText) \ M(DrawTextOnPath) \ M(DrawRRect) \ M(DrawRect) \ M(DrawTextBlob) \ M(DrawAtlas) \ M(DrawVertices) // 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; } template <typename T> class RefBox : SkNoncopyable { public: RefBox() {} RefBox(T* obj) : fObj(SkSafeRef(obj)) {} RefBox(RefBox&& o) : fObj(o.fObj) { o.fObj = nullptr; } ~RefBox() { SkSafeUnref(fObj); } ACT_AS_PTR(fObj); private: T* fObj; }; // 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 // Like SkBitmap, but deep copies pixels if they're not immutable. // Using this, we guarantee the immutability of all bitmaps we record. class ImmutableBitmap : SkNoncopyable { public: ImmutableBitmap() {} ImmutableBitmap(const SkBitmap& bitmap); ImmutableBitmap(ImmutableBitmap&& o) { fBitmap.swap(o.fBitmap); } int width() const { return fBitmap.width(); } int height() const { return fBitmap.height(); } // While the pixels are immutable, SkBitmap itself is not thread-safe, so return a copy. SkBitmap shallowCopy() const { return fBitmap; } private: SkBitmap fBitmap; }; // 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. }; // 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(Restore, 0, SkIRect devBounds; TypedMatrix matrix); RECORD(Save, 0); RECORD(SaveLayer, 0, Optional<SkRect> bounds; Optional<SkPaint> paint; RefBox<const SkImageFilter> backdrop; SkCanvas::SaveLayerFlags saveLayerFlags); RECORD(SetMatrix, 0, TypedMatrix matrix); RECORD(Concat, 0, TypedMatrix matrix); struct RegionOpAndAA { RegionOpAndAA() {} RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {} SkRegion::Op op : 31; // This really only needs to be 3, but there's no win today to do so. unsigned aa : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. }; static_assert(sizeof(RegionOpAndAA) == 4, "RegionOpAndAASize"); RECORD(ClipPath, 0, SkIRect devBounds; PreCachedPath path; 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. RECORD(DrawBitmap, kDraw_Tag|kHasImage_Tag, Optional<SkPaint> paint; ImmutableBitmap bitmap; SkScalar left; SkScalar top); RECORD(DrawBitmapNine, kDraw_Tag|kHasImage_Tag, Optional<SkPaint> paint; ImmutableBitmap bitmap; SkIRect center; SkRect dst); RECORD(DrawBitmapRect, kDraw_Tag|kHasImage_Tag, Optional<SkPaint> paint; ImmutableBitmap bitmap; Optional<SkRect> src; SkRect dst); RECORD(DrawBitmapRectFast, kDraw_Tag|kHasImage_Tag, Optional<SkPaint> paint; ImmutableBitmap bitmap; Optional<SkRect> src; SkRect dst); RECORD(DrawBitmapRectFixedSize, kDraw_Tag|kHasImage_Tag, SkPaint paint; ImmutableBitmap bitmap; SkRect src; SkRect dst; SkCanvas::SrcRectConstraint constraint); RECORD(DrawDRRect, kDraw_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, Optional<SkPaint> paint; RefBox<const SkImage> image; SkScalar left; SkScalar top); RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag, Optional<SkPaint> paint; RefBox<const SkImage> image; Optional<SkRect> src; SkRect dst; SkCanvas::SrcRectConstraint constraint); RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag, Optional<SkPaint> paint; RefBox<const SkImage> image; SkIRect center; SkRect dst); RECORD(DrawOval, kDraw_Tag, SkPaint paint; SkRect oval); RECORD(DrawPaint, kDraw_Tag, SkPaint paint); RECORD(DrawPath, kDraw_Tag, SkPaint paint; PreCachedPath path); RECORD(DrawPicture, kDraw_Tag, Optional<SkPaint> paint; RefBox<const SkPicture> picture; TypedMatrix matrix); RECORD(DrawPoints, kDraw_Tag, SkPaint paint; SkCanvas::PointMode mode; unsigned count; SkPoint* pts); RECORD(DrawPosText, kDraw_Tag|kHasText_Tag, 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(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); #undef RECORD } // namespace SkRecords #endif//SkRecords_DEFINED