aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkGlyphRun.cpp
diff options
context:
space:
mode:
authorGravatar Herb Derby <herb@google.com>2018-05-09 16:36:11 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-06-05 20:11:39 +0000
commit4225b3220ef4bf50f0d9403f812ea94d50c4ee59 (patch)
treea03d6ff5708e6c41fdc4b1edb8f5200d08d7dc63 /src/core/SkGlyphRun.cpp
parentf105dc71e4200db5a57a1e28b8bca2b3689debdb (diff)
Have draw(Text|PosText|PosTextH) use a single entry on the device
Handle the positioning of drawText at the canvas layer. Simplify the code by removing similar implementations. Change-Id: I8b711783435072f560e29fca1dd934fa2e345ed2 Reviewed-on: https://skia-review.googlesource.com/127131 Reviewed-by: Ben Wagner <bungeman@google.com> Commit-Queue: Herb Derby <herb@google.com>
Diffstat (limited to 'src/core/SkGlyphRun.cpp')
-rw-r--r--src/core/SkGlyphRun.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/src/core/SkGlyphRun.cpp b/src/core/SkGlyphRun.cpp
new file mode 100644
index 0000000000..a25b9afa8e
--- /dev/null
+++ b/src/core/SkGlyphRun.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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 "SkGlyphRun.h"
+
+#include <algorithm>
+#include <tuple>
+
+#include "SkDraw.h"
+#include "SkGlyphCache.h"
+#include "SkMakeUnique.h"
+#include "SkMSAN.h"
+#include "SkPaint.h"
+#include "SkPaintPriv.h"
+#include "SkStrikeCache.h"
+#include "SkUtils.h"
+
+namespace {
+
+// 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"
+class GlyphSet {
+public:
+ GlyphSet(uint32_t glyphUniverseSize)
+ : fUniverseSize{glyphUniverseSize}
+ , fIndexes{skstd::make_unique_default<uint16_t[]>(2 * glyphUniverseSize)}
+ , fUniqueGlyphIDs{&fIndexes[glyphUniverseSize]} {
+ SkASSERT(glyphUniverseSize <= (1 << 16));
+ sk_msan_mark_initialized(fIndexes.get(), &fIndexes[glyphUniverseSize], "works with uninited");
+ }
+
+ uint16_t add(SkGlyphID glyphID) {
+ if (glyphID >= fUniverseSize) {
+ glyphID = kUndefGlyph;
+ }
+ auto index = fIndexes[glyphID];
+ if (index < fUniqueCount && fUniqueGlyphIDs[index] == glyphID) {
+ return index;
+ }
+
+ fUniqueGlyphIDs[fUniqueCount] = glyphID;
+ fIndexes[glyphID] = fUniqueCount;
+ fUniqueCount += 1;
+ return fUniqueCount - 1;
+ }
+
+ std::tuple<uint16_t, std::unique_ptr<SkGlyphID[]>> uniqueGlyphIDs() const {
+ auto uniqueGlyphs = skstd::make_unique_default<SkGlyphID[]>(fUniqueCount);
+ memcpy(uniqueGlyphs.get(), fUniqueGlyphIDs, fUniqueCount * sizeof(SkGlyphID));
+ return std::make_tuple(fUniqueCount, std::move(uniqueGlyphs));
+ }
+
+private:
+ static constexpr SkGlyphID kUndefGlyph{0};
+ const uint32_t fUniverseSize;
+ uint16_t fUniqueCount{0};
+ std::unique_ptr<uint16_t[]> fIndexes;
+ SkGlyphID* fUniqueGlyphIDs;
+ };
+
+template<typename T>
+bool is_aligned(const void* ptr) {
+ uintptr_t bits = reinterpret_cast<uintptr_t>(ptr);
+ return (bits & (alignof(T) - 1)) == 0;
+}
+
+template<typename T>
+bool is_aligned_size(size_t size) {
+ return size % sizeof(T) == 0;
+}
+
+SkTypeface::Encoding convert_encoding(SkPaint::TextEncoding encoding) {
+ switch (encoding) {
+ case SkPaint::kUTF8_TextEncoding: return SkTypeface::kUTF8_Encoding;
+ case SkPaint::kUTF16_TextEncoding: return SkTypeface::kUTF16_Encoding;
+ case SkPaint::kUTF32_TextEncoding: return SkTypeface::kUTF32_Encoding;
+ default: return SkTypeface::kUTF32_Encoding;
+ }
+}
+
+using Core = std::tuple<size_t, std::unique_ptr<uint16_t[]>,
+ uint16_t, std::unique_ptr<SkGlyphID[]>>;
+
+Core make_from_glyphids(size_t glyphCount, const SkGlyphID* glyphs, SkGlyphID maxGlyphID) {
+ if (glyphCount == 0) { return Core(0, nullptr, 0, nullptr); }
+
+ GlyphSet glyphSet{maxGlyphID};
+
+ auto denseIndex = skstd::make_unique_default<uint16_t[]>(glyphCount);
+ for (size_t i = 0; i < glyphCount; i++) {
+ denseIndex[i] = glyphSet.add(glyphs[i]);
+ }
+
+ std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
+ uint16_t uniqueCount;
+ std::tie(uniqueCount, uniqueGlyphIDs) = glyphSet.uniqueGlyphIDs();
+
+ return Core(glyphCount, std::move(denseIndex), uniqueCount, std::move(uniqueGlyphIDs));
+}
+
+Core make_from_utfn(size_t byteLength, const void* utfN, const SkTypeface& typeface,
+ SkTypeface::Encoding encoding) {
+ auto count = SkUTFN_CountUnichars(encoding, utfN, byteLength);
+
+ if (count <= 0) {
+ return Core(0, nullptr, 0, nullptr);
+ }
+
+ auto glyphs = skstd::make_unique_default<SkGlyphID[]>(count);
+
+ // TODO: move to using cached version.
+ typeface.charsToGlyphs(utfN, encoding, glyphs.get(), count);
+
+ return make_from_glyphids(count, glyphs.get(), typeface.countGlyphs());
+}
+
+Core make_core(const SkPaint& paint, const void* bytes, size_t byteLength) {
+ auto encoding = paint.getTextEncoding();
+ auto typeface = SkPaintPriv::GetTypefaceOrDefault(paint);
+ if (encoding == SkPaint::kGlyphID_TextEncoding) {
+ return make_from_glyphids(
+ byteLength / 2, reinterpret_cast<const SkGlyphID*>(bytes), typeface->countGlyphs());
+ } else {
+ return make_from_utfn(byteLength, bytes, *typeface, convert_encoding(encoding));
+ }
+}
+
+} // namespace
+
+SkGlyphRun SkGlyphRun::MakeFromDrawText(
+ const SkPaint& paint, const void* bytes, size_t byteLength,
+ const SkPoint origin) {
+ size_t runSize;
+ std::unique_ptr<uint16_t[]> denseIndex;
+ uint16_t uniqueSize;
+ std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
+ std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
+
+ if (runSize == 0) { return SkGlyphRun{}; }
+
+ auto advances = skstd::make_unique_default<SkPoint[]>(uniqueSize);
+
+ {
+ auto cache = SkStrikeCache::FindOrCreateStrikeExclusive(paint);
+ cache->getAdvances(SkSpan<SkGlyphID>{uniqueGlyphIDs.get(), uniqueSize}, advances.get());
+ }
+
+ auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
+
+ SkPoint endOfLastGlyph = origin;
+
+ for (size_t i = 0; i < runSize; i++) {
+ positions[i] = endOfLastGlyph;
+ endOfLastGlyph += advances[denseIndex[i]];
+ }
+
+ if (paint.getTextAlign() != SkPaint::kLeft_Align) {
+ SkVector len = endOfLastGlyph - origin;
+ if (paint.getTextAlign() == SkPaint::kCenter_Align) {
+ len.scale(SK_ScalarHalf);
+ }
+ for (size_t i = 0; i < runSize; i++) {
+ positions[i] -= len;
+ }
+ }
+
+ return SkGlyphRun{
+ runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
+}
+
+SkGlyphRun SkGlyphRun::MakeFromDrawPosTextH(
+ const SkPaint& paint, const void* bytes, size_t byteLength,
+ const SkScalar xpos[], SkScalar constY) {
+ size_t runSize;
+ std::unique_ptr<uint16_t[]> denseIndex;
+ uint16_t uniqueSize;
+ std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
+ std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
+
+ if (runSize == 0) { return SkGlyphRun{}; }
+
+ auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
+
+ for (size_t i = 0; i < runSize; i++) {
+ positions[i] = SkPoint::Make(xpos[i], constY);
+ }
+
+ return SkGlyphRun{
+ runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
+}
+
+SkGlyphRun SkGlyphRun::MakeFromDrawPosText(
+ const SkPaint& paint, const void* bytes, size_t byteLength,
+ const SkPoint pos[]) {
+ size_t runSize;
+ std::unique_ptr<uint16_t[]> denseIndex;
+ uint16_t uniqueSize;
+ std::unique_ptr<SkGlyphID[]> uniqueGlyphIDs;
+ std::tie(runSize, denseIndex, uniqueSize, uniqueGlyphIDs) = make_core(paint, bytes, byteLength);
+
+ if (runSize == 0) { return SkGlyphRun{}; }
+
+ auto positions = skstd::make_unique_default<SkPoint[]>(runSize);
+
+ memcpy(positions.get(), pos, sizeof(SkPoint) * runSize);
+
+ return SkGlyphRun{
+ runSize, std::move(denseIndex), std::move(positions), uniqueSize, std::move(uniqueGlyphIDs)};
+}
+
+std::unique_ptr<SkGlyphID[]> SkGlyphRun::copyGlyphIDs() const {
+ auto glyphs = skstd::make_unique_default<SkGlyphID[]>(fRunSize);
+
+ for (size_t i = 0; i < fRunSize; i++) {
+ glyphs[i] = fUniqueGlyphs[fDenseIndex[i]];
+ }
+
+ return glyphs;
+}
+
+SkGlyphRun::SkGlyphRun(size_t runSize,
+ std::unique_ptr<uint16_t[]>&& denseIndex,
+ std::unique_ptr<SkPoint[]>&& positions,
+ uint16_t uniqueSize,
+ std::unique_ptr<SkGlyphID[]>&& uniqueGlyphIDs)
+ : fDenseIndex{std::move(denseIndex)}
+ , fPositions{std::move(positions)}
+ , fUniqueGlyphs{std::move(uniqueGlyphIDs)}
+ , fRunSize{runSize}
+ , fUniqueSize{uniqueSize} { }