#include "SkPictureRecord.h" #include "SkTSearch.h" #define MIN_WRITER_SIZE 16384 #define HEAP_BLOCK_SIZE 4096 SkPictureRecord::SkPictureRecord(uint32_t flags) : fHeap(HEAP_BLOCK_SIZE), fWriter(MIN_WRITER_SIZE), fRecordFlags(flags) { fBitmapIndex = fMatrixIndex = fPaintIndex = fRegionIndex = 1; #ifdef SK_DEBUG_SIZE fPointBytes = fRectBytes = fTextBytes = 0; fPointWrites = fRectWrites = fTextWrites = 0; #endif fRestoreOffsetStack.setReserve(32); fRestoreOffsetStack.push(0); fPathHeap = NULL; // lazy allocate } SkPictureRecord::~SkPictureRecord() { reset(); } /////////////////////////////////////////////////////////////////////////////// int SkPictureRecord::save(SaveFlags flags) { addDraw(SAVE); addInt(flags); fRestoreOffsetStack.push(0); validate(); return this->INHERITED::save(flags); } int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) { addDraw(SAVE_LAYER); addRectPtr(bounds); addPaintPtr(paint); addInt(flags); fRestoreOffsetStack.push(0); validate(); return this->INHERITED::saveLayer(bounds, paint, flags); } void SkPictureRecord::restore() { // patch up the clip offsets { uint32_t restoreOffset = (uint32_t)fWriter.size(); uint32_t offset = fRestoreOffsetStack.top(); while (offset) { uint32_t* peek = fWriter.peek32(offset); offset = *peek; *peek = restoreOffset; } fRestoreOffsetStack.pop(); } addDraw(RESTORE); validate(); return this->INHERITED::restore(); } bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) { addDraw(TRANSLATE); addScalar(dx); addScalar(dy); validate(); return this->INHERITED::translate(dx, dy); } bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) { addDraw(SCALE); addScalar(sx); addScalar(sy); validate(); return this->INHERITED::scale(sx, sy); } bool SkPictureRecord::rotate(SkScalar degrees) { addDraw(ROTATE); addScalar(degrees); validate(); return this->INHERITED::rotate(degrees); } bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) { addDraw(SKEW); addScalar(sx); addScalar(sy); validate(); return this->INHERITED::skew(sx, sy); } bool SkPictureRecord::concat(const SkMatrix& matrix) { validate(); addDraw(CONCAT); addMatrix(matrix); validate(); return this->INHERITED::concat(matrix); } void SkPictureRecord::setMatrix(const SkMatrix& matrix) { validate(); addDraw(SET_MATRIX); addMatrix(matrix); validate(); this->INHERITED::setMatrix(matrix); } bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op) { addDraw(CLIP_RECT); addRect(rect); addInt(op); size_t offset = fWriter.size(); addInt(fRestoreOffsetStack.top()); fRestoreOffsetStack.top() = offset; validate(); return this->INHERITED::clipRect(rect, op); } bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op) { addDraw(CLIP_PATH); addPath(path); addInt(op); size_t offset = fWriter.size(); addInt(fRestoreOffsetStack.top()); fRestoreOffsetStack.top() = offset; validate(); if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { return this->INHERITED::clipRect(path.getBounds(), op); } else { return this->INHERITED::clipPath(path, op); } } bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { addDraw(CLIP_REGION); addRegion(region); addInt(op); size_t offset = fWriter.size(); addInt(fRestoreOffsetStack.top()); fRestoreOffsetStack.top() = offset; validate(); return this->INHERITED::clipRegion(region, op); } void SkPictureRecord::drawPaint(const SkPaint& paint) { addDraw(DRAW_PAINT); addPaint(paint); validate(); } void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { addDraw(DRAW_POINTS); addPaint(paint); addInt(mode); addInt(count); fWriter.writeMul4(pts, count * sizeof(SkPoint)); validate(); } void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { addDraw(DRAW_RECT); addPaint(paint); addRect(rect); validate(); } void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { addDraw(DRAW_PATH); addPaint(paint); addPath(path); validate(); } void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint = NULL) { addDraw(DRAW_BITMAP); addPaintPtr(paint); addBitmap(bitmap); addScalar(left); addScalar(top); validate(); } void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, const SkRect& dst, const SkPaint* paint) { addDraw(DRAW_BITMAP_RECT); addPaintPtr(paint); addBitmap(bitmap); addIRectPtr(src); // may be null addRect(dst); validate(); } void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) { addDraw(DRAW_BITMAP_MATRIX); addPaintPtr(paint); addBitmap(bitmap); addMatrix(matrix); validate(); } void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint = NULL) { addDraw(DRAW_SPRITE); addPaintPtr(paint); addBitmap(bitmap); addInt(left); addInt(top); validate(); } void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, SkScalar baselineY) { SkPaint::FontMetrics metrics; paint.getFontMetrics(&metrics); SkRect bounds; // construct a rect so we can see any adjustments from the paint. // we use 0,1 for left,right, just so the rect isn't empty bounds.set(0, metrics.fTop + baselineY, SK_Scalar1, metrics.fBottom + baselineY); (void)paint.computeFastBounds(bounds, &bounds); // now record the top and bottom addScalar(bounds.fTop); addScalar(bounds.fBottom); } void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { bool fast = paint.canComputeFastBounds(); addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT); addPaint(paint); addText(text, byteLength); addScalar(x); addScalar(y); if (fast) { addFontMetricsTopBottom(paint, y); } validate(); } void SkPictureRecord::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { size_t points = paint.countText(text, byteLength); if (0 == points) return; bool canUseDrawH = true; // check if the caller really should have used drawPosTextH() { const SkScalar firstY = pos[0].fY; for (size_t index = 1; index < points; index++) { if (pos[index].fY != firstY) { canUseDrawH = false; break; } } } bool fast = canUseDrawH && paint.canComputeFastBounds(); if (fast) { addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM); } else { addDraw(canUseDrawH ? DRAW_POS_TEXT_H : DRAW_POS_TEXT); } addPaint(paint); addText(text, byteLength); addInt(points); #ifdef SK_DEBUG_SIZE size_t start = fWriter.size(); #endif if (canUseDrawH) { if (fast) { addFontMetricsTopBottom(paint, pos[0].fY); } 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)); } #ifdef SK_DEBUG_SIZE fPointBytes += fWriter.size() - start; fPointWrites += points; #endif validate(); } 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) return; bool fast = paint.canComputeFastBounds(); addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H); addPaint(paint); addText(text, byteLength); addInt(points); #ifdef SK_DEBUG_SIZE size_t start = fWriter.size(); #endif if (fast) { addFontMetricsTopBottom(paint, constY); } addScalar(constY); fWriter.writeMul4(xpos, points * sizeof(SkScalar)); #ifdef SK_DEBUG_SIZE fPointBytes += fWriter.size() - start; fPointWrites += points; #endif validate(); } void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { addDraw(DRAW_TEXT_ON_PATH); addPaint(paint); addText(text, byteLength); addPath(path); addMatrixPtr(matrix); validate(); } void SkPictureRecord::drawPicture(SkPicture& picture) { addDraw(DRAW_PICTURE); addPicture(picture); validate(); } void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[], int indexCount, const SkPaint& paint) { uint32_t flags = 0; if (texs) { flags |= DRAW_VERTICES_HAS_TEXS; } if (colors) { flags |= DRAW_VERTICES_HAS_COLORS; } if (indexCount > 0) { flags |= DRAW_VERTICES_HAS_INDICES; } addDraw(DRAW_VERTICES); addPaint(paint); addInt(flags); addInt(vmode); addInt(vertexCount); addPoints(vertices, vertexCount); if (flags & DRAW_VERTICES_HAS_TEXS) { addPoints(texs, vertexCount); } if (flags & DRAW_VERTICES_HAS_COLORS) { fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); } if (flags & DRAW_VERTICES_HAS_INDICES) { addInt(indexCount); fWriter.writePad(indices, indexCount * sizeof(uint16_t)); } } /////////////////////////////////////////////////////////////////////////////// void SkPictureRecord::reset() { fPathHeap->safeUnref(); fPathHeap = NULL; fBitmaps.reset(); fMatrices.reset(); fPaints.reset(); fPictureRefs.unrefAll(); fRegions.reset(); fWriter.reset(); fHeap.reset(); fRestoreOffsetStack.setCount(1); fRestoreOffsetStack.top() = 0; fRCRecorder.reset(); fTFRecorder.reset(); } void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { addInt(find(fBitmaps, bitmap)); } void SkPictureRecord::addMatrix(const SkMatrix& matrix) { addMatrixPtr(&matrix); } void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) { addInt(find(fMatrices, matrix)); } void SkPictureRecord::addPaint(const SkPaint& paint) { addPaintPtr(&paint); } void SkPictureRecord::addPaintPtr(const SkPaint* paint) { addInt(find(fPaints, paint)); } void SkPictureRecord::addPath(const SkPath& path) { if (NULL == fPathHeap) { fPathHeap = SkNEW(SkPathHeap); } addInt(fPathHeap->append(path)); } void SkPictureRecord::addPicture(SkPicture& picture) { int index = fPictureRefs.find(&picture); if (index < 0) { // not found index = fPictureRefs.count(); *fPictureRefs.append() = &picture; picture.ref(); } // follow the convention of recording a 1-based index addInt(index + 1); } void SkPictureRecord::addPoint(const SkPoint& point) { #ifdef SK_DEBUG_SIZE size_t start = fWriter.size(); #endif fWriter.writePoint(point); #ifdef SK_DEBUG_SIZE fPointBytes += fWriter.size() - start; fPointWrites++; #endif } void SkPictureRecord::addPoints(const SkPoint pts[], int count) { fWriter.writeMul4(pts, count * sizeof(SkPoint)); #ifdef SK_DEBUG_SIZE fPointBytes += count * sizeof(SkPoint); fPointWrites++; #endif } void SkPictureRecord::addRect(const SkRect& rect) { #ifdef SK_DEBUG_SIZE size_t start = fWriter.size(); #endif fWriter.writeRect(rect); #ifdef SK_DEBUG_SIZE fRectBytes += fWriter.size() - start; fRectWrites++; #endif } void SkPictureRecord::addRectPtr(const SkRect* rect) { if (fWriter.writeBool(rect != NULL)) { fWriter.writeRect(*rect); } } void SkPictureRecord::addIRectPtr(const SkIRect* rect) { if (fWriter.writeBool(rect != NULL)) { *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; } } void SkPictureRecord::addRegion(const SkRegion& region) { addInt(find(fRegions, region)); } void SkPictureRecord::addText(const void* text, size_t byteLength) { #ifdef SK_DEBUG_SIZE size_t start = fWriter.size(); #endif addInt(byteLength); fWriter.writePad(text, byteLength); #ifdef SK_DEBUG_SIZE fTextBytes += fWriter.size() - start; fTextWrites++; #endif } /////////////////////////////////////////////////////////////////////////////// int SkPictureRecord::find(SkTDArray& bitmaps, const SkBitmap& bitmap) { SkFlatBitmap* flat = SkFlatBitmap::Flatten(&fHeap, bitmap, fBitmapIndex, &fRCRecorder); int index = SkTSearch((const SkFlatData**) bitmaps.begin(), bitmaps.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); if (index >= 0) { (void)fHeap.unalloc(flat); return bitmaps[index]->index(); } index = ~index; *bitmaps.insert(index) = flat; return fBitmapIndex++; } int SkPictureRecord::find(SkTDArray& matrices, const SkMatrix* matrix) { if (matrix == NULL) return 0; SkFlatMatrix* flat = SkFlatMatrix::Flatten(&fHeap, *matrix, fMatrixIndex); int index = SkTSearch((const SkFlatData**) matrices.begin(), matrices.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); if (index >= 0) { (void)fHeap.unalloc(flat); return matrices[index]->index(); } index = ~index; *matrices.insert(index) = flat; return fMatrixIndex++; } int SkPictureRecord::find(SkTDArray& paints, const SkPaint* paint) { if (paint == NULL) { return 0; } SkFlatPaint* flat = SkFlatPaint::Flatten(&fHeap, *paint, fPaintIndex, &fRCRecorder, &fTFRecorder); int index = SkTSearch((const SkFlatData**) paints.begin(), paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); if (index >= 0) { (void)fHeap.unalloc(flat); return paints[index]->index(); } index = ~index; *paints.insert(index) = flat; return fPaintIndex++; } int SkPictureRecord::find(SkTDArray& regions, const SkRegion& region) { SkFlatRegion* flat = SkFlatRegion::Flatten(&fHeap, region, fRegionIndex); int index = SkTSearch((const SkFlatData**) regions.begin(), regions.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare); if (index >= 0) { (void)fHeap.unalloc(flat); return regions[index]->index(); } index = ~index; *regions.insert(index) = flat; return fRegionIndex++; } #ifdef SK_DEBUG_DUMP void SkPictureRecord::dumpMatrices() { int count = fMatrices.count(); SkMatrix defaultMatrix; defaultMatrix.reset(); for (int index = 0; index < count; index++) { const SkFlatMatrix* flatMatrix = fMatrices[index]; flatMatrix->dump(); } } void SkPictureRecord::dumpPaints() { int count = fPaints.count(); for (int index = 0; index < count; index++) fPaints[index]->dump(); } #endif #ifdef SK_DEBUG_SIZE size_t SkPictureRecord::size() const { size_t result = 0; size_t sizeData; bitmaps(&sizeData); result += sizeData; matrices(&sizeData); result += sizeData; paints(&sizeData); result += sizeData; paths(&sizeData); result += sizeData; pictures(&sizeData); result += sizeData; regions(&sizeData); result += sizeData; result += streamlen(); return result; } int SkPictureRecord::bitmaps(size_t* size) const { size_t result = 0; int count = fBitmaps.count(); for (int index = 0; index < count; index++) result += sizeof(fBitmaps[index]) + fBitmaps[index]->size(); *size = result; return count; } int SkPictureRecord::matrices(size_t* size) const { int count = fMatrices.count(); *size = sizeof(fMatrices[0]) * count; return count; } int SkPictureRecord::paints(size_t* size) const { size_t result = 0; int count = fPaints.count(); for (int index = 0; index < count; index++) result += sizeof(fPaints[index]) + fPaints[index]->size(); *size = result; return count; } int SkPictureRecord::paths(size_t* size) const { size_t result = 0; int count = fPaths.count(); for (int index = 0; index < count; index++) result += sizeof(fPaths[index]) + fPaths[index]->size(); *size = result; return count; } int SkPictureRecord::regions(size_t* size) const { size_t result = 0; int count = fRegions.count(); for (int index = 0; index < count; index++) result += sizeof(fRegions[index]) + fRegions[index]->size(); *size = result; return count; } size_t SkPictureRecord::streamlen() const { return fWriter.size(); } #endif #ifdef SK_DEBUG_VALIDATE void SkPictureRecord::validate() const { validateBitmaps(); validateMatrices(); validatePaints(); validatePaths(); validatePictures(); validateRegions(); } void SkPictureRecord::validateBitmaps() const { int count = fBitmaps.count(); SkASSERT((unsigned) count < 0x1000); for (int index = 0; index < count; index++) { const SkFlatBitmap* bitPtr = fBitmaps[index]; SkASSERT(bitPtr); bitPtr->validate(); } } void SkPictureRecord::validateMatrices() const { int count = fMatrices.count(); SkASSERT((unsigned) count < 0x1000); for (int index = 0; index < count; index++) { const SkFlatMatrix* matrix = fMatrices[index]; SkASSERT(matrix); matrix->validate(); } } void SkPictureRecord::validatePaints() const { int count = fPaints.count(); SkASSERT((unsigned) count < 0x1000); for (int index = 0; index < count; index++) { const SkFlatPaint* paint = fPaints[index]; SkASSERT(paint); // paint->validate(); } } void SkPictureRecord::validatePaths() const { int count = fPaths.count(); SkASSERT((unsigned) count < 0x1000); for (int index = 0; index < count; index++) { const SkFlatPath* path = fPaths[index]; SkASSERT(path); path->validate(); } } void SkPictureRecord::validateRegions() const { int count = fRegions.count(); SkASSERT((unsigned) count < 0x1000); for (int index = 0; index < count; index++) { const SkFlatRegion* region = fRegions[index]; SkASSERT(region); region->validate(); } } #endif