Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Unified Diff: src/core/SkPictureRecord.cpp

Issue 12545009: Adding option in SkPicture to record device-space bounds of draw commands. (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkPictureRecord.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
+
robertphillips 2013/03/11 17:31:39 left justify the # commands?
Justin Novosad 2013/03/11 17:52:10 Done.
+ #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);
« no previous file with comments | « src/core/SkPictureRecord.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698