1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkPictureRecord.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1893 @@ 1.4 +/* 1.5 + * Copyright 2011 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkPictureRecord.h" 1.12 +#include "SkTSearch.h" 1.13 +#include "SkPixelRef.h" 1.14 +#include "SkRRect.h" 1.15 +#include "SkBBoxHierarchy.h" 1.16 +#include "SkDevice.h" 1.17 +#include "SkOffsetTable.h" 1.18 +#include "SkPictureStateTree.h" 1.19 +#include "SkSurface.h" 1.20 + 1.21 +#define HEAP_BLOCK_SIZE 4096 1.22 + 1.23 +enum { 1.24 + // just need a value that save or getSaveCount would never return 1.25 + kNoInitialSave = -1, 1.26 +}; 1.27 + 1.28 +// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc. 1.29 +static int const kUInt32Size = 4; 1.30 + 1.31 +static const uint32_t kSaveSize = 2 * kUInt32Size; 1.32 +static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; 1.33 +static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect); 1.34 + 1.35 +SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) 1.36 + : INHERITED(dimensions.width(), dimensions.height()) 1.37 + , fBoundingHierarchy(NULL) 1.38 + , fStateTree(NULL) 1.39 + , fFlattenableHeap(HEAP_BLOCK_SIZE) 1.40 + , fPaints(&fFlattenableHeap) 1.41 + , fRecordFlags(flags) 1.42 + , fOptsEnabled(true) { 1.43 +#ifdef SK_DEBUG_SIZE 1.44 + fPointBytes = fRectBytes = fTextBytes = 0; 1.45 + fPointWrites = fRectWrites = fTextWrites = 0; 1.46 +#endif 1.47 + 1.48 + fBitmapHeap = SkNEW(SkBitmapHeap); 1.49 + fFlattenableHeap.setBitmapStorage(fBitmapHeap); 1.50 + fPathHeap = NULL; // lazy allocate 1.51 + 1.52 +#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE 1.53 + fFirstSavedLayerIndex = kNoSavedLayerIndex; 1.54 +#endif 1.55 + 1.56 + fInitialSaveCount = kNoInitialSave; 1.57 + 1.58 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.59 + fMCMgr.init(this); 1.60 +#endif 1.61 +} 1.62 + 1.63 +SkPictureRecord::~SkPictureRecord() { 1.64 + SkSafeUnref(fBitmapHeap); 1.65 + SkSafeUnref(fPathHeap); 1.66 + SkSafeUnref(fBoundingHierarchy); 1.67 + SkSafeUnref(fStateTree); 1.68 + fFlattenableHeap.setBitmapStorage(NULL); 1.69 + fPictureRefs.unrefAll(); 1.70 +} 1.71 + 1.72 +/////////////////////////////////////////////////////////////////////////////// 1.73 + 1.74 +// Return the offset of the paint inside a given op's byte stream. A zero 1.75 +// return value means there is no paint (and you really shouldn't be calling 1.76 +// this method) 1.77 +static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) { 1.78 + // These offsets are where the paint would be if the op size doesn't overflow 1.79 + static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = { 1.80 + 0, // UNUSED - no paint 1.81 + 0, // CLIP_PATH - no paint 1.82 + 0, // CLIP_REGION - no paint 1.83 + 0, // CLIP_RECT - no paint 1.84 + 0, // CLIP_RRECT - no paint 1.85 + 0, // CONCAT - no paint 1.86 + 1, // DRAW_BITMAP - right after op code 1.87 + 1, // DRAW_BITMAP_MATRIX - right after op code 1.88 + 1, // DRAW_BITMAP_NINE - right after op code 1.89 + 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code 1.90 + 0, // DRAW_CLEAR - no paint 1.91 + 0, // DRAW_DATA - no paint 1.92 + 1, // DRAW_OVAL - right after op code 1.93 + 1, // DRAW_PAINT - right after op code 1.94 + 1, // DRAW_PATH - right after op code 1.95 + 0, // DRAW_PICTURE - no paint 1.96 + 1, // DRAW_POINTS - right after op code 1.97 + 1, // DRAW_POS_TEXT - right after op code 1.98 + 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code 1.99 + 1, // DRAW_POS_TEXT_H - right after op code 1.100 + 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code 1.101 + 1, // DRAW_RECT - right after op code 1.102 + 1, // DRAW_RRECT - right after op code 1.103 + 1, // DRAW_SPRITE - right after op code 1.104 + 1, // DRAW_TEXT - right after op code 1.105 + 1, // DRAW_TEXT_ON_PATH - right after op code 1.106 + 1, // DRAW_TEXT_TOP_BOTTOM - right after op code 1.107 + 1, // DRAW_VERTICES - right after op code 1.108 + 0, // RESTORE - no paint 1.109 + 0, // ROTATE - no paint 1.110 + 0, // SAVE - no paint 1.111 + 0, // SAVE_LAYER - see below - this paint's location varies 1.112 + 0, // SCALE - no paint 1.113 + 0, // SET_MATRIX - no paint 1.114 + 0, // SKEW - no paint 1.115 + 0, // TRANSLATE - no paint 1.116 + 0, // NOOP - no paint 1.117 + 0, // BEGIN_GROUP - no paint 1.118 + 0, // COMMENT - no paint 1.119 + 0, // END_GROUP - no paint 1.120 + 1, // DRAWDRRECT - right after op code 1.121 + 0, // PUSH_CULL - no paint 1.122 + 0, // POP_CULL - no paint 1.123 + }; 1.124 + 1.125 + SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, 1.126 + need_to_be_in_sync); 1.127 + SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM); 1.128 + 1.129 + int overflow = 0; 1.130 + if (0 != (opSize & ~MASK_24) || opSize == MASK_24) { 1.131 + // This op's size overflows so an extra uint32_t will be written 1.132 + // after the op code 1.133 + overflow = sizeof(uint32_t); 1.134 + } 1.135 + 1.136 + if (SAVE_LAYER == op) { 1.137 + static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size; 1.138 + static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect); 1.139 + 1.140 + if (kSaveLayerNoBoundsSize == opSize) { 1.141 + return kSaveLayerNoBoundsPaintOffset + overflow; 1.142 + } else { 1.143 + SkASSERT(kSaveLayerWithBoundsSize == opSize); 1.144 + return kSaveLayerWithBoundsPaintOffset + overflow; 1.145 + } 1.146 + } 1.147 + 1.148 + SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method 1.149 + return gPaintOffsets[op] * sizeof(uint32_t) + overflow; 1.150 +} 1.151 + 1.152 +void SkPictureRecord::willSave(SaveFlags flags) { 1.153 + 1.154 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.155 + fMCMgr.save(flags); 1.156 +#else 1.157 + // record the offset to us, making it non-positive to distinguish a save 1.158 + // from a clip entry. 1.159 + fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); 1.160 + this->recordSave(flags); 1.161 +#endif 1.162 + 1.163 + this->INHERITED::willSave(flags); 1.164 +} 1.165 + 1.166 +void SkPictureRecord::recordSave(SaveFlags flags) { 1.167 + // op + flags 1.168 + uint32_t size = kSaveSize; 1.169 + size_t initialOffset = this->addDraw(SAVE, &size); 1.170 + this->addInt(flags); 1.171 + 1.172 + this->validate(initialOffset, size); 1.173 +} 1.174 + 1.175 +SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds, 1.176 + const SkPaint* paint, SaveFlags flags) { 1.177 + 1.178 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.179 + fMCMgr.saveLayer(bounds, paint, flags); 1.180 +#else 1.181 + // record the offset to us, making it non-positive to distinguish a save 1.182 + // from a clip entry. 1.183 + fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); 1.184 + this->recordSaveLayer(bounds, paint, flags); 1.185 + if (kNoSavedLayerIndex == fFirstSavedLayerIndex) { 1.186 + fFirstSavedLayerIndex = fRestoreOffsetStack.count(); 1.187 + } 1.188 +#endif 1.189 + 1.190 + this->INHERITED::willSaveLayer(bounds, paint, flags); 1.191 + /* No need for a (potentially very big) layer which we don't actually need 1.192 + at this time (and may not be able to afford since during record our 1.193 + clip starts out the size of the picture, which is often much larger 1.194 + than the size of the actual device we'll use during playback). 1.195 + */ 1.196 + return kNoLayer_SaveLayerStrategy; 1.197 +} 1.198 + 1.199 +void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint, 1.200 + SaveFlags flags) { 1.201 + // op + bool for 'bounds' 1.202 + uint32_t size = 2 * kUInt32Size; 1.203 + if (NULL != bounds) { 1.204 + size += sizeof(*bounds); // + rect 1.205 + } 1.206 + // + paint index + flags 1.207 + size += 2 * kUInt32Size; 1.208 + 1.209 + SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size); 1.210 + 1.211 + size_t initialOffset = this->addDraw(SAVE_LAYER, &size); 1.212 + this->addRectPtr(bounds); 1.213 + SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten()); 1.214 + this->addPaintPtr(paint); 1.215 + this->addInt(flags); 1.216 + 1.217 + this->validate(initialOffset, size); 1.218 +} 1.219 + 1.220 +bool SkPictureRecord::isDrawingToLayer() const { 1.221 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.222 + return fMCMgr.isDrawingToLayer(); 1.223 +#else 1.224 + return fFirstSavedLayerIndex != kNoSavedLayerIndex; 1.225 +#endif 1.226 +} 1.227 + 1.228 +/* 1.229 + * Read the op code from 'offset' in 'writer'. 1.230 + */ 1.231 +#ifdef SK_DEBUG 1.232 +static DrawType peek_op(SkWriter32* writer, int32_t offset) { 1.233 + return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24); 1.234 +} 1.235 +#endif 1.236 + 1.237 +/* 1.238 + * Read the op code from 'offset' in 'writer' and extract the size too. 1.239 + */ 1.240 +static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) { 1.241 + uint32_t peek = writer->readTAt<uint32_t>(offset); 1.242 + 1.243 + uint32_t op; 1.244 + UNPACK_8_24(peek, op, *size); 1.245 + if (MASK_24 == *size) { 1.246 + // size required its own slot right after the op code 1.247 + *size = writer->readTAt<uint32_t>(offset + kUInt32Size); 1.248 + } 1.249 + return (DrawType) op; 1.250 +} 1.251 + 1.252 +#ifdef TRACK_COLLAPSE_STATS 1.253 + static int gCollapseCount, gCollapseCalls; 1.254 +#endif 1.255 + 1.256 +// Is the supplied paint simply a color? 1.257 +static bool is_simple(const SkPaint& p) { 1.258 + intptr_t orAccum = (intptr_t)p.getPathEffect() | 1.259 + (intptr_t)p.getShader() | 1.260 + (intptr_t)p.getXfermode() | 1.261 + (intptr_t)p.getMaskFilter() | 1.262 + (intptr_t)p.getColorFilter() | 1.263 + (intptr_t)p.getRasterizer() | 1.264 + (intptr_t)p.getLooper() | 1.265 + (intptr_t)p.getImageFilter(); 1.266 + return 0 == orAccum; 1.267 +} 1.268 + 1.269 +// CommandInfos are fed to the 'match' method and filled in with command 1.270 +// information. 1.271 +struct CommandInfo { 1.272 + DrawType fActualOp; 1.273 + uint32_t fOffset; 1.274 + uint32_t fSize; 1.275 +}; 1.276 + 1.277 +/* 1.278 + * Attempt to match the provided pattern of commands starting at 'offset' 1.279 + * in the byte stream and stopping at the end of the stream. Upon success, 1.280 + * return true with all the pattern information filled out in the result 1.281 + * array (i.e., actual ops, offsets and sizes). 1.282 + * Note this method skips any NOOPs seen in the stream 1.283 + */ 1.284 +static bool match(SkWriter32* writer, uint32_t offset, 1.285 + int* pattern, CommandInfo* result, int numCommands) { 1.286 + SkASSERT(offset < writer->bytesWritten()); 1.287 + 1.288 + uint32_t curOffset = offset; 1.289 + uint32_t curSize = 0; 1.290 + int numMatched; 1.291 + for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) { 1.292 + DrawType op = peek_op_and_size(writer, curOffset, &curSize); 1.293 + while (NOOP == op && curOffset < writer->bytesWritten()) { 1.294 + curOffset += curSize; 1.295 + op = peek_op_and_size(writer, curOffset, &curSize); 1.296 + } 1.297 + 1.298 + if (curOffset >= writer->bytesWritten()) { 1.299 + return false; // ran out of byte stream 1.300 + } 1.301 + 1.302 + if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) { 1.303 + if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op && 1.304 + DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) { 1.305 + return false; 1.306 + } 1.307 + } else if (op != pattern[numMatched]) { 1.308 + return false; 1.309 + } 1.310 + 1.311 + result[numMatched].fActualOp = op; 1.312 + result[numMatched].fOffset = curOffset; 1.313 + result[numMatched].fSize = curSize; 1.314 + 1.315 + curOffset += curSize; 1.316 + } 1.317 + 1.318 + if (numMatched != numCommands) { 1.319 + return false; 1.320 + } 1.321 + 1.322 + curOffset += curSize; 1.323 + if (curOffset < writer->bytesWritten()) { 1.324 + // Something else between the last command and the end of the stream 1.325 + return false; 1.326 + } 1.327 + 1.328 + return true; 1.329 +} 1.330 + 1.331 +// temporarily here to make code review easier 1.332 +static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, 1.333 + SkPaintDictionary* paintDict, 1.334 + const CommandInfo& saveLayerInfo, 1.335 + const CommandInfo& dbmInfo); 1.336 + 1.337 +/* 1.338 + * Restore has just been called (but not recorded), look back at the 1.339 + * matching save* and see if we are in the configuration: 1.340 + * SAVE_LAYER 1.341 + * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT 1.342 + * RESTORE 1.343 + * where the saveLayer's color can be moved into the drawBitmap*'s paint 1.344 + */ 1.345 +static bool remove_save_layer1(SkWriter32* writer, int32_t offset, 1.346 + SkPaintDictionary* paintDict) { 1.347 + // back up to the save block 1.348 + // TODO: add a stack to track save*/restore offsets rather than searching backwards 1.349 + while (offset > 0) { 1.350 + offset = writer->readTAt<uint32_t>(offset); 1.351 + } 1.352 + 1.353 + int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ }; 1.354 + CommandInfo result[SK_ARRAY_COUNT(pattern)]; 1.355 + 1.356 + if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { 1.357 + return false; 1.358 + } 1.359 + 1.360 + if (kSaveLayerWithBoundsSize == result[0].fSize) { 1.361 + // The saveLayer's bound can offset where the dbm is drawn 1.362 + return false; 1.363 + } 1.364 + 1.365 + return merge_savelayer_paint_into_drawbitmp(writer, paintDict, 1.366 + result[0], result[1]); 1.367 +} 1.368 + 1.369 +/* 1.370 + * Convert the command code located at 'offset' to a NOOP. Leave the size 1.371 + * field alone so the NOOP can be skipped later. 1.372 + */ 1.373 +static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) { 1.374 + uint32_t command = writer->readTAt<uint32_t>(offset); 1.375 + writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24)); 1.376 +} 1.377 + 1.378 +/* 1.379 + * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint. 1.380 + * Return true on success; false otherwise. 1.381 + */ 1.382 +static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, 1.383 + SkPaintDictionary* paintDict, 1.384 + const CommandInfo& saveLayerInfo, 1.385 + const CommandInfo& dbmInfo) { 1.386 + SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp); 1.387 + SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp || 1.388 + DRAW_BITMAP_MATRIX == dbmInfo.fActualOp || 1.389 + DRAW_BITMAP_NINE == dbmInfo.fActualOp || 1.390 + DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp); 1.391 + 1.392 + uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize); 1.393 + uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize); 1.394 + 1.395 + // we have a match, now we need to get the paints involved 1.396 + uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset); 1.397 + uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset); 1.398 + 1.399 + if (0 == saveLayerPaintId) { 1.400 + // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer 1.401 + // and signal the caller (by returning true) to not add the RESTORE op 1.402 + convert_command_to_noop(writer, saveLayerInfo.fOffset); 1.403 + return true; 1.404 + } 1.405 + 1.406 + if (0 == dbmPaintId) { 1.407 + // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer 1.408 + // and signal the caller (by returning true) to not add the RESTORE op 1.409 + convert_command_to_noop(writer, saveLayerInfo.fOffset); 1.410 + writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId); 1.411 + return true; 1.412 + } 1.413 + 1.414 + SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId)); 1.415 + if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) { 1.416 + return false; 1.417 + } 1.418 + 1.419 + // For this optimization we only fold the saveLayer and drawBitmapRect 1.420 + // together if the saveLayer's draw is simple (i.e., no fancy effects) and 1.421 + // and the only difference in the colors is that the saveLayer's can have 1.422 + // an alpha while the drawBitmapRect's is opaque. 1.423 + // TODO: it should be possible to fold them together even if they both 1.424 + // have different non-255 alphas 1.425 + SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque 1.426 + 1.427 + SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId)); 1.428 + if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) { 1.429 + return false; 1.430 + } 1.431 + 1.432 + SkColor newColor = SkColorSetA(dbmPaint->getColor(), 1.433 + SkColorGetA(saveLayerPaint->getColor())); 1.434 + dbmPaint->setColor(newColor); 1.435 + 1.436 + const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint); 1.437 + if (NULL == data) { 1.438 + return false; 1.439 + } 1.440 + 1.441 + // kill the saveLayer and alter the DBMR2R's paint to be the modified one 1.442 + convert_command_to_noop(writer, saveLayerInfo.fOffset); 1.443 + writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index()); 1.444 + return true; 1.445 +} 1.446 + 1.447 +/* 1.448 + * Restore has just been called (but not recorded), look back at the 1.449 + * matching save* and see if we are in the configuration: 1.450 + * SAVE_LAYER (with NULL == bounds) 1.451 + * SAVE 1.452 + * CLIP_RECT 1.453 + * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT 1.454 + * RESTORE 1.455 + * RESTORE 1.456 + * where the saveLayer's color can be moved into the drawBitmap*'s paint 1.457 + */ 1.458 +static bool remove_save_layer2(SkWriter32* writer, int32_t offset, 1.459 + SkPaintDictionary* paintDict) { 1.460 + 1.461 + // back up to the save block 1.462 + // TODO: add a stack to track save*/restore offsets rather than searching backwards 1.463 + while (offset > 0) { 1.464 + offset = writer->readTAt<uint32_t>(offset); 1.465 + } 1.466 + 1.467 + int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ }; 1.468 + CommandInfo result[SK_ARRAY_COUNT(pattern)]; 1.469 + 1.470 + if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { 1.471 + return false; 1.472 + } 1.473 + 1.474 + if (kSaveLayerWithBoundsSize == result[0].fSize) { 1.475 + // The saveLayer's bound can offset where the dbm is drawn 1.476 + return false; 1.477 + } 1.478 + 1.479 + return merge_savelayer_paint_into_drawbitmp(writer, paintDict, 1.480 + result[0], result[3]); 1.481 +} 1.482 + 1.483 +static bool is_drawing_op(DrawType op) { 1.484 + return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op; 1.485 +} 1.486 + 1.487 +/* 1.488 + * Restore has just been called (but not recorded), so look back at the 1.489 + * matching save(), and see if we can eliminate the pair of them, due to no 1.490 + * intervening matrix/clip calls. 1.491 + * 1.492 + * If so, update the writer and return true, in which case we won't even record 1.493 + * the restore() call. If we still need the restore(), return false. 1.494 + */ 1.495 +static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset, 1.496 + SkPaintDictionary* paintDict) { 1.497 +#ifdef TRACK_COLLAPSE_STATS 1.498 + gCollapseCalls += 1; 1.499 +#endif 1.500 + 1.501 + int32_t restoreOffset = (int32_t)writer->bytesWritten(); 1.502 + 1.503 + // back up to the save block 1.504 + while (offset > 0) { 1.505 + offset = writer->readTAt<uint32_t>(offset); 1.506 + } 1.507 + 1.508 + // now offset points to a save 1.509 + offset = -offset; 1.510 + uint32_t opSize; 1.511 + DrawType op = peek_op_and_size(writer, offset, &opSize); 1.512 + if (SAVE_LAYER == op) { 1.513 + // not ready to cull these out yet (mrr) 1.514 + return false; 1.515 + } 1.516 + SkASSERT(SAVE == op); 1.517 + SkASSERT(kSaveSize == opSize); 1.518 + 1.519 + // get the save flag (last 4-bytes of the space allocated for the opSize) 1.520 + SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4); 1.521 + if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) { 1.522 + // This function's optimization is only correct for kMatrixClip style saves. 1.523 + // TODO: set checkMatrix & checkClip booleans here and then check for the 1.524 + // offending operations in the following loop. 1.525 + return false; 1.526 + } 1.527 + 1.528 + // Walk forward until we get back to either a draw-verb (abort) or we hit 1.529 + // our restore (success). 1.530 + int32_t saveOffset = offset; 1.531 + 1.532 + offset += opSize; 1.533 + while (offset < restoreOffset) { 1.534 + op = peek_op_and_size(writer, offset, &opSize); 1.535 + if (is_drawing_op(op) || (SAVE_LAYER == op)) { 1.536 + // drawing verb, abort 1.537 + return false; 1.538 + } 1.539 + offset += opSize; 1.540 + } 1.541 + 1.542 +#ifdef TRACK_COLLAPSE_STATS 1.543 + gCollapseCount += 1; 1.544 + SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls, 1.545 + (double)gCollapseCount / gCollapseCalls, "%"); 1.546 +#endif 1.547 + 1.548 + writer->rewindToOffset(saveOffset); 1.549 + return true; 1.550 +} 1.551 + 1.552 +typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset, 1.553 + SkPaintDictionary* paintDict); 1.554 +enum PictureRecordOptType { 1.555 + kRewind_OptType, // Optimization rewinds the command stream 1.556 + kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair 1.557 +}; 1.558 + 1.559 +enum PictureRecordOptFlags { 1.560 + kSkipIfBBoxHierarchy_Flag = 0x1, // Optimization should be skipped if the 1.561 + // SkPicture has a bounding box hierarchy. 1.562 +}; 1.563 + 1.564 +struct PictureRecordOpt { 1.565 + PictureRecordOptProc fProc; 1.566 + PictureRecordOptType fType; 1.567 + unsigned fFlags; 1.568 +}; 1.569 +/* 1.570 + * A list of the optimizations that are tried upon seeing a restore 1.571 + * TODO: add a real API for such optimizations 1.572 + * Add the ability to fire optimizations on any op (not just RESTORE) 1.573 + */ 1.574 +static const PictureRecordOpt gPictureRecordOpts[] = { 1.575 + // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy 1.576 + // because it is redundant with the state traversal optimization in 1.577 + // SkPictureStateTree, and applying the optimization introduces significant 1.578 + // record time overhead because it requires rewinding contents that were 1.579 + // recorded into the BBoxHierarchy. 1.580 + { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag }, 1.581 + { remove_save_layer1, kCollapseSaveLayer_OptType, 0 }, 1.582 + { remove_save_layer2, kCollapseSaveLayer_OptType, 0 } 1.583 +}; 1.584 + 1.585 +// This is called after an optimization has been applied to the command stream 1.586 +// in order to adjust the contents and state of the bounding box hierarchy and 1.587 +// state tree to reflect the optimization. 1.588 +static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree, 1.589 + SkBBoxHierarchy* boundingHierarchy) { 1.590 + switch (opt) { 1.591 + case kCollapseSaveLayer_OptType: 1.592 + if (NULL != stateTree) { 1.593 + stateTree->saveCollapsed(); 1.594 + } 1.595 + break; 1.596 + case kRewind_OptType: 1.597 + if (NULL != boundingHierarchy) { 1.598 + boundingHierarchy->rewindInserts(); 1.599 + } 1.600 + // Note: No need to touch the state tree for this to work correctly. 1.601 + // Unused branches do not burden the playback, and pruning the tree 1.602 + // would be O(N^2), so it is best to leave it alone. 1.603 + break; 1.604 + default: 1.605 + SkASSERT(0); 1.606 + } 1.607 +} 1.608 + 1.609 +void SkPictureRecord::willRestore() { 1.610 + // FIXME: SkDeferredCanvas needs to be refactored to respect 1.611 + // save/restore balancing so that the following test can be 1.612 + // turned on permanently. 1.613 +#if 0 1.614 + SkASSERT(fRestoreOffsetStack.count() > 1); 1.615 +#endif 1.616 + 1.617 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.618 + if (fMCMgr.getSaveCount() == 1) { 1.619 + return; 1.620 + } 1.621 + 1.622 + fMCMgr.restore(); 1.623 +#else 1.624 + // check for underflow 1.625 + if (fRestoreOffsetStack.count() == 0) { 1.626 + return; 1.627 + } 1.628 + 1.629 + if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) { 1.630 + fFirstSavedLayerIndex = kNoSavedLayerIndex; 1.631 + } 1.632 + 1.633 + size_t opt = 0; 1.634 + if (fOptsEnabled) { 1.635 + for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) { 1.636 + if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag) 1.637 + && NULL != fBoundingHierarchy) { 1.638 + continue; 1.639 + } 1.640 + if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) { 1.641 + // Some optimization fired so don't add the RESTORE 1.642 + apply_optimization_to_bbh(gPictureRecordOpts[opt].fType, 1.643 + fStateTree, fBoundingHierarchy); 1.644 + break; 1.645 + } 1.646 + } 1.647 + } 1.648 + 1.649 + if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) { 1.650 + // No optimization fired so add the RESTORE 1.651 + this->recordRestore(); 1.652 + } 1.653 + 1.654 + fRestoreOffsetStack.pop(); 1.655 +#endif 1.656 + 1.657 + this->INHERITED::willRestore(); 1.658 +} 1.659 + 1.660 +void SkPictureRecord::recordRestore(bool fillInSkips) { 1.661 + uint32_t initialOffset, size; 1.662 + if (fillInSkips) { 1.663 + this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten()); 1.664 + } 1.665 + size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code 1.666 + initialOffset = this->addDraw(RESTORE, &size); 1.667 + this->validate(initialOffset, size); 1.668 +} 1.669 + 1.670 +void SkPictureRecord::didTranslate(SkScalar dx, SkScalar dy) { 1.671 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.672 + fMCMgr.translate(dx, dy); 1.673 +#else 1.674 + // op + dx + dy 1.675 + uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 1.676 + size_t initialOffset = this->addDraw(TRANSLATE, &size); 1.677 + this->addScalar(dx); 1.678 + this->addScalar(dy); 1.679 + this->validate(initialOffset, size); 1.680 +#endif 1.681 + this->INHERITED::didTranslate(dx, dy); 1.682 +} 1.683 + 1.684 +void SkPictureRecord::didScale(SkScalar sx, SkScalar sy) { 1.685 + 1.686 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.687 + fMCMgr.scale(sx, sy); 1.688 +#else 1.689 + // op + sx + sy 1.690 + uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 1.691 + size_t initialOffset = this->addDraw(SCALE, &size); 1.692 + this->addScalar(sx); 1.693 + this->addScalar(sy); 1.694 + this->validate(initialOffset, size); 1.695 +#endif 1.696 + this->INHERITED::didScale(sx, sy); 1.697 +} 1.698 + 1.699 +void SkPictureRecord::didRotate(SkScalar degrees) { 1.700 + 1.701 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.702 + fMCMgr.rotate(degrees); 1.703 +#else 1.704 + // op + degrees 1.705 + uint32_t size = 1 * kUInt32Size + sizeof(SkScalar); 1.706 + size_t initialOffset = this->addDraw(ROTATE, &size); 1.707 + this->addScalar(degrees); 1.708 + this->validate(initialOffset, size); 1.709 +#endif 1.710 + this->INHERITED::didRotate(degrees); 1.711 +} 1.712 + 1.713 +void SkPictureRecord::didSkew(SkScalar sx, SkScalar sy) { 1.714 + 1.715 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.716 + fMCMgr.skew(sx, sy); 1.717 +#else 1.718 + // op + sx + sy 1.719 + uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 1.720 + size_t initialOffset = this->addDraw(SKEW, &size); 1.721 + this->addScalar(sx); 1.722 + this->addScalar(sy); 1.723 + this->validate(initialOffset, size); 1.724 +#endif 1.725 + this->INHERITED::didSkew(sx, sy); 1.726 +} 1.727 + 1.728 +void SkPictureRecord::didConcat(const SkMatrix& matrix) { 1.729 + 1.730 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.731 + fMCMgr.concat(matrix); 1.732 +#else 1.733 + this->recordConcat(matrix); 1.734 +#endif 1.735 + this->INHERITED::didConcat(matrix); 1.736 +} 1.737 + 1.738 +void SkPictureRecord::recordConcat(const SkMatrix& matrix) { 1.739 + this->validate(fWriter.bytesWritten(), 0); 1.740 + // op + matrix 1.741 + uint32_t size = kUInt32Size + matrix.writeToMemory(NULL); 1.742 + size_t initialOffset = this->addDraw(CONCAT, &size); 1.743 + this->addMatrix(matrix); 1.744 + this->validate(initialOffset, size); 1.745 +} 1.746 + 1.747 +void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) { 1.748 + 1.749 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.750 + fMCMgr.setMatrix(matrix); 1.751 +#else 1.752 + this->validate(fWriter.bytesWritten(), 0); 1.753 + // op + matrix 1.754 + uint32_t size = kUInt32Size + matrix.writeToMemory(NULL); 1.755 + size_t initialOffset = this->addDraw(SET_MATRIX, &size); 1.756 + this->addMatrix(matrix); 1.757 + this->validate(initialOffset, size); 1.758 +#endif 1.759 + this->INHERITED::didSetMatrix(matrix); 1.760 +} 1.761 + 1.762 +static bool regionOpExpands(SkRegion::Op op) { 1.763 + switch (op) { 1.764 + case SkRegion::kUnion_Op: 1.765 + case SkRegion::kXOR_Op: 1.766 + case SkRegion::kReverseDifference_Op: 1.767 + case SkRegion::kReplace_Op: 1.768 + return true; 1.769 + case SkRegion::kIntersect_Op: 1.770 + case SkRegion::kDifference_Op: 1.771 + return false; 1.772 + default: 1.773 + SkDEBUGFAIL("unknown region op"); 1.774 + return false; 1.775 + } 1.776 +} 1.777 + 1.778 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.779 +void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { 1.780 + fMCMgr.fillInSkips(&fWriter, restoreOffset); 1.781 +} 1.782 +#else 1.783 +void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { 1.784 + int32_t offset = fRestoreOffsetStack.top(); 1.785 + while (offset > 0) { 1.786 + uint32_t peek = fWriter.readTAt<uint32_t>(offset); 1.787 + fWriter.overwriteTAt(offset, restoreOffset); 1.788 + offset = peek; 1.789 + } 1.790 + 1.791 +#ifdef SK_DEBUG 1.792 + // assert that the final offset value points to a save verb 1.793 + uint32_t opSize; 1.794 + DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); 1.795 + SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); 1.796 +#endif 1.797 +} 1.798 +#endif 1.799 + 1.800 +void SkPictureRecord::beginRecording() { 1.801 + // we have to call this *after* our constructor, to ensure that it gets 1.802 + // recorded. This is balanced by restoreToCount() call from endRecording, 1.803 + // which in-turn calls our overridden restore(), so those get recorded too. 1.804 + fInitialSaveCount = this->save(kMatrixClip_SaveFlag); 1.805 +} 1.806 + 1.807 +void SkPictureRecord::endRecording() { 1.808 + SkASSERT(kNoInitialSave != fInitialSaveCount); 1.809 + this->restoreToCount(fInitialSaveCount); 1.810 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.811 + fMCMgr.finish(); 1.812 +#endif 1.813 +} 1.814 + 1.815 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.816 +int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { 1.817 + size_t offset = fWriter.bytesWritten(); 1.818 + this->addInt(-1); 1.819 + return offset; 1.820 +} 1.821 +#else 1.822 +int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { 1.823 + if (fRestoreOffsetStack.isEmpty()) { 1.824 + return -1; 1.825 + } 1.826 + 1.827 + // The RestoreOffset field is initially filled with a placeholder 1.828 + // value that points to the offset of the previous RestoreOffset 1.829 + // in the current stack level, thus forming a linked list so that 1.830 + // the restore offsets can be filled in when the corresponding 1.831 + // restore command is recorded. 1.832 + int32_t prevOffset = fRestoreOffsetStack.top(); 1.833 + 1.834 + if (regionOpExpands(op)) { 1.835 + // Run back through any previous clip ops, and mark their offset to 1.836 + // be 0, disabling their ability to trigger a jump-to-restore, otherwise 1.837 + // they could hide this clips ability to expand the clip (i.e. go from 1.838 + // empty to non-empty). 1.839 + this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0); 1.840 + 1.841 + // Reset the pointer back to the previous clip so that subsequent 1.842 + // restores don't overwrite the offsets we just cleared. 1.843 + prevOffset = 0; 1.844 + } 1.845 + 1.846 + size_t offset = fWriter.bytesWritten(); 1.847 + this->addInt(prevOffset); 1.848 + fRestoreOffsetStack.top() = offset; 1.849 + return offset; 1.850 +} 1.851 +#endif 1.852 + 1.853 +void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1.854 + 1.855 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.856 + fMCMgr.clipRect(rect, op, doAA); 1.857 +#else 1.858 + this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); 1.859 +#endif 1.860 + this->INHERITED::onClipRect(rect, op, edgeStyle); 1.861 +} 1.862 + 1.863 +int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 1.864 + // id + rect + clip params 1.865 + uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; 1.866 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.867 + size += kUInt32Size; // + restore offset 1.868 +#else 1.869 + // recordRestoreOffsetPlaceholder doesn't always write an offset 1.870 + if (!fRestoreOffsetStack.isEmpty()) { 1.871 + // + restore offset 1.872 + size += kUInt32Size; 1.873 + } 1.874 +#endif 1.875 + size_t initialOffset = this->addDraw(CLIP_RECT, &size); 1.876 + this->addRect(rect); 1.877 + this->addInt(ClipParams_pack(op, doAA)); 1.878 + int offset = this->recordRestoreOffsetPlaceholder(op); 1.879 + 1.880 + this->validate(initialOffset, size); 1.881 + return offset; 1.882 +} 1.883 + 1.884 +void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1.885 + 1.886 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.887 + fMCMgr.clipRRect(rrect, op, doAA); 1.888 +#else 1.889 + this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); 1.890 +#endif 1.891 + if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 1.892 + this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false); 1.893 + } else { 1.894 + this->INHERITED::onClipRRect(rrect, op, edgeStyle); 1.895 + } 1.896 +} 1.897 + 1.898 +int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1.899 + // op + rrect + clip params 1.900 + uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; 1.901 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.902 + size += kUInt32Size; // + restore offset 1.903 +#else 1.904 + // recordRestoreOffsetPlaceholder doesn't always write an offset 1.905 + if (!fRestoreOffsetStack.isEmpty()) { 1.906 + // + restore offset 1.907 + size += kUInt32Size; 1.908 + } 1.909 +#endif 1.910 + size_t initialOffset = this->addDraw(CLIP_RRECT, &size); 1.911 + this->addRRect(rrect); 1.912 + this->addInt(ClipParams_pack(op, doAA)); 1.913 + int offset = recordRestoreOffsetPlaceholder(op); 1.914 + this->validate(initialOffset, size); 1.915 + return offset; 1.916 +} 1.917 + 1.918 +void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1.919 + 1.920 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.921 + fMCMgr.clipPath(path, op, doAA); 1.922 +#else 1.923 + int pathID = this->addPathToHeap(path); 1.924 + this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle); 1.925 +#endif 1.926 + 1.927 + if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 1.928 + this->updateClipConservativelyUsingBounds(path.getBounds(), op, 1.929 + path.isInverseFillType()); 1.930 + } else { 1.931 + this->INHERITED::onClipPath(path, op, edgeStyle); 1.932 + } 1.933 +} 1.934 + 1.935 +int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) { 1.936 + // op + path index + clip params 1.937 + uint32_t size = 3 * kUInt32Size; 1.938 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.939 + size += kUInt32Size; // + restore offset 1.940 +#else 1.941 + // recordRestoreOffsetPlaceholder doesn't always write an offset 1.942 + if (!fRestoreOffsetStack.isEmpty()) { 1.943 + // + restore offset 1.944 + size += kUInt32Size; 1.945 + } 1.946 +#endif 1.947 + size_t initialOffset = this->addDraw(CLIP_PATH, &size); 1.948 + this->addInt(pathID); 1.949 + this->addInt(ClipParams_pack(op, doAA)); 1.950 + int offset = recordRestoreOffsetPlaceholder(op); 1.951 + this->validate(initialOffset, size); 1.952 + return offset; 1.953 +} 1.954 + 1.955 +void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) { 1.956 + 1.957 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.958 + fMCMgr.clipRegion(region, op); 1.959 +#else 1.960 + this->recordClipRegion(region, op); 1.961 +#endif 1.962 + this->INHERITED::onClipRegion(region, op); 1.963 +} 1.964 + 1.965 +int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) { 1.966 + // op + clip params + region 1.967 + uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL); 1.968 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.969 + size += kUInt32Size; // + restore offset 1.970 +#else 1.971 + // recordRestoreOffsetPlaceholder doesn't always write an offset 1.972 + if (!fRestoreOffsetStack.isEmpty()) { 1.973 + // + restore offset 1.974 + size += kUInt32Size; 1.975 + } 1.976 +#endif 1.977 + size_t initialOffset = this->addDraw(CLIP_REGION, &size); 1.978 + this->addRegion(region); 1.979 + this->addInt(ClipParams_pack(op, false)); 1.980 + int offset = this->recordRestoreOffsetPlaceholder(op); 1.981 + 1.982 + this->validate(initialOffset, size); 1.983 + return offset; 1.984 +} 1.985 + 1.986 +void SkPictureRecord::clear(SkColor color) { 1.987 + 1.988 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.989 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.990 +#endif 1.991 + 1.992 + // op + color 1.993 + uint32_t size = 2 * kUInt32Size; 1.994 + size_t initialOffset = this->addDraw(DRAW_CLEAR, &size); 1.995 + this->addInt(color); 1.996 + this->validate(initialOffset, size); 1.997 +} 1.998 + 1.999 +void SkPictureRecord::drawPaint(const SkPaint& paint) { 1.1000 + 1.1001 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1002 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1003 +#endif 1.1004 + 1.1005 + // op + paint index 1.1006 + uint32_t size = 2 * kUInt32Size; 1.1007 + size_t initialOffset = this->addDraw(DRAW_PAINT, &size); 1.1008 + SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten()); 1.1009 + this->addPaint(paint); 1.1010 + this->validate(initialOffset, size); 1.1011 +} 1.1012 + 1.1013 +void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 1.1014 + const SkPaint& paint) { 1.1015 + 1.1016 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1017 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1018 +#endif 1.1019 + 1.1020 + // op + paint index + mode + count + point data 1.1021 + uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); 1.1022 + size_t initialOffset = this->addDraw(DRAW_POINTS, &size); 1.1023 + SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten()); 1.1024 + this->addPaint(paint); 1.1025 + this->addInt(mode); 1.1026 + this->addInt(count); 1.1027 + fWriter.writeMul4(pts, count * sizeof(SkPoint)); 1.1028 + this->validate(initialOffset, size); 1.1029 +} 1.1030 + 1.1031 +void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { 1.1032 + 1.1033 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1034 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1035 +#endif 1.1036 + 1.1037 + // op + paint index + rect 1.1038 + uint32_t size = 2 * kUInt32Size + sizeof(oval); 1.1039 + size_t initialOffset = this->addDraw(DRAW_OVAL, &size); 1.1040 + SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten()); 1.1041 + this->addPaint(paint); 1.1042 + this->addRect(oval); 1.1043 + this->validate(initialOffset, size); 1.1044 +} 1.1045 + 1.1046 +void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { 1.1047 + 1.1048 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1049 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1050 +#endif 1.1051 + 1.1052 + // op + paint index + rect 1.1053 + uint32_t size = 2 * kUInt32Size + sizeof(rect); 1.1054 + size_t initialOffset = this->addDraw(DRAW_RECT, &size); 1.1055 + SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten()); 1.1056 + this->addPaint(paint); 1.1057 + this->addRect(rect); 1.1058 + this->validate(initialOffset, size); 1.1059 +} 1.1060 + 1.1061 +void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 1.1062 + 1.1063 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1064 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1065 +#endif 1.1066 + 1.1067 + if (rrect.isRect()) { 1.1068 + this->SkPictureRecord::drawRect(rrect.getBounds(), paint); 1.1069 + } else if (rrect.isOval()) { 1.1070 + this->SkPictureRecord::drawOval(rrect.getBounds(), paint); 1.1071 + } else { 1.1072 + // op + paint index + rrect 1.1073 + uint32_t initialOffset, size; 1.1074 + size = 2 * kUInt32Size + SkRRect::kSizeInMemory; 1.1075 + initialOffset = this->addDraw(DRAW_RRECT, &size); 1.1076 + SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten()); 1.1077 + this->addPaint(paint); 1.1078 + this->addRRect(rrect); 1.1079 + this->validate(initialOffset, size); 1.1080 + } 1.1081 +} 1.1082 + 1.1083 +void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 1.1084 + const SkPaint& paint) { 1.1085 + 1.1086 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1087 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1088 +#endif 1.1089 + 1.1090 + // op + paint index + rrects 1.1091 + uint32_t initialOffset, size; 1.1092 + size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; 1.1093 + initialOffset = this->addDraw(DRAW_DRRECT, &size); 1.1094 + SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten()); 1.1095 + this->addPaint(paint); 1.1096 + this->addRRect(outer); 1.1097 + this->addRRect(inner); 1.1098 + this->validate(initialOffset, size); 1.1099 +} 1.1100 + 1.1101 +void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { 1.1102 + 1.1103 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1104 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1105 +#endif 1.1106 + 1.1107 + // op + paint index + path index 1.1108 + uint32_t size = 3 * kUInt32Size; 1.1109 + size_t initialOffset = this->addDraw(DRAW_PATH, &size); 1.1110 + SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten()); 1.1111 + this->addPaint(paint); 1.1112 + this->addPath(path); 1.1113 + this->validate(initialOffset, size); 1.1114 +} 1.1115 + 1.1116 +void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 1.1117 + const SkPaint* paint = NULL) { 1.1118 + if (bitmap.drawsNothing()) { 1.1119 + return; 1.1120 + } 1.1121 + 1.1122 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1123 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1124 +#endif 1.1125 + 1.1126 + // op + paint index + bitmap index + left + top 1.1127 + uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 1.1128 + size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); 1.1129 + SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten()); 1.1130 + this->addPaintPtr(paint); 1.1131 + int bitmapID = this->addBitmap(bitmap); 1.1132 + this->addScalar(left); 1.1133 + this->addScalar(top); 1.1134 + this->validate(initialOffset, size); 1.1135 + this->trackBitmapUse(bitmapID, initialOffset); 1.1136 +} 1.1137 + 1.1138 +void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 1.1139 + const SkRect& dst, const SkPaint* paint, 1.1140 + DrawBitmapRectFlags flags) { 1.1141 + if (bitmap.drawsNothing()) { 1.1142 + return; 1.1143 + } 1.1144 + 1.1145 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1146 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1147 +#endif 1.1148 + // id + paint index + bitmap index + bool for 'src' + flags 1.1149 + uint32_t size = 5 * kUInt32Size; 1.1150 + if (NULL != src) { 1.1151 + size += sizeof(*src); // + rect 1.1152 + } 1.1153 + size += sizeof(dst); // + rect 1.1154 + 1.1155 + size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); 1.1156 + SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) 1.1157 + == fWriter.bytesWritten()); 1.1158 + this->addPaintPtr(paint); 1.1159 + int bitmapID = this->addBitmap(bitmap); 1.1160 + this->addRectPtr(src); // may be null 1.1161 + this->addRect(dst); 1.1162 + this->addInt(flags); 1.1163 + this->validate(initialOffset, size); 1.1164 + this->trackBitmapUse(bitmapID, initialOffset); 1.1165 +} 1.1166 + 1.1167 +void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 1.1168 + const SkPaint* paint) { 1.1169 + if (bitmap.drawsNothing()) { 1.1170 + return; 1.1171 + } 1.1172 + 1.1173 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1174 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1175 +#endif 1.1176 + 1.1177 + // id + paint index + bitmap index + matrix 1.1178 + uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL); 1.1179 + size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); 1.1180 + SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten()); 1.1181 + this->addPaintPtr(paint); 1.1182 + int bitmapID = this->addBitmap(bitmap); 1.1183 + this->addMatrix(matrix); 1.1184 + this->validate(initialOffset, size); 1.1185 + this->trackBitmapUse(bitmapID, initialOffset); 1.1186 +} 1.1187 + 1.1188 +void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1.1189 + const SkRect& dst, const SkPaint* paint) { 1.1190 + if (bitmap.drawsNothing()) { 1.1191 + return; 1.1192 + } 1.1193 + 1.1194 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1195 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1196 +#endif 1.1197 + 1.1198 + // op + paint index + bitmap id + center + dst rect 1.1199 + uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); 1.1200 + size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); 1.1201 + SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten()); 1.1202 + this->addPaintPtr(paint); 1.1203 + int bitmapID = this->addBitmap(bitmap); 1.1204 + this->addIRect(center); 1.1205 + this->addRect(dst); 1.1206 + this->validate(initialOffset, size); 1.1207 + this->trackBitmapUse(bitmapID, initialOffset); 1.1208 +} 1.1209 + 1.1210 +void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, 1.1211 + const SkPaint* paint = NULL) { 1.1212 + if (bitmap.drawsNothing()) { 1.1213 + return; 1.1214 + } 1.1215 + 1.1216 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1217 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1218 +#endif 1.1219 + 1.1220 + // op + paint index + bitmap index + left + top 1.1221 + uint32_t size = 5 * kUInt32Size; 1.1222 + size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); 1.1223 + SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten()); 1.1224 + this->addPaintPtr(paint); 1.1225 + int bitmapID = this->addBitmap(bitmap); 1.1226 + this->addInt(left); 1.1227 + this->addInt(top); 1.1228 + this->validate(initialOffset, size); 1.1229 + this->trackBitmapUse(bitmapID, initialOffset); 1.1230 +} 1.1231 + 1.1232 +void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) { 1.1233 + SkPaint::FontMetrics metrics; 1.1234 + paint.getFontMetrics(&metrics); 1.1235 + SkRect bounds; 1.1236 + // construct a rect so we can see any adjustments from the paint. 1.1237 + // we use 0,1 for left,right, just so the rect isn't empty 1.1238 + bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); 1.1239 + (void)paint.computeFastBounds(bounds, &bounds); 1.1240 + topbot[0] = bounds.fTop; 1.1241 + topbot[1] = bounds.fBottom; 1.1242 +} 1.1243 + 1.1244 +void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat, 1.1245 + SkScalar minY, SkScalar maxY) { 1.1246 + WriteTopBot(paint, flat); 1.1247 + this->addScalar(flat.topBot()[0] + minY); 1.1248 + this->addScalar(flat.topBot()[1] + maxY); 1.1249 +} 1.1250 + 1.1251 +void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, 1.1252 + SkScalar y, const SkPaint& paint) { 1.1253 + 1.1254 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1255 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1256 +#endif 1.1257 + 1.1258 + bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 1.1259 + 1.1260 + // op + paint index + length + 'length' worth of chars + x + y 1.1261 + uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); 1.1262 + if (fast) { 1.1263 + size += 2 * sizeof(SkScalar); // + top & bottom 1.1264 + } 1.1265 + 1.1266 + DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; 1.1267 + size_t initialOffset = this->addDraw(op, &size); 1.1268 + SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); 1.1269 + const SkFlatData* flatPaintData = addPaint(paint); 1.1270 + SkASSERT(flatPaintData); 1.1271 + this->addText(text, byteLength); 1.1272 + this->addScalar(x); 1.1273 + this->addScalar(y); 1.1274 + if (fast) { 1.1275 + this->addFontMetricsTopBottom(paint, *flatPaintData, y, y); 1.1276 + } 1.1277 + this->validate(initialOffset, size); 1.1278 +} 1.1279 + 1.1280 +void SkPictureRecord::drawPosText(const void* text, size_t byteLength, 1.1281 + const SkPoint pos[], const SkPaint& paint) { 1.1282 + 1.1283 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1284 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1285 +#endif 1.1286 + 1.1287 + size_t points = paint.countText(text, byteLength); 1.1288 + if (0 == points) 1.1289 + return; 1.1290 + 1.1291 + bool canUseDrawH = true; 1.1292 + SkScalar minY = pos[0].fY; 1.1293 + SkScalar maxY = pos[0].fY; 1.1294 + // check if the caller really should have used drawPosTextH() 1.1295 + { 1.1296 + const SkScalar firstY = pos[0].fY; 1.1297 + for (size_t index = 1; index < points; index++) { 1.1298 + if (pos[index].fY != firstY) { 1.1299 + canUseDrawH = false; 1.1300 + if (pos[index].fY < minY) { 1.1301 + minY = pos[index].fY; 1.1302 + } else if (pos[index].fY > maxY) { 1.1303 + maxY = pos[index].fY; 1.1304 + } 1.1305 + } 1.1306 + } 1.1307 + } 1.1308 + 1.1309 + bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds(); 1.1310 + bool fast = canUseDrawH && fastBounds; 1.1311 + 1.1312 + // op + paint index + length + 'length' worth of data + num points 1.1313 + uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1.1314 + if (canUseDrawH) { 1.1315 + if (fast) { 1.1316 + size += 2 * sizeof(SkScalar); // + top & bottom 1.1317 + } 1.1318 + // + y-pos + actual x-point data 1.1319 + size += sizeof(SkScalar) + points * sizeof(SkScalar); 1.1320 + } else { 1.1321 + // + x&y point data 1.1322 + size += points * sizeof(SkPoint); 1.1323 + if (fastBounds) { 1.1324 + size += 2 * sizeof(SkScalar); // + top & bottom 1.1325 + } 1.1326 + } 1.1327 + 1.1328 + DrawType op; 1.1329 + if (fast) { 1.1330 + op = DRAW_POS_TEXT_H_TOP_BOTTOM; 1.1331 + } else if (canUseDrawH) { 1.1332 + op = DRAW_POS_TEXT_H; 1.1333 + } else if (fastBounds) { 1.1334 + op = DRAW_POS_TEXT_TOP_BOTTOM; 1.1335 + } else { 1.1336 + op = DRAW_POS_TEXT; 1.1337 + } 1.1338 + size_t initialOffset = this->addDraw(op, &size); 1.1339 + SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten()); 1.1340 + const SkFlatData* flatPaintData = this->addPaint(paint); 1.1341 + SkASSERT(flatPaintData); 1.1342 + this->addText(text, byteLength); 1.1343 + this->addInt(points); 1.1344 + 1.1345 +#ifdef SK_DEBUG_SIZE 1.1346 + size_t start = fWriter.bytesWritten(); 1.1347 +#endif 1.1348 + if (canUseDrawH) { 1.1349 + if (fast) { 1.1350 + this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY); 1.1351 + } 1.1352 + this->addScalar(pos[0].fY); 1.1353 + SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); 1.1354 + for (size_t index = 0; index < points; index++) 1.1355 + *xptr++ = pos[index].fX; 1.1356 + } else { 1.1357 + fWriter.writeMul4(pos, points * sizeof(SkPoint)); 1.1358 + if (fastBounds) { 1.1359 + this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); 1.1360 + } 1.1361 + } 1.1362 +#ifdef SK_DEBUG_SIZE 1.1363 + fPointBytes += fWriter.bytesWritten() - start; 1.1364 + fPointWrites += points; 1.1365 +#endif 1.1366 + this->validate(initialOffset, size); 1.1367 +} 1.1368 + 1.1369 +void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength, 1.1370 + const SkScalar xpos[], SkScalar constY, 1.1371 + const SkPaint& paint) { 1.1372 + 1.1373 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1374 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1375 +#endif 1.1376 + 1.1377 + const SkFlatData* flatPaintData = this->getFlatPaintData(paint); 1.1378 + this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData); 1.1379 +} 1.1380 + 1.1381 +void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength, 1.1382 + const SkScalar xpos[], SkScalar constY, 1.1383 + const SkPaint& paint, const SkFlatData* flatPaintData) { 1.1384 + size_t points = paint.countText(text, byteLength); 1.1385 + if (0 == points) 1.1386 + return; 1.1387 + 1.1388 + bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 1.1389 + 1.1390 + // op + paint index + length + 'length' worth of data + num points 1.1391 + uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1.1392 + if (fast) { 1.1393 + size += 2 * sizeof(SkScalar); // + top & bottom 1.1394 + } 1.1395 + // + y + the actual points 1.1396 + size += 1 * kUInt32Size + points * sizeof(SkScalar); 1.1397 + size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, 1.1398 + &size); 1.1399 + SkASSERT(flatPaintData); 1.1400 + this->addFlatPaint(flatPaintData); 1.1401 + 1.1402 + this->addText(text, byteLength); 1.1403 + this->addInt(points); 1.1404 + 1.1405 +#ifdef SK_DEBUG_SIZE 1.1406 + size_t start = fWriter.bytesWritten(); 1.1407 +#endif 1.1408 + if (fast) { 1.1409 + this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); 1.1410 + } 1.1411 + this->addScalar(constY); 1.1412 + fWriter.writeMul4(xpos, points * sizeof(SkScalar)); 1.1413 +#ifdef SK_DEBUG_SIZE 1.1414 + fPointBytes += fWriter.bytesWritten() - start; 1.1415 + fPointWrites += points; 1.1416 +#endif 1.1417 + this->validate(initialOffset, size); 1.1418 +} 1.1419 + 1.1420 +void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, 1.1421 + const SkPath& path, const SkMatrix* matrix, 1.1422 + const SkPaint& paint) { 1.1423 + 1.1424 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1425 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1426 +#endif 1.1427 + 1.1428 + // op + paint index + length + 'length' worth of data + path index + matrix 1.1429 + const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); 1.1430 + uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL); 1.1431 + size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); 1.1432 + SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten()); 1.1433 + this->addPaint(paint); 1.1434 + this->addText(text, byteLength); 1.1435 + this->addPath(path); 1.1436 + this->addMatrix(m); 1.1437 + this->validate(initialOffset, size); 1.1438 +} 1.1439 + 1.1440 +void SkPictureRecord::drawPicture(SkPicture& picture) { 1.1441 + 1.1442 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1443 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1444 +#endif 1.1445 + 1.1446 + // op + picture index 1.1447 + uint32_t size = 2 * kUInt32Size; 1.1448 + size_t initialOffset = this->addDraw(DRAW_PICTURE, &size); 1.1449 + this->addPicture(picture); 1.1450 + this->validate(initialOffset, size); 1.1451 +} 1.1452 + 1.1453 +void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, 1.1454 + const SkPoint vertices[], const SkPoint texs[], 1.1455 + const SkColor colors[], SkXfermode* xfer, 1.1456 + const uint16_t indices[], int indexCount, 1.1457 + const SkPaint& paint) { 1.1458 + 1.1459 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1460 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1461 +#endif 1.1462 + 1.1463 + uint32_t flags = 0; 1.1464 + if (texs) { 1.1465 + flags |= DRAW_VERTICES_HAS_TEXS; 1.1466 + } 1.1467 + if (colors) { 1.1468 + flags |= DRAW_VERTICES_HAS_COLORS; 1.1469 + } 1.1470 + if (indexCount > 0) { 1.1471 + flags |= DRAW_VERTICES_HAS_INDICES; 1.1472 + } 1.1473 + if (NULL != xfer) { 1.1474 + SkXfermode::Mode mode; 1.1475 + if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { 1.1476 + flags |= DRAW_VERTICES_HAS_XFER; 1.1477 + } 1.1478 + } 1.1479 + 1.1480 + // op + paint index + flags + vmode + vCount + vertices 1.1481 + uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); 1.1482 + if (flags & DRAW_VERTICES_HAS_TEXS) { 1.1483 + size += vertexCount * sizeof(SkPoint); // + uvs 1.1484 + } 1.1485 + if (flags & DRAW_VERTICES_HAS_COLORS) { 1.1486 + size += vertexCount * sizeof(SkColor); // + vert colors 1.1487 + } 1.1488 + if (flags & DRAW_VERTICES_HAS_INDICES) { 1.1489 + // + num indices + indices 1.1490 + size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); 1.1491 + } 1.1492 + if (flags & DRAW_VERTICES_HAS_XFER) { 1.1493 + size += kUInt32Size; // mode enum 1.1494 + } 1.1495 + 1.1496 + size_t initialOffset = this->addDraw(DRAW_VERTICES, &size); 1.1497 + SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten()); 1.1498 + this->addPaint(paint); 1.1499 + this->addInt(flags); 1.1500 + this->addInt(vmode); 1.1501 + this->addInt(vertexCount); 1.1502 + this->addPoints(vertices, vertexCount); 1.1503 + if (flags & DRAW_VERTICES_HAS_TEXS) { 1.1504 + this->addPoints(texs, vertexCount); 1.1505 + } 1.1506 + if (flags & DRAW_VERTICES_HAS_COLORS) { 1.1507 + fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); 1.1508 + } 1.1509 + if (flags & DRAW_VERTICES_HAS_INDICES) { 1.1510 + this->addInt(indexCount); 1.1511 + fWriter.writePad(indices, indexCount * sizeof(uint16_t)); 1.1512 + } 1.1513 + if (flags & DRAW_VERTICES_HAS_XFER) { 1.1514 + SkXfermode::Mode mode = SkXfermode::kModulate_Mode; 1.1515 + (void)xfer->asMode(&mode); 1.1516 + this->addInt(mode); 1.1517 + } 1.1518 + this->validate(initialOffset, size); 1.1519 +} 1.1520 + 1.1521 +void SkPictureRecord::drawData(const void* data, size_t length) { 1.1522 + 1.1523 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE 1.1524 + fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); 1.1525 +#endif 1.1526 + 1.1527 + // op + length + 'length' worth of data 1.1528 + uint32_t size = 2 * kUInt32Size + SkAlign4(length); 1.1529 + size_t initialOffset = this->addDraw(DRAW_DATA, &size); 1.1530 + this->addInt(length); 1.1531 + fWriter.writePad(data, length); 1.1532 + this->validate(initialOffset, size); 1.1533 +} 1.1534 + 1.1535 +void SkPictureRecord::beginCommentGroup(const char* description) { 1.1536 + // op/size + length of string + \0 terminated chars 1.1537 + int length = strlen(description); 1.1538 + uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1); 1.1539 + size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size); 1.1540 + fWriter.writeString(description, length); 1.1541 + this->validate(initialOffset, size); 1.1542 +} 1.1543 + 1.1544 +void SkPictureRecord::addComment(const char* kywd, const char* value) { 1.1545 + // op/size + 2x length of string + 2x \0 terminated chars 1.1546 + int kywdLen = strlen(kywd); 1.1547 + int valueLen = strlen(value); 1.1548 + uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1); 1.1549 + size_t initialOffset = this->addDraw(COMMENT, &size); 1.1550 + fWriter.writeString(kywd, kywdLen); 1.1551 + fWriter.writeString(value, valueLen); 1.1552 + this->validate(initialOffset, size); 1.1553 +} 1.1554 + 1.1555 +void SkPictureRecord::endCommentGroup() { 1.1556 + // op/size 1.1557 + uint32_t size = 1 * kUInt32Size; 1.1558 + size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size); 1.1559 + this->validate(initialOffset, size); 1.1560 +} 1.1561 + 1.1562 +// [op/size] [rect] [skip offset] 1.1563 +static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect); 1.1564 +void SkPictureRecord::onPushCull(const SkRect& cullRect) { 1.1565 + // Skip identical cull rects. 1.1566 + if (!fCullOffsetStack.isEmpty()) { 1.1567 + const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect)); 1.1568 + if (prevCull == cullRect) { 1.1569 + // Skipped culls are tracked on the stack, but they point to the previous offset. 1.1570 + fCullOffsetStack.push(fCullOffsetStack.top()); 1.1571 + return; 1.1572 + } 1.1573 + 1.1574 + SkASSERT(prevCull.contains(cullRect)); 1.1575 + } 1.1576 + 1.1577 + uint32_t size = kPushCullOpSize; 1.1578 + size_t initialOffset = this->addDraw(PUSH_CULL, &size); 1.1579 + // PUSH_CULL's size should stay constant (used to rewind). 1.1580 + SkASSERT(size == kPushCullOpSize); 1.1581 + 1.1582 + this->addRect(cullRect); 1.1583 + fCullOffsetStack.push(fWriter.bytesWritten()); 1.1584 + this->addInt(0); 1.1585 + this->validate(initialOffset, size); 1.1586 +} 1.1587 + 1.1588 +void SkPictureRecord::onPopCull() { 1.1589 + SkASSERT(!fCullOffsetStack.isEmpty()); 1.1590 + 1.1591 + uint32_t cullSkipOffset = fCullOffsetStack.top(); 1.1592 + fCullOffsetStack.pop(); 1.1593 + 1.1594 + // Skipped push, do the same for pop. 1.1595 + if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) { 1.1596 + return; 1.1597 + } 1.1598 + 1.1599 + // Collapse empty push/pop pairs. 1.1600 + if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) { 1.1601 + SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize); 1.1602 + SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize)); 1.1603 + fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize); 1.1604 + return; 1.1605 + } 1.1606 + 1.1607 + // op only 1.1608 + uint32_t size = kUInt32Size; 1.1609 + size_t initialOffset = this->addDraw(POP_CULL, &size); 1.1610 + 1.1611 + // update the cull skip offset to point past this op. 1.1612 + fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten()); 1.1613 + 1.1614 + this->validate(initialOffset, size); 1.1615 +} 1.1616 + 1.1617 +/////////////////////////////////////////////////////////////////////////////// 1.1618 + 1.1619 +SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) { 1.1620 + return SkSurface::NewPicture(info.fWidth, info.fHeight); 1.1621 +} 1.1622 + 1.1623 +void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) { 1.1624 +#ifndef SK_ALLOW_BITMAP_TRACKING 1.1625 + return; 1.1626 +#endif 1.1627 + 1.1628 + if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) { 1.1629 + return; 1.1630 + } 1.1631 + 1.1632 + if (SkBitmapHeap::INVALID_SLOT == bitmapID) { 1.1633 + return; 1.1634 + } 1.1635 + 1.1636 + if (NULL == fBitmapUseOffsets) { 1.1637 + fBitmapUseOffsets.reset(SkNEW(SkOffsetTable)); 1.1638 + } 1.1639 + 1.1640 + fBitmapUseOffsets->add(bitmapID, offset); 1.1641 +} 1.1642 + 1.1643 +int SkPictureRecord::addBitmap(const SkBitmap& bitmap) { 1.1644 + const int index = fBitmapHeap->insert(bitmap); 1.1645 + // In debug builds, a bad return value from insert() will crash, allowing for debugging. In 1.1646 + // release builds, the invalid value will be recorded so that the reader will know that there 1.1647 + // was a problem. 1.1648 + SkASSERT(index != SkBitmapHeap::INVALID_SLOT); 1.1649 + this->addInt(index); 1.1650 + return index; 1.1651 +} 1.1652 + 1.1653 +void SkPictureRecord::addMatrix(const SkMatrix& matrix) { 1.1654 + fWriter.writeMatrix(matrix); 1.1655 +} 1.1656 + 1.1657 +const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) { 1.1658 + return fPaints.findAndReturnFlat(paint); 1.1659 +} 1.1660 + 1.1661 +const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { 1.1662 + const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL; 1.1663 + this->addFlatPaint(data); 1.1664 + return data; 1.1665 +} 1.1666 + 1.1667 +void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) { 1.1668 + int index = flatPaint ? flatPaint->index() : 0; 1.1669 + this->addInt(index); 1.1670 +} 1.1671 + 1.1672 +int SkPictureRecord::addPathToHeap(const SkPath& path) { 1.1673 + if (NULL == fPathHeap) { 1.1674 + fPathHeap = SkNEW(SkPathHeap); 1.1675 + } 1.1676 +#ifdef SK_DEDUP_PICTURE_PATHS 1.1677 + return fPathHeap->insert(path); 1.1678 +#else 1.1679 + return fPathHeap->append(path); 1.1680 +#endif 1.1681 +} 1.1682 + 1.1683 +void SkPictureRecord::addPath(const SkPath& path) { 1.1684 + this->addInt(this->addPathToHeap(path)); 1.1685 +} 1.1686 + 1.1687 +void SkPictureRecord::addPicture(SkPicture& picture) { 1.1688 + int index = fPictureRefs.find(&picture); 1.1689 + if (index < 0) { // not found 1.1690 + index = fPictureRefs.count(); 1.1691 + *fPictureRefs.append() = &picture; 1.1692 + picture.ref(); 1.1693 + } 1.1694 + // follow the convention of recording a 1-based index 1.1695 + this->addInt(index + 1); 1.1696 +} 1.1697 + 1.1698 +void SkPictureRecord::addPoint(const SkPoint& point) { 1.1699 +#ifdef SK_DEBUG_SIZE 1.1700 + size_t start = fWriter.bytesWritten(); 1.1701 +#endif 1.1702 + fWriter.writePoint(point); 1.1703 +#ifdef SK_DEBUG_SIZE 1.1704 + fPointBytes += fWriter.bytesWritten() - start; 1.1705 + fPointWrites++; 1.1706 +#endif 1.1707 +} 1.1708 + 1.1709 +void SkPictureRecord::addPoints(const SkPoint pts[], int count) { 1.1710 + fWriter.writeMul4(pts, count * sizeof(SkPoint)); 1.1711 +#ifdef SK_DEBUG_SIZE 1.1712 + fPointBytes += count * sizeof(SkPoint); 1.1713 + fPointWrites++; 1.1714 +#endif 1.1715 +} 1.1716 + 1.1717 +void SkPictureRecord::addRect(const SkRect& rect) { 1.1718 +#ifdef SK_DEBUG_SIZE 1.1719 + size_t start = fWriter.bytesWritten(); 1.1720 +#endif 1.1721 + fWriter.writeRect(rect); 1.1722 +#ifdef SK_DEBUG_SIZE 1.1723 + fRectBytes += fWriter.bytesWritten() - start; 1.1724 + fRectWrites++; 1.1725 +#endif 1.1726 +} 1.1727 + 1.1728 +void SkPictureRecord::addRectPtr(const SkRect* rect) { 1.1729 + if (fWriter.writeBool(rect != NULL)) { 1.1730 + fWriter.writeRect(*rect); 1.1731 + } 1.1732 +} 1.1733 + 1.1734 +void SkPictureRecord::addIRect(const SkIRect& rect) { 1.1735 + fWriter.write(&rect, sizeof(rect)); 1.1736 +} 1.1737 + 1.1738 +void SkPictureRecord::addIRectPtr(const SkIRect* rect) { 1.1739 + if (fWriter.writeBool(rect != NULL)) { 1.1740 + *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; 1.1741 + } 1.1742 +} 1.1743 + 1.1744 +void SkPictureRecord::addRRect(const SkRRect& rrect) { 1.1745 + fWriter.writeRRect(rrect); 1.1746 +} 1.1747 + 1.1748 +void SkPictureRecord::addRegion(const SkRegion& region) { 1.1749 + fWriter.writeRegion(region); 1.1750 +} 1.1751 + 1.1752 +void SkPictureRecord::addText(const void* text, size_t byteLength) { 1.1753 +#ifdef SK_DEBUG_SIZE 1.1754 + size_t start = fWriter.bytesWritten(); 1.1755 +#endif 1.1756 + addInt(byteLength); 1.1757 + fWriter.writePad(text, byteLength); 1.1758 +#ifdef SK_DEBUG_SIZE 1.1759 + fTextBytes += fWriter.bytesWritten() - start; 1.1760 + fTextWrites++; 1.1761 +#endif 1.1762 +} 1.1763 + 1.1764 +/////////////////////////////////////////////////////////////////////////////// 1.1765 + 1.1766 +#ifdef SK_DEBUG_SIZE 1.1767 +size_t SkPictureRecord::size() const { 1.1768 + size_t result = 0; 1.1769 + size_t sizeData; 1.1770 + bitmaps(&sizeData); 1.1771 + result += sizeData; 1.1772 + matrices(&sizeData); 1.1773 + result += sizeData; 1.1774 + paints(&sizeData); 1.1775 + result += sizeData; 1.1776 + paths(&sizeData); 1.1777 + result += sizeData; 1.1778 + pictures(&sizeData); 1.1779 + result += sizeData; 1.1780 + regions(&sizeData); 1.1781 + result += sizeData; 1.1782 + result += streamlen(); 1.1783 + return result; 1.1784 +} 1.1785 + 1.1786 +int SkPictureRecord::bitmaps(size_t* size) const { 1.1787 + size_t result = 0; 1.1788 + int count = fBitmaps.count(); 1.1789 + for (int index = 0; index < count; index++) 1.1790 + result += sizeof(fBitmaps[index]) + fBitmaps[index]->size(); 1.1791 + *size = result; 1.1792 + return count; 1.1793 +} 1.1794 + 1.1795 +int SkPictureRecord::matrices(size_t* size) const { 1.1796 + int count = fMatrices.count(); 1.1797 + *size = sizeof(fMatrices[0]) * count; 1.1798 + return count; 1.1799 +} 1.1800 + 1.1801 +int SkPictureRecord::paints(size_t* size) const { 1.1802 + size_t result = 0; 1.1803 + int count = fPaints.count(); 1.1804 + for (int index = 0; index < count; index++) 1.1805 + result += sizeof(fPaints[index]) + fPaints[index]->size(); 1.1806 + *size = result; 1.1807 + return count; 1.1808 +} 1.1809 + 1.1810 +int SkPictureRecord::paths(size_t* size) const { 1.1811 + size_t result = 0; 1.1812 + int count = fPaths.count(); 1.1813 + for (int index = 0; index < count; index++) 1.1814 + result += sizeof(fPaths[index]) + fPaths[index]->size(); 1.1815 + *size = result; 1.1816 + return count; 1.1817 +} 1.1818 + 1.1819 +int SkPictureRecord::regions(size_t* size) const { 1.1820 + size_t result = 0; 1.1821 + int count = fRegions.count(); 1.1822 + for (int index = 0; index < count; index++) 1.1823 + result += sizeof(fRegions[index]) + fRegions[index]->size(); 1.1824 + *size = result; 1.1825 + return count; 1.1826 +} 1.1827 + 1.1828 +size_t SkPictureRecord::streamlen() const { 1.1829 + return fWriter.size(); 1.1830 +} 1.1831 +#endif 1.1832 + 1.1833 +#ifdef SK_DEBUG_VALIDATE 1.1834 +void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const { 1.1835 + SkASSERT(fWriter.size() == initialOffset + size); 1.1836 + 1.1837 + validateBitmaps(); 1.1838 + validateMatrices(); 1.1839 + validatePaints(); 1.1840 + validatePaths(); 1.1841 + validateRegions(); 1.1842 +} 1.1843 + 1.1844 +void SkPictureRecord::validateBitmaps() const { 1.1845 + int count = fBitmapHeap->count(); 1.1846 + SkASSERT((unsigned) count < 0x1000); 1.1847 + for (int index = 0; index < count; index++) { 1.1848 + const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index); 1.1849 + SkASSERT(bitPtr); 1.1850 + bitPtr->validate(); 1.1851 + } 1.1852 +} 1.1853 + 1.1854 +void SkPictureRecord::validateMatrices() const { 1.1855 + int count = fMatrices.count(); 1.1856 + SkASSERT((unsigned) count < 0x1000); 1.1857 + for (int index = 0; index < count; index++) { 1.1858 + const SkFlatData* matrix = fMatrices[index]; 1.1859 + SkASSERT(matrix); 1.1860 +// matrix->validate(); 1.1861 + } 1.1862 +} 1.1863 + 1.1864 +void SkPictureRecord::validatePaints() const { 1.1865 + int count = fPaints.count(); 1.1866 + SkASSERT((unsigned) count < 0x1000); 1.1867 + for (int index = 0; index < count; index++) { 1.1868 + const SkFlatData* paint = fPaints[index]; 1.1869 + SkASSERT(paint); 1.1870 +// paint->validate(); 1.1871 + } 1.1872 +} 1.1873 + 1.1874 +void SkPictureRecord::validatePaths() const { 1.1875 + if (NULL == fPathHeap) { 1.1876 + return; 1.1877 + } 1.1878 + 1.1879 + int count = fPathHeap->count(); 1.1880 + SkASSERT((unsigned) count < 0x1000); 1.1881 + for (int index = 0; index < count; index++) { 1.1882 + const SkPath& path = (*fPathHeap)[index]; 1.1883 + path.validate(); 1.1884 + } 1.1885 +} 1.1886 + 1.1887 +void SkPictureRecord::validateRegions() const { 1.1888 + int count = fRegions.count(); 1.1889 + SkASSERT((unsigned) count < 0x1000); 1.1890 + for (int index = 0; index < count; index++) { 1.1891 + const SkFlatData* region = fRegions[index]; 1.1892 + SkASSERT(region); 1.1893 +// region->validate(); 1.1894 + } 1.1895 +} 1.1896 +#endif