SkRecords.h revision c54d8db4d169ea5f2af2a9a2349df007bd428475
1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#ifndef SkRecords_DEFINED 9#define SkRecords_DEFINED 10 11#include "SkCanvas.h" 12#include "SkCanvasDrawable.h" 13#include "SkPicture.h" 14#include "SkTextBlob.h" 15 16namespace SkRecords { 17 18// A list of all the types of canvas calls we can record. 19// Each of these is reified into a struct below. 20// 21// (We're using the macro-of-macro trick here to do several different things with the same list.) 22// 23// We leave this SK_RECORD_TYPES macro defined for use by code that wants to operate on SkRecords 24// types polymorphically. (See SkRecord::Record::{visit,mutate} for an example.) 25// 26// Order doesn't technically matter here, but the compiler can generally generate better code if 27// you keep them semantically grouped, especially the Draws. It's also nice to leave NoOp at 0. 28#define SK_RECORD_TYPES(M) \ 29 M(NoOp) \ 30 M(Restore) \ 31 M(Save) \ 32 M(SaveLayer) \ 33 M(PushCull) \ 34 M(PopCull) \ 35 M(SetMatrix) \ 36 M(ClipPath) \ 37 M(ClipRRect) \ 38 M(ClipRect) \ 39 M(ClipRegion) \ 40 M(Clear) \ 41 M(BeginCommentGroup) \ 42 M(AddComment) \ 43 M(EndCommentGroup) \ 44 M(DrawBitmap) \ 45 M(DrawBitmapNine) \ 46 M(DrawBitmapRectToRect) \ 47 M(DrawBitmapRectToRectBleed) \ 48 M(DrawDrawable) \ 49 M(DrawImage) \ 50 M(DrawImageRect) \ 51 M(DrawDRRect) \ 52 M(DrawOval) \ 53 M(DrawPaint) \ 54 M(DrawPath) \ 55 M(DrawPatch) \ 56 M(DrawPicture) \ 57 M(DrawPoints) \ 58 M(DrawPosText) \ 59 M(DrawPosTextH) \ 60 M(DrawText) \ 61 M(DrawTextOnPath) \ 62 M(DrawRRect) \ 63 M(DrawRect) \ 64 M(DrawSprite) \ 65 M(DrawTextBlob) \ 66 M(DrawData) \ 67 M(DrawVertices) 68 69// Defines SkRecords::Type, an enum of all record types. 70#define ENUM(T) T##_Type, 71enum Type { SK_RECORD_TYPES(ENUM) }; 72#undef ENUM 73 74// Macros to make it easier to define a record for a draw call with 0 args, 1 args, 2 args, etc. 75// These should be clearer when you look at their use below. 76#define RECORD0(T) \ 77struct T { \ 78 static const Type kType = T##_Type; \ 79}; 80 81// We try to be flexible about the types the constructors take. Instead of requring the exact type 82// A here, we take any type Z which implicitly casts to A. This allows the delay_copy() trick to 83// work, allowing the caller to decide whether to pass by value or by const&. 84 85#define RECORD1(T, A, a) \ 86struct T { \ 87 static const Type kType = T##_Type; \ 88 template <typename Z> \ 89 T(Z a) : a(a) {} \ 90 A a; \ 91}; 92 93#define RECORD2(T, A, a, B, b) \ 94struct T { \ 95 static const Type kType = T##_Type; \ 96 template <typename Z, typename Y> \ 97 T(Z a, Y b) : a(a), b(b) {} \ 98 A a; B b; \ 99}; 100 101#define RECORD3(T, A, a, B, b, C, c) \ 102struct T { \ 103 static const Type kType = T##_Type; \ 104 template <typename Z, typename Y, typename X> \ 105 T(Z a, Y b, X c) : a(a), b(b), c(c) {} \ 106 A a; B b; C c; \ 107}; 108 109#define RECORD4(T, A, a, B, b, C, c, D, d) \ 110struct T { \ 111 static const Type kType = T##_Type; \ 112 template <typename Z, typename Y, typename X, typename W> \ 113 T(Z a, Y b, X c, W d) : a(a), b(b), c(c), d(d) {} \ 114 A a; B b; C c; D d; \ 115}; 116 117#define RECORD5(T, A, a, B, b, C, c, D, d, E, e) \ 118struct T { \ 119 static const Type kType = T##_Type; \ 120 template <typename Z, typename Y, typename X, typename W, typename V> \ 121 T(Z a, Y b, X c, W d, V e) : a(a), b(b), c(c), d(d), e(e) {} \ 122 A a; B b; C c; D d; E e; \ 123}; 124 125#define ACT_AS_PTR(ptr) \ 126 operator T*() const { return ptr; } \ 127 T* operator->() const { return ptr; } 128 129template <typename T> 130class RefBox : SkNoncopyable { 131public: 132 RefBox(T* obj) : fObj(SkSafeRef(obj)) {} 133 ~RefBox() { SkSafeUnref(fObj); } 134 135 ACT_AS_PTR(fObj); 136 137private: 138 T* fObj; 139}; 140 141// An Optional doesn't own the pointer's memory, but may need to destroy non-POD data. 142template <typename T> 143class Optional : SkNoncopyable { 144public: 145 Optional(T* ptr) : fPtr(ptr) {} 146 ~Optional() { if (fPtr) fPtr->~T(); } 147 148 ACT_AS_PTR(fPtr); 149private: 150 T* fPtr; 151}; 152 153// Like Optional, but ptr must not be NULL. 154template <typename T> 155class Adopted : SkNoncopyable { 156public: 157 Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); } 158 Adopted(Adopted* source) { 159 // Transfer ownership from source to this. 160 fPtr = source->fPtr; 161 source->fPtr = NULL; 162 } 163 ~Adopted() { if (fPtr) fPtr->~T(); } 164 165 ACT_AS_PTR(fPtr); 166private: 167 T* fPtr; 168}; 169 170// PODArray doesn't own the pointer's memory, and we assume the data is POD. 171template <typename T> 172class PODArray { 173public: 174 PODArray(T* ptr) : fPtr(ptr) {} 175 // Default copy and assign. 176 177 ACT_AS_PTR(fPtr); 178private: 179 T* fPtr; 180}; 181 182#undef ACT_AS_PTR 183 184// Like SkBitmap, but deep copies pixels if they're not immutable. 185// Using this, we guarantee the immutability of all bitmaps we record. 186struct ImmutableBitmap : public SkBitmap { 187 explicit ImmutableBitmap(const SkBitmap& bitmap) { 188 if (bitmap.isImmutable()) { 189 *(SkBitmap*)this = bitmap; 190 } else { 191 bitmap.copyTo(this); 192 } 193 this->setImmutable(); 194 } 195}; 196 197// SkPath::getBounds() isn't thread safe unless we precache the bounds in a singlethreaded context. 198// Recording is a convenient time to do this, but we could delay it to between record and playback. 199struct BoundedPath : public SkPath { 200 explicit BoundedPath(const SkPath& path) : SkPath(path) { 201 this->updateBoundsCache(); 202 } 203}; 204 205// Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it. 206// This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader). 207struct TypedMatrix : public SkMatrix { 208 explicit TypedMatrix(const SkMatrix& matrix) : SkMatrix(matrix) { 209 (void)this->getType(); 210 } 211}; 212 213RECORD0(NoOp); 214 215RECORD2(Restore, SkIRect, devBounds, TypedMatrix, matrix); 216RECORD0(Save); 217RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags); 218 219RECORD1(PushCull, SkRect, rect); 220RECORD0(PopCull); 221 222RECORD1(SetMatrix, TypedMatrix, matrix); 223 224struct RegionOpAndAA { 225 RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {} 226 SkRegion::Op op : 31; // This really only needs to be 3, but there's no win today to do so. 227 unsigned aa : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. 228}; 229SK_COMPILE_ASSERT(sizeof(RegionOpAndAA) == 4, RegionOpAndAASize); 230 231RECORD3(ClipPath, SkIRect, devBounds, BoundedPath, path, RegionOpAndAA, opAA); 232RECORD3(ClipRRect, SkIRect, devBounds, SkRRect, rrect, RegionOpAndAA, opAA); 233RECORD3(ClipRect, SkIRect, devBounds, SkRect, rect, RegionOpAndAA, opAA); 234RECORD3(ClipRegion, SkIRect, devBounds, SkRegion, region, SkRegion::Op, op); 235 236// Picture version 37 was last to record this op-code; clear is now non-virtual 237RECORD1(Clear, SkColor, color); 238 239RECORD1(BeginCommentGroup, PODArray<char>, description); 240RECORD2(AddComment, PODArray<char>, key, PODArray<char>, value); 241RECORD0(EndCommentGroup); 242 243// While not strictly required, if you have an SkPaint, it's fastest to put it first. 244RECORD4(DrawBitmap, Optional<SkPaint>, paint, 245 ImmutableBitmap, bitmap, 246 SkScalar, left, 247 SkScalar, top); 248RECORD4(DrawBitmapNine, Optional<SkPaint>, paint, 249 ImmutableBitmap, bitmap, 250 SkIRect, center, 251 SkRect, dst); 252RECORD4(DrawBitmapRectToRect, Optional<SkPaint>, paint, 253 ImmutableBitmap, bitmap, 254 Optional<SkRect>, src, 255 SkRect, dst); 256RECORD4(DrawBitmapRectToRectBleed, Optional<SkPaint>, paint, 257 ImmutableBitmap, bitmap, 258 Optional<SkRect>, src, 259 SkRect, dst); 260RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner); 261RECORD2(DrawDrawable, SkRect, worstCaseBounds, int32_t, index); 262RECORD4(DrawImage, Optional<SkPaint>, paint, 263 RefBox<const SkImage>, image, 264 SkScalar, left, 265 SkScalar, top); 266RECORD4(DrawImageRect, Optional<SkPaint>, paint, 267 RefBox<const SkImage>, image, 268 Optional<SkRect>, src, 269 SkRect, dst); 270RECORD2(DrawOval, SkPaint, paint, SkRect, oval); 271RECORD1(DrawPaint, SkPaint, paint); 272RECORD2(DrawPath, SkPaint, paint, BoundedPath, path); 273RECORD3(DrawPicture, Optional<SkPaint>, paint, 274 RefBox<const SkPicture>, picture, 275 TypedMatrix, matrix); 276RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, unsigned, count, SkPoint*, pts); 277RECORD4(DrawPosText, SkPaint, paint, 278 PODArray<char>, text, 279 size_t, byteLength, 280 PODArray<SkPoint>, pos); 281RECORD5(DrawPosTextH, SkPaint, paint, 282 PODArray<char>, text, 283 unsigned, byteLength, 284 SkScalar, y, 285 PODArray<SkScalar>, xpos); 286RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect); 287RECORD2(DrawRect, SkPaint, paint, SkRect, rect); 288RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top); 289RECORD5(DrawText, SkPaint, paint, 290 PODArray<char>, text, 291 size_t, byteLength, 292 SkScalar, x, 293 SkScalar, y); 294RECORD4(DrawTextBlob, SkPaint, paint, 295 RefBox<const SkTextBlob>, blob, 296 SkScalar, x, 297 SkScalar, y); 298RECORD5(DrawTextOnPath, SkPaint, paint, 299 PODArray<char>, text, 300 size_t, byteLength, 301 BoundedPath, path, 302 TypedMatrix, matrix); 303 304RECORD2(DrawData, PODArray<char>, data, size_t, length); 305 306RECORD5(DrawPatch, SkPaint, paint, 307 PODArray<SkPoint>, cubics, 308 PODArray<SkColor>, colors, 309 PODArray<SkPoint>, texCoords, 310 RefBox<SkXfermode>, xmode); 311 312// This guy is so ugly we just write it manually. 313struct DrawVertices { 314 static const Type kType = DrawVertices_Type; 315 316 DrawVertices(const SkPaint& paint, 317 SkCanvas::VertexMode vmode, 318 int vertexCount, 319 SkPoint* vertices, 320 SkPoint* texs, 321 SkColor* colors, 322 SkXfermode* xmode, 323 uint16_t* indices, 324 int indexCount) 325 : paint(paint) 326 , vmode(vmode) 327 , vertexCount(vertexCount) 328 , vertices(vertices) 329 , texs(texs) 330 , colors(colors) 331 , xmode(SkSafeRef(xmode)) 332 , indices(indices) 333 , indexCount(indexCount) {} 334 335 SkPaint paint; 336 SkCanvas::VertexMode vmode; 337 int vertexCount; 338 PODArray<SkPoint> vertices; 339 PODArray<SkPoint> texs; 340 PODArray<SkColor> colors; 341 SkAutoTUnref<SkXfermode> xmode; 342 PODArray<uint16_t> indices; 343 int indexCount; 344}; 345 346#undef RECORD0 347#undef RECORD1 348#undef RECORD2 349#undef RECORD3 350#undef RECORD4 351#undef RECORD5 352 353} // namespace SkRecords 354 355#endif//SkRecords_DEFINED 356