Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2018 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkGlyphRun.h"
      9 
     10 #include "SkDevice.h"
     11 #include "SkFont.h"
     12 #include "SkFontPriv.h"
     13 #include "SkPaint.h"
     14 #include "SkStrike.h"
     15 #include "SkStrikeCache.h"
     16 #include "SkTextBlob.h"
     17 #include "SkTextBlobPriv.h"
     18 #include "SkTo.h"
     19 #include "SkUtils.h"
     20 
     21 // -- SkGlyphRun -----------------------------------------------------------------------------------
     22 SkGlyphRun::SkGlyphRun(const SkFont& font,
     23                        SkSpan<const SkPoint> positions,
     24                        SkSpan<const SkGlyphID> glyphIDs,
     25                        SkSpan<const char> text,
     26                        SkSpan<const uint32_t> clusters)
     27         : fPositions{positions}
     28         , fGlyphIDs{glyphIDs}
     29         , fText{text}
     30         , fClusters{clusters}
     31         , fFont{font} {}
     32 
     33 SkGlyphRun::SkGlyphRun(const SkGlyphRun& that, const SkFont& font)
     34     : fPositions{that.fPositions}
     35     , fGlyphIDs{that.fGlyphIDs}
     36     , fText{that.fText}
     37     , fClusters{that.fClusters}
     38     , fFont{font} {}
     39 
     40 void SkGlyphRun::filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions) {
     41     memcpy(glyphIDs, fGlyphIDs.data(), fGlyphIDs.size_bytes());
     42     memcpy(positions, fPositions.data(), fPositions.size_bytes());
     43 }
     44 
     45 // -- SkGlyphRunList -------------------------------------------------------------------------------
     46 SkGlyphRunList::SkGlyphRunList() = default;
     47 SkGlyphRunList::SkGlyphRunList(
     48         const SkPaint& paint,
     49         const SkTextBlob* blob,
     50         SkPoint origin,
     51         SkSpan<const SkGlyphRun> glyphRunList)
     52         : fOriginalPaint{&paint}
     53         , fOriginalTextBlob{blob}
     54         , fOrigin{origin}
     55         , fGlyphRuns{glyphRunList} { }
     56 
     57 SkGlyphRunList::SkGlyphRunList(const SkGlyphRun& glyphRun, const SkPaint& paint)
     58         : fOriginalPaint{&paint}
     59         , fOriginalTextBlob{nullptr}
     60         , fOrigin{SkPoint::Make(0, 0)}
     61         , fGlyphRuns{SkSpan<const SkGlyphRun>{&glyphRun, 1}} {}
     62 
     63 uint64_t SkGlyphRunList::uniqueID() const {
     64     return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID()
     65                                         : SK_InvalidUniqueID;
     66 }
     67 
     68 bool SkGlyphRunList::anyRunsLCD() const {
     69     for (const auto& r : fGlyphRuns) {
     70         if (r.font().getEdging() == SkFont::Edging::kSubpixelAntiAlias) {
     71             return true;
     72         }
     73     }
     74     return false;
     75 }
     76 
     77 bool SkGlyphRunList::anyRunsSubpixelPositioned() const {
     78     for (const auto& r : fGlyphRuns) {
     79         if (r.font().isSubpixel()) {
     80             return true;
     81         }
     82     }
     83     return false;
     84 }
     85 
     86 bool SkGlyphRunList::allFontsFinite() const {
     87     for (const auto& r : fGlyphRuns) {
     88         if (!SkFontPriv::IsFinite(r.font())) {
     89             return false;
     90         }
     91     }
     92     return true;
     93 }
     94 
     95 void SkGlyphRunList::temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const {
     96     SkASSERT(fOriginalTextBlob != nullptr);
     97     fOriginalTextBlob->notifyAddedToCache(cacheID);
     98 }
     99 
    100 // -- SkGlyphIDSet ---------------------------------------------------------------------------------
    101 // A faster set implementation that does not need any initialization, and reading the set items
    102 // is order the number of items, and not the size of the universe.
    103 // This implementation is based on the paper by Briggs and Torczon, "An Efficient Representation
    104 // for Sparse Sets"
    105 //
    106 // This implementation assumes that the unique glyphs added are appended to a vector that may
    107 // already have unique glyph from a previous computation. This allows the packing of multiple
    108 // UniqueID sequences in a single vector.
    109 SkSpan<const SkGlyphID> SkGlyphIDSet::uniquifyGlyphIDs(
    110         uint32_t universeSize,
    111         SkSpan<const SkGlyphID> glyphIDs,
    112         SkGlyphID* uniqueGlyphIDs,
    113         uint16_t* denseIndices) {
    114     static constexpr SkGlyphID  kUndefGlyph{0};
    115 
    116     if (universeSize > fUniverseToUniqueSize) {
    117         fUniverseToUnique.reset(universeSize);
    118         fUniverseToUniqueSize = universeSize;
    119         // If the following bzero becomes a performance problem, the memory can be marked as
    120         // initialized for valgrind and msan.
    121         // valgrind = VALGRIND_MAKE_MEM_DEFINED(fUniverseToUnique, universeSize * sizeof(SkGlyphID))
    122         // msan = sk_msan_mark_initialized(fUniverseToUnique, universeSize * sizeof(SkGlyphID))
    123         sk_bzero(fUniverseToUnique, universeSize * sizeof(SkGlyphID));
    124     }
    125 
    126     // No need to clear fUniverseToUnique here... the set insertion algorithm is designed to work
    127     // correctly even when the fUniverseToUnique buffer is uninitialized!
    128 
    129     size_t uniqueSize = 0;
    130     size_t denseIndicesCursor = 0;
    131     for (auto glyphID : glyphIDs) {
    132 
    133         // If the glyphID is not in range then it is the undefined glyph.
    134         if (glyphID >= universeSize) {
    135             glyphID = kUndefGlyph;
    136         }
    137 
    138         // The index into the unique ID vector.
    139         auto uniqueIndex = fUniverseToUnique[glyphID];
    140 
    141         if (uniqueIndex >= uniqueSize || uniqueGlyphIDs[uniqueIndex] != glyphID) {
    142             uniqueIndex = SkTo<uint16_t>(uniqueSize);
    143             uniqueGlyphIDs[uniqueSize] = glyphID;
    144             fUniverseToUnique[glyphID] = uniqueIndex;
    145             uniqueSize += 1;
    146         }
    147 
    148         denseIndices[denseIndicesCursor++] = uniqueIndex;
    149     }
    150 
    151     // If we're hanging onto these arrays for a long time, we don't want their size to drift
    152     // endlessly upwards. It's unusual to see a typeface with more than 4096 possible glyphs.
    153     if (fUniverseToUniqueSize > 4096) {
    154         fUniverseToUnique.reset(4096);
    155         sk_bzero(fUniverseToUnique, 4096 * sizeof(SkGlyphID));
    156         fUniverseToUniqueSize = 4096;
    157     }
    158 
    159     return SkSpan<const SkGlyphID>(uniqueGlyphIDs, uniqueSize);
    160 }
    161 
    162 // -- SkGlyphRunBuilder ----------------------------------------------------------------------------
    163 void SkGlyphRunBuilder::drawTextUTF8(const SkPaint& paint, const SkFont& font, const void* bytes,
    164                                      size_t byteLength, SkPoint origin) {
    165     auto glyphIDs = textToGlyphIDs(font, bytes, byteLength, kUTF8_SkTextEncoding);
    166     if (!glyphIDs.empty()) {
    167         this->initialize(glyphIDs.size());
    168         this->simplifyDrawText(font, glyphIDs, origin, fPositions);
    169     }
    170 
    171     this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
    172 }
    173 
    174 void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin,
    175                                      SkBaseDevice* device) {
    176     // Figure out all the storage needed to pre-size everything below.
    177     size_t totalGlyphs = 0;
    178     for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
    179         totalGlyphs += it.glyphCount();
    180     }
    181 
    182     // Pre-size all the buffers so they don't move during processing.
    183     this->initialize(totalGlyphs);
    184 
    185     SkPoint* positions = fPositions;
    186 
    187     for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
    188         // applyFontToPaint() always overwrites the exact same attributes,
    189         // so it is safe to not re-seed the paint for this reason.
    190         size_t runSize = it.glyphCount();
    191 
    192         auto text = SkSpan<const char>(it.text(), it.textSize());
    193         auto clusters = SkSpan<const uint32_t>(it.clusters(), runSize);
    194         const SkPoint& offset = it.offset();
    195         auto glyphIDs = SkSpan<const SkGlyphID>{it.glyphs(), runSize};
    196 
    197         switch (it.positioning()) {
    198             case SkTextBlobRunIterator::kDefault_Positioning: {
    199                 this->simplifyDrawText(
    200                         it.font(), glyphIDs, offset, positions, text, clusters);
    201             }
    202                 break;
    203             case SkTextBlobRunIterator::kHorizontal_Positioning: {
    204                 auto constY = offset.y();
    205                 this->simplifyDrawPosTextH(
    206                         it.font(), glyphIDs, it.pos(), constY, positions, text, clusters);
    207             }
    208                 break;
    209             case SkTextBlobRunIterator::kFull_Positioning:
    210                 this->simplifyDrawPosText(
    211                         it.font(), glyphIDs, (const SkPoint*)it.pos(), text, clusters);
    212                 break;
    213             case SkTextBlobRunIterator::kRSXform_Positioning: {
    214                 if (!this->empty()) {
    215                     this->makeGlyphRunList(paint, &blob, origin);
    216                     device->drawGlyphRunList(this->useGlyphRunList());
    217                 }
    218 
    219                 device->drawGlyphRunRSXform(it.font(), it.glyphs(), (const SkRSXform*)it.pos(),
    220                                             runSize, origin, paint);
    221 
    222                 // re-init in case we keep looping and need the builder again
    223                 this->initialize(totalGlyphs);
    224             } break;
    225         }
    226 
    227         positions += runSize;
    228     }
    229 
    230     if (!this->empty()) {
    231         this->makeGlyphRunList(paint, &blob, origin);
    232         device->drawGlyphRunList(this->useGlyphRunList());
    233     }
    234 }
    235 
    236 void SkGlyphRunBuilder::drawGlyphsWithPositions(const SkPaint& paint, const SkFont& font,
    237                                             SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos) {
    238     if (!glyphIDs.empty()) {
    239         this->initialize(glyphIDs.size());
    240         this->simplifyDrawPosText(font, glyphIDs, pos);
    241         this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
    242     }
    243 }
    244 
    245 const SkGlyphRunList& SkGlyphRunBuilder::useGlyphRunList() {
    246     return fGlyphRunList;
    247 }
    248 
    249 void SkGlyphRunBuilder::initialize(size_t totalRunSize) {
    250 
    251     if (totalRunSize > fMaxTotalRunSize) {
    252         fMaxTotalRunSize = totalRunSize;
    253         fPositions.reset(fMaxTotalRunSize);
    254     }
    255 
    256     fGlyphRunListStorage.clear();
    257 }
    258 
    259 SkSpan<const SkGlyphID> SkGlyphRunBuilder::textToGlyphIDs(
    260         const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding encoding) {
    261     if (encoding != kGlyphID_SkTextEncoding) {
    262         int count = font.countText(bytes, byteLength, encoding);
    263         if (count > 0) {
    264             fScratchGlyphIDs.resize(count);
    265             font.textToGlyphs(bytes, byteLength, encoding, fScratchGlyphIDs.data(), count);
    266             return SkSpan<const SkGlyphID>{fScratchGlyphIDs};
    267         } else {
    268             return SkSpan<const SkGlyphID>();
    269         }
    270     } else {
    271         return SkSpan<const SkGlyphID>((const SkGlyphID*)bytes, byteLength / 2);
    272     }
    273 }
    274 
    275 void SkGlyphRunBuilder::makeGlyphRun(
    276         const SkFont& font,
    277         SkSpan<const SkGlyphID> glyphIDs,
    278         SkSpan<const SkPoint> positions,
    279         SkSpan<const char> text,
    280         SkSpan<const uint32_t> clusters) {
    281 
    282     // Ignore empty runs.
    283     if (!glyphIDs.empty()) {
    284         fGlyphRunListStorage.emplace_back(
    285                 font,
    286                 positions,
    287                 glyphIDs,
    288                 text,
    289                 clusters);
    290     }
    291 }
    292 
    293 void SkGlyphRunBuilder::makeGlyphRunList(
    294         const SkPaint& paint, const SkTextBlob* blob, SkPoint origin) {
    295 
    296     fGlyphRunList.~SkGlyphRunList();
    297     new (&fGlyphRunList) SkGlyphRunList{
    298         paint, blob, origin, SkSpan<const SkGlyphRun>{fGlyphRunListStorage}};
    299 }
    300 
    301 void SkGlyphRunBuilder::simplifyDrawText(
    302         const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
    303         SkPoint origin, SkPoint* positions,
    304         SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
    305     SkASSERT(!glyphIDs.empty());
    306 
    307     auto runSize = glyphIDs.size();
    308 
    309     if (!glyphIDs.empty()) {
    310         fScratchAdvances.resize(runSize);
    311         {
    312             auto cache = SkStrikeCache::FindOrCreateStrikeWithNoDeviceExclusive(font);
    313             cache->getAdvances(glyphIDs, fScratchAdvances.data());
    314         }
    315 
    316         SkPoint endOfLastGlyph = origin;
    317 
    318         for (size_t i = 0; i < runSize; i++) {
    319             positions[i] = endOfLastGlyph;
    320             endOfLastGlyph += fScratchAdvances[i];
    321         }
    322 
    323         this->makeGlyphRun(
    324                 font,
    325                 glyphIDs,
    326                 SkSpan<const SkPoint>{positions, runSize},
    327                 text,
    328                 clusters);
    329     }
    330 }
    331 
    332 void SkGlyphRunBuilder::simplifyDrawPosTextH(
    333         const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
    334         const SkScalar* xpos, SkScalar constY, SkPoint* positions,
    335         SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
    336 
    337     auto posCursor = positions;
    338     for (auto x : SkSpan<const SkScalar>{xpos, glyphIDs.size()}) {
    339         *posCursor++ = SkPoint::Make(x, constY);
    340     }
    341 
    342     simplifyDrawPosText(font, glyphIDs, positions, text, clusters);
    343 }
    344 
    345 void SkGlyphRunBuilder::simplifyDrawPosText(
    346         const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
    347         const SkPoint* pos,
    348         SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
    349     auto runSize = glyphIDs.size();
    350 
    351     this->makeGlyphRun(
    352             font,
    353             glyphIDs,
    354             SkSpan<const SkPoint>{pos, runSize},
    355             text,
    356             clusters);
    357 }
    358