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 "SkDrawable.h" 13 #include "SkPicture.h" 14 #include "SkTextBlob.h" 15 16 namespace 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(SetMatrix) \ 34 M(ClipPath) \ 35 M(ClipRRect) \ 36 M(ClipRect) \ 37 M(ClipRegion) \ 38 M(BeginCommentGroup) \ 39 M(AddComment) \ 40 M(EndCommentGroup) \ 41 M(DrawBitmap) \ 42 M(DrawBitmapNine) \ 43 M(DrawBitmapRectToRect) \ 44 M(DrawBitmapRectToRectBleed) \ 45 M(DrawDrawable) \ 46 M(DrawImage) \ 47 M(DrawImageRect) \ 48 M(DrawDRRect) \ 49 M(DrawOval) \ 50 M(DrawPaint) \ 51 M(DrawPath) \ 52 M(DrawPatch) \ 53 M(DrawPicture) \ 54 M(DrawPoints) \ 55 M(DrawPosText) \ 56 M(DrawPosTextH) \ 57 M(DrawText) \ 58 M(DrawTextOnPath) \ 59 M(DrawRRect) \ 60 M(DrawRect) \ 61 M(DrawSprite) \ 62 M(DrawTextBlob) \ 63 M(DrawVertices) 64 65 // Defines SkRecords::Type, an enum of all record types. 66 #define ENUM(T) T##_Type, 67 enum Type { SK_RECORD_TYPES(ENUM) }; 68 #undef ENUM 69 70 // Macros to make it easier to define a record for a draw call with 0 args, 1 args, 2 args, etc. 71 // These should be clearer when you look at their use below. 72 #define RECORD0(T) \ 73 struct T { \ 74 static const Type kType = T##_Type; \ 75 }; 76 77 // We try to be flexible about the types the constructors take. Instead of requring the exact type 78 // A here, we take any type Z which implicitly casts to A. This allows the delay_copy() trick to 79 // work, allowing the caller to decide whether to pass by value or by const&. 80 81 #define RECORD1(T, A, a) \ 82 struct T { \ 83 static const Type kType = T##_Type; \ 84 template <typename Z> \ 85 T(Z a) : a(a) {} \ 86 A a; \ 87 }; 88 89 #define RECORD2(T, A, a, B, b) \ 90 struct T { \ 91 static const Type kType = T##_Type; \ 92 template <typename Z, typename Y> \ 93 T(Z a, Y b) : a(a), b(b) {} \ 94 A a; B b; \ 95 }; 96 97 #define RECORD3(T, A, a, B, b, C, c) \ 98 struct T { \ 99 static const Type kType = T##_Type; \ 100 template <typename Z, typename Y, typename X> \ 101 T(Z a, Y b, X c) : a(a), b(b), c(c) {} \ 102 A a; B b; C c; \ 103 }; 104 105 #define RECORD4(T, A, a, B, b, C, c, D, d) \ 106 struct T { \ 107 static const Type kType = T##_Type; \ 108 template <typename Z, typename Y, typename X, typename W> \ 109 T(Z a, Y b, X c, W d) : a(a), b(b), c(c), d(d) {} \ 110 A a; B b; C c; D d; \ 111 }; 112 113 #define RECORD5(T, A, a, B, b, C, c, D, d, E, e) \ 114 struct T { \ 115 static const Type kType = T##_Type; \ 116 template <typename Z, typename Y, typename X, typename W, typename V> \ 117 T(Z a, Y b, X c, W d, V e) : a(a), b(b), c(c), d(d), e(e) {} \ 118 A a; B b; C c; D d; E e; \ 119 }; 120 121 #define ACT_AS_PTR(ptr) \ 122 operator T*() const { return ptr; } \ 123 T* operator->() const { return ptr; } 124 125 template <typename T> 126 class RefBox : SkNoncopyable { 127 public: RefBox(T * obj)128 RefBox(T* obj) : fObj(SkSafeRef(obj)) {} ~RefBox()129 ~RefBox() { SkSafeUnref(fObj); } 130 131 ACT_AS_PTR(fObj); 132 133 private: 134 T* fObj; 135 }; 136 137 // An Optional doesn't own the pointer's memory, but may need to destroy non-POD data. 138 template <typename T> 139 class Optional : SkNoncopyable { 140 public: Optional(T * ptr)141 Optional(T* ptr) : fPtr(ptr) {} ~Optional()142 ~Optional() { if (fPtr) fPtr->~T(); } 143 144 ACT_AS_PTR(fPtr); 145 private: 146 T* fPtr; 147 }; 148 149 // Like Optional, but ptr must not be NULL. 150 template <typename T> 151 class Adopted : SkNoncopyable { 152 public: Adopted(T * ptr)153 Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); } Adopted(Adopted * source)154 Adopted(Adopted* source) { 155 // Transfer ownership from source to this. 156 fPtr = source->fPtr; 157 source->fPtr = NULL; 158 } ~Adopted()159 ~Adopted() { if (fPtr) fPtr->~T(); } 160 161 ACT_AS_PTR(fPtr); 162 private: 163 T* fPtr; 164 }; 165 166 // PODArray doesn't own the pointer's memory, and we assume the data is POD. 167 template <typename T> 168 class PODArray { 169 public: PODArray(T * ptr)170 PODArray(T* ptr) : fPtr(ptr) {} 171 // Default copy and assign. 172 173 ACT_AS_PTR(fPtr); 174 private: 175 T* fPtr; 176 }; 177 178 #undef ACT_AS_PTR 179 180 // Like SkBitmap, but deep copies pixels if they're not immutable. 181 // Using this, we guarantee the immutability of all bitmaps we record. 182 class ImmutableBitmap : SkNoncopyable { 183 public: ImmutableBitmap(const SkBitmap & bitmap)184 explicit ImmutableBitmap(const SkBitmap& bitmap) { 185 if (bitmap.isImmutable()) { 186 fBitmap = bitmap; 187 } else { 188 bitmap.copyTo(&fBitmap); 189 } 190 fBitmap.setImmutable(); 191 } 192 width()193 int width() const { return fBitmap.width(); } height()194 int height() const { return fBitmap.height(); } 195 196 // While the pixels are immutable, SkBitmap itself is not thread-safe, so return a copy. shallowCopy()197 SkBitmap shallowCopy() const { return fBitmap; } 198 private: 199 SkBitmap fBitmap; 200 }; 201 202 // SkPath::getBounds() isn't thread safe unless we precache the bounds in a singlethreaded context. 203 // SkPath::cheapComputeDirection() is similar. 204 // Recording is a convenient time to cache these, or we can delay it to between record and playback. 205 struct PreCachedPath : public SkPath { PreCachedPathPreCachedPath206 explicit PreCachedPath(const SkPath& path) : SkPath(path) { 207 this->updateBoundsCache(); 208 SkPath::Direction junk; 209 (void)this->cheapComputeDirection(&junk); 210 } 211 }; 212 213 // Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it. 214 // This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader). 215 struct TypedMatrix : public SkMatrix { TypedMatrixTypedMatrix216 explicit TypedMatrix(const SkMatrix& matrix) : SkMatrix(matrix) { 217 (void)this->getType(); 218 } 219 }; 220 221 RECORD0(NoOp); 222 223 RECORD2(Restore, SkIRect, devBounds, TypedMatrix, matrix); 224 RECORD0(Save); 225 RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags); 226 227 RECORD1(SetMatrix, TypedMatrix, matrix); 228 229 struct RegionOpAndAA { RegionOpAndAARegionOpAndAA230 RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {} 231 SkRegion::Op op : 31; // This really only needs to be 3, but there's no win today to do so. 232 unsigned aa : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. 233 }; 234 SK_COMPILE_ASSERT(sizeof(RegionOpAndAA) == 4, RegionOpAndAASize); 235 236 RECORD3(ClipPath, SkIRect, devBounds, PreCachedPath, path, RegionOpAndAA, opAA); 237 RECORD3(ClipRRect, SkIRect, devBounds, SkRRect, rrect, RegionOpAndAA, opAA); 238 RECORD3(ClipRect, SkIRect, devBounds, SkRect, rect, RegionOpAndAA, opAA); 239 RECORD3(ClipRegion, SkIRect, devBounds, SkRegion, region, SkRegion::Op, op); 240 241 RECORD1(BeginCommentGroup, PODArray<char>, description); 242 RECORD2(AddComment, PODArray<char>, key, PODArray<char>, value); 243 RECORD0(EndCommentGroup); 244 245 // While not strictly required, if you have an SkPaint, it's fastest to put it first. 246 RECORD4(DrawBitmap, Optional<SkPaint>, paint, 247 ImmutableBitmap, bitmap, 248 SkScalar, left, 249 SkScalar, top); 250 RECORD4(DrawBitmapNine, Optional<SkPaint>, paint, 251 ImmutableBitmap, bitmap, 252 SkIRect, center, 253 SkRect, dst); 254 RECORD4(DrawBitmapRectToRect, Optional<SkPaint>, paint, 255 ImmutableBitmap, bitmap, 256 Optional<SkRect>, src, 257 SkRect, dst); 258 RECORD4(DrawBitmapRectToRectBleed, Optional<SkPaint>, paint, 259 ImmutableBitmap, bitmap, 260 Optional<SkRect>, src, 261 SkRect, dst); 262 RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner); 263 RECORD2(DrawDrawable, SkRect, worstCaseBounds, int32_t, index); 264 RECORD4(DrawImage, Optional<SkPaint>, paint, 265 RefBox<const SkImage>, image, 266 SkScalar, left, 267 SkScalar, top); 268 RECORD4(DrawImageRect, Optional<SkPaint>, paint, 269 RefBox<const SkImage>, image, 270 Optional<SkRect>, src, 271 SkRect, dst); 272 RECORD2(DrawOval, SkPaint, paint, SkRect, oval); 273 RECORD1(DrawPaint, SkPaint, paint); 274 RECORD2(DrawPath, SkPaint, paint, PreCachedPath, path); 275 RECORD3(DrawPicture, Optional<SkPaint>, paint, 276 RefBox<const SkPicture>, picture, 277 TypedMatrix, matrix); 278 RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, unsigned, count, SkPoint*, pts); 279 RECORD4(DrawPosText, SkPaint, paint, 280 PODArray<char>, text, 281 size_t, byteLength, 282 PODArray<SkPoint>, pos); 283 RECORD5(DrawPosTextH, SkPaint, paint, 284 PODArray<char>, text, 285 unsigned, byteLength, 286 SkScalar, y, 287 PODArray<SkScalar>, xpos); 288 RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect); 289 RECORD2(DrawRect, SkPaint, paint, SkRect, rect); 290 RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top); 291 RECORD5(DrawText, SkPaint, paint, 292 PODArray<char>, text, 293 size_t, byteLength, 294 SkScalar, x, 295 SkScalar, y); 296 RECORD4(DrawTextBlob, SkPaint, paint, 297 RefBox<const SkTextBlob>, blob, 298 SkScalar, x, 299 SkScalar, y); 300 RECORD5(DrawTextOnPath, SkPaint, paint, 301 PODArray<char>, text, 302 size_t, byteLength, 303 PreCachedPath, path, 304 TypedMatrix, matrix); 305 306 RECORD5(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. 313 struct DrawVertices { 314 static const Type kType = DrawVertices_Type; 315 DrawVerticesDrawVertices316 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