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 "SkPicture.h" 13#include "SkTextBlob.h" 14 15namespace SkRecords { 16 17// A list of all the types of canvas calls we can record. 18// Each of these is reified into a struct below. 19// 20// (We're using the macro-of-macro trick here to do several different things with the same list.) 21// 22// We leave this SK_RECORD_TYPES macro defined for use by code that wants to operate on SkRecords 23// types polymorphically. (See SkRecord::Record::{visit,mutate} for an example.) 24// 25// Order doesn't technically matter here, but the compiler can generally generate better code if 26// you keep them semantically grouped, especially the Draws. It's also nice to leave NoOp at 0. 27#define SK_RECORD_TYPES(M) \ 28 M(NoOp) \ 29 M(Restore) \ 30 M(Save) \ 31 M(SaveLayer) \ 32 M(PushCull) \ 33 M(PopCull) \ 34 M(SetMatrix) \ 35 M(ClipPath) \ 36 M(ClipRRect) \ 37 M(ClipRect) \ 38 M(ClipRegion) \ 39 M(Clear) \ 40 M(BeginCommentGroup) \ 41 M(AddComment) \ 42 M(EndCommentGroup) \ 43 M(DrawBitmap) \ 44 M(DrawBitmapMatrix) \ 45 M(DrawBitmapNine) \ 46 M(DrawBitmapRectToRect) \ 47 M(DrawDRRect) \ 48 M(DrawOval) \ 49 M(DrawPaint) \ 50 M(DrawPath) \ 51 M(DrawPatch) \ 52 M(DrawPicture) \ 53 M(DrawPoints) \ 54 M(DrawPosText) \ 55 M(DrawPosTextH) \ 56 M(DrawText) \ 57 M(DrawTextOnPath) \ 58 M(DrawRRect) \ 59 M(DrawRect) \ 60 M(DrawSprite) \ 61 M(DrawTextBlob) \ 62 M(DrawData) \ 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 operator const SkBitmap& () const { return fBitmap; } 194 195private: 196 SkBitmap fBitmap; 197}; 198 199RECORD0(NoOp); 200 201RECORD2(Restore, SkIRect, devBounds, SkMatrix, matrix); 202RECORD0(Save); 203RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags); 204 205RECORD1(PushCull, SkRect, rect); 206RECORD0(PopCull); 207 208RECORD1(SetMatrix, SkMatrix, matrix); 209 210RECORD4(ClipPath, SkIRect, devBounds, SkPath, path, SkRegion::Op, op, bool, doAA); 211RECORD4(ClipRRect, SkIRect, devBounds, SkRRect, rrect, SkRegion::Op, op, bool, doAA); 212RECORD4(ClipRect, SkIRect, devBounds, SkRect, rect, SkRegion::Op, op, bool, doAA); 213RECORD3(ClipRegion, SkIRect, devBounds, SkRegion, region, SkRegion::Op, op); 214 215RECORD1(Clear, SkColor, color); 216 217RECORD1(BeginCommentGroup, PODArray<char>, description); 218RECORD2(AddComment, PODArray<char>, key, PODArray<char>, value); 219RECORD0(EndCommentGroup); 220 221// While not strictly required, if you have an SkPaint, it's fastest to put it first. 222RECORD4(DrawBitmap, Optional<SkPaint>, paint, 223 ImmutableBitmap, bitmap, 224 SkScalar, left, 225 SkScalar, top); 226RECORD3(DrawBitmapMatrix, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, SkMatrix, matrix); 227RECORD4(DrawBitmapNine, Optional<SkPaint>, paint, 228 ImmutableBitmap, bitmap, 229 SkIRect, center, 230 SkRect, dst); 231RECORD5(DrawBitmapRectToRect, Optional<SkPaint>, paint, 232 ImmutableBitmap, bitmap, 233 Optional<SkRect>, src, 234 SkRect, dst, 235 SkCanvas::DrawBitmapRectFlags, flags); 236RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner); 237RECORD2(DrawOval, SkPaint, paint, SkRect, oval); 238RECORD1(DrawPaint, SkPaint, paint); 239RECORD2(DrawPath, SkPaint, paint, SkPath, path); 240RECORD3(DrawPicture, Optional<SkPaint>, paint, 241 RefBox<const SkPicture>, picture, 242 Optional<SkMatrix>, matrix); 243RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, size_t, count, SkPoint*, pts); 244RECORD4(DrawPosText, SkPaint, paint, 245 PODArray<char>, text, 246 size_t, byteLength, 247 PODArray<SkPoint>, pos); 248RECORD5(DrawPosTextH, SkPaint, paint, 249 PODArray<char>, text, 250 size_t, byteLength, 251 PODArray<SkScalar>, xpos, 252 SkScalar, y); 253RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect); 254RECORD2(DrawRect, SkPaint, paint, SkRect, rect); 255RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top); 256RECORD5(DrawText, SkPaint, paint, 257 PODArray<char>, text, 258 size_t, byteLength, 259 SkScalar, x, 260 SkScalar, y); 261RECORD4(DrawTextBlob, SkPaint, paint, 262 RefBox<const SkTextBlob>, blob, 263 SkScalar, x, 264 SkScalar, y); 265RECORD5(DrawTextOnPath, SkPaint, paint, 266 PODArray<char>, text, 267 size_t, byteLength, 268 SkPath, path, 269 Optional<SkMatrix>, matrix); 270 271RECORD2(DrawData, PODArray<char>, data, size_t, length); 272 273RECORD5(DrawPatch, SkPaint, paint, 274 PODArray<SkPoint>, cubics, 275 PODArray<SkColor>, colors, 276 PODArray<SkPoint>, texCoords, 277 RefBox<SkXfermode>, xmode); 278 279// This guy is so ugly we just write it manually. 280struct DrawVertices { 281 static const Type kType = DrawVertices_Type; 282 283 DrawVertices(const SkPaint& paint, 284 SkCanvas::VertexMode vmode, 285 int vertexCount, 286 SkPoint* vertices, 287 SkPoint* texs, 288 SkColor* colors, 289 SkXfermode* xmode, 290 uint16_t* indices, 291 int indexCount) 292 : paint(paint) 293 , vmode(vmode) 294 , vertexCount(vertexCount) 295 , vertices(vertices) 296 , texs(texs) 297 , colors(colors) 298 , xmode(SkSafeRef(xmode)) 299 , indices(indices) 300 , indexCount(indexCount) {} 301 302 SkPaint paint; 303 SkCanvas::VertexMode vmode; 304 int vertexCount; 305 PODArray<SkPoint> vertices; 306 PODArray<SkPoint> texs; 307 PODArray<SkColor> colors; 308 SkAutoTUnref<SkXfermode> xmode; 309 PODArray<uint16_t> indices; 310 int indexCount; 311}; 312 313#undef RECORD0 314#undef RECORD1 315#undef RECORD2 316#undef RECORD3 317#undef RECORD4 318#undef RECORD5 319 320} // namespace SkRecords 321 322#endif//SkRecords_DEFINED 323