Chromium Code Reviews| Index: src/core/SkPictureRecord.cpp |
| =================================================================== |
| --- src/core/SkPictureRecord.cpp (revision 8010) |
| +++ src/core/SkPictureRecord.cpp (working copy) |
| @@ -30,6 +30,7 @@ |
| INHERITED(device), |
| fBoundingHierarchy(NULL), |
| fStateTree(NULL), |
| + fLastDrawRejected(false), |
| fFlattenableHeap(HEAP_BLOCK_SIZE), |
| fMatrices(&fFlattenableHeap), |
| fPaints(&fFlattenableHeap), |
| @@ -62,10 +63,30 @@ |
| /////////////////////////////////////////////////////////////////////////////// |
| +bool SkPictureRecord::canRecordBounds(DrawType op) { |
| + SkASSERT(op != DRAW_POS_TEXT_TOP_BOTTOM); // Should never be used when encoding bounds |
| + SkASSERT(op != DRAW_POS_TEXT_H_TOP_BOTTOM); |
| + return |
| + op == DRAW_BITMAP || |
| + op == DRAW_BITMAP_MATRIX || |
| + op == DRAW_BITMAP_NINE || |
| + op == DRAW_BITMAP_RECT_TO_RECT || |
| + op == DRAW_OVAL || |
| + op == DRAW_PATH || |
| + op == DRAW_POINTS || |
| + op == DRAW_POS_TEXT || |
| + op == DRAW_POS_TEXT_H || |
| + op == DRAW_RECT || |
| + op == DRAW_RRECT || |
| + op == DRAW_TEXT || |
| + op == DRAW_TEXT_ON_PATH || |
| + op == DRAW_VERTICES; |
| +} |
| + |
| // 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) { |
| +static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize, bool recordBounds) { |
| // 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 |
| @@ -116,6 +137,9 @@ |
| // after the op code |
| overflow = sizeof(uint32_t); |
| } |
| + if (recordBounds && SkPictureRecord::canRecordBounds(op)) { |
| + overflow += sizeof(SkIRect); |
| + } |
| if (SAVE_LAYER == op) { |
| static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size; |
| @@ -146,6 +170,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 +194,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, false) == fWriter.size()); |
| addPaintPtr(paint); |
| addInt(flags); |
| @@ -235,7 +261,7 @@ |
| * where the saveLayer's color can be moved into the drawBitmap*'s paint |
| */ |
| static bool remove_save_layer1(SkWriter32* writer, int32_t offset, |
| - SkPaintDictionary* paintDict) { |
| + SkPaintDictionary* paintDict, bool recordBounds) { |
| #ifdef SK_IGNORE_PICTURE_RECORD_SAVE_LAYER_OPT |
| return false; |
| @@ -283,8 +309,8 @@ |
| return false; // something else between the dbm* and the restore |
| } |
| - uint32_t dbmPaintOffset = getPaintOffset(op, dbmSize); |
| - uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerSize); |
| + uint32_t dbmPaintOffset = getPaintOffset(op, dbmSize, recordBounds); |
| + uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerSize, false); |
| // we have a match, now we need to get the paints involved |
| int dbmPaintId = *((int32_t*)writer->peek32(dbmOffset+dbmPaintOffset)); |
| @@ -418,7 +444,8 @@ |
| uint32_t initialOffset, size; |
| if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top()) && |
| - !remove_save_layer1(&fWriter, fRestoreOffsetStack.top(), &fPaints)) { |
| + !remove_save_layer1(&fWriter, fRestoreOffsetStack.top(), &fPaints, |
|
robertphillips
2013/03/06 23:02:02
SkToBool?
|
| + 0 != (fRecordFlags & SkPicture::kRecordBounds_RecordingFlag))) { |
| fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size()); |
| // op |
| size = 1 * kUInt32Size; |
| @@ -434,6 +461,55 @@ |
| return this->INHERITED::restore(); |
| } |
| +uint32_t SkPictureRecord::addDrawWithBounds(DrawType drawType, uint32_t* size, |
| + const SkPaint* paint, const SkRect* localBounds) { |
| + SkASSERT(canRecordBounds(drawType)); |
| + |
| + SkIRect clippedDevBounds; |
| + if (recordBounds()) { |
| + SkIRect devClipBounds; |
| + if (!this->getClipDeviceBounds(&devClipBounds)) { |
|
robertphillips
2013/03/06 23:02:02
Comment here about this optimization and why it is
|
| + fLastDrawRejected = true; |
| + return 0; |
| + } |
| + 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()) { |
| + fLastDrawRejected = true; |
| + return 0; |
| + } |
| + SkRect devBounds; |
| + this->getTotalMatrix().mapRect(&devBounds, paintBounds); |
| + devBounds.roundOut(&clippedDevBounds); |
| + if (!clippedDevBounds.intersect(devClipBounds)) { |
| + fLastDrawRejected = true; |
| + return 0; |
| + } |
| + } |
| + *size += sizeof(SkIRect); |
| + } |
| + |
| + uint32_t offset = addDraw(drawType, size); |
| + |
| + if (recordBounds()) { |
| + fWriter.write(&clippedDevBounds, sizeof(clippedDevBounds)); |
| + } |
| + return offset; |
| +} |
| + |
| bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) { |
| // op + dx + dy |
| uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); |
| @@ -660,7 +736,7 @@ |
| // op + paint index |
| uint32_t size = 2 * kUInt32Size; |
| uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size()); |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_PAINT, size, false) == fWriter.size()); |
| addPaint(paint); |
| validate(initialOffset, size); |
| } |
| @@ -669,8 +745,18 @@ |
| const SkPaint& paint) { |
| // op + paint index + mode + count + point data |
| uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); |
| - uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + SkRect bbox; |
| + bbox.set(pts, count); |
| + initialOffset = this->addDrawWithBounds(DRAW_POINTS, &size, &paint, &bbox); |
|
robertphillips
2013/03/06 23:02:02
Could fLastDrawRejected be passed in as a paramete
Justin Novosad
2013/03/07 14:41:42
It could, but I need to have as a member anyways b
|
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_POINTS, &size); |
| + } |
|
robertphillips
2013/03/06 23:02:02
this->recordBounds()? Also in following changes to
|
| + SkASSERT(initialOffset + getPaintOffset(DRAW_POINTS, size, recordBounds()) == fWriter.size()); |
| addPaint(paint); |
| addInt(mode); |
| addInt(count); |
| @@ -681,8 +767,16 @@ |
| void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { |
| // op + paint index + rect |
| uint32_t size = 2 * kUInt32Size + sizeof(oval); |
| - uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + initialOffset = this->addDrawWithBounds(DRAW_OVAL, &size, &paint, &oval); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_OVAL, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_OVAL, size, recordBounds()) == fWriter.size()); |
| addPaint(paint); |
| addRect(oval); |
| validate(initialOffset, size); |
| @@ -691,45 +785,60 @@ |
| void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { |
| // op + paint index + rect |
| uint32_t size = 2 * kUInt32Size + sizeof(rect); |
| - uint32_t initialOffset = this->addDraw(DRAW_RECT, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + initialOffset = this->addDrawWithBounds(DRAW_RECT, &size, &paint, &rect); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_RECT, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_RECT, size, recordBounds()) == 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 |
| + uint32_t initialOffset, size; |
| size = 2 * kUInt32Size + SkRRect::kSizeInMemory; |
| - initialOffset = this->addDraw(DRAW_RRECT, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size()); |
| + if (recordBounds()) { |
|
robertphillips
2013/03/06 23:02:02
What do you think about modifying addDraw to alway
Justin Novosad
2013/03/07 14:41:42
Well, I also want to avoid computing the bounds th
|
| + initialOffset = this->addDrawWithBounds(DRAW_RRECT, &size, &paint, &rrect.getBounds()); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_RRECT, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_RRECT, size, recordBounds()) \ |
| + == 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; |
| - uint32_t initialOffset = this->addDraw(DRAW_PATH, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size()); |
| + const SkRect* bounds = path.isInverseFillType() ? NULL : &path.getBounds(); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + initialOffset = this->addDrawWithBounds(DRAW_PATH, &size, &paint, bounds); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_PATH, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_PATH, size, recordBounds()) == fWriter.size()); |
| addPaint(paint); |
| addPath(path); |
| validate(initialOffset, size); |
| @@ -739,8 +848,17 @@ |
| const SkPaint* paint = NULL) { |
| // op + paint index + bitmap index + left + top |
| uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); |
| - uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size()); |
| + SkRect bounds = SkRect::MakeXYWH(left, top, bitmap.width(), bitmap.height()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + initialOffset = this->addDrawWithBounds(DRAW_BITMAP, &size, paint, &bounds); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_BITMAP, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP, size, recordBounds()) == fWriter.size()); |
| addPaintPtr(paint); |
| addBitmap(bitmap); |
| addScalar(left); |
| @@ -757,8 +875,17 @@ |
| } |
| size += sizeof(dst); // + rect |
| - uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + initialOffset = this->addDrawWithBounds(DRAW_BITMAP_RECT_TO_RECT, &size, paint, &dst); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size, recordBounds()) \ |
| + == fWriter.size()); |
| addPaintPtr(paint); |
| addBitmap(bitmap); |
| addRectPtr(src); // may be null |
| @@ -770,8 +897,19 @@ |
| const SkPaint* paint) { |
| // id + paint index + bitmap index + matrix index |
| uint32_t size = 4 * kUInt32Size; |
| - uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + SkRect bounds = SkRect::MakeWH(bitmap.width(), bitmap.height()); |
| + matrix.mapRect(&bounds); |
| + initialOffset = this->addDrawWithBounds(DRAW_BITMAP_MATRIX, &size, paint, &bounds); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP_MATRIX, size, recordBounds()) \ |
| + == fWriter.size()); |
| addPaintPtr(paint); |
| addBitmap(bitmap); |
| addMatrix(matrix); |
| @@ -782,8 +920,17 @@ |
| const SkRect& dst, const SkPaint* paint) { |
| // op + paint index + bitmap id + center + dst rect |
| uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); |
| - uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + initialOffset = this->addDrawWithBounds(DRAW_BITMAP_NINE, &size, paint, &dst); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_BITMAP_NINE, size, recordBounds()) == \ |
| + fWriter.size()); |
| addPaintPtr(paint); |
| addBitmap(bitmap); |
| addIRect(center); |
| @@ -792,11 +939,13 @@ |
| } |
| 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; |
| - uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + // Note: Bounds encoding not supported. |
| + initialOffset = this->addDraw(DRAW_SPRITE, &size); |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_SPRITE, size, false) == fWriter.size()); |
| addPaintPtr(paint); |
| addBitmap(bitmap); |
| addInt(left); |
| @@ -831,7 +980,8 @@ |
| void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, |
| SkScalar y, const SkPaint& paint) { |
|
robertphillips
2013/03/06 23:02:02
// We disallow DRAW_TEXT_TOP_BOTTOM when saving bo
|
| - bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); |
| + bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && |
| + (fRecordFlags & SkPicture::kRecordBounds_RecordingFlag) == 0; |
| // op + paint index + length + 'length' worth of chars + x + y |
| uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); |
| @@ -840,8 +990,57 @@ |
| } |
| DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; |
| - uint32_t initialOffset = this->addDraw(op, &size); |
| - SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + 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 horizontal bounds on each side by half of 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) / 2; |
| + bbox.fLeft -= pad; |
| + bbox.fRight += pad; |
| + |
| + bbox.fLeft += x; |
| + bbox.fRight += x; |
| + bbox.fTop += y; |
| + bbox.fBottom += y; |
| + initialOffset = this->addDrawWithBounds(op, &size, &paint, &bbox); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(op, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(op, size, recordBounds()) == fWriter.size()); |
| const SkFlatData* flatPaintData = addPaint(paint); |
| SkASSERT(flatPaintData); |
| addText(text, byteLength); |
| @@ -877,7 +1076,8 @@ |
| } |
| } |
| - bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds(); |
| + bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && |
| + (fRecordFlags & SkPicture::kRecordBounds_RecordingFlag) == 0; |
| bool fast = canUseDrawH && fastBounds; |
| // op + paint index + length + 'length' worth of data + num points |
| @@ -906,8 +1106,27 @@ |
| } else { |
| op = DRAW_POS_TEXT; |
| } |
| - uint32_t initialOffset = this->addDraw(op, &size); |
| - SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + 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 |
| + SkScalar pad = (metrics.fTop - metrics.fBottom) / 2; |
| + bbox.fLeft += pad; |
| + bbox.fRight -= pad; |
| + initialOffset = this->addDrawWithBounds(op, &size, &paint, &bbox); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(op, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(op, size, recordBounds()) == fWriter.size()); |
| const SkFlatData* flatPaintData = addPaint(paint); |
| SkASSERT(flatPaintData); |
| addText(text, byteLength); |
| @@ -944,7 +1163,8 @@ |
| if (0 == points) |
| return; |
| - bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); |
| + bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && |
| + (fRecordFlags & SkPicture::kRecordBounds_RecordingFlag) == 0; |
| // op + paint index + length + 'length' worth of data + num points |
| uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; |
| @@ -954,8 +1174,41 @@ |
| // + y + the actual points |
| size += 1 * kUInt32Size + points * sizeof(SkScalar); |
| - uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, |
| - &size); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + size_t numChars = paint.countText(text, byteLength); |
| + 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 = 1; 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 horizontally by max glyph height |
| + SkScalar pad = (metrics.fTop - metrics.fBottom); |
| + bbox.fLeft += pad; |
| + bbox.fRight -= pad; |
| + |
| + bbox.fTop = metrics.fTop + constY; |
| + bbox.fBottom = metrics.fBottom + constY; |
| + initialOffset = this->addDrawWithBounds(DRAW_POS_TEXT_H, &size, &paint, &bbox); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, |
| + &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_TEXT_ON_PATH, size, recordBounds()) \ |
| + == fWriter.size()); |
| const SkFlatData* flatPaintData = addPaint(paint); |
| SkASSERT(flatPaintData); |
| addText(text, byteLength); |
| @@ -981,8 +1234,26 @@ |
| const SkPaint& paint) { |
| // op + paint index + length + 'length' worth of data + path index + matrix index |
| uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size; |
| - uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + 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; |
| + initialOffset = this->addDrawWithBounds(DRAW_TEXT_ON_PATH, &size, &paint, &bbox); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_TEXT_ON_PATH, size, recordBounds()) \ |
| + == fWriter.size()); |
| addPaint(paint); |
| addText(text, byteLength); |
| addPath(path); |
| @@ -1027,8 +1298,19 @@ |
| size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); |
| } |
| - uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size); |
| - SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size()); |
| + uint32_t initialOffset; |
| + if (recordBounds()) { |
| + SkRect bbox; |
| + bbox.set(vertices, vertexCount); |
| + initialOffset = this->addDrawWithBounds(DRAW_VERTICES, &size, &paint, &bbox); |
| + if (fLastDrawRejected) { |
| + return; |
| + } |
| + } else { |
| + initialOffset = this->addDraw(DRAW_VERTICES, &size); |
| + } |
| + SkASSERT(initialOffset + getPaintOffset(DRAW_VERTICES, size, recordBounds()) \ |
| + == fWriter.size()); |
| addPaint(paint); |
| addInt(flags); |
| addInt(vmode); |