gfx/skia/trunk/src/core/SkPictureRecord.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /*
michael@0 2 * Copyright 2011 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7
michael@0 8 #include "SkPictureRecord.h"
michael@0 9 #include "SkTSearch.h"
michael@0 10 #include "SkPixelRef.h"
michael@0 11 #include "SkRRect.h"
michael@0 12 #include "SkBBoxHierarchy.h"
michael@0 13 #include "SkDevice.h"
michael@0 14 #include "SkOffsetTable.h"
michael@0 15 #include "SkPictureStateTree.h"
michael@0 16 #include "SkSurface.h"
michael@0 17
michael@0 18 #define HEAP_BLOCK_SIZE 4096
michael@0 19
michael@0 20 enum {
michael@0 21 // just need a value that save or getSaveCount would never return
michael@0 22 kNoInitialSave = -1,
michael@0 23 };
michael@0 24
michael@0 25 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
michael@0 26 static int const kUInt32Size = 4;
michael@0 27
michael@0 28 static const uint32_t kSaveSize = 2 * kUInt32Size;
michael@0 29 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
michael@0 30 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
michael@0 31
michael@0 32 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
michael@0 33 : INHERITED(dimensions.width(), dimensions.height())
michael@0 34 , fBoundingHierarchy(NULL)
michael@0 35 , fStateTree(NULL)
michael@0 36 , fFlattenableHeap(HEAP_BLOCK_SIZE)
michael@0 37 , fPaints(&fFlattenableHeap)
michael@0 38 , fRecordFlags(flags)
michael@0 39 , fOptsEnabled(true) {
michael@0 40 #ifdef SK_DEBUG_SIZE
michael@0 41 fPointBytes = fRectBytes = fTextBytes = 0;
michael@0 42 fPointWrites = fRectWrites = fTextWrites = 0;
michael@0 43 #endif
michael@0 44
michael@0 45 fBitmapHeap = SkNEW(SkBitmapHeap);
michael@0 46 fFlattenableHeap.setBitmapStorage(fBitmapHeap);
michael@0 47 fPathHeap = NULL; // lazy allocate
michael@0 48
michael@0 49 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 50 fFirstSavedLayerIndex = kNoSavedLayerIndex;
michael@0 51 #endif
michael@0 52
michael@0 53 fInitialSaveCount = kNoInitialSave;
michael@0 54
michael@0 55 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 56 fMCMgr.init(this);
michael@0 57 #endif
michael@0 58 }
michael@0 59
michael@0 60 SkPictureRecord::~SkPictureRecord() {
michael@0 61 SkSafeUnref(fBitmapHeap);
michael@0 62 SkSafeUnref(fPathHeap);
michael@0 63 SkSafeUnref(fBoundingHierarchy);
michael@0 64 SkSafeUnref(fStateTree);
michael@0 65 fFlattenableHeap.setBitmapStorage(NULL);
michael@0 66 fPictureRefs.unrefAll();
michael@0 67 }
michael@0 68
michael@0 69 ///////////////////////////////////////////////////////////////////////////////
michael@0 70
michael@0 71 // Return the offset of the paint inside a given op's byte stream. A zero
michael@0 72 // return value means there is no paint (and you really shouldn't be calling
michael@0 73 // this method)
michael@0 74 static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
michael@0 75 // These offsets are where the paint would be if the op size doesn't overflow
michael@0 76 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
michael@0 77 0, // UNUSED - no paint
michael@0 78 0, // CLIP_PATH - no paint
michael@0 79 0, // CLIP_REGION - no paint
michael@0 80 0, // CLIP_RECT - no paint
michael@0 81 0, // CLIP_RRECT - no paint
michael@0 82 0, // CONCAT - no paint
michael@0 83 1, // DRAW_BITMAP - right after op code
michael@0 84 1, // DRAW_BITMAP_MATRIX - right after op code
michael@0 85 1, // DRAW_BITMAP_NINE - right after op code
michael@0 86 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
michael@0 87 0, // DRAW_CLEAR - no paint
michael@0 88 0, // DRAW_DATA - no paint
michael@0 89 1, // DRAW_OVAL - right after op code
michael@0 90 1, // DRAW_PAINT - right after op code
michael@0 91 1, // DRAW_PATH - right after op code
michael@0 92 0, // DRAW_PICTURE - no paint
michael@0 93 1, // DRAW_POINTS - right after op code
michael@0 94 1, // DRAW_POS_TEXT - right after op code
michael@0 95 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
michael@0 96 1, // DRAW_POS_TEXT_H - right after op code
michael@0 97 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
michael@0 98 1, // DRAW_RECT - right after op code
michael@0 99 1, // DRAW_RRECT - right after op code
michael@0 100 1, // DRAW_SPRITE - right after op code
michael@0 101 1, // DRAW_TEXT - right after op code
michael@0 102 1, // DRAW_TEXT_ON_PATH - right after op code
michael@0 103 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
michael@0 104 1, // DRAW_VERTICES - right after op code
michael@0 105 0, // RESTORE - no paint
michael@0 106 0, // ROTATE - no paint
michael@0 107 0, // SAVE - no paint
michael@0 108 0, // SAVE_LAYER - see below - this paint's location varies
michael@0 109 0, // SCALE - no paint
michael@0 110 0, // SET_MATRIX - no paint
michael@0 111 0, // SKEW - no paint
michael@0 112 0, // TRANSLATE - no paint
michael@0 113 0, // NOOP - no paint
michael@0 114 0, // BEGIN_GROUP - no paint
michael@0 115 0, // COMMENT - no paint
michael@0 116 0, // END_GROUP - no paint
michael@0 117 1, // DRAWDRRECT - right after op code
michael@0 118 0, // PUSH_CULL - no paint
michael@0 119 0, // POP_CULL - no paint
michael@0 120 };
michael@0 121
michael@0 122 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
michael@0 123 need_to_be_in_sync);
michael@0 124 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
michael@0 125
michael@0 126 int overflow = 0;
michael@0 127 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
michael@0 128 // This op's size overflows so an extra uint32_t will be written
michael@0 129 // after the op code
michael@0 130 overflow = sizeof(uint32_t);
michael@0 131 }
michael@0 132
michael@0 133 if (SAVE_LAYER == op) {
michael@0 134 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
michael@0 135 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
michael@0 136
michael@0 137 if (kSaveLayerNoBoundsSize == opSize) {
michael@0 138 return kSaveLayerNoBoundsPaintOffset + overflow;
michael@0 139 } else {
michael@0 140 SkASSERT(kSaveLayerWithBoundsSize == opSize);
michael@0 141 return kSaveLayerWithBoundsPaintOffset + overflow;
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
michael@0 146 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
michael@0 147 }
michael@0 148
michael@0 149 void SkPictureRecord::willSave(SaveFlags flags) {
michael@0 150
michael@0 151 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 152 fMCMgr.save(flags);
michael@0 153 #else
michael@0 154 // record the offset to us, making it non-positive to distinguish a save
michael@0 155 // from a clip entry.
michael@0 156 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
michael@0 157 this->recordSave(flags);
michael@0 158 #endif
michael@0 159
michael@0 160 this->INHERITED::willSave(flags);
michael@0 161 }
michael@0 162
michael@0 163 void SkPictureRecord::recordSave(SaveFlags flags) {
michael@0 164 // op + flags
michael@0 165 uint32_t size = kSaveSize;
michael@0 166 size_t initialOffset = this->addDraw(SAVE, &size);
michael@0 167 this->addInt(flags);
michael@0 168
michael@0 169 this->validate(initialOffset, size);
michael@0 170 }
michael@0 171
michael@0 172 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
michael@0 173 const SkPaint* paint, SaveFlags flags) {
michael@0 174
michael@0 175 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 176 fMCMgr.saveLayer(bounds, paint, flags);
michael@0 177 #else
michael@0 178 // record the offset to us, making it non-positive to distinguish a save
michael@0 179 // from a clip entry.
michael@0 180 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
michael@0 181 this->recordSaveLayer(bounds, paint, flags);
michael@0 182 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
michael@0 183 fFirstSavedLayerIndex = fRestoreOffsetStack.count();
michael@0 184 }
michael@0 185 #endif
michael@0 186
michael@0 187 this->INHERITED::willSaveLayer(bounds, paint, flags);
michael@0 188 /* No need for a (potentially very big) layer which we don't actually need
michael@0 189 at this time (and may not be able to afford since during record our
michael@0 190 clip starts out the size of the picture, which is often much larger
michael@0 191 than the size of the actual device we'll use during playback).
michael@0 192 */
michael@0 193 return kNoLayer_SaveLayerStrategy;
michael@0 194 }
michael@0 195
michael@0 196 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
michael@0 197 SaveFlags flags) {
michael@0 198 // op + bool for 'bounds'
michael@0 199 uint32_t size = 2 * kUInt32Size;
michael@0 200 if (NULL != bounds) {
michael@0 201 size += sizeof(*bounds); // + rect
michael@0 202 }
michael@0 203 // + paint index + flags
michael@0 204 size += 2 * kUInt32Size;
michael@0 205
michael@0 206 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
michael@0 207
michael@0 208 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
michael@0 209 this->addRectPtr(bounds);
michael@0 210 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
michael@0 211 this->addPaintPtr(paint);
michael@0 212 this->addInt(flags);
michael@0 213
michael@0 214 this->validate(initialOffset, size);
michael@0 215 }
michael@0 216
michael@0 217 bool SkPictureRecord::isDrawingToLayer() const {
michael@0 218 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 219 return fMCMgr.isDrawingToLayer();
michael@0 220 #else
michael@0 221 return fFirstSavedLayerIndex != kNoSavedLayerIndex;
michael@0 222 #endif
michael@0 223 }
michael@0 224
michael@0 225 /*
michael@0 226 * Read the op code from 'offset' in 'writer'.
michael@0 227 */
michael@0 228 #ifdef SK_DEBUG
michael@0 229 static DrawType peek_op(SkWriter32* writer, int32_t offset) {
michael@0 230 return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
michael@0 231 }
michael@0 232 #endif
michael@0 233
michael@0 234 /*
michael@0 235 * Read the op code from 'offset' in 'writer' and extract the size too.
michael@0 236 */
michael@0 237 static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
michael@0 238 uint32_t peek = writer->readTAt<uint32_t>(offset);
michael@0 239
michael@0 240 uint32_t op;
michael@0 241 UNPACK_8_24(peek, op, *size);
michael@0 242 if (MASK_24 == *size) {
michael@0 243 // size required its own slot right after the op code
michael@0 244 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
michael@0 245 }
michael@0 246 return (DrawType) op;
michael@0 247 }
michael@0 248
michael@0 249 #ifdef TRACK_COLLAPSE_STATS
michael@0 250 static int gCollapseCount, gCollapseCalls;
michael@0 251 #endif
michael@0 252
michael@0 253 // Is the supplied paint simply a color?
michael@0 254 static bool is_simple(const SkPaint& p) {
michael@0 255 intptr_t orAccum = (intptr_t)p.getPathEffect() |
michael@0 256 (intptr_t)p.getShader() |
michael@0 257 (intptr_t)p.getXfermode() |
michael@0 258 (intptr_t)p.getMaskFilter() |
michael@0 259 (intptr_t)p.getColorFilter() |
michael@0 260 (intptr_t)p.getRasterizer() |
michael@0 261 (intptr_t)p.getLooper() |
michael@0 262 (intptr_t)p.getImageFilter();
michael@0 263 return 0 == orAccum;
michael@0 264 }
michael@0 265
michael@0 266 // CommandInfos are fed to the 'match' method and filled in with command
michael@0 267 // information.
michael@0 268 struct CommandInfo {
michael@0 269 DrawType fActualOp;
michael@0 270 uint32_t fOffset;
michael@0 271 uint32_t fSize;
michael@0 272 };
michael@0 273
michael@0 274 /*
michael@0 275 * Attempt to match the provided pattern of commands starting at 'offset'
michael@0 276 * in the byte stream and stopping at the end of the stream. Upon success,
michael@0 277 * return true with all the pattern information filled out in the result
michael@0 278 * array (i.e., actual ops, offsets and sizes).
michael@0 279 * Note this method skips any NOOPs seen in the stream
michael@0 280 */
michael@0 281 static bool match(SkWriter32* writer, uint32_t offset,
michael@0 282 int* pattern, CommandInfo* result, int numCommands) {
michael@0 283 SkASSERT(offset < writer->bytesWritten());
michael@0 284
michael@0 285 uint32_t curOffset = offset;
michael@0 286 uint32_t curSize = 0;
michael@0 287 int numMatched;
michael@0 288 for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
michael@0 289 DrawType op = peek_op_and_size(writer, curOffset, &curSize);
michael@0 290 while (NOOP == op && curOffset < writer->bytesWritten()) {
michael@0 291 curOffset += curSize;
michael@0 292 op = peek_op_and_size(writer, curOffset, &curSize);
michael@0 293 }
michael@0 294
michael@0 295 if (curOffset >= writer->bytesWritten()) {
michael@0 296 return false; // ran out of byte stream
michael@0 297 }
michael@0 298
michael@0 299 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
michael@0 300 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
michael@0 301 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
michael@0 302 return false;
michael@0 303 }
michael@0 304 } else if (op != pattern[numMatched]) {
michael@0 305 return false;
michael@0 306 }
michael@0 307
michael@0 308 result[numMatched].fActualOp = op;
michael@0 309 result[numMatched].fOffset = curOffset;
michael@0 310 result[numMatched].fSize = curSize;
michael@0 311
michael@0 312 curOffset += curSize;
michael@0 313 }
michael@0 314
michael@0 315 if (numMatched != numCommands) {
michael@0 316 return false;
michael@0 317 }
michael@0 318
michael@0 319 curOffset += curSize;
michael@0 320 if (curOffset < writer->bytesWritten()) {
michael@0 321 // Something else between the last command and the end of the stream
michael@0 322 return false;
michael@0 323 }
michael@0 324
michael@0 325 return true;
michael@0 326 }
michael@0 327
michael@0 328 // temporarily here to make code review easier
michael@0 329 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
michael@0 330 SkPaintDictionary* paintDict,
michael@0 331 const CommandInfo& saveLayerInfo,
michael@0 332 const CommandInfo& dbmInfo);
michael@0 333
michael@0 334 /*
michael@0 335 * Restore has just been called (but not recorded), look back at the
michael@0 336 * matching save* and see if we are in the configuration:
michael@0 337 * SAVE_LAYER
michael@0 338 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
michael@0 339 * RESTORE
michael@0 340 * where the saveLayer's color can be moved into the drawBitmap*'s paint
michael@0 341 */
michael@0 342 static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
michael@0 343 SkPaintDictionary* paintDict) {
michael@0 344 // back up to the save block
michael@0 345 // TODO: add a stack to track save*/restore offsets rather than searching backwards
michael@0 346 while (offset > 0) {
michael@0 347 offset = writer->readTAt<uint32_t>(offset);
michael@0 348 }
michael@0 349
michael@0 350 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
michael@0 351 CommandInfo result[SK_ARRAY_COUNT(pattern)];
michael@0 352
michael@0 353 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
michael@0 354 return false;
michael@0 355 }
michael@0 356
michael@0 357 if (kSaveLayerWithBoundsSize == result[0].fSize) {
michael@0 358 // The saveLayer's bound can offset where the dbm is drawn
michael@0 359 return false;
michael@0 360 }
michael@0 361
michael@0 362 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
michael@0 363 result[0], result[1]);
michael@0 364 }
michael@0 365
michael@0 366 /*
michael@0 367 * Convert the command code located at 'offset' to a NOOP. Leave the size
michael@0 368 * field alone so the NOOP can be skipped later.
michael@0 369 */
michael@0 370 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
michael@0 371 uint32_t command = writer->readTAt<uint32_t>(offset);
michael@0 372 writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
michael@0 373 }
michael@0 374
michael@0 375 /*
michael@0 376 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
michael@0 377 * Return true on success; false otherwise.
michael@0 378 */
michael@0 379 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
michael@0 380 SkPaintDictionary* paintDict,
michael@0 381 const CommandInfo& saveLayerInfo,
michael@0 382 const CommandInfo& dbmInfo) {
michael@0 383 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
michael@0 384 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
michael@0 385 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
michael@0 386 DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
michael@0 387 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
michael@0 388
michael@0 389 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
michael@0 390 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
michael@0 391
michael@0 392 // we have a match, now we need to get the paints involved
michael@0 393 uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
michael@0 394 uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
michael@0 395
michael@0 396 if (0 == saveLayerPaintId) {
michael@0 397 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
michael@0 398 // and signal the caller (by returning true) to not add the RESTORE op
michael@0 399 convert_command_to_noop(writer, saveLayerInfo.fOffset);
michael@0 400 return true;
michael@0 401 }
michael@0 402
michael@0 403 if (0 == dbmPaintId) {
michael@0 404 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
michael@0 405 // and signal the caller (by returning true) to not add the RESTORE op
michael@0 406 convert_command_to_noop(writer, saveLayerInfo.fOffset);
michael@0 407 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
michael@0 408 return true;
michael@0 409 }
michael@0 410
michael@0 411 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
michael@0 412 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
michael@0 413 return false;
michael@0 414 }
michael@0 415
michael@0 416 // For this optimization we only fold the saveLayer and drawBitmapRect
michael@0 417 // together if the saveLayer's draw is simple (i.e., no fancy effects) and
michael@0 418 // and the only difference in the colors is that the saveLayer's can have
michael@0 419 // an alpha while the drawBitmapRect's is opaque.
michael@0 420 // TODO: it should be possible to fold them together even if they both
michael@0 421 // have different non-255 alphas
michael@0 422 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
michael@0 423
michael@0 424 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
michael@0 425 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
michael@0 426 return false;
michael@0 427 }
michael@0 428
michael@0 429 SkColor newColor = SkColorSetA(dbmPaint->getColor(),
michael@0 430 SkColorGetA(saveLayerPaint->getColor()));
michael@0 431 dbmPaint->setColor(newColor);
michael@0 432
michael@0 433 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
michael@0 434 if (NULL == data) {
michael@0 435 return false;
michael@0 436 }
michael@0 437
michael@0 438 // kill the saveLayer and alter the DBMR2R's paint to be the modified one
michael@0 439 convert_command_to_noop(writer, saveLayerInfo.fOffset);
michael@0 440 writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
michael@0 441 return true;
michael@0 442 }
michael@0 443
michael@0 444 /*
michael@0 445 * Restore has just been called (but not recorded), look back at the
michael@0 446 * matching save* and see if we are in the configuration:
michael@0 447 * SAVE_LAYER (with NULL == bounds)
michael@0 448 * SAVE
michael@0 449 * CLIP_RECT
michael@0 450 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
michael@0 451 * RESTORE
michael@0 452 * RESTORE
michael@0 453 * where the saveLayer's color can be moved into the drawBitmap*'s paint
michael@0 454 */
michael@0 455 static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
michael@0 456 SkPaintDictionary* paintDict) {
michael@0 457
michael@0 458 // back up to the save block
michael@0 459 // TODO: add a stack to track save*/restore offsets rather than searching backwards
michael@0 460 while (offset > 0) {
michael@0 461 offset = writer->readTAt<uint32_t>(offset);
michael@0 462 }
michael@0 463
michael@0 464 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
michael@0 465 CommandInfo result[SK_ARRAY_COUNT(pattern)];
michael@0 466
michael@0 467 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
michael@0 468 return false;
michael@0 469 }
michael@0 470
michael@0 471 if (kSaveLayerWithBoundsSize == result[0].fSize) {
michael@0 472 // The saveLayer's bound can offset where the dbm is drawn
michael@0 473 return false;
michael@0 474 }
michael@0 475
michael@0 476 return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
michael@0 477 result[0], result[3]);
michael@0 478 }
michael@0 479
michael@0 480 static bool is_drawing_op(DrawType op) {
michael@0 481 return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
michael@0 482 }
michael@0 483
michael@0 484 /*
michael@0 485 * Restore has just been called (but not recorded), so look back at the
michael@0 486 * matching save(), and see if we can eliminate the pair of them, due to no
michael@0 487 * intervening matrix/clip calls.
michael@0 488 *
michael@0 489 * If so, update the writer and return true, in which case we won't even record
michael@0 490 * the restore() call. If we still need the restore(), return false.
michael@0 491 */
michael@0 492 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
michael@0 493 SkPaintDictionary* paintDict) {
michael@0 494 #ifdef TRACK_COLLAPSE_STATS
michael@0 495 gCollapseCalls += 1;
michael@0 496 #endif
michael@0 497
michael@0 498 int32_t restoreOffset = (int32_t)writer->bytesWritten();
michael@0 499
michael@0 500 // back up to the save block
michael@0 501 while (offset > 0) {
michael@0 502 offset = writer->readTAt<uint32_t>(offset);
michael@0 503 }
michael@0 504
michael@0 505 // now offset points to a save
michael@0 506 offset = -offset;
michael@0 507 uint32_t opSize;
michael@0 508 DrawType op = peek_op_and_size(writer, offset, &opSize);
michael@0 509 if (SAVE_LAYER == op) {
michael@0 510 // not ready to cull these out yet (mrr)
michael@0 511 return false;
michael@0 512 }
michael@0 513 SkASSERT(SAVE == op);
michael@0 514 SkASSERT(kSaveSize == opSize);
michael@0 515
michael@0 516 // get the save flag (last 4-bytes of the space allocated for the opSize)
michael@0 517 SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
michael@0 518 if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
michael@0 519 // This function's optimization is only correct for kMatrixClip style saves.
michael@0 520 // TODO: set checkMatrix & checkClip booleans here and then check for the
michael@0 521 // offending operations in the following loop.
michael@0 522 return false;
michael@0 523 }
michael@0 524
michael@0 525 // Walk forward until we get back to either a draw-verb (abort) or we hit
michael@0 526 // our restore (success).
michael@0 527 int32_t saveOffset = offset;
michael@0 528
michael@0 529 offset += opSize;
michael@0 530 while (offset < restoreOffset) {
michael@0 531 op = peek_op_and_size(writer, offset, &opSize);
michael@0 532 if (is_drawing_op(op) || (SAVE_LAYER == op)) {
michael@0 533 // drawing verb, abort
michael@0 534 return false;
michael@0 535 }
michael@0 536 offset += opSize;
michael@0 537 }
michael@0 538
michael@0 539 #ifdef TRACK_COLLAPSE_STATS
michael@0 540 gCollapseCount += 1;
michael@0 541 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
michael@0 542 (double)gCollapseCount / gCollapseCalls, "%");
michael@0 543 #endif
michael@0 544
michael@0 545 writer->rewindToOffset(saveOffset);
michael@0 546 return true;
michael@0 547 }
michael@0 548
michael@0 549 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
michael@0 550 SkPaintDictionary* paintDict);
michael@0 551 enum PictureRecordOptType {
michael@0 552 kRewind_OptType, // Optimization rewinds the command stream
michael@0 553 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair
michael@0 554 };
michael@0 555
michael@0 556 enum PictureRecordOptFlags {
michael@0 557 kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the
michael@0 558 // SkPicture has a bounding box hierarchy.
michael@0 559 };
michael@0 560
michael@0 561 struct PictureRecordOpt {
michael@0 562 PictureRecordOptProc fProc;
michael@0 563 PictureRecordOptType fType;
michael@0 564 unsigned fFlags;
michael@0 565 };
michael@0 566 /*
michael@0 567 * A list of the optimizations that are tried upon seeing a restore
michael@0 568 * TODO: add a real API for such optimizations
michael@0 569 * Add the ability to fire optimizations on any op (not just RESTORE)
michael@0 570 */
michael@0 571 static const PictureRecordOpt gPictureRecordOpts[] = {
michael@0 572 // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
michael@0 573 // because it is redundant with the state traversal optimization in
michael@0 574 // SkPictureStateTree, and applying the optimization introduces significant
michael@0 575 // record time overhead because it requires rewinding contents that were
michael@0 576 // recorded into the BBoxHierarchy.
michael@0 577 { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
michael@0 578 { remove_save_layer1, kCollapseSaveLayer_OptType, 0 },
michael@0 579 { remove_save_layer2, kCollapseSaveLayer_OptType, 0 }
michael@0 580 };
michael@0 581
michael@0 582 // This is called after an optimization has been applied to the command stream
michael@0 583 // in order to adjust the contents and state of the bounding box hierarchy and
michael@0 584 // state tree to reflect the optimization.
michael@0 585 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
michael@0 586 SkBBoxHierarchy* boundingHierarchy) {
michael@0 587 switch (opt) {
michael@0 588 case kCollapseSaveLayer_OptType:
michael@0 589 if (NULL != stateTree) {
michael@0 590 stateTree->saveCollapsed();
michael@0 591 }
michael@0 592 break;
michael@0 593 case kRewind_OptType:
michael@0 594 if (NULL != boundingHierarchy) {
michael@0 595 boundingHierarchy->rewindInserts();
michael@0 596 }
michael@0 597 // Note: No need to touch the state tree for this to work correctly.
michael@0 598 // Unused branches do not burden the playback, and pruning the tree
michael@0 599 // would be O(N^2), so it is best to leave it alone.
michael@0 600 break;
michael@0 601 default:
michael@0 602 SkASSERT(0);
michael@0 603 }
michael@0 604 }
michael@0 605
michael@0 606 void SkPictureRecord::willRestore() {
michael@0 607 // FIXME: SkDeferredCanvas needs to be refactored to respect
michael@0 608 // save/restore balancing so that the following test can be
michael@0 609 // turned on permanently.
michael@0 610 #if 0
michael@0 611 SkASSERT(fRestoreOffsetStack.count() > 1);
michael@0 612 #endif
michael@0 613
michael@0 614 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 615 if (fMCMgr.getSaveCount() == 1) {
michael@0 616 return;
michael@0 617 }
michael@0 618
michael@0 619 fMCMgr.restore();
michael@0 620 #else
michael@0 621 // check for underflow
michael@0 622 if (fRestoreOffsetStack.count() == 0) {
michael@0 623 return;
michael@0 624 }
michael@0 625
michael@0 626 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
michael@0 627 fFirstSavedLayerIndex = kNoSavedLayerIndex;
michael@0 628 }
michael@0 629
michael@0 630 size_t opt = 0;
michael@0 631 if (fOptsEnabled) {
michael@0 632 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
michael@0 633 if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
michael@0 634 && NULL != fBoundingHierarchy) {
michael@0 635 continue;
michael@0 636 }
michael@0 637 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
michael@0 638 // Some optimization fired so don't add the RESTORE
michael@0 639 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
michael@0 640 fStateTree, fBoundingHierarchy);
michael@0 641 break;
michael@0 642 }
michael@0 643 }
michael@0 644 }
michael@0 645
michael@0 646 if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
michael@0 647 // No optimization fired so add the RESTORE
michael@0 648 this->recordRestore();
michael@0 649 }
michael@0 650
michael@0 651 fRestoreOffsetStack.pop();
michael@0 652 #endif
michael@0 653
michael@0 654 this->INHERITED::willRestore();
michael@0 655 }
michael@0 656
michael@0 657 void SkPictureRecord::recordRestore(bool fillInSkips) {
michael@0 658 uint32_t initialOffset, size;
michael@0 659 if (fillInSkips) {
michael@0 660 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
michael@0 661 }
michael@0 662 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
michael@0 663 initialOffset = this->addDraw(RESTORE, &size);
michael@0 664 this->validate(initialOffset, size);
michael@0 665 }
michael@0 666
michael@0 667 void SkPictureRecord::didTranslate(SkScalar dx, SkScalar dy) {
michael@0 668 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 669 fMCMgr.translate(dx, dy);
michael@0 670 #else
michael@0 671 // op + dx + dy
michael@0 672 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
michael@0 673 size_t initialOffset = this->addDraw(TRANSLATE, &size);
michael@0 674 this->addScalar(dx);
michael@0 675 this->addScalar(dy);
michael@0 676 this->validate(initialOffset, size);
michael@0 677 #endif
michael@0 678 this->INHERITED::didTranslate(dx, dy);
michael@0 679 }
michael@0 680
michael@0 681 void SkPictureRecord::didScale(SkScalar sx, SkScalar sy) {
michael@0 682
michael@0 683 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 684 fMCMgr.scale(sx, sy);
michael@0 685 #else
michael@0 686 // op + sx + sy
michael@0 687 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
michael@0 688 size_t initialOffset = this->addDraw(SCALE, &size);
michael@0 689 this->addScalar(sx);
michael@0 690 this->addScalar(sy);
michael@0 691 this->validate(initialOffset, size);
michael@0 692 #endif
michael@0 693 this->INHERITED::didScale(sx, sy);
michael@0 694 }
michael@0 695
michael@0 696 void SkPictureRecord::didRotate(SkScalar degrees) {
michael@0 697
michael@0 698 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 699 fMCMgr.rotate(degrees);
michael@0 700 #else
michael@0 701 // op + degrees
michael@0 702 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
michael@0 703 size_t initialOffset = this->addDraw(ROTATE, &size);
michael@0 704 this->addScalar(degrees);
michael@0 705 this->validate(initialOffset, size);
michael@0 706 #endif
michael@0 707 this->INHERITED::didRotate(degrees);
michael@0 708 }
michael@0 709
michael@0 710 void SkPictureRecord::didSkew(SkScalar sx, SkScalar sy) {
michael@0 711
michael@0 712 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 713 fMCMgr.skew(sx, sy);
michael@0 714 #else
michael@0 715 // op + sx + sy
michael@0 716 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
michael@0 717 size_t initialOffset = this->addDraw(SKEW, &size);
michael@0 718 this->addScalar(sx);
michael@0 719 this->addScalar(sy);
michael@0 720 this->validate(initialOffset, size);
michael@0 721 #endif
michael@0 722 this->INHERITED::didSkew(sx, sy);
michael@0 723 }
michael@0 724
michael@0 725 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
michael@0 726
michael@0 727 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 728 fMCMgr.concat(matrix);
michael@0 729 #else
michael@0 730 this->recordConcat(matrix);
michael@0 731 #endif
michael@0 732 this->INHERITED::didConcat(matrix);
michael@0 733 }
michael@0 734
michael@0 735 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
michael@0 736 this->validate(fWriter.bytesWritten(), 0);
michael@0 737 // op + matrix
michael@0 738 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
michael@0 739 size_t initialOffset = this->addDraw(CONCAT, &size);
michael@0 740 this->addMatrix(matrix);
michael@0 741 this->validate(initialOffset, size);
michael@0 742 }
michael@0 743
michael@0 744 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
michael@0 745
michael@0 746 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 747 fMCMgr.setMatrix(matrix);
michael@0 748 #else
michael@0 749 this->validate(fWriter.bytesWritten(), 0);
michael@0 750 // op + matrix
michael@0 751 uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
michael@0 752 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
michael@0 753 this->addMatrix(matrix);
michael@0 754 this->validate(initialOffset, size);
michael@0 755 #endif
michael@0 756 this->INHERITED::didSetMatrix(matrix);
michael@0 757 }
michael@0 758
michael@0 759 static bool regionOpExpands(SkRegion::Op op) {
michael@0 760 switch (op) {
michael@0 761 case SkRegion::kUnion_Op:
michael@0 762 case SkRegion::kXOR_Op:
michael@0 763 case SkRegion::kReverseDifference_Op:
michael@0 764 case SkRegion::kReplace_Op:
michael@0 765 return true;
michael@0 766 case SkRegion::kIntersect_Op:
michael@0 767 case SkRegion::kDifference_Op:
michael@0 768 return false;
michael@0 769 default:
michael@0 770 SkDEBUGFAIL("unknown region op");
michael@0 771 return false;
michael@0 772 }
michael@0 773 }
michael@0 774
michael@0 775 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 776 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
michael@0 777 fMCMgr.fillInSkips(&fWriter, restoreOffset);
michael@0 778 }
michael@0 779 #else
michael@0 780 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
michael@0 781 int32_t offset = fRestoreOffsetStack.top();
michael@0 782 while (offset > 0) {
michael@0 783 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
michael@0 784 fWriter.overwriteTAt(offset, restoreOffset);
michael@0 785 offset = peek;
michael@0 786 }
michael@0 787
michael@0 788 #ifdef SK_DEBUG
michael@0 789 // assert that the final offset value points to a save verb
michael@0 790 uint32_t opSize;
michael@0 791 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
michael@0 792 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
michael@0 793 #endif
michael@0 794 }
michael@0 795 #endif
michael@0 796
michael@0 797 void SkPictureRecord::beginRecording() {
michael@0 798 // we have to call this *after* our constructor, to ensure that it gets
michael@0 799 // recorded. This is balanced by restoreToCount() call from endRecording,
michael@0 800 // which in-turn calls our overridden restore(), so those get recorded too.
michael@0 801 fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
michael@0 802 }
michael@0 803
michael@0 804 void SkPictureRecord::endRecording() {
michael@0 805 SkASSERT(kNoInitialSave != fInitialSaveCount);
michael@0 806 this->restoreToCount(fInitialSaveCount);
michael@0 807 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 808 fMCMgr.finish();
michael@0 809 #endif
michael@0 810 }
michael@0 811
michael@0 812 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 813 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
michael@0 814 size_t offset = fWriter.bytesWritten();
michael@0 815 this->addInt(-1);
michael@0 816 return offset;
michael@0 817 }
michael@0 818 #else
michael@0 819 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
michael@0 820 if (fRestoreOffsetStack.isEmpty()) {
michael@0 821 return -1;
michael@0 822 }
michael@0 823
michael@0 824 // The RestoreOffset field is initially filled with a placeholder
michael@0 825 // value that points to the offset of the previous RestoreOffset
michael@0 826 // in the current stack level, thus forming a linked list so that
michael@0 827 // the restore offsets can be filled in when the corresponding
michael@0 828 // restore command is recorded.
michael@0 829 int32_t prevOffset = fRestoreOffsetStack.top();
michael@0 830
michael@0 831 if (regionOpExpands(op)) {
michael@0 832 // Run back through any previous clip ops, and mark their offset to
michael@0 833 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
michael@0 834 // they could hide this clips ability to expand the clip (i.e. go from
michael@0 835 // empty to non-empty).
michael@0 836 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
michael@0 837
michael@0 838 // Reset the pointer back to the previous clip so that subsequent
michael@0 839 // restores don't overwrite the offsets we just cleared.
michael@0 840 prevOffset = 0;
michael@0 841 }
michael@0 842
michael@0 843 size_t offset = fWriter.bytesWritten();
michael@0 844 this->addInt(prevOffset);
michael@0 845 fRestoreOffsetStack.top() = offset;
michael@0 846 return offset;
michael@0 847 }
michael@0 848 #endif
michael@0 849
michael@0 850 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
michael@0 851
michael@0 852 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 853 fMCMgr.clipRect(rect, op, doAA);
michael@0 854 #else
michael@0 855 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
michael@0 856 #endif
michael@0 857 this->INHERITED::onClipRect(rect, op, edgeStyle);
michael@0 858 }
michael@0 859
michael@0 860 int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
michael@0 861 // id + rect + clip params
michael@0 862 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
michael@0 863 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 864 size += kUInt32Size; // + restore offset
michael@0 865 #else
michael@0 866 // recordRestoreOffsetPlaceholder doesn't always write an offset
michael@0 867 if (!fRestoreOffsetStack.isEmpty()) {
michael@0 868 // + restore offset
michael@0 869 size += kUInt32Size;
michael@0 870 }
michael@0 871 #endif
michael@0 872 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
michael@0 873 this->addRect(rect);
michael@0 874 this->addInt(ClipParams_pack(op, doAA));
michael@0 875 int offset = this->recordRestoreOffsetPlaceholder(op);
michael@0 876
michael@0 877 this->validate(initialOffset, size);
michael@0 878 return offset;
michael@0 879 }
michael@0 880
michael@0 881 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
michael@0 882
michael@0 883 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 884 fMCMgr.clipRRect(rrect, op, doAA);
michael@0 885 #else
michael@0 886 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
michael@0 887 #endif
michael@0 888 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
michael@0 889 this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
michael@0 890 } else {
michael@0 891 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
michael@0 892 }
michael@0 893 }
michael@0 894
michael@0 895 int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
michael@0 896 // op + rrect + clip params
michael@0 897 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
michael@0 898 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 899 size += kUInt32Size; // + restore offset
michael@0 900 #else
michael@0 901 // recordRestoreOffsetPlaceholder doesn't always write an offset
michael@0 902 if (!fRestoreOffsetStack.isEmpty()) {
michael@0 903 // + restore offset
michael@0 904 size += kUInt32Size;
michael@0 905 }
michael@0 906 #endif
michael@0 907 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
michael@0 908 this->addRRect(rrect);
michael@0 909 this->addInt(ClipParams_pack(op, doAA));
michael@0 910 int offset = recordRestoreOffsetPlaceholder(op);
michael@0 911 this->validate(initialOffset, size);
michael@0 912 return offset;
michael@0 913 }
michael@0 914
michael@0 915 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
michael@0 916
michael@0 917 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 918 fMCMgr.clipPath(path, op, doAA);
michael@0 919 #else
michael@0 920 int pathID = this->addPathToHeap(path);
michael@0 921 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
michael@0 922 #endif
michael@0 923
michael@0 924 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
michael@0 925 this->updateClipConservativelyUsingBounds(path.getBounds(), op,
michael@0 926 path.isInverseFillType());
michael@0 927 } else {
michael@0 928 this->INHERITED::onClipPath(path, op, edgeStyle);
michael@0 929 }
michael@0 930 }
michael@0 931
michael@0 932 int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
michael@0 933 // op + path index + clip params
michael@0 934 uint32_t size = 3 * kUInt32Size;
michael@0 935 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 936 size += kUInt32Size; // + restore offset
michael@0 937 #else
michael@0 938 // recordRestoreOffsetPlaceholder doesn't always write an offset
michael@0 939 if (!fRestoreOffsetStack.isEmpty()) {
michael@0 940 // + restore offset
michael@0 941 size += kUInt32Size;
michael@0 942 }
michael@0 943 #endif
michael@0 944 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
michael@0 945 this->addInt(pathID);
michael@0 946 this->addInt(ClipParams_pack(op, doAA));
michael@0 947 int offset = recordRestoreOffsetPlaceholder(op);
michael@0 948 this->validate(initialOffset, size);
michael@0 949 return offset;
michael@0 950 }
michael@0 951
michael@0 952 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
michael@0 953
michael@0 954 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 955 fMCMgr.clipRegion(region, op);
michael@0 956 #else
michael@0 957 this->recordClipRegion(region, op);
michael@0 958 #endif
michael@0 959 this->INHERITED::onClipRegion(region, op);
michael@0 960 }
michael@0 961
michael@0 962 int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
michael@0 963 // op + clip params + region
michael@0 964 uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
michael@0 965 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 966 size += kUInt32Size; // + restore offset
michael@0 967 #else
michael@0 968 // recordRestoreOffsetPlaceholder doesn't always write an offset
michael@0 969 if (!fRestoreOffsetStack.isEmpty()) {
michael@0 970 // + restore offset
michael@0 971 size += kUInt32Size;
michael@0 972 }
michael@0 973 #endif
michael@0 974 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
michael@0 975 this->addRegion(region);
michael@0 976 this->addInt(ClipParams_pack(op, false));
michael@0 977 int offset = this->recordRestoreOffsetPlaceholder(op);
michael@0 978
michael@0 979 this->validate(initialOffset, size);
michael@0 980 return offset;
michael@0 981 }
michael@0 982
michael@0 983 void SkPictureRecord::clear(SkColor color) {
michael@0 984
michael@0 985 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 986 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 987 #endif
michael@0 988
michael@0 989 // op + color
michael@0 990 uint32_t size = 2 * kUInt32Size;
michael@0 991 size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
michael@0 992 this->addInt(color);
michael@0 993 this->validate(initialOffset, size);
michael@0 994 }
michael@0 995
michael@0 996 void SkPictureRecord::drawPaint(const SkPaint& paint) {
michael@0 997
michael@0 998 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 999 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1000 #endif
michael@0 1001
michael@0 1002 // op + paint index
michael@0 1003 uint32_t size = 2 * kUInt32Size;
michael@0 1004 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
michael@0 1005 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
michael@0 1006 this->addPaint(paint);
michael@0 1007 this->validate(initialOffset, size);
michael@0 1008 }
michael@0 1009
michael@0 1010 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
michael@0 1011 const SkPaint& paint) {
michael@0 1012
michael@0 1013 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1014 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1015 #endif
michael@0 1016
michael@0 1017 // op + paint index + mode + count + point data
michael@0 1018 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
michael@0 1019 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
michael@0 1020 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
michael@0 1021 this->addPaint(paint);
michael@0 1022 this->addInt(mode);
michael@0 1023 this->addInt(count);
michael@0 1024 fWriter.writeMul4(pts, count * sizeof(SkPoint));
michael@0 1025 this->validate(initialOffset, size);
michael@0 1026 }
michael@0 1027
michael@0 1028 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
michael@0 1029
michael@0 1030 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1031 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1032 #endif
michael@0 1033
michael@0 1034 // op + paint index + rect
michael@0 1035 uint32_t size = 2 * kUInt32Size + sizeof(oval);
michael@0 1036 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
michael@0 1037 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
michael@0 1038 this->addPaint(paint);
michael@0 1039 this->addRect(oval);
michael@0 1040 this->validate(initialOffset, size);
michael@0 1041 }
michael@0 1042
michael@0 1043 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
michael@0 1044
michael@0 1045 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1046 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1047 #endif
michael@0 1048
michael@0 1049 // op + paint index + rect
michael@0 1050 uint32_t size = 2 * kUInt32Size + sizeof(rect);
michael@0 1051 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
michael@0 1052 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
michael@0 1053 this->addPaint(paint);
michael@0 1054 this->addRect(rect);
michael@0 1055 this->validate(initialOffset, size);
michael@0 1056 }
michael@0 1057
michael@0 1058 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
michael@0 1059
michael@0 1060 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1061 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1062 #endif
michael@0 1063
michael@0 1064 if (rrect.isRect()) {
michael@0 1065 this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
michael@0 1066 } else if (rrect.isOval()) {
michael@0 1067 this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
michael@0 1068 } else {
michael@0 1069 // op + paint index + rrect
michael@0 1070 uint32_t initialOffset, size;
michael@0 1071 size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
michael@0 1072 initialOffset = this->addDraw(DRAW_RRECT, &size);
michael@0 1073 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
michael@0 1074 this->addPaint(paint);
michael@0 1075 this->addRRect(rrect);
michael@0 1076 this->validate(initialOffset, size);
michael@0 1077 }
michael@0 1078 }
michael@0 1079
michael@0 1080 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
michael@0 1081 const SkPaint& paint) {
michael@0 1082
michael@0 1083 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1084 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1085 #endif
michael@0 1086
michael@0 1087 // op + paint index + rrects
michael@0 1088 uint32_t initialOffset, size;
michael@0 1089 size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
michael@0 1090 initialOffset = this->addDraw(DRAW_DRRECT, &size);
michael@0 1091 SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
michael@0 1092 this->addPaint(paint);
michael@0 1093 this->addRRect(outer);
michael@0 1094 this->addRRect(inner);
michael@0 1095 this->validate(initialOffset, size);
michael@0 1096 }
michael@0 1097
michael@0 1098 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
michael@0 1099
michael@0 1100 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1101 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1102 #endif
michael@0 1103
michael@0 1104 // op + paint index + path index
michael@0 1105 uint32_t size = 3 * kUInt32Size;
michael@0 1106 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
michael@0 1107 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
michael@0 1108 this->addPaint(paint);
michael@0 1109 this->addPath(path);
michael@0 1110 this->validate(initialOffset, size);
michael@0 1111 }
michael@0 1112
michael@0 1113 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
michael@0 1114 const SkPaint* paint = NULL) {
michael@0 1115 if (bitmap.drawsNothing()) {
michael@0 1116 return;
michael@0 1117 }
michael@0 1118
michael@0 1119 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1120 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1121 #endif
michael@0 1122
michael@0 1123 // op + paint index + bitmap index + left + top
michael@0 1124 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
michael@0 1125 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
michael@0 1126 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
michael@0 1127 this->addPaintPtr(paint);
michael@0 1128 int bitmapID = this->addBitmap(bitmap);
michael@0 1129 this->addScalar(left);
michael@0 1130 this->addScalar(top);
michael@0 1131 this->validate(initialOffset, size);
michael@0 1132 this->trackBitmapUse(bitmapID, initialOffset);
michael@0 1133 }
michael@0 1134
michael@0 1135 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
michael@0 1136 const SkRect& dst, const SkPaint* paint,
michael@0 1137 DrawBitmapRectFlags flags) {
michael@0 1138 if (bitmap.drawsNothing()) {
michael@0 1139 return;
michael@0 1140 }
michael@0 1141
michael@0 1142 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1143 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1144 #endif
michael@0 1145 // id + paint index + bitmap index + bool for 'src' + flags
michael@0 1146 uint32_t size = 5 * kUInt32Size;
michael@0 1147 if (NULL != src) {
michael@0 1148 size += sizeof(*src); // + rect
michael@0 1149 }
michael@0 1150 size += sizeof(dst); // + rect
michael@0 1151
michael@0 1152 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
michael@0 1153 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
michael@0 1154 == fWriter.bytesWritten());
michael@0 1155 this->addPaintPtr(paint);
michael@0 1156 int bitmapID = this->addBitmap(bitmap);
michael@0 1157 this->addRectPtr(src); // may be null
michael@0 1158 this->addRect(dst);
michael@0 1159 this->addInt(flags);
michael@0 1160 this->validate(initialOffset, size);
michael@0 1161 this->trackBitmapUse(bitmapID, initialOffset);
michael@0 1162 }
michael@0 1163
michael@0 1164 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
michael@0 1165 const SkPaint* paint) {
michael@0 1166 if (bitmap.drawsNothing()) {
michael@0 1167 return;
michael@0 1168 }
michael@0 1169
michael@0 1170 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1171 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1172 #endif
michael@0 1173
michael@0 1174 // id + paint index + bitmap index + matrix
michael@0 1175 uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
michael@0 1176 size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
michael@0 1177 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
michael@0 1178 this->addPaintPtr(paint);
michael@0 1179 int bitmapID = this->addBitmap(bitmap);
michael@0 1180 this->addMatrix(matrix);
michael@0 1181 this->validate(initialOffset, size);
michael@0 1182 this->trackBitmapUse(bitmapID, initialOffset);
michael@0 1183 }
michael@0 1184
michael@0 1185 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
michael@0 1186 const SkRect& dst, const SkPaint* paint) {
michael@0 1187 if (bitmap.drawsNothing()) {
michael@0 1188 return;
michael@0 1189 }
michael@0 1190
michael@0 1191 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1192 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1193 #endif
michael@0 1194
michael@0 1195 // op + paint index + bitmap id + center + dst rect
michael@0 1196 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
michael@0 1197 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
michael@0 1198 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
michael@0 1199 this->addPaintPtr(paint);
michael@0 1200 int bitmapID = this->addBitmap(bitmap);
michael@0 1201 this->addIRect(center);
michael@0 1202 this->addRect(dst);
michael@0 1203 this->validate(initialOffset, size);
michael@0 1204 this->trackBitmapUse(bitmapID, initialOffset);
michael@0 1205 }
michael@0 1206
michael@0 1207 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
michael@0 1208 const SkPaint* paint = NULL) {
michael@0 1209 if (bitmap.drawsNothing()) {
michael@0 1210 return;
michael@0 1211 }
michael@0 1212
michael@0 1213 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1214 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1215 #endif
michael@0 1216
michael@0 1217 // op + paint index + bitmap index + left + top
michael@0 1218 uint32_t size = 5 * kUInt32Size;
michael@0 1219 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
michael@0 1220 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
michael@0 1221 this->addPaintPtr(paint);
michael@0 1222 int bitmapID = this->addBitmap(bitmap);
michael@0 1223 this->addInt(left);
michael@0 1224 this->addInt(top);
michael@0 1225 this->validate(initialOffset, size);
michael@0 1226 this->trackBitmapUse(bitmapID, initialOffset);
michael@0 1227 }
michael@0 1228
michael@0 1229 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
michael@0 1230 SkPaint::FontMetrics metrics;
michael@0 1231 paint.getFontMetrics(&metrics);
michael@0 1232 SkRect bounds;
michael@0 1233 // construct a rect so we can see any adjustments from the paint.
michael@0 1234 // we use 0,1 for left,right, just so the rect isn't empty
michael@0 1235 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
michael@0 1236 (void)paint.computeFastBounds(bounds, &bounds);
michael@0 1237 topbot[0] = bounds.fTop;
michael@0 1238 topbot[1] = bounds.fBottom;
michael@0 1239 }
michael@0 1240
michael@0 1241 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
michael@0 1242 SkScalar minY, SkScalar maxY) {
michael@0 1243 WriteTopBot(paint, flat);
michael@0 1244 this->addScalar(flat.topBot()[0] + minY);
michael@0 1245 this->addScalar(flat.topBot()[1] + maxY);
michael@0 1246 }
michael@0 1247
michael@0 1248 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
michael@0 1249 SkScalar y, const SkPaint& paint) {
michael@0 1250
michael@0 1251 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1252 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1253 #endif
michael@0 1254
michael@0 1255 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
michael@0 1256
michael@0 1257 // op + paint index + length + 'length' worth of chars + x + y
michael@0 1258 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
michael@0 1259 if (fast) {
michael@0 1260 size += 2 * sizeof(SkScalar); // + top & bottom
michael@0 1261 }
michael@0 1262
michael@0 1263 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
michael@0 1264 size_t initialOffset = this->addDraw(op, &size);
michael@0 1265 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
michael@0 1266 const SkFlatData* flatPaintData = addPaint(paint);
michael@0 1267 SkASSERT(flatPaintData);
michael@0 1268 this->addText(text, byteLength);
michael@0 1269 this->addScalar(x);
michael@0 1270 this->addScalar(y);
michael@0 1271 if (fast) {
michael@0 1272 this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
michael@0 1273 }
michael@0 1274 this->validate(initialOffset, size);
michael@0 1275 }
michael@0 1276
michael@0 1277 void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
michael@0 1278 const SkPoint pos[], const SkPaint& paint) {
michael@0 1279
michael@0 1280 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1281 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1282 #endif
michael@0 1283
michael@0 1284 size_t points = paint.countText(text, byteLength);
michael@0 1285 if (0 == points)
michael@0 1286 return;
michael@0 1287
michael@0 1288 bool canUseDrawH = true;
michael@0 1289 SkScalar minY = pos[0].fY;
michael@0 1290 SkScalar maxY = pos[0].fY;
michael@0 1291 // check if the caller really should have used drawPosTextH()
michael@0 1292 {
michael@0 1293 const SkScalar firstY = pos[0].fY;
michael@0 1294 for (size_t index = 1; index < points; index++) {
michael@0 1295 if (pos[index].fY != firstY) {
michael@0 1296 canUseDrawH = false;
michael@0 1297 if (pos[index].fY < minY) {
michael@0 1298 minY = pos[index].fY;
michael@0 1299 } else if (pos[index].fY > maxY) {
michael@0 1300 maxY = pos[index].fY;
michael@0 1301 }
michael@0 1302 }
michael@0 1303 }
michael@0 1304 }
michael@0 1305
michael@0 1306 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
michael@0 1307 bool fast = canUseDrawH && fastBounds;
michael@0 1308
michael@0 1309 // op + paint index + length + 'length' worth of data + num points
michael@0 1310 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
michael@0 1311 if (canUseDrawH) {
michael@0 1312 if (fast) {
michael@0 1313 size += 2 * sizeof(SkScalar); // + top & bottom
michael@0 1314 }
michael@0 1315 // + y-pos + actual x-point data
michael@0 1316 size += sizeof(SkScalar) + points * sizeof(SkScalar);
michael@0 1317 } else {
michael@0 1318 // + x&y point data
michael@0 1319 size += points * sizeof(SkPoint);
michael@0 1320 if (fastBounds) {
michael@0 1321 size += 2 * sizeof(SkScalar); // + top & bottom
michael@0 1322 }
michael@0 1323 }
michael@0 1324
michael@0 1325 DrawType op;
michael@0 1326 if (fast) {
michael@0 1327 op = DRAW_POS_TEXT_H_TOP_BOTTOM;
michael@0 1328 } else if (canUseDrawH) {
michael@0 1329 op = DRAW_POS_TEXT_H;
michael@0 1330 } else if (fastBounds) {
michael@0 1331 op = DRAW_POS_TEXT_TOP_BOTTOM;
michael@0 1332 } else {
michael@0 1333 op = DRAW_POS_TEXT;
michael@0 1334 }
michael@0 1335 size_t initialOffset = this->addDraw(op, &size);
michael@0 1336 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
michael@0 1337 const SkFlatData* flatPaintData = this->addPaint(paint);
michael@0 1338 SkASSERT(flatPaintData);
michael@0 1339 this->addText(text, byteLength);
michael@0 1340 this->addInt(points);
michael@0 1341
michael@0 1342 #ifdef SK_DEBUG_SIZE
michael@0 1343 size_t start = fWriter.bytesWritten();
michael@0 1344 #endif
michael@0 1345 if (canUseDrawH) {
michael@0 1346 if (fast) {
michael@0 1347 this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
michael@0 1348 }
michael@0 1349 this->addScalar(pos[0].fY);
michael@0 1350 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
michael@0 1351 for (size_t index = 0; index < points; index++)
michael@0 1352 *xptr++ = pos[index].fX;
michael@0 1353 } else {
michael@0 1354 fWriter.writeMul4(pos, points * sizeof(SkPoint));
michael@0 1355 if (fastBounds) {
michael@0 1356 this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
michael@0 1357 }
michael@0 1358 }
michael@0 1359 #ifdef SK_DEBUG_SIZE
michael@0 1360 fPointBytes += fWriter.bytesWritten() - start;
michael@0 1361 fPointWrites += points;
michael@0 1362 #endif
michael@0 1363 this->validate(initialOffset, size);
michael@0 1364 }
michael@0 1365
michael@0 1366 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
michael@0 1367 const SkScalar xpos[], SkScalar constY,
michael@0 1368 const SkPaint& paint) {
michael@0 1369
michael@0 1370 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1371 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1372 #endif
michael@0 1373
michael@0 1374 const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
michael@0 1375 this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
michael@0 1376 }
michael@0 1377
michael@0 1378 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
michael@0 1379 const SkScalar xpos[], SkScalar constY,
michael@0 1380 const SkPaint& paint, const SkFlatData* flatPaintData) {
michael@0 1381 size_t points = paint.countText(text, byteLength);
michael@0 1382 if (0 == points)
michael@0 1383 return;
michael@0 1384
michael@0 1385 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
michael@0 1386
michael@0 1387 // op + paint index + length + 'length' worth of data + num points
michael@0 1388 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
michael@0 1389 if (fast) {
michael@0 1390 size += 2 * sizeof(SkScalar); // + top & bottom
michael@0 1391 }
michael@0 1392 // + y + the actual points
michael@0 1393 size += 1 * kUInt32Size + points * sizeof(SkScalar);
michael@0 1394 size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
michael@0 1395 &size);
michael@0 1396 SkASSERT(flatPaintData);
michael@0 1397 this->addFlatPaint(flatPaintData);
michael@0 1398
michael@0 1399 this->addText(text, byteLength);
michael@0 1400 this->addInt(points);
michael@0 1401
michael@0 1402 #ifdef SK_DEBUG_SIZE
michael@0 1403 size_t start = fWriter.bytesWritten();
michael@0 1404 #endif
michael@0 1405 if (fast) {
michael@0 1406 this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
michael@0 1407 }
michael@0 1408 this->addScalar(constY);
michael@0 1409 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
michael@0 1410 #ifdef SK_DEBUG_SIZE
michael@0 1411 fPointBytes += fWriter.bytesWritten() - start;
michael@0 1412 fPointWrites += points;
michael@0 1413 #endif
michael@0 1414 this->validate(initialOffset, size);
michael@0 1415 }
michael@0 1416
michael@0 1417 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
michael@0 1418 const SkPath& path, const SkMatrix* matrix,
michael@0 1419 const SkPaint& paint) {
michael@0 1420
michael@0 1421 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1422 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1423 #endif
michael@0 1424
michael@0 1425 // op + paint index + length + 'length' worth of data + path index + matrix
michael@0 1426 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
michael@0 1427 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
michael@0 1428 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
michael@0 1429 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
michael@0 1430 this->addPaint(paint);
michael@0 1431 this->addText(text, byteLength);
michael@0 1432 this->addPath(path);
michael@0 1433 this->addMatrix(m);
michael@0 1434 this->validate(initialOffset, size);
michael@0 1435 }
michael@0 1436
michael@0 1437 void SkPictureRecord::drawPicture(SkPicture& picture) {
michael@0 1438
michael@0 1439 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1440 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1441 #endif
michael@0 1442
michael@0 1443 // op + picture index
michael@0 1444 uint32_t size = 2 * kUInt32Size;
michael@0 1445 size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
michael@0 1446 this->addPicture(picture);
michael@0 1447 this->validate(initialOffset, size);
michael@0 1448 }
michael@0 1449
michael@0 1450 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
michael@0 1451 const SkPoint vertices[], const SkPoint texs[],
michael@0 1452 const SkColor colors[], SkXfermode* xfer,
michael@0 1453 const uint16_t indices[], int indexCount,
michael@0 1454 const SkPaint& paint) {
michael@0 1455
michael@0 1456 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1457 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1458 #endif
michael@0 1459
michael@0 1460 uint32_t flags = 0;
michael@0 1461 if (texs) {
michael@0 1462 flags |= DRAW_VERTICES_HAS_TEXS;
michael@0 1463 }
michael@0 1464 if (colors) {
michael@0 1465 flags |= DRAW_VERTICES_HAS_COLORS;
michael@0 1466 }
michael@0 1467 if (indexCount > 0) {
michael@0 1468 flags |= DRAW_VERTICES_HAS_INDICES;
michael@0 1469 }
michael@0 1470 if (NULL != xfer) {
michael@0 1471 SkXfermode::Mode mode;
michael@0 1472 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
michael@0 1473 flags |= DRAW_VERTICES_HAS_XFER;
michael@0 1474 }
michael@0 1475 }
michael@0 1476
michael@0 1477 // op + paint index + flags + vmode + vCount + vertices
michael@0 1478 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
michael@0 1479 if (flags & DRAW_VERTICES_HAS_TEXS) {
michael@0 1480 size += vertexCount * sizeof(SkPoint); // + uvs
michael@0 1481 }
michael@0 1482 if (flags & DRAW_VERTICES_HAS_COLORS) {
michael@0 1483 size += vertexCount * sizeof(SkColor); // + vert colors
michael@0 1484 }
michael@0 1485 if (flags & DRAW_VERTICES_HAS_INDICES) {
michael@0 1486 // + num indices + indices
michael@0 1487 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
michael@0 1488 }
michael@0 1489 if (flags & DRAW_VERTICES_HAS_XFER) {
michael@0 1490 size += kUInt32Size; // mode enum
michael@0 1491 }
michael@0 1492
michael@0 1493 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
michael@0 1494 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
michael@0 1495 this->addPaint(paint);
michael@0 1496 this->addInt(flags);
michael@0 1497 this->addInt(vmode);
michael@0 1498 this->addInt(vertexCount);
michael@0 1499 this->addPoints(vertices, vertexCount);
michael@0 1500 if (flags & DRAW_VERTICES_HAS_TEXS) {
michael@0 1501 this->addPoints(texs, vertexCount);
michael@0 1502 }
michael@0 1503 if (flags & DRAW_VERTICES_HAS_COLORS) {
michael@0 1504 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
michael@0 1505 }
michael@0 1506 if (flags & DRAW_VERTICES_HAS_INDICES) {
michael@0 1507 this->addInt(indexCount);
michael@0 1508 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
michael@0 1509 }
michael@0 1510 if (flags & DRAW_VERTICES_HAS_XFER) {
michael@0 1511 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
michael@0 1512 (void)xfer->asMode(&mode);
michael@0 1513 this->addInt(mode);
michael@0 1514 }
michael@0 1515 this->validate(initialOffset, size);
michael@0 1516 }
michael@0 1517
michael@0 1518 void SkPictureRecord::drawData(const void* data, size_t length) {
michael@0 1519
michael@0 1520 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
michael@0 1521 fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
michael@0 1522 #endif
michael@0 1523
michael@0 1524 // op + length + 'length' worth of data
michael@0 1525 uint32_t size = 2 * kUInt32Size + SkAlign4(length);
michael@0 1526 size_t initialOffset = this->addDraw(DRAW_DATA, &size);
michael@0 1527 this->addInt(length);
michael@0 1528 fWriter.writePad(data, length);
michael@0 1529 this->validate(initialOffset, size);
michael@0 1530 }
michael@0 1531
michael@0 1532 void SkPictureRecord::beginCommentGroup(const char* description) {
michael@0 1533 // op/size + length of string + \0 terminated chars
michael@0 1534 int length = strlen(description);
michael@0 1535 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
michael@0 1536 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
michael@0 1537 fWriter.writeString(description, length);
michael@0 1538 this->validate(initialOffset, size);
michael@0 1539 }
michael@0 1540
michael@0 1541 void SkPictureRecord::addComment(const char* kywd, const char* value) {
michael@0 1542 // op/size + 2x length of string + 2x \0 terminated chars
michael@0 1543 int kywdLen = strlen(kywd);
michael@0 1544 int valueLen = strlen(value);
michael@0 1545 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
michael@0 1546 size_t initialOffset = this->addDraw(COMMENT, &size);
michael@0 1547 fWriter.writeString(kywd, kywdLen);
michael@0 1548 fWriter.writeString(value, valueLen);
michael@0 1549 this->validate(initialOffset, size);
michael@0 1550 }
michael@0 1551
michael@0 1552 void SkPictureRecord::endCommentGroup() {
michael@0 1553 // op/size
michael@0 1554 uint32_t size = 1 * kUInt32Size;
michael@0 1555 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
michael@0 1556 this->validate(initialOffset, size);
michael@0 1557 }
michael@0 1558
michael@0 1559 // [op/size] [rect] [skip offset]
michael@0 1560 static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
michael@0 1561 void SkPictureRecord::onPushCull(const SkRect& cullRect) {
michael@0 1562 // Skip identical cull rects.
michael@0 1563 if (!fCullOffsetStack.isEmpty()) {
michael@0 1564 const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect));
michael@0 1565 if (prevCull == cullRect) {
michael@0 1566 // Skipped culls are tracked on the stack, but they point to the previous offset.
michael@0 1567 fCullOffsetStack.push(fCullOffsetStack.top());
michael@0 1568 return;
michael@0 1569 }
michael@0 1570
michael@0 1571 SkASSERT(prevCull.contains(cullRect));
michael@0 1572 }
michael@0 1573
michael@0 1574 uint32_t size = kPushCullOpSize;
michael@0 1575 size_t initialOffset = this->addDraw(PUSH_CULL, &size);
michael@0 1576 // PUSH_CULL's size should stay constant (used to rewind).
michael@0 1577 SkASSERT(size == kPushCullOpSize);
michael@0 1578
michael@0 1579 this->addRect(cullRect);
michael@0 1580 fCullOffsetStack.push(fWriter.bytesWritten());
michael@0 1581 this->addInt(0);
michael@0 1582 this->validate(initialOffset, size);
michael@0 1583 }
michael@0 1584
michael@0 1585 void SkPictureRecord::onPopCull() {
michael@0 1586 SkASSERT(!fCullOffsetStack.isEmpty());
michael@0 1587
michael@0 1588 uint32_t cullSkipOffset = fCullOffsetStack.top();
michael@0 1589 fCullOffsetStack.pop();
michael@0 1590
michael@0 1591 // Skipped push, do the same for pop.
michael@0 1592 if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) {
michael@0 1593 return;
michael@0 1594 }
michael@0 1595
michael@0 1596 // Collapse empty push/pop pairs.
michael@0 1597 if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
michael@0 1598 SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
michael@0 1599 SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
michael@0 1600 fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
michael@0 1601 return;
michael@0 1602 }
michael@0 1603
michael@0 1604 // op only
michael@0 1605 uint32_t size = kUInt32Size;
michael@0 1606 size_t initialOffset = this->addDraw(POP_CULL, &size);
michael@0 1607
michael@0 1608 // update the cull skip offset to point past this op.
michael@0 1609 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
michael@0 1610
michael@0 1611 this->validate(initialOffset, size);
michael@0 1612 }
michael@0 1613
michael@0 1614 ///////////////////////////////////////////////////////////////////////////////
michael@0 1615
michael@0 1616 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
michael@0 1617 return SkSurface::NewPicture(info.fWidth, info.fHeight);
michael@0 1618 }
michael@0 1619
michael@0 1620 void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) {
michael@0 1621 #ifndef SK_ALLOW_BITMAP_TRACKING
michael@0 1622 return;
michael@0 1623 #endif
michael@0 1624
michael@0 1625 if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) {
michael@0 1626 return;
michael@0 1627 }
michael@0 1628
michael@0 1629 if (SkBitmapHeap::INVALID_SLOT == bitmapID) {
michael@0 1630 return;
michael@0 1631 }
michael@0 1632
michael@0 1633 if (NULL == fBitmapUseOffsets) {
michael@0 1634 fBitmapUseOffsets.reset(SkNEW(SkOffsetTable));
michael@0 1635 }
michael@0 1636
michael@0 1637 fBitmapUseOffsets->add(bitmapID, offset);
michael@0 1638 }
michael@0 1639
michael@0 1640 int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
michael@0 1641 const int index = fBitmapHeap->insert(bitmap);
michael@0 1642 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
michael@0 1643 // release builds, the invalid value will be recorded so that the reader will know that there
michael@0 1644 // was a problem.
michael@0 1645 SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
michael@0 1646 this->addInt(index);
michael@0 1647 return index;
michael@0 1648 }
michael@0 1649
michael@0 1650 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
michael@0 1651 fWriter.writeMatrix(matrix);
michael@0 1652 }
michael@0 1653
michael@0 1654 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
michael@0 1655 return fPaints.findAndReturnFlat(paint);
michael@0 1656 }
michael@0 1657
michael@0 1658 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
michael@0 1659 const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
michael@0 1660 this->addFlatPaint(data);
michael@0 1661 return data;
michael@0 1662 }
michael@0 1663
michael@0 1664 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
michael@0 1665 int index = flatPaint ? flatPaint->index() : 0;
michael@0 1666 this->addInt(index);
michael@0 1667 }
michael@0 1668
michael@0 1669 int SkPictureRecord::addPathToHeap(const SkPath& path) {
michael@0 1670 if (NULL == fPathHeap) {
michael@0 1671 fPathHeap = SkNEW(SkPathHeap);
michael@0 1672 }
michael@0 1673 #ifdef SK_DEDUP_PICTURE_PATHS
michael@0 1674 return fPathHeap->insert(path);
michael@0 1675 #else
michael@0 1676 return fPathHeap->append(path);
michael@0 1677 #endif
michael@0 1678 }
michael@0 1679
michael@0 1680 void SkPictureRecord::addPath(const SkPath& path) {
michael@0 1681 this->addInt(this->addPathToHeap(path));
michael@0 1682 }
michael@0 1683
michael@0 1684 void SkPictureRecord::addPicture(SkPicture& picture) {
michael@0 1685 int index = fPictureRefs.find(&picture);
michael@0 1686 if (index < 0) { // not found
michael@0 1687 index = fPictureRefs.count();
michael@0 1688 *fPictureRefs.append() = &picture;
michael@0 1689 picture.ref();
michael@0 1690 }
michael@0 1691 // follow the convention of recording a 1-based index
michael@0 1692 this->addInt(index + 1);
michael@0 1693 }
michael@0 1694
michael@0 1695 void SkPictureRecord::addPoint(const SkPoint& point) {
michael@0 1696 #ifdef SK_DEBUG_SIZE
michael@0 1697 size_t start = fWriter.bytesWritten();
michael@0 1698 #endif
michael@0 1699 fWriter.writePoint(point);
michael@0 1700 #ifdef SK_DEBUG_SIZE
michael@0 1701 fPointBytes += fWriter.bytesWritten() - start;
michael@0 1702 fPointWrites++;
michael@0 1703 #endif
michael@0 1704 }
michael@0 1705
michael@0 1706 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
michael@0 1707 fWriter.writeMul4(pts, count * sizeof(SkPoint));
michael@0 1708 #ifdef SK_DEBUG_SIZE
michael@0 1709 fPointBytes += count * sizeof(SkPoint);
michael@0 1710 fPointWrites++;
michael@0 1711 #endif
michael@0 1712 }
michael@0 1713
michael@0 1714 void SkPictureRecord::addRect(const SkRect& rect) {
michael@0 1715 #ifdef SK_DEBUG_SIZE
michael@0 1716 size_t start = fWriter.bytesWritten();
michael@0 1717 #endif
michael@0 1718 fWriter.writeRect(rect);
michael@0 1719 #ifdef SK_DEBUG_SIZE
michael@0 1720 fRectBytes += fWriter.bytesWritten() - start;
michael@0 1721 fRectWrites++;
michael@0 1722 #endif
michael@0 1723 }
michael@0 1724
michael@0 1725 void SkPictureRecord::addRectPtr(const SkRect* rect) {
michael@0 1726 if (fWriter.writeBool(rect != NULL)) {
michael@0 1727 fWriter.writeRect(*rect);
michael@0 1728 }
michael@0 1729 }
michael@0 1730
michael@0 1731 void SkPictureRecord::addIRect(const SkIRect& rect) {
michael@0 1732 fWriter.write(&rect, sizeof(rect));
michael@0 1733 }
michael@0 1734
michael@0 1735 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
michael@0 1736 if (fWriter.writeBool(rect != NULL)) {
michael@0 1737 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
michael@0 1738 }
michael@0 1739 }
michael@0 1740
michael@0 1741 void SkPictureRecord::addRRect(const SkRRect& rrect) {
michael@0 1742 fWriter.writeRRect(rrect);
michael@0 1743 }
michael@0 1744
michael@0 1745 void SkPictureRecord::addRegion(const SkRegion& region) {
michael@0 1746 fWriter.writeRegion(region);
michael@0 1747 }
michael@0 1748
michael@0 1749 void SkPictureRecord::addText(const void* text, size_t byteLength) {
michael@0 1750 #ifdef SK_DEBUG_SIZE
michael@0 1751 size_t start = fWriter.bytesWritten();
michael@0 1752 #endif
michael@0 1753 addInt(byteLength);
michael@0 1754 fWriter.writePad(text, byteLength);
michael@0 1755 #ifdef SK_DEBUG_SIZE
michael@0 1756 fTextBytes += fWriter.bytesWritten() - start;
michael@0 1757 fTextWrites++;
michael@0 1758 #endif
michael@0 1759 }
michael@0 1760
michael@0 1761 ///////////////////////////////////////////////////////////////////////////////
michael@0 1762
michael@0 1763 #ifdef SK_DEBUG_SIZE
michael@0 1764 size_t SkPictureRecord::size() const {
michael@0 1765 size_t result = 0;
michael@0 1766 size_t sizeData;
michael@0 1767 bitmaps(&sizeData);
michael@0 1768 result += sizeData;
michael@0 1769 matrices(&sizeData);
michael@0 1770 result += sizeData;
michael@0 1771 paints(&sizeData);
michael@0 1772 result += sizeData;
michael@0 1773 paths(&sizeData);
michael@0 1774 result += sizeData;
michael@0 1775 pictures(&sizeData);
michael@0 1776 result += sizeData;
michael@0 1777 regions(&sizeData);
michael@0 1778 result += sizeData;
michael@0 1779 result += streamlen();
michael@0 1780 return result;
michael@0 1781 }
michael@0 1782
michael@0 1783 int SkPictureRecord::bitmaps(size_t* size) const {
michael@0 1784 size_t result = 0;
michael@0 1785 int count = fBitmaps.count();
michael@0 1786 for (int index = 0; index < count; index++)
michael@0 1787 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
michael@0 1788 *size = result;
michael@0 1789 return count;
michael@0 1790 }
michael@0 1791
michael@0 1792 int SkPictureRecord::matrices(size_t* size) const {
michael@0 1793 int count = fMatrices.count();
michael@0 1794 *size = sizeof(fMatrices[0]) * count;
michael@0 1795 return count;
michael@0 1796 }
michael@0 1797
michael@0 1798 int SkPictureRecord::paints(size_t* size) const {
michael@0 1799 size_t result = 0;
michael@0 1800 int count = fPaints.count();
michael@0 1801 for (int index = 0; index < count; index++)
michael@0 1802 result += sizeof(fPaints[index]) + fPaints[index]->size();
michael@0 1803 *size = result;
michael@0 1804 return count;
michael@0 1805 }
michael@0 1806
michael@0 1807 int SkPictureRecord::paths(size_t* size) const {
michael@0 1808 size_t result = 0;
michael@0 1809 int count = fPaths.count();
michael@0 1810 for (int index = 0; index < count; index++)
michael@0 1811 result += sizeof(fPaths[index]) + fPaths[index]->size();
michael@0 1812 *size = result;
michael@0 1813 return count;
michael@0 1814 }
michael@0 1815
michael@0 1816 int SkPictureRecord::regions(size_t* size) const {
michael@0 1817 size_t result = 0;
michael@0 1818 int count = fRegions.count();
michael@0 1819 for (int index = 0; index < count; index++)
michael@0 1820 result += sizeof(fRegions[index]) + fRegions[index]->size();
michael@0 1821 *size = result;
michael@0 1822 return count;
michael@0 1823 }
michael@0 1824
michael@0 1825 size_t SkPictureRecord::streamlen() const {
michael@0 1826 return fWriter.size();
michael@0 1827 }
michael@0 1828 #endif
michael@0 1829
michael@0 1830 #ifdef SK_DEBUG_VALIDATE
michael@0 1831 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
michael@0 1832 SkASSERT(fWriter.size() == initialOffset + size);
michael@0 1833
michael@0 1834 validateBitmaps();
michael@0 1835 validateMatrices();
michael@0 1836 validatePaints();
michael@0 1837 validatePaths();
michael@0 1838 validateRegions();
michael@0 1839 }
michael@0 1840
michael@0 1841 void SkPictureRecord::validateBitmaps() const {
michael@0 1842 int count = fBitmapHeap->count();
michael@0 1843 SkASSERT((unsigned) count < 0x1000);
michael@0 1844 for (int index = 0; index < count; index++) {
michael@0 1845 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
michael@0 1846 SkASSERT(bitPtr);
michael@0 1847 bitPtr->validate();
michael@0 1848 }
michael@0 1849 }
michael@0 1850
michael@0 1851 void SkPictureRecord::validateMatrices() const {
michael@0 1852 int count = fMatrices.count();
michael@0 1853 SkASSERT((unsigned) count < 0x1000);
michael@0 1854 for (int index = 0; index < count; index++) {
michael@0 1855 const SkFlatData* matrix = fMatrices[index];
michael@0 1856 SkASSERT(matrix);
michael@0 1857 // matrix->validate();
michael@0 1858 }
michael@0 1859 }
michael@0 1860
michael@0 1861 void SkPictureRecord::validatePaints() const {
michael@0 1862 int count = fPaints.count();
michael@0 1863 SkASSERT((unsigned) count < 0x1000);
michael@0 1864 for (int index = 0; index < count; index++) {
michael@0 1865 const SkFlatData* paint = fPaints[index];
michael@0 1866 SkASSERT(paint);
michael@0 1867 // paint->validate();
michael@0 1868 }
michael@0 1869 }
michael@0 1870
michael@0 1871 void SkPictureRecord::validatePaths() const {
michael@0 1872 if (NULL == fPathHeap) {
michael@0 1873 return;
michael@0 1874 }
michael@0 1875
michael@0 1876 int count = fPathHeap->count();
michael@0 1877 SkASSERT((unsigned) count < 0x1000);
michael@0 1878 for (int index = 0; index < count; index++) {
michael@0 1879 const SkPath& path = (*fPathHeap)[index];
michael@0 1880 path.validate();
michael@0 1881 }
michael@0 1882 }
michael@0 1883
michael@0 1884 void SkPictureRecord::validateRegions() const {
michael@0 1885 int count = fRegions.count();
michael@0 1886 SkASSERT((unsigned) count < 0x1000);
michael@0 1887 for (int index = 0; index < count; index++) {
michael@0 1888 const SkFlatData* region = fRegions[index];
michael@0 1889 SkASSERT(region);
michael@0 1890 // region->validate();
michael@0 1891 }
michael@0 1892 }
michael@0 1893 #endif

mercurial