Souped-up SkTextBlob.
Refactored text blob backend for improved performance: instead of using
separate buffers for runs/positions/glyphs, everything is now packed in
a consolidated slab (including the SkTextBlob object itself!).
Benefits:
* number of allocations per blob construction reduced from ~4 to 1
(also minimizes internal fragmentation)
* run record size reduced by 8 bytes
This takes the blob construction overhead down to negligible levels
(for the current Blink uncached textblob implementation).
Unfortunately, the code is much more finicky (run merging in
particular) -- hence the assert spree.
Multi-run blobs are vulnerable to realloc storms but this is not a
problem at the moment because Blink is using one-run blobs 99% of the
time. Will be addressed in the future.
R=mtklein@google.com, reed@google.com, robertphillips@google.com
Committed: https://skia.googlesource.com/skia/+/13645ea0ea87038ebd71be3bd6d53b313069a9e4
Author: fmalita@chromium.org
Review URL: https://codereview.chromium.org/581173003
diff --git a/include/core/SkTextBlob.h b/include/core/SkTextBlob.h
index 8e67723..8ee1d19 100644
--- a/include/core/SkTextBlob.h
+++ b/include/core/SkTextBlob.h
@@ -53,6 +53,8 @@
kFull_Positioning = 2 // Point positioning -- two scalars per glyph.
};
+ class RunRecord;
+
class RunIterator {
public:
RunIterator(const SkTextBlob* blob);
@@ -68,21 +70,16 @@
GlyphPositioning positioning() const;
private:
- const SkTextBlob* fBlob;
- int fIndex;
+ const RunRecord* fCurrentRun;
+ int fRemainingRuns;
+
+ SkDEBUGCODE(uint8_t* fStorageTop;)
};
- // A run is a sequence of glyphs sharing the same font metrics and positioning mode.
- struct Run {
- uint32_t count;
- uint32_t glyphStart; // index into fGlyphBuffer
- uint32_t posStart; // index into fPosBuffer
- SkPoint offset; // run offset (unsued for fully positioned glyphs)
- SkPaint font;
- GlyphPositioning positioning;
- };
+ SkTextBlob(int runCount, const SkRect& bounds);
- SkTextBlob(uint16_t* glyphs, SkScalar* pos, const SkTArray<Run>* runs, const SkRect& bounds);
+ virtual ~SkTextBlob();
+ virtual void internal_dispose() const SK_OVERRIDE;
static unsigned ScalarsPerGlyph(GlyphPositioning pos);
@@ -90,14 +87,14 @@
friend class SkTextBlobBuilder;
friend class TextBlobTester;
- const SkAutoTMalloc<uint16_t> fGlyphBuffer;
- const SkAutoTMalloc<SkScalar> fPosBuffer;
+ const int fRunCount;
+ const SkRect fBounds;
+ mutable uint32_t fUniqueID;
- // SkTArray required here for run font destruction.
- SkAutoTDelete<const SkTArray<Run> > fRuns;
- const SkRect fBounds;
+ SkDEBUGCODE(size_t fStorageSize;)
- mutable uint32_t fUniqueID;
+ // The actual payload resides in externally-managed storage, following the object.
+ // (see the .cpp for more details)
typedef SkRefCnt INHERITED;
};
@@ -108,11 +105,7 @@
*/
class SK_API SkTextBlobBuilder {
public:
- /**
- * @param runs The number of runs to be added, if known. This is a storage hint and
- * not a limit.
- */
- SkTextBlobBuilder(unsigned runs = 0);
+ SkTextBlobBuilder();
~SkTextBlobBuilder();
@@ -180,20 +173,23 @@
const RunBuffer& allocRunPos(const SkPaint& font, int count, const SkRect* bounds = NULL);
private:
+ void reserve(size_t size);
void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
int count, SkPoint offset, const SkRect* bounds);
- void ensureRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
- const SkPoint& offset);
+ bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning,
+ int count, SkPoint offset);
void updateDeferredBounds();
- SkTDArray<uint16_t> fGlyphBuffer;
- SkTDArray<SkScalar> fPosBuffer;
- SkTArray<SkTextBlob::Run>* fRuns;
+ SkAutoTMalloc<uint8_t> fStorage;
+ size_t fStorageSize;
+ size_t fStorageUsed;
- SkRect fBounds;
- bool fDeferredBounds;
+ SkRect fBounds;
+ int fRunCount;
+ bool fDeferredBounds;
+ size_t fLastRun; // index into fStorage
- RunBuffer fCurrentRunBuffer;
+ RunBuffer fCurrentRunBuffer;
};
#endif // SkTextBlob_DEFINED