123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- /*
- * Copyright 2018 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/core/SkGlyphRun.h"
- #include "include/core/SkFont.h"
- #include "include/core/SkPaint.h"
- #include "include/core/SkTextBlob.h"
- #include "include/private/SkTo.h"
- #include "src/core/SkDevice.h"
- #include "src/core/SkFontPriv.h"
- #include "src/core/SkStrike.h"
- #include "src/core/SkStrikeCache.h"
- #include "src/core/SkStrikeSpec.h"
- #include "src/core/SkTextBlobPriv.h"
- #include "src/core/SkUtils.h"
- // -- SkGlyphRun -----------------------------------------------------------------------------------
- SkGlyphRun::SkGlyphRun(const SkFont& font,
- SkSpan<const SkPoint> positions,
- SkSpan<const SkGlyphID> glyphIDs,
- SkSpan<const char> text,
- SkSpan<const uint32_t> clusters)
- : fPositions{positions}
- , fGlyphIDs{glyphIDs}
- , fText{text}
- , fClusters{clusters}
- , fFont{font} {}
- SkGlyphRun::SkGlyphRun(const SkGlyphRun& that, const SkFont& font)
- : fPositions{that.fPositions}
- , fGlyphIDs{that.fGlyphIDs}
- , fText{that.fText}
- , fClusters{that.fClusters}
- , fFont{font} {}
- void SkGlyphRun::filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions) {
- memcpy(glyphIDs, fGlyphIDs.data(), fGlyphIDs.size_bytes());
- memcpy(positions, fPositions.data(), fPositions.size_bytes());
- }
- // -- SkGlyphRunList -------------------------------------------------------------------------------
- SkGlyphRunList::SkGlyphRunList() = default;
- SkGlyphRunList::SkGlyphRunList(
- const SkPaint& paint,
- const SkTextBlob* blob,
- SkPoint origin,
- SkSpan<const SkGlyphRun> glyphRunList)
- : fOriginalPaint{&paint}
- , fOriginalTextBlob{blob}
- , fOrigin{origin}
- , fGlyphRuns{glyphRunList} { }
- SkGlyphRunList::SkGlyphRunList(const SkGlyphRun& glyphRun, const SkPaint& paint)
- : fOriginalPaint{&paint}
- , fOriginalTextBlob{nullptr}
- , fOrigin{SkPoint::Make(0, 0)}
- , fGlyphRuns{SkSpan<const SkGlyphRun>{&glyphRun, 1}} {}
- uint64_t SkGlyphRunList::uniqueID() const {
- return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID()
- : SK_InvalidUniqueID;
- }
- bool SkGlyphRunList::anyRunsLCD() const {
- for (const auto& r : fGlyphRuns) {
- if (r.font().getEdging() == SkFont::Edging::kSubpixelAntiAlias) {
- return true;
- }
- }
- return false;
- }
- bool SkGlyphRunList::anyRunsSubpixelPositioned() const {
- for (const auto& r : fGlyphRuns) {
- if (r.font().isSubpixel()) {
- return true;
- }
- }
- return false;
- }
- bool SkGlyphRunList::allFontsFinite() const {
- for (const auto& r : fGlyphRuns) {
- if (!SkFontPriv::IsFinite(r.font())) {
- return false;
- }
- }
- return true;
- }
- void SkGlyphRunList::temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const {
- SkASSERT(fOriginalTextBlob != nullptr);
- fOriginalTextBlob->notifyAddedToCache(cacheID);
- }
- // -- SkGlyphIDSet ---------------------------------------------------------------------------------
- // A faster set implementation that does not need any initialization, and reading the set items
- // is order the number of items, and not the size of the universe.
- // This implementation is based on the paper by Briggs and Torczon, "An Efficient Representation
- // for Sparse Sets"
- //
- // This implementation assumes that the unique glyphs added are appended to a vector that may
- // already have unique glyph from a previous computation. This allows the packing of multiple
- // UniqueID sequences in a single vector.
- SkSpan<const SkGlyphID> SkGlyphIDSet::uniquifyGlyphIDs(
- uint32_t universeSize,
- SkSpan<const SkGlyphID> glyphIDs,
- SkGlyphID* uniqueGlyphIDs,
- uint16_t* denseIndices) {
- static constexpr SkGlyphID kUndefGlyph{0};
- if (universeSize > fUniverseToUniqueSize) {
- fUniverseToUnique.reset(universeSize);
- fUniverseToUniqueSize = universeSize;
- // If the following bzero becomes a performance problem, the memory can be marked as
- // initialized for valgrind and msan.
- // valgrind = VALGRIND_MAKE_MEM_DEFINED(fUniverseToUnique, universeSize * sizeof(SkGlyphID))
- // msan = sk_msan_mark_initialized(fUniverseToUnique, universeSize * sizeof(SkGlyphID))
- sk_bzero(fUniverseToUnique, universeSize * sizeof(SkGlyphID));
- }
- // No need to clear fUniverseToUnique here... the set insertion algorithm is designed to work
- // correctly even when the fUniverseToUnique buffer is uninitialized!
- size_t uniqueSize = 0;
- size_t denseIndicesCursor = 0;
- for (auto glyphID : glyphIDs) {
- // If the glyphID is not in range then it is the undefined glyph.
- if (glyphID >= universeSize) {
- glyphID = kUndefGlyph;
- }
- // The index into the unique ID vector.
- auto uniqueIndex = fUniverseToUnique[glyphID];
- if (uniqueIndex >= uniqueSize || uniqueGlyphIDs[uniqueIndex] != glyphID) {
- uniqueIndex = SkTo<uint16_t>(uniqueSize);
- uniqueGlyphIDs[uniqueSize] = glyphID;
- fUniverseToUnique[glyphID] = uniqueIndex;
- uniqueSize += 1;
- }
- denseIndices[denseIndicesCursor++] = uniqueIndex;
- }
- // If we're hanging onto these arrays for a long time, we don't want their size to drift
- // endlessly upwards. It's unusual to see a typeface with more than 4096 possible glyphs.
- if (fUniverseToUniqueSize > 4096) {
- fUniverseToUnique.reset(4096);
- sk_bzero(fUniverseToUnique, 4096 * sizeof(SkGlyphID));
- fUniverseToUniqueSize = 4096;
- }
- return SkSpan<const SkGlyphID>(uniqueGlyphIDs, uniqueSize);
- }
- // -- SkGlyphRunBuilder ----------------------------------------------------------------------------
- void SkGlyphRunBuilder::drawTextUTF8(const SkPaint& paint, const SkFont& font, const void* bytes,
- size_t byteLength, SkPoint origin) {
- auto glyphIDs = textToGlyphIDs(font, bytes, byteLength, SkTextEncoding::kUTF8);
- if (!glyphIDs.empty()) {
- this->initialize(glyphIDs.size());
- this->simplifyDrawText(font, glyphIDs, origin, fPositions);
- }
- this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
- }
- void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin,
- SkBaseDevice* device) {
- // Figure out all the storage needed to pre-size everything below.
- size_t totalGlyphs = 0;
- for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
- totalGlyphs += it.glyphCount();
- }
- // Pre-size all the buffers so they don't move during processing.
- this->initialize(totalGlyphs);
- SkPoint* positions = fPositions;
- for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
- if (it.positioning() != SkTextBlobRunIterator::kRSXform_Positioning) {
- simplifyTextBlobIgnoringRSXForm(paint, it, positions);
- } else {
- // Handle kRSXform_Positioning
- if (!this->empty()) {
- this->makeGlyphRunList(paint, &blob, origin);
- device->drawGlyphRunList(this->useGlyphRunList());
- }
- device->drawGlyphRunRSXform(it.font(), it.glyphs(), (const SkRSXform*)it.pos(),
- it.glyphCount(), origin, paint);
- // re-init in case we keep looping and need the builder again
- this->initialize(totalGlyphs);
- }
- positions += it.glyphCount();
- }
- if (!this->empty()) {
- this->makeGlyphRunList(paint, &blob, origin);
- device->drawGlyphRunList(this->useGlyphRunList());
- }
- }
- void SkGlyphRunBuilder::textBlobToGlyphRunListIgnoringRSXForm(
- const SkPaint& paint, const SkTextBlob& blob, SkPoint origin) {
- // Figure out all the storage needed to pre-size everything below.
- size_t totalGlyphs = 0;
- for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
- totalGlyphs += it.glyphCount();
- }
- // Pre-size all the buffers so they don't move during processing.
- this->initialize(totalGlyphs);
- SkPoint* positions = fPositions;
- for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
- simplifyTextBlobIgnoringRSXForm(paint, it, positions);
- positions += it.glyphCount();
- }
- if (!this->empty()) {
- this->makeGlyphRunList(paint, &blob, origin);
- }
- }
- void SkGlyphRunBuilder::simplifyTextBlobIgnoringRSXForm(const SkPaint& paint,
- const SkTextBlobRunIterator& it,
- SkPoint* positions) {
- size_t runSize = it.glyphCount();
- auto text = SkSpan<const char>(it.text(), it.textSize());
- auto clusters = SkSpan<const uint32_t>(it.clusters(), runSize);
- const SkPoint& offset = it.offset();
- auto glyphIDs = SkSpan<const SkGlyphID>{it.glyphs(), runSize};
- switch (it.positioning()) {
- case SkTextBlobRunIterator::kDefault_Positioning: {
- this->simplifyDrawText(
- it.font(), glyphIDs, offset, positions, text, clusters);
- break;
- }
- case SkTextBlobRunIterator::kHorizontal_Positioning: {
- auto constY = offset.y();
- this->simplifyDrawPosTextH(
- it.font(), glyphIDs, it.pos(), constY, positions, text, clusters);
- break;
- }
- case SkTextBlobRunIterator::kFull_Positioning: {
- this->simplifyDrawPosText(
- it.font(), glyphIDs, (const SkPoint*) it.pos(), text, clusters);
- break;
- }
- case SkTextBlobRunIterator::kRSXform_Positioning: break;
- }
- }
- void SkGlyphRunBuilder::drawGlyphsWithPositions(const SkPaint& paint, const SkFont& font,
- SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos) {
- if (!glyphIDs.empty()) {
- this->initialize(glyphIDs.size());
- this->simplifyDrawPosText(font, glyphIDs, pos);
- this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
- }
- }
- const SkGlyphRunList& SkGlyphRunBuilder::useGlyphRunList() {
- return fGlyphRunList;
- }
- void SkGlyphRunBuilder::initialize(size_t totalRunSize) {
- if (totalRunSize > fMaxTotalRunSize) {
- fMaxTotalRunSize = totalRunSize;
- fPositions.reset(fMaxTotalRunSize);
- }
- fGlyphRunListStorage.clear();
- }
- SkSpan<const SkGlyphID> SkGlyphRunBuilder::textToGlyphIDs(
- const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding encoding) {
- if (encoding != SkTextEncoding::kGlyphID) {
- int count = font.countText(bytes, byteLength, encoding);
- if (count > 0) {
- fScratchGlyphIDs.resize(count);
- font.textToGlyphs(bytes, byteLength, encoding, fScratchGlyphIDs.data(), count);
- return SkMakeSpan(fScratchGlyphIDs);
- } else {
- return SkSpan<const SkGlyphID>();
- }
- } else {
- return SkSpan<const SkGlyphID>((const SkGlyphID*)bytes, byteLength / 2);
- }
- }
- void SkGlyphRunBuilder::makeGlyphRun(
- const SkFont& font,
- SkSpan<const SkGlyphID> glyphIDs,
- SkSpan<const SkPoint> positions,
- SkSpan<const char> text,
- SkSpan<const uint32_t> clusters) {
- // Ignore empty runs.
- if (!glyphIDs.empty()) {
- fGlyphRunListStorage.emplace_back(
- font,
- positions,
- glyphIDs,
- text,
- clusters);
- }
- }
- void SkGlyphRunBuilder::makeGlyphRunList(
- const SkPaint& paint, const SkTextBlob* blob, SkPoint origin) {
- fGlyphRunList.~SkGlyphRunList();
- new (&fGlyphRunList) SkGlyphRunList{
- paint, blob, origin, SkMakeSpan(fGlyphRunListStorage)};
- }
- void SkGlyphRunBuilder::simplifyDrawText(
- const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
- SkPoint origin, SkPoint* positions,
- SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
- SkASSERT(!glyphIDs.empty());
- auto runSize = glyphIDs.size();
- if (!glyphIDs.empty()) {
- SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(font);
- SkBulkGlyphMetrics storage{strikeSpec};
- auto glyphs = storage.glyphs(glyphIDs);
- SkPoint endOfLastGlyph = origin;
- SkPoint* cursor = positions;
- for (auto glyph : glyphs) {
- *cursor++ = endOfLastGlyph;
- endOfLastGlyph += glyph->advanceVector();
- }
- this->makeGlyphRun(
- font,
- glyphIDs,
- SkSpan<const SkPoint>{positions, runSize},
- text,
- clusters);
- }
- }
- void SkGlyphRunBuilder::simplifyDrawPosTextH(
- const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
- const SkScalar* xpos, SkScalar constY, SkPoint* positions,
- SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
- auto posCursor = positions;
- for (auto x : SkSpan<const SkScalar>{xpos, glyphIDs.size()}) {
- *posCursor++ = SkPoint::Make(x, constY);
- }
- simplifyDrawPosText(font, glyphIDs, positions, text, clusters);
- }
- void SkGlyphRunBuilder::simplifyDrawPosText(
- const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
- const SkPoint* pos,
- SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
- auto runSize = glyphIDs.size();
- this->makeGlyphRun(
- font,
- glyphIDs,
- SkSpan<const SkPoint>{pos, runSize},
- text,
- clusters);
- }
|