| Index: src/core/SkPictureRecord.cpp
|
| ===================================================================
|
| --- src/core/SkPictureRecord.cpp (revision 8043)
|
| +++ src/core/SkPictureRecord.cpp (working copy)
|
| @@ -62,75 +62,97 @@
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +enum DrawTypeFlags {
|
| + kHasPaint_DrawTypeFlag = 1 << 0,
|
| + kModifiesState_DrawTypeFlag = 1 << 1, // modifes clip or matrix state
|
| + kCanRecordBounds_DrawTypeFlag = 1 << 2,
|
| +};
|
| +
|
| +static const uint8_t gDrawTypeFlags[LAST_DRAWTYPE_ENUM + 1] = {
|
| + 0, // UNUSED
|
| + kModifiesState_DrawTypeFlag, // CLIP_PATH
|
| + kModifiesState_DrawTypeFlag, // CLIP_REGION
|
| + kModifiesState_DrawTypeFlag, // CLIP_RECT
|
| + kModifiesState_DrawTypeFlag, // CLIP_RRECT
|
| + kModifiesState_DrawTypeFlag, // CONCAT
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_BITMAP
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_BITMAP_MATRIX
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_BITMAP_NINE
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_BITMAP_RECT_TO_RECT
|
| + 0, // DRAW_CLEAR
|
| + 0, // DRAW_DATA
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_OVAL
|
| + kHasPaint_DrawTypeFlag, // DRAW_PAINT
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_PATH
|
| + kModifiesState_DrawTypeFlag, // DRAW_PICTURE
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_POINTS
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_POS_TEXT
|
| + kHasPaint_DrawTypeFlag, // DRAW_POS_TEXT_TOP_BOTTOM
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_POS_TEXT_H
|
| + kHasPaint_DrawTypeFlag, // DRAW_POS_TEXT_H_TOP_BOTTOM
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_RECT
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_RRECT
|
| + kHasPaint_DrawTypeFlag, // DRAW_SPRITE
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_TEXT
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_TEXT_ON_PATH
|
| + kHasPaint_DrawTypeFlag, // DRAW_TEXT_TOP_BOTTOM
|
| + kHasPaint_DrawTypeFlag | kCanRecordBounds_DrawTypeFlag, // DRAW_VERTICES
|
| + kModifiesState_DrawTypeFlag, // RESTORE
|
| + kModifiesState_DrawTypeFlag, // ROTATE
|
| + kModifiesState_DrawTypeFlag, // SAVE
|
| + kHasPaint_DrawTypeFlag | kModifiesState_DrawTypeFlag, // SAVE_LAYER
|
| + kModifiesState_DrawTypeFlag, // SCALE
|
| + kModifiesState_DrawTypeFlag, // SET_MATRIX
|
| + kModifiesState_DrawTypeFlag, // SKEW
|
| + kModifiesState_DrawTypeFlag, // TRANSLATE
|
| + 0, // NOOP
|
| +};
|
| +
|
| +bool SkPictureRecord::canRecordBounds(DrawType op) {
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
|
| + return SkToBool(gDrawTypeFlags[op] & kCanRecordBounds_DrawTypeFlag);
|
| +#else
|
| + return false;
|
| +#endif
|
| +}
|
| +
|
| +static inline bool modifies_state(DrawType op) {
|
| + SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
|
| + return SkToBool(gDrawTypeFlags[op] & kModifiesState_DrawTypeFlag);
|
| +}
|
| +
|
| // Return the offset of the paint inside a given op's byte stream. A zero
|
| // return value means there is no paint (and you really shouldn't be calling
|
| // this method)
|
| static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
|
| // These offsets are where the paint would be if the op size doesn't overflow
|
| - static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
|
| - 0, // UNUSED - no paint
|
| - 0, // CLIP_PATH - no paint
|
| - 0, // CLIP_REGION - no paint
|
| - 0, // CLIP_RECT - no paint
|
| - 0, // CLIP_RRECT - no paint
|
| - 0, // CONCAT - no paint
|
| - 1, // DRAW_BITMAP - right after op code
|
| - 1, // DRAW_BITMAP_MATRIX - right after op code
|
| - 1, // DRAW_BITMAP_NINE - right after op code
|
| - 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code
|
| - 0, // DRAW_CLEAR - no paint
|
| - 0, // DRAW_DATA - no paint
|
| - 1, // DRAW_OVAL - right after op code
|
| - 1, // DRAW_PAINT - right after op code
|
| - 1, // DRAW_PATH - right after op code
|
| - 0, // DRAW_PICTURE - no paint
|
| - 1, // DRAW_POINTS - right after op code
|
| - 1, // DRAW_POS_TEXT - right after op code
|
| - 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
|
| - 1, // DRAW_POS_TEXT_H - right after op code
|
| - 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
|
| - 1, // DRAW_RECT - right after op code
|
| - 1, // DRAW_RRECT - right after op code
|
| - 1, // DRAW_SPRITE - right after op code
|
| - 1, // DRAW_TEXT - right after op code
|
| - 1, // DRAW_TEXT_ON_PATH - right after op code
|
| - 1, // DRAW_TEXT_TOP_BOTTOM - right after op code
|
| - 1, // DRAW_VERTICES - right after op code
|
| - 0, // RESTORE - no paint
|
| - 0, // ROTATE - no paint
|
| - 0, // SAVE - no paint
|
| - 0, // SAVE_LAYER - see below - this paint's location varies
|
| - 0, // SCALE - no paint
|
| - 0, // SET_MATRIX - no paint
|
| - 0, // SKEW - no paint
|
| - 0, // TRANSLATE - no paint
|
| - 0, // NOOP - no paint
|
| - };
|
| -
|
| - SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1);
|
| SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
|
|
|
| - int overflow = 0;
|
| + int offset = sizeof(uint32_t); // storage for op and 24-bit size
|
| if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
|
| // This op's size overflows so an extra uint32_t will be written
|
| // after the op code
|
| - overflow = sizeof(uint32_t);
|
| + offset += sizeof(uint32_t);
|
| }
|
| + if (SkPictureRecord::canRecordBounds(op)) {
|
| + offset += sizeof(SkIRect);
|
| + }
|
|
|
| if (SAVE_LAYER == op) {
|
| - static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
|
| - static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
|
| + static const uint32_t kSaveLayerNoBoundsPaintOffset = kUInt32Size;
|
| + static const uint32_t kSaveLayerWithBoundsPaintOffset = kUInt32Size + sizeof(SkRect);
|
|
|
| if (kSaveLayerNoBoundsSize == opSize) {
|
| - return kSaveLayerNoBoundsPaintOffset + overflow;
|
| + offset += kSaveLayerNoBoundsPaintOffset;
|
| } else {
|
| SkASSERT(kSaveLayerWithBoundsSize == opSize);
|
| - return kSaveLayerWithBoundsPaintOffset + overflow;
|
| + offset += kSaveLayerWithBoundsPaintOffset;
|
| }
|
| }
|
|
|
| - SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
|
| - return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
|
| + SkASSERT(kHasPaint_DrawTypeFlag & gDrawTypeFlags[op]); // Shouldn't be calling this method
|
| + return offset;
|
| }
|
|
|
| SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
|
| @@ -146,6 +168,7 @@
|
| // op + flags
|
| uint32_t size = 2 * kUInt32Size;
|
| uint32_t initialOffset = this->addDraw(SAVE, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addInt(flags);
|
|
|
| validate(initialOffset, size);
|
| @@ -169,8 +192,9 @@
|
| SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
|
|
|
| uint32_t initialOffset = this->addDraw(SAVE_LAYER, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addRectPtr(bounds);
|
| - SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.size());
|
| + SkASSERT(initialOffset + getPaintOffset(SAVE_LAYER, size) == fWriter.size());
|
| addPaintPtr(paint);
|
| addInt(flags);
|
|
|
| @@ -427,6 +451,7 @@
|
| size = 0;
|
| initialOffset = fWriter.size();
|
| }
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
|
|
| fRestoreOffsetStack.pop();
|
|
|
| @@ -434,10 +459,88 @@
|
| return this->INHERITED::restore();
|
| }
|
|
|
| +uint32_t SkPictureRecord::addDraw(DrawType drawType, uint32_t* size,
|
| + const SkPaint* paint, const SkRect* localBounds) {
|
| + SkIRect devClipBounds; // Bounds of the current clip in device space
|
| + if (!modifies_state(drawType) && !this->getClipDeviceBounds(&devClipBounds)) {
|
| + // Optimize-out calls that are clipped-out. State modifying commands
|
| + // can not be optimized-out because they may have an impact on future calls
|
| + // if the clip is ever expanded. For example, with a union clip op.
|
| + return kInvalidOffset;
|
| + }
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + bool writeBounds = canRecordBounds(drawType);
|
| + SkIRect clippedDevBounds; // Bounds of the clipped draw in device space
|
| + if (writeBounds) {
|
| + SkASSERT(!modifies_state(drawType)); // Ensure devClipBounds is initialized
|
| + if (NULL == localBounds || (NULL != paint && !paint->canComputeFastBounds())) {
|
| + clippedDevBounds = devClipBounds;
|
| + } else {
|
| + SkRect paintBounds;
|
| + SkRect rectifiedBounds = *localBounds;
|
| + rectifiedBounds.sort();
|
| + if (NULL != paint) {
|
| + if (drawType == DRAW_POINTS) {
|
| + paintBounds = paint->computeFastStrokeBounds(rectifiedBounds, &paintBounds);
|
| + } else {
|
| + paintBounds = paint->computeFastBounds(rectifiedBounds, &paintBounds);
|
| + }
|
| + } else {
|
| + paintBounds = *localBounds;
|
| + }
|
| + if (paintBounds.isEmpty()) {
|
| + // Area affected by draw op is empty even after accounting
|
| + // for stroke width.
|
| + return kInvalidOffset;
|
| + }
|
| + SkRect devBounds;
|
| + this->getTotalMatrix().mapRect(&devBounds, paintBounds);
|
| + devBounds.roundOut(&clippedDevBounds);
|
| + if (!clippedDevBounds.intersect(devClipBounds)) {
|
| + // Draw lies outside of clip. The clip can only get further
|
| + // restricted at playback time, so it is safe to reject during
|
| + // record stage.
|
| + return kInvalidOffset;
|
| + }
|
| + }
|
| + *size += sizeof(SkIRect);
|
| + }
|
| +#else
|
| + sk_ignore_unused_variable(paint);
|
| + sk_ignore_unused_variable(localBounds);
|
| +#endif
|
| +
|
| + uint32_t offset = fWriter.size();
|
| +
|
| + this->predrawNotify();
|
| +
|
| +#ifdef SK_DEBUG_TRACE
|
| + SkDebugf("add %s\n", DrawTypeToString(drawType));
|
| +#endif
|
| + SkASSERT(0 != *size);
|
| + SkASSERT(((uint8_t) drawType) == drawType);
|
| + if (0 != (*size & ~MASK_24) || *size == MASK_24) {
|
| + fWriter.writeInt(PACK_8_24(drawType, MASK_24));
|
| + *size += 1;
|
| + fWriter.writeInt(*size);
|
| + } else {
|
| + fWriter.writeInt(PACK_8_24(drawType, *size));
|
| + }
|
| +
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + if (writeBounds) {
|
| + fWriter.write(&clippedDevBounds, sizeof(clippedDevBounds));
|
| + }
|
| +#endif
|
| +
|
| + return offset;
|
| +}
|
| +
|
| bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
|
| // op + dx + dy
|
| uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
|
| uint32_t initialOffset = this->addDraw(TRANSLATE, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addScalar(dx);
|
| addScalar(dy);
|
| validate(initialOffset, size);
|
| @@ -448,6 +551,7 @@
|
| // op + sx + sy
|
| uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
|
| uint32_t initialOffset = this->addDraw(SCALE, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addScalar(sx);
|
| addScalar(sy);
|
| validate(initialOffset, size);
|
| @@ -458,6 +562,7 @@
|
| // op + degrees
|
| uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
|
| uint32_t initialOffset = this->addDraw(ROTATE, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addScalar(degrees);
|
| validate(initialOffset, size);
|
| return this->INHERITED::rotate(degrees);
|
| @@ -467,6 +572,7 @@
|
| // op + sx + sy
|
| uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
|
| uint32_t initialOffset = this->addDraw(SKEW, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addScalar(sx);
|
| addScalar(sy);
|
| validate(initialOffset, size);
|
| @@ -478,6 +584,7 @@
|
| // op + matrix index
|
| uint32_t size = 2 * kUInt32Size;
|
| uint32_t initialOffset = this->addDraw(CONCAT, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addMatrix(matrix);
|
| validate(initialOffset, size);
|
| return this->INHERITED::concat(matrix);
|
| @@ -488,6 +595,7 @@
|
| // op + matrix index
|
| uint32_t size = 2 * kUInt32Size;
|
| uint32_t initialOffset = this->addDraw(SET_MATRIX, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addMatrix(matrix);
|
| validate(initialOffset, size);
|
| this->INHERITED::setMatrix(matrix);
|
| @@ -569,6 +677,7 @@
|
| size += kUInt32Size;
|
| }
|
| uint32_t initialOffset = this->addDraw(CLIP_RECT, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addRect(rect);
|
| addInt(ClipParams_pack(op, doAA));
|
| recordRestoreOffsetPlaceholder(op);
|
| @@ -590,6 +699,7 @@
|
| size += kUInt32Size;
|
| }
|
| uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addRRect(rrect);
|
| addInt(ClipParams_pack(op, doAA));
|
| recordRestoreOffsetPlaceholder(op);
|
| @@ -618,6 +728,7 @@
|
| size += kUInt32Size;
|
| }
|
| uint32_t initialOffset = this->addDraw(CLIP_PATH, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addPath(path);
|
| addInt(ClipParams_pack(op, doAA));
|
| recordRestoreOffsetPlaceholder(op);
|
| @@ -640,6 +751,7 @@
|
| size += kUInt32Size;
|
| }
|
| uint32_t initialOffset = this->addDraw(CLIP_REGION, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addRegion(region);
|
| addInt(ClipParams_pack(op, false));
|
| recordRestoreOffsetPlaceholder(op);
|
| @@ -652,6 +764,9 @@
|
| // op + color
|
| uint32_t size = 2 * kUInt32Size;
|
| uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| addInt(color);
|
| validate(initialOffset, size);
|
| }
|
| @@ -660,7 +775,10 @@
|
| // op + paint index
|
| uint32_t size = 2 * kUInt32Size;
|
| uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size());
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_PAINT, size) == fWriter.size());
|
| addPaint(paint);
|
| validate(initialOffset, size);
|
| }
|
| @@ -669,8 +787,17 @@
|
| const SkPaint& paint) {
|
| // op + paint index + mode + count + point data
|
| uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkRect bbox;
|
| + bbox.set(pts, count);
|
| + uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size, &paint, &bbox);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_POINTS, size) == fWriter.size());
|
| addPaint(paint);
|
| addInt(mode);
|
| addInt(count);
|
| @@ -681,8 +808,15 @@
|
| void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
|
| // op + paint index + rect
|
| uint32_t size = 2 * kUInt32Size + sizeof(oval);
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size, &paint, &oval);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_OVAL, size) == fWriter.size());
|
| addPaint(paint);
|
| addRect(oval);
|
| validate(initialOffset, size);
|
| @@ -691,45 +825,56 @@
|
| void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
|
| // op + paint index + rect
|
| uint32_t size = 2 * kUInt32Size + sizeof(rect);
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + uint32_t initialOffset = this->addDraw(DRAW_RECT, &size, &paint, &rect);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_RECT, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_RECT, size) == fWriter.size());
|
| addPaint(paint);
|
| addRect(rect);
|
| validate(initialOffset, size);
|
| }
|
|
|
| void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
| - uint32_t initialOffset, size;
|
| if (rrect.isRect()) {
|
| - // op + paint index + rect
|
| - size = 2 * kUInt32Size + sizeof(SkRect);
|
| - initialOffset = this->addDraw(DRAW_RECT, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size());
|
| - addPaint(paint);
|
| - addRect(rrect.getBounds());
|
| + this->drawRect(rrect.getBounds(), paint);
|
| } else if (rrect.isOval()) {
|
| - // op + paint index + rect
|
| - size = 2 * kUInt32Size + sizeof(SkRect);
|
| - initialOffset = this->addDraw(DRAW_OVAL, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size());
|
| - addPaint(paint);
|
| - addRect(rrect.getBounds());
|
| + this->drawOval(rrect.getBounds(), paint);
|
| } else {
|
| // op + paint index + rrect
|
| - size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
|
| - initialOffset = this->addDraw(DRAW_RRECT, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size());
|
| + uint32_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + uint32_t initialOffset = this->addDraw(DRAW_RRECT, &size, &paint, &rrect.getBounds());
|
| +#else
|
| + uint32_t initialOffset = this->addDraw(DRAW_RRECT, &size);
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_RRECT, size) == fWriter.size());
|
| addPaint(paint);
|
| addRRect(rrect);
|
| + validate(initialOffset, size);
|
| }
|
| - validate(initialOffset, size);
|
| }
|
|
|
| void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
|
| // op + paint index + path index
|
| uint32_t size = 3 * kUInt32Size;
|
| + const SkRect* bounds = path.isInverseFillType() ? NULL : &path.getBounds();
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + uint32_t initialOffset = this->addDraw(DRAW_PATH, &size, &paint, bounds);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_PATH, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_PATH, size) == fWriter.size());
|
| addPaint(paint);
|
| addPath(path);
|
| validate(initialOffset, size);
|
| @@ -739,8 +884,16 @@
|
| const SkPaint* paint = NULL) {
|
| // op + paint index + bitmap index + left + top
|
| uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
|
| + SkRect bounds = SkRect::MakeXYWH(left, top, bitmap.width(), bitmap.height());
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size, paint, &bounds);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP, size) == fWriter.size());
|
| addPaintPtr(paint);
|
| addBitmap(bitmap);
|
| addScalar(left);
|
| @@ -757,8 +910,15 @@
|
| }
|
| size += sizeof(dst); // + rect
|
|
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size, paint, &dst);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size());
|
| addPaintPtr(paint);
|
| addBitmap(bitmap);
|
| addRectPtr(src); // may be null
|
| @@ -770,8 +930,17 @@
|
| const SkPaint* paint) {
|
| // id + paint index + bitmap index + matrix index
|
| uint32_t size = 4 * kUInt32Size;
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkRect bounds = SkRect::MakeWH(bitmap.width(), bitmap.height());
|
| + matrix.mapRect(&bounds);
|
| + uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size, paint, &bounds);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size());
|
| addPaintPtr(paint);
|
| addBitmap(bitmap);
|
| addMatrix(matrix);
|
| @@ -782,8 +951,15 @@
|
| const SkRect& dst, const SkPaint* paint) {
|
| // op + paint index + bitmap id + center + dst rect
|
| uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size, paint, &dst);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size());
|
| addPaintPtr(paint);
|
| addBitmap(bitmap);
|
| addIRect(center);
|
| @@ -792,11 +968,19 @@
|
| }
|
|
|
| void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
|
| - const SkPaint* paint = NULL) {
|
| + const SkPaint* paint) {
|
| // op + paint index + bitmap index + left + top
|
| uint32_t size = 5 * kUInt32Size;
|
| + // Note: Bounds encoding not supported on drawSprite. Because drawSprite
|
| + // ignores the current transform matrix, the bounds will not follow the
|
| + // playback canvas's initial tranform matrix at playback time, and
|
| + // recorded bounds are assumed to be in the playback canvas' initial
|
| + // local frame of reference.
|
| uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size());
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_SPRITE, size) == fWriter.size());
|
| addPaintPtr(paint);
|
| addBitmap(bitmap);
|
| addInt(left);
|
| @@ -819,6 +1003,7 @@
|
| topbot[1] = bounds.fBottom;
|
| }
|
|
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
|
| SkScalar minY, SkScalar maxY) {
|
| if (!flat.isTopBotWritten()) {
|
| @@ -828,28 +1013,90 @@
|
| addScalar(flat.topBot()[0] + minY);
|
| addScalar(flat.topBot()[1] + maxY);
|
| }
|
| +#endif
|
|
|
| +static void pad_text_bbox_horizontally(const SkPaint::FontMetrics& metrics, SkRect* bbox) {
|
| + // Pad horizontal bounds on each side by max vertical extents.
|
| + // This is sort of arbitrary, but seems to produce reasonable results.
|
| + // If there were a way of getting max glyph X-extents to pad by, that
|
| + // may be better here, but FontMetrics fXMin and fXMax seem incorrect
|
| + // on most platforms (too small in Linux, never even set in Windows).
|
| + SkScalar pad = (metrics.fBottom - metrics.fTop);
|
| + SkASSERT(pad > 0);
|
| + bbox->fLeft -= pad;
|
| + bbox->fRight += pad;
|
| +}
|
| +
|
| void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
|
| SkScalar y, const SkPaint& paint) {
|
| - bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
|
| + // Note: The DRAW_TEXT_TOP_BOTTOM optimization is redundant if we are
|
| + // already recording full bounds.
|
|
|
| // op + paint index + length + 'length' worth of chars + x + y
|
| uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
|
| +
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkRect bbox;
|
| + paint.measureText(text, byteLength, &bbox);
|
| + SkPaint::FontMetrics metrics;
|
| + paint.getFontMetrics(&metrics);
|
| +
|
| + // Vertical and aligned text need to be offset
|
| + if (paint.isVerticalText()) {
|
| + SkScalar h = bbox.fBottom - bbox.fTop;
|
| + if (paint.getTextAlign() == SkPaint::kCenter_Align) {
|
| + bbox.fTop -= h / 2;
|
| + bbox.fBottom -= h / 2;
|
| + }
|
| + // Pad top and bottom with max extents from FontMetrics
|
| + bbox.fBottom += metrics.fBottom;
|
| + bbox.fTop += metrics.fTop;
|
| + } else {
|
| + SkScalar w = bbox.fRight - bbox.fLeft;
|
| + if (paint.getTextAlign() == SkPaint::kCenter_Align) {
|
| + bbox.fLeft -= w / 2;
|
| + bbox.fRight -= w / 2;
|
| + } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
|
| + bbox.fLeft -= w;
|
| + bbox.fRight -= w;
|
| + }
|
| + // Set vertical bounds to max extents from font metrics
|
| + bbox.fTop = metrics.fTop;
|
| + bbox.fBottom = metrics.fBottom;
|
| + }
|
| + pad_text_bbox_horizontally(metrics, &bbox);
|
| + bbox.fLeft += x;
|
| + bbox.fRight += x;
|
| + bbox.fTop += y;
|
| + bbox.fBottom += y;
|
| + uint32_t initialOffset = this->addDraw(DRAW_TEXT, &size, &paint, &bbox);
|
| +#else
|
| + bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
|
| +
|
| if (fast) {
|
| size += 2 * sizeof(SkScalar); // + top & bottom
|
| }
|
| -
|
| DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
|
| uint32_t initialOffset = this->addDraw(op, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_TEXT, size) == fWriter.size());
|
| +#else
|
| + SkASSERT(initialOffset + getPaintOffset(op, size) == fWriter.size());
|
| +#endif
|
| const SkFlatData* flatPaintData = addPaint(paint);
|
| SkASSERT(flatPaintData);
|
| addText(text, byteLength);
|
| addScalar(x);
|
| addScalar(y);
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| if (fast) {
|
| addFontMetricsTopBottom(paint, *flatPaintData, y, y);
|
| }
|
| +#endif
|
| validate(initialOffset, size);
|
| }
|
|
|
| @@ -877,37 +1124,66 @@
|
| }
|
| }
|
|
|
| + // Note: The DRAW_TEXT_[H_]TOP_BOTTOM optimization is redundant if we are
|
| + // already recording full bounds.
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
|
| bool fast = canUseDrawH && fastBounds;
|
| +#endif
|
|
|
| // op + paint index + length + 'length' worth of data + num points
|
| uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
|
| if (canUseDrawH) {
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| if (fast) {
|
| size += 2 * sizeof(SkScalar); // + top & bottom
|
| }
|
| +#endif
|
| // + y-pos + actual x-point data
|
| size += sizeof(SkScalar) + points * sizeof(SkScalar);
|
| } else {
|
| // + x&y point data
|
| size += points * sizeof(SkPoint);
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| if (fastBounds) {
|
| size += 2 * sizeof(SkScalar); // + top & bottom
|
| }
|
| +#endif
|
| }
|
|
|
| DrawType op;
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| if (fast) {
|
| op = DRAW_POS_TEXT_H_TOP_BOTTOM;
|
| - } else if (canUseDrawH) {
|
| + } else
|
| +#endif
|
| + if (canUseDrawH) {
|
| op = DRAW_POS_TEXT_H;
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| } else if (fastBounds) {
|
| op = DRAW_POS_TEXT_TOP_BOTTOM;
|
| +#endif
|
| } else {
|
| op = DRAW_POS_TEXT;
|
| }
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkRect bbox;
|
| + bbox.set(pos, paint.countText(text, byteLength));
|
| + SkPaint::FontMetrics metrics;
|
| + paint.getFontMetrics(&metrics);
|
| + bbox.fTop += metrics.fTop;
|
| + bbox.fBottom += metrics.fBottom;
|
| +
|
| + // pad on left and right by half of max vertical glyph extents
|
| + pad_text_bbox_horizontally(metrics, &bbox);
|
| + uint32_t initialOffset = this->addDraw(op, &size, &paint, &bbox);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(op, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(op, size) == fWriter.size());
|
| const SkFlatData* flatPaintData = addPaint(paint);
|
| SkASSERT(flatPaintData);
|
| addText(text, byteLength);
|
| @@ -917,18 +1193,22 @@
|
| size_t start = fWriter.size();
|
| #endif
|
| if (canUseDrawH) {
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| if (fast) {
|
| addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
|
| }
|
| +#endif
|
| addScalar(pos[0].fY);
|
| SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
|
| for (size_t index = 0; index < points; index++)
|
| *xptr++ = pos[index].fX;
|
| } else {
|
| fWriter.writeMul4(pos, points * sizeof(SkPoint));
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| if (fastBounds) {
|
| addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
|
| }
|
| +#endif
|
| }
|
| #ifdef SK_DEBUG_SIZE
|
| fPointBytes += fWriter.size() - start;
|
| @@ -940,35 +1220,67 @@
|
| void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
|
| const SkScalar xpos[], SkScalar constY,
|
| const SkPaint& paint) {
|
| - size_t points = paint.countText(text, byteLength);
|
| - if (0 == points)
|
| + size_t numChars = paint.countText(text, byteLength);
|
| + if (0 == numChars)
|
| return;
|
|
|
| - bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
|
| -
|
| // op + paint index + length + 'length' worth of data + num points
|
| uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
|
| +
|
| + // Note: The DRAW_POS_TEXT_H_TOP_BOTTOM optimization is redundant if we are
|
| + // already recording full bounds.
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| + bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
|
| if (fast) {
|
| size += 2 * sizeof(SkScalar); // + top & bottom
|
| }
|
| +#endif
|
| +
|
| // + y + the actual points
|
| - size += 1 * kUInt32Size + points * sizeof(SkScalar);
|
| + size += 1 * kUInt32Size + numChars * sizeof(SkScalar);
|
|
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkRect bbox;
|
| + bbox.fLeft = xpos[0];
|
| + bbox.fRight = xpos[numChars - 1];
|
| + // if we had a guarantee that these will be monotonically increasing, this could be sped up
|
| + for (size_t i = 0; i < numChars; ++i) {
|
| + if (xpos[i] < bbox.fLeft) {
|
| + bbox.fLeft = xpos[i];
|
| + }
|
| + if (xpos[i] > bbox.fRight) {
|
| + bbox.fRight = xpos[i];
|
| + }
|
| + }
|
| + SkPaint::FontMetrics metrics;
|
| + paint.getFontMetrics(&metrics);
|
| + pad_text_bbox_horizontally(metrics, &bbox);
|
| + bbox.fTop = metrics.fTop + constY;
|
| + bbox.fBottom = metrics.fBottom + constY;
|
| + uint32_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size, &paint, &bbox);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
|
| &size);
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size());
|
| const SkFlatData* flatPaintData = addPaint(paint);
|
| SkASSERT(flatPaintData);
|
| addText(text, byteLength);
|
| - addInt(points);
|
| + addInt(numChars);
|
|
|
| #ifdef SK_DEBUG_SIZE
|
| size_t start = fWriter.size();
|
| #endif
|
| +#if !(SK_RECORD_BOUNDS_IN_PICTURE)
|
| if (fast) {
|
| addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
|
| }
|
| +#endif
|
| addScalar(constY);
|
| - fWriter.writeMul4(xpos, points * sizeof(SkScalar));
|
| + fWriter.writeMul4(xpos, numChars * sizeof(SkScalar));
|
| #ifdef SK_DEBUG_SIZE
|
| fPointBytes += fWriter.size() - start;
|
| fPointWrites += points;
|
| @@ -981,8 +1293,24 @@
|
| const SkPaint& paint) {
|
| // op + paint index + length + 'length' worth of data + path index + matrix index
|
| uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkRect bbox = path.getBounds();
|
| + SkPaint::FontMetrics metrics;
|
| + paint.getFontMetrics(&metrics);
|
| + // pad out all sides by the max glyph height above baseline
|
| + SkScalar pad = metrics.fTop;
|
| + bbox.fLeft += pad;
|
| + bbox.fRight -= pad;
|
| + bbox.fTop += pad;
|
| + bbox.fBottom -= pad;
|
| + uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size, &paint, &bbox);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size());
|
| addPaint(paint);
|
| addText(text, byteLength);
|
| addPath(path);
|
| @@ -994,6 +1322,7 @@
|
| // op + picture index
|
| uint32_t size = 2 * kUInt32Size;
|
| uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addPicture(picture);
|
| validate(initialOffset, size);
|
| }
|
| @@ -1026,9 +1355,17 @@
|
| // + num indices + indices
|
| size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
|
| }
|
| -
|
| +#if SK_RECORD_BOUNDS_IN_PICTURE
|
| + SkRect bbox;
|
| + bbox.set(vertices, vertexCount);
|
| + uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size, &paint, &bbox);
|
| +#else
|
| uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
|
| - SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size());
|
| +#endif
|
| + if (kInvalidOffset == initialOffset) {
|
| + return;
|
| + }
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_VERTICES, size) == fWriter.size());
|
| addPaint(paint);
|
| addInt(flags);
|
| addInt(vmode);
|
| @@ -1051,6 +1388,7 @@
|
| // op + length + 'length' worth of data
|
| uint32_t size = 2 * kUInt32Size + SkAlign4(length);
|
| uint32_t initialOffset = this->addDraw(DRAW_DATA, &size);
|
| + SkASSERT(kInvalidOffset != initialOffset);
|
| addInt(length);
|
| fWriter.writePad(data, length);
|
| validate(initialOffset, size);
|
|
|