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 13namespace SkRecords { 14 15// A list of all the types of canvas calls we can record. 16// Each of these is reified into a struct below. 17// 18// (We're using the macro-of-macro trick here to do several different things with the same list.) 19// 20// We leave this SK_RECORD_TYPES macro defined for use by code that wants to operate on SkRecords 21// types polymorphically. (See SkRecord::Record::{visit,mutate} for an example.) 22// 23// Order doesn't technically matter here, but the compiler can generally generate better code if 24// you keep them semantically grouped, especially the Draws. It's also nice to leave NoOp at 0. 25#define SK_RECORD_TYPES(M) \ 26 M(NoOp) \ 27 M(Restore) \ 28 M(Save) \ 29 M(SaveLayer) \ 30 M(PushCull) \ 31 M(PopCull) \ 32 M(PairedPushCull) /*From SkRecordAnnotateCullingPairs*/ \ 33 M(Concat) \ 34 M(SetMatrix) \ 35 M(ClipPath) \ 36 M(ClipRRect) \ 37 M(ClipRect) \ 38 M(ClipRegion) \ 39 M(Clear) \ 40 M(DrawBitmap) \ 41 M(DrawBitmapMatrix) \ 42 M(DrawBitmapNine) \ 43 M(DrawBitmapRectToRect) \ 44 M(DrawDRRect) \ 45 M(DrawOval) \ 46 M(DrawPaint) \ 47 M(DrawPath) \ 48 M(DrawPoints) \ 49 M(DrawPosText) \ 50 M(DrawPosTextH) \ 51 M(DrawRRect) \ 52 M(DrawRect) \ 53 M(DrawSprite) \ 54 M(DrawText) \ 55 M(DrawTextOnPath) \ 56 M(DrawVertices) \ 57 M(BoundedDrawPosTextH) /*From SkRecordBoundDrawPosTextH*/ 58 59// Defines SkRecords::Type, an enum of all record types. 60#define ENUM(T) T##_Type, 61enum Type { SK_RECORD_TYPES(ENUM) }; 62#undef ENUM 63 64// Macros to make it easier to define a record for a draw call with 0 args, 1 args, 2 args, etc. 65// These should be clearer when you look at their use below. 66#define RECORD0(T) \ 67struct T { \ 68 static const Type kType = T##_Type; \ 69}; 70 71// We try to be flexible about the types the constructors take. Instead of requring the exact type 72// A here, we take any type Z which implicitly casts to A. This allows the delay_copy() trick to 73// work, allowing the caller to decide whether to pass by value or by const&. 74 75#define RECORD1(T, A, a) \ 76struct T { \ 77 static const Type kType = T##_Type; \ 78 template <typename Z> \ 79 T(Z a) : a(a) {} \ 80 A a; \ 81}; 82 83#define RECORD2(T, A, a, B, b) \ 84struct T { \ 85 static const Type kType = T##_Type; \ 86 template <typename Z, typename Y> \ 87 T(Z a, Y b) : a(a), b(b) {} \ 88 A a; B b; \ 89}; 90 91#define RECORD3(T, A, a, B, b, C, c) \ 92struct T { \ 93 static const Type kType = T##_Type; \ 94 template <typename Z, typename Y, typename X> \ 95 T(Z a, Y b, X c) : a(a), b(b), c(c) {} \ 96 A a; B b; C c; \ 97}; 98 99#define RECORD4(T, A, a, B, b, C, c, D, d) \ 100struct T { \ 101 static const Type kType = T##_Type; \ 102 template <typename Z, typename Y, typename X, typename W> \ 103 T(Z a, Y b, X c, W d) : a(a), b(b), c(c), d(d) {} \ 104 A a; B b; C c; D d; \ 105}; 106 107#define RECORD5(T, A, a, B, b, C, c, D, d, E, e) \ 108struct T { \ 109 static const Type kType = T##_Type; \ 110 template <typename Z, typename Y, typename X, typename W, typename V> \ 111 T(Z a, Y b, X c, W d, V e) : a(a), b(b), c(c), d(d), e(e) {} \ 112 A a; B b; C c; D d; E e; \ 113}; 114 115#define ACT_AS_PTR(ptr) \ 116 operator T*() { return ptr; } \ 117 operator const T*() const { return ptr; } \ 118 T* operator->() { return ptr; } \ 119 const T* operator->() const { return ptr; } 120 121// An Optional doesn't own the pointer's memory, but may need to destroy non-POD data. 122template <typename T> 123class Optional : SkNoncopyable { 124public: 125 Optional(T* ptr) : fPtr(ptr) {} 126 ~Optional() { if (fPtr) fPtr->~T(); } 127 128 ACT_AS_PTR(fPtr); 129private: 130 T* fPtr; 131}; 132 133// Like Optional, but ptr must not be NULL. 134template <typename T> 135class Adopted : SkNoncopyable { 136public: 137 Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); } 138 Adopted(Adopted* source) { 139 // Transfer ownership from source to this. 140 fPtr = source->fPtr; 141 source->fPtr = NULL; 142 } 143 ~Adopted() { if (fPtr) fPtr->~T(); } 144 145 ACT_AS_PTR(fPtr); 146private: 147 T* fPtr; 148}; 149 150// PODArray doesn't own the pointer's memory, and we assume the data is POD. 151template <typename T> 152class PODArray { 153public: 154 PODArray(T* ptr) : fPtr(ptr) {} 155 // Default copy and assign. 156 157 ACT_AS_PTR(fPtr); 158private: 159 T* fPtr; 160}; 161 162#undef ACT_AS_PTR 163 164// Like SkBitmap, but deep copies pixels if they're not immutable. 165// Using this, we guarantee the immutability of all bitmaps we record. 166class ImmutableBitmap { 167public: 168 explicit ImmutableBitmap(const SkBitmap& bitmap) { 169 if (bitmap.isImmutable()) { 170 fBitmap = bitmap; 171 } else { 172 bitmap.copyTo(&fBitmap); 173 } 174 fBitmap.setImmutable(); 175 } 176 177 operator const SkBitmap& () const { return fBitmap; } 178 179private: 180 SkBitmap fBitmap; 181}; 182 183RECORD0(NoOp); 184 185RECORD0(Restore); 186RECORD1(Save, SkCanvas::SaveFlags, flags); 187RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas::SaveFlags, flags); 188 189RECORD1(PushCull, SkRect, rect); 190RECORD0(PopCull); 191 192RECORD1(Concat, SkMatrix, matrix); 193RECORD1(SetMatrix, SkMatrix, matrix); 194 195RECORD3(ClipPath, SkPath, path, SkRegion::Op, op, bool, doAA); 196RECORD3(ClipRRect, SkRRect, rrect, SkRegion::Op, op, bool, doAA); 197RECORD3(ClipRect, SkRect, rect, SkRegion::Op, op, bool, doAA); 198RECORD2(ClipRegion, SkRegion, region, SkRegion::Op, op); 199 200RECORD1(Clear, SkColor, color); 201// While not strictly required, if you have an SkPaint, it's fastest to put it first. 202RECORD4(DrawBitmap, Optional<SkPaint>, paint, 203 ImmutableBitmap, bitmap, 204 SkScalar, left, 205 SkScalar, top); 206RECORD3(DrawBitmapMatrix, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, SkMatrix, matrix); 207RECORD4(DrawBitmapNine, Optional<SkPaint>, paint, 208 ImmutableBitmap, bitmap, 209 SkIRect, center, 210 SkRect, dst); 211RECORD5(DrawBitmapRectToRect, Optional<SkPaint>, paint, 212 ImmutableBitmap, bitmap, 213 Optional<SkRect>, src, 214 SkRect, dst, 215 SkCanvas::DrawBitmapRectFlags, flags); 216RECORD3(DrawDRRect, SkPaint, paint, SkRRect, outer, SkRRect, inner); 217RECORD2(DrawOval, SkPaint, paint, SkRect, oval); 218RECORD1(DrawPaint, SkPaint, paint); 219RECORD2(DrawPath, SkPaint, paint, SkPath, path); 220RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, size_t, count, SkPoint*, pts); 221RECORD4(DrawPosText, SkPaint, paint, 222 PODArray<char>, text, 223 size_t, byteLength, 224 PODArray<SkPoint>, pos); 225RECORD5(DrawPosTextH, SkPaint, paint, 226 PODArray<char>, text, 227 size_t, byteLength, 228 PODArray<SkScalar>, xpos, 229 SkScalar, y); 230RECORD2(DrawRRect, SkPaint, paint, SkRRect, rrect); 231RECORD2(DrawRect, SkPaint, paint, SkRect, rect); 232RECORD4(DrawSprite, Optional<SkPaint>, paint, ImmutableBitmap, bitmap, int, left, int, top); 233RECORD5(DrawText, SkPaint, paint, 234 PODArray<char>, text, 235 size_t, byteLength, 236 SkScalar, x, 237 SkScalar, y); 238RECORD5(DrawTextOnPath, SkPaint, paint, 239 PODArray<char>, text, 240 size_t, byteLength, 241 SkPath, path, 242 Optional<SkMatrix>, matrix); 243 244// This guy is so ugly we just write it manually. 245struct DrawVertices { 246 static const Type kType = DrawVertices_Type; 247 248 DrawVertices(const SkPaint& paint, 249 SkCanvas::VertexMode vmode, 250 int vertexCount, 251 SkPoint* vertices, 252 SkPoint* texs, 253 SkColor* colors, 254 SkXfermode* xmode, 255 uint16_t* indices, 256 int indexCount) 257 : paint(paint) 258 , vmode(vmode) 259 , vertexCount(vertexCount) 260 , vertices(vertices) 261 , texs(texs) 262 , colors(colors) 263 , xmode(SkSafeRef(xmode)) 264 , indices(indices) 265 , indexCount(indexCount) {} 266 267 SkPaint paint; 268 SkCanvas::VertexMode vmode; 269 int vertexCount; 270 PODArray<SkPoint> vertices; 271 PODArray<SkPoint> texs; 272 PODArray<SkColor> colors; 273 SkAutoTUnref<SkXfermode> xmode; 274 PODArray<uint16_t> indices; 275 int indexCount; 276}; 277 278// Records added by optimizations. 279RECORD2(PairedPushCull, Adopted<PushCull>, base, unsigned, skip); 280RECORD3(BoundedDrawPosTextH, Adopted<DrawPosTextH>, base, SkScalar, minY, SkScalar, maxY); 281 282#undef RECORD0 283#undef RECORD1 284#undef RECORD2 285#undef RECORD3 286#undef RECORD4 287#undef RECORD5 288 289} // namespace SkRecords 290 291#endif//SkRecords_DEFINED 292