[SkTextBlob] Custom run font record
authorfmalita <fmalita@chromium.org>
Thu, 9 Apr 2015 15:49:32 +0000 (08:49 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 9 Apr 2015 15:49:32 +0000 (08:49 -0700)
Instead of using a full-blown SkPaint to store run font info, use a
custom structure.

This saves 96 bytes / run on 64bit platforms.

R=reed@google.com,mtklein@google.com,joshualitt@google.com

Review URL: https://codereview.chromium.org/1070943002

include/core/SkTypes.h
src/core/SkTextBlob.cpp

index 3f4bc2c..9014620 100644 (file)
@@ -448,7 +448,7 @@ template <typename Dst> Dst SkTCast(const void* ptr) {
 
 /** \class SkNoncopyable
 
-SkNoncopyable is the base class for objects that may do not want to
+SkNoncopyable is the base class for objects that do not want to
 be copied. It hides its copy-constructor and its assignment-operator.
 */
 class SK_API SkNoncopyable {
index 3ffc41e..3d396de 100644 (file)
 #include "SkTypeface.h"
 #include "SkWriteBuffer.h"
 
+namespace {
+
+// TODO(fmalita): replace with SkFont.
+class RunFont : SkNoncopyable {
+public:
+    RunFont(const SkPaint& paint)
+        : fSize(paint.getTextSize())
+        , fScaleX(paint.getTextScaleX())
+        , fTypeface(SkSafeRef(paint.getTypeface()))
+        , fSkewX(paint.getTextSkewX())
+        , fHinting(paint.getHinting())
+        , fFlags(paint.getFlags() & kFlagsMask) { }
+
+    void applyToPaint(SkPaint* paint) const {
+        paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        paint->setTypeface(fTypeface.get());
+        paint->setTextSize(fSize);
+        paint->setTextScaleX(fScaleX);
+        paint->setTextSkewX(fSkewX);
+        paint->setHinting(static_cast<SkPaint::Hinting>(fHinting));
+
+        paint->setFlags((paint->getFlags() & ~kFlagsMask) | fFlags);
+    }
+
+    bool operator==(const RunFont& other) const {
+        return fTypeface == other.fTypeface
+            && fSize == other.fSize
+            && fScaleX == other.fScaleX
+            && fSkewX == other.fSkewX
+            && fHinting == other.fHinting
+            && fFlags == other.fFlags;
+    }
+
+    bool operator!=(const RunFont& other) const {
+        return !(*this == other);
+    }
+private:
+    const static uint32_t kFlagsMask =
+        SkPaint::kAntiAlias_Flag          |
+        SkPaint::kUnderlineText_Flag      |
+        SkPaint::kStrikeThruText_Flag     |
+        SkPaint::kFakeBoldText_Flag       |
+        SkPaint::kLinearText_Flag         |
+        SkPaint::kSubpixelText_Flag       |
+        SkPaint::kDevKernText_Flag        |
+        SkPaint::kLCDRenderText_Flag      |
+        SkPaint::kEmbeddedBitmapText_Flag |
+        SkPaint::kAutoHinting_Flag        |
+        SkPaint::kVerticalText_Flag       |
+        SkPaint::kGenA8FromLCD_Flag       |
+        SkPaint::kDistanceFieldTextTEMP_Flag;
+
+    SkScalar                 fSize;
+    SkScalar                 fScaleX;
+
+    // Keep this SkAutoTUnref off the first position, to avoid interfering with SkNoncopyable
+    // empty baseclass optimization (http://code.google.com/p/skia/issues/detail?id=3694).
+    SkAutoTUnref<SkTypeface> fTypeface;
+    SkScalar                 fSkewX;
+
+    SK_COMPILE_ASSERT(SkPaint::kFull_Hinting < 4, insufficient_hinting_bits);
+    uint32_t                 fHinting : 2;
+    SK_COMPILE_ASSERT((kFlagsMask & 0xffff) == kFlagsMask, insufficient_flags_bits);
+    uint32_t                 fFlags : 16;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+struct RunFontStorageEquivalent {
+    SkScalar fSize, fScaleX;
+    void*    fTypeface;
+    SkScalar fSkewX;
+    uint32_t fFlags;
+};
+SK_COMPILE_ASSERT(sizeof(RunFont) == sizeof(RunFontStorageEquivalent), runfont_should_stay_packed);
+
+} // anonymous namespace
+
 //
 // Textblob data is laid out into externally-managed storage as follows:
 //
@@ -26,9 +104,9 @@ SkDEBUGCODE(static const unsigned kRunRecordMagic = 0xb10bcafe;)
 class SkTextBlob::RunRecord {
 public:
     RunRecord(uint32_t count, const SkPoint& offset, const SkPaint& font, GlyphPositioning pos)
-        : fCount(count)
+        : fFont(font)
+        , fCount(count)
         , fOffset(offset)
-        , fFont(font)
         , fPositioning(pos) {
         SkDEBUGCODE(fMagic = kRunRecordMagic);
     }
@@ -41,7 +119,7 @@ public:
         return fOffset;
     }
 
-    const SkPaint& font() const {
+    const RunFont& font() const {
         return fFont;
     }
 
@@ -100,9 +178,9 @@ private:
         memmove(posBuffer(), initialPosBuffer, copySize);
     }
 
+    RunFont          fFont;
     uint32_t         fCount;
     SkPoint          fOffset;
-    SkPaint          fFont;
     GlyphPositioning fPositioning;
 
     SkDEBUGCODE(unsigned fMagic;)
@@ -262,29 +340,7 @@ SkTextBlob::GlyphPositioning SkTextBlob::RunIterator::positioning() const {
 void SkTextBlob::RunIterator::applyFontToPaint(SkPaint* paint) const {
     SkASSERT(!this->done());
 
-    const SkPaint& font = fCurrentRun->font();
-
-    paint->setTypeface(font.getTypeface());
-    paint->setTextEncoding(font.getTextEncoding());
-    paint->setTextSize(font.getTextSize());
-    paint->setTextScaleX(font.getTextScaleX());
-    paint->setTextSkewX(font.getTextSkewX());
-    paint->setHinting(font.getHinting());
-
-    uint32_t flagsMask = SkPaint::kAntiAlias_Flag
-                       | SkPaint::kUnderlineText_Flag
-                       | SkPaint::kStrikeThruText_Flag
-                       | SkPaint::kFakeBoldText_Flag
-                       | SkPaint::kLinearText_Flag
-                       | SkPaint::kSubpixelText_Flag
-                       | SkPaint::kDevKernText_Flag
-                       | SkPaint::kLCDRenderText_Flag
-                       | SkPaint::kEmbeddedBitmapText_Flag
-                       | SkPaint::kAutoHinting_Flag
-                       | SkPaint::kVerticalText_Flag
-                       | SkPaint::kGenA8FromLCD_Flag
-                       | SkPaint::kDistanceFieldTextTEMP_Flag;
-    paint->setFlags((paint->getFlags() & ~flagsMask) | (font.getFlags() & flagsMask));
+    fCurrentRun->font().applyToPaint(paint);
 }
 
 SkTextBlobBuilder::SkTextBlobBuilder()
@@ -308,7 +364,9 @@ SkRect SkTextBlobBuilder::TightRunBounds(const SkTextBlob::RunRecord& run) {
     SkASSERT(SkTextBlob::kDefault_Positioning == run.positioning());
 
     SkRect bounds;
-    run.font().measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds);
+    SkPaint paint;
+    run.font().applyToPaint(&paint);
+    paint.measureText(run.glyphBuffer(), run.glyphCount() * sizeof(uint16_t), &bounds);
 
     return bounds.makeOffset(run.offset().x(), run.offset().y());
 }
@@ -346,7 +404,9 @@ SkRect SkTextBlobBuilder::ConservativeRunBounds(const SkTextBlob::RunRecord& run
     }
 
     // Expand by typeface glyph bounds.
-    const SkRect fontBounds = run.font().getFontBounds();
+    SkPaint paint;
+    run.font().applyToPaint(&paint);
+    const SkRect fontBounds = paint.getFontBounds();
     bounds.fLeft   += fontBounds.left();
     bounds.fTop    += fontBounds.top();
     bounds.fRight  += fontBounds.right();
@@ -366,7 +426,6 @@ void SkTextBlobBuilder::updateDeferredBounds() {
     SkASSERT(fLastRun >= sizeof(SkTextBlob));
     SkTextBlob::RunRecord* run = reinterpret_cast<SkTextBlob::RunRecord*>(fStorage.get() +
                                                                           fLastRun);
-    SkASSERT(SkPaint::kGlyphID_TextEncoding == run->font().getTextEncoding());
 
     // FIXME: we should also use conservative bounds for kDefault_Positioning.
     SkRect runBounds = SkTextBlob::kDefault_Positioning == run->positioning() ?