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 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(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, 67enum 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) \ 73struct 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) \ 82struct 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) \ 90struct 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) \ 98struct 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) \ 106struct 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) \ 114struct 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 125template <typename T> 126class RefBox : SkNoncopyable { 127public: 128 RefBox(T* obj) : fObj(SkSafeRef(obj)) {} 129 ~RefBox() { SkSafeUnref(fObj); } 130 131 ACT_AS_PTR(fObj); 132 133private: 134 T* fObj; 135}; 136 137// An Optional doesn't own the pointer's memory, but may need to destroy non-POD data. 138template <typename T> 139class Optional : SkNoncopyable { 140public: 141 Optional(T* ptr) : fPtr(ptr) {} 142 ~Optional() { if (fPtr) fPtr->~T(); } 143 144 ACT_AS_PTR(fPtr); 145private: 146 T* fPtr; 147}; 148 149// Like Optional, but ptr must not be NULL. 150template <typename T> 151class Adopted : SkNoncopyable { 152public: 153 Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); } 154 Adopted(Adopted* source) { 155 // Transfer ownership from source to this. 156 fPtr = source->fPtr; 157 source->fPtr = NULL; 158 } 159 ~Adopted() { if (fPtr) fPtr->~T(); } 160 161 ACT_AS_PTR(fPtr); 162private: 163 T* fPtr; 164}; 165 166// PODArray doesn't own the pointer's memory, and we assume the data is POD. 167template <typename T> 168class PODArray { 169public: 170 PODArray(T* ptr) : fPtr(ptr) {} 171 // Default copy and assign. 172 173 ACT_AS_PTR(fPtr); 174private: 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. 182class ImmutableBitmap : SkNoncopyable { 183public: 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 193 int width() const { return fBitmap.width(); } 194 int height() const { return fBitmap.height(); } 195 196 // While the pixels are immutable, SkBitmap itself is not thread-safe, so return a copy. 197 SkBitmap shallowCopy() const { return fBitmap; } 198private: 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. 205struct PreCachedPath : public SkPath { 206 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). 215struct TypedMatrix : public SkMatrix { 216 explicit TypedMatrix(const SkMatrix& matrix) : SkMatrix(matrix) { 217 (void)this->getType(); 218 } 219}; 220 221RECORD0(NoOp); 222 223RECORD2(Restore, SkIRect, devBounds, TypedMatrix, matrix); 224RECORD0(Save); 225RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags); 226 227RECORD1(SetMatrix, TypedMatrix, matrix); 228 229struct RegionOpAndAA { 230 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}; 234SK_COMPILE_ASSERT(sizeof(RegionOpAndAA) == 4, RegionOpAndAASize); 235 236RECORD3(ClipPath, SkIRect, devBounds, PreCachedPath, path, RegionOpAndAA, opAA); 237RECORD3(ClipRRect, SkIRect, devBounds, SkRRect, rrect, RegionOpAndAA, opAA); 238RECORD3(ClipRect, SkIRect, devBounds, SkRect, rect, RegionOpAndAA, opAA); 239RECORD3(ClipRegion, SkIRect, devBounds, SkRegion, region, SkRegion::Op, op); 240 241RECORD1(BeginCommentGroup, PODArray<char>, description); 242RECORD2(AddComment, PODArray<char>, key, PODArray<char>, value); 243RECORD0(EndCommentGroup); 244 245// While not strictly required, if you have an SkPaint, it's fastest to put it first. 246RECORD4(DrawBitmap, Optional<SkPaint>, paint, 247 ImmutableBitmap, bitmap, 248 SkScalar, left, 249 SkScalar, top); 250RECORD4(DrawBitmapNine, Optional<SkPaint>, paint, 251 ImmutableBitmap, bitmap, 252 SkIRect, center, 253 SkRect, dst); 254RECORD4(DrawBitmapRectToRect, Optional<SkPaint>, paint, 255 ImmutableBitmap, bitmap, 256 Optional<SkRect>, src, 257 SkRect, dst); 258RECORD4(DrawBitmapRectToRectBleed, Optional<SkPaint>, paint, 259 ImmutableBitmap, bitmap, 260 Optional<SkRect>, src, 261 SkRect, dst); 262RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner); 263RECORD2(DrawDrawable, SkRect, worstCaseBounds, int32_t, index); 264RECORD4(DrawImage, Optional<SkPaint>, paint, 265 RefBox<const SkImage>, image, 266 SkScalar, left, 267 SkScalar, top); 268RECORD4(DrawImageRect, Optional<SkPaint>, paint, 269 RefBox<const SkImage>, image, 270 Optional<SkRect>, src, 271 SkRect, dst); 272RECORD2(DrawOval, SkPaint, paint, SkRect, oval); 273RECORD1(DrawPaint, SkPaint, paint); 274RECORD2(DrawPath, SkPaint, paint, PreCachedPath, path); 275RECORD3(DrawPicture, Optional<SkPaint>, paint, 276 RefBox<const SkPicture>, picture, 277 TypedMatrix, matrix); 278RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, unsigned, count, SkPoint*, pts); 279RECORD4(DrawPosText, SkPaint, paint, 280 PODArray<char>, text, 281 size_t, byteLength, 282 PODArray<SkPoint>, pos); 283RECORD5(DrawPosTextH, SkPaint, paint, 284 PODArray<char>, text, 285 unsigned, byteLength, 286 SkScalar, y, 287 PODArray<SkScalar>, xpos); 288RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect); 289RECORD2(DrawRect, SkPaint, paint, SkRect, rect); 290RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top); 291RECORD5(DrawText, SkPaint, paint, 292 PODArray<char>, text, 293 size_t, byteLength, 294 SkScalar, x, 295 SkScalar, y); 296RECORD4(DrawTextBlob, SkPaint, paint, 297 RefBox<const SkTextBlob>, blob, 298 SkScalar, x, 299 SkScalar, y); 300RECORD5(DrawTextOnPath, SkPaint, paint, 301 PODArray<char>, text, 302 size_t, byteLength, 303 PreCachedPath, path, 304 TypedMatrix, matrix); 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