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 #ifndef SkGlyphRun_DEFINED
9 #define SkGlyphRun_DEFINED
10
11 #include <functional>
12 #include <optional>
13 #include <vector>
14
15 #include "include/core/SkFont.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRSXform.h"
19 #include "include/core/SkSpan.h"
20 #include "include/core/SkTypes.h"
21 #include "include/private/base/SkTemplates.h"
22 #include "src/base/SkZip.h"
23 #include "src/core/SkGlyphBuffer.h"
24
25 class SkBaseDevice;
26 class SkCanvas;
27 class SkGlyph;
28 class SkTextBlob;
29 class SkTextBlobRunIterator;
30
31 namespace sktext {
32 class GlyphRunBuilder;
33 class GlyphRunList;
34
35 class SkSubRunBuffers {
36 public:
37 class ScopedBuffers {
38 public:
39 ScopedBuffers(SkSubRunBuffers* painter, size_t size);
40 ~ScopedBuffers();
buffers()41 std::tuple<SkDrawableGlyphBuffer*, SkSourceGlyphBuffer*> buffers() {
42 return {&fBuffers->fAccepted, &fBuffers->fRejected};
43 }
44
45 private:
46 SkSubRunBuffers* const fBuffers;
47 };
48 static ScopedBuffers SK_WARN_UNUSED_RESULT EnsureBuffers(const GlyphRunList& glyphRunList);
49
50 private:
51 SkDrawableGlyphBuffer fAccepted;
52 SkSourceGlyphBuffer fRejected;
53 };
54
55 class GlyphRun {
56 public:
57 GlyphRun(const SkFont& font,
58 SkSpan<const SkPoint> positions,
59 SkSpan<const SkGlyphID> glyphIDs,
60 SkSpan<const char> text,
61 SkSpan<const uint32_t> clusters,
62 SkSpan<const SkVector> scaledRotations);
63
64 GlyphRun(const GlyphRun& glyphRun, const SkFont& font);
65
runSize()66 size_t runSize() const { return fSource.size(); }
positions()67 SkSpan<const SkPoint> positions() const { return fSource.get<1>(); }
glyphsIDs()68 SkSpan<const SkGlyphID> glyphsIDs() const { return fSource.get<0>(); }
source()69 SkZip<const SkGlyphID, const SkPoint> source() const { return fSource; }
font()70 const SkFont& font() const { return fFont; }
clusters()71 SkSpan<const uint32_t> clusters() const { return fClusters; }
text()72 SkSpan<const char> text() const { return fText; }
scaledRotations()73 SkSpan<const SkVector> scaledRotations() const { return fScaledRotations; }
74
75 private:
76 // GlyphIDs and positions.
77 const SkZip<const SkGlyphID, const SkPoint> fSource;
78 // Original text from SkTextBlob if present. Will be empty of not present.
79 const SkSpan<const char> fText;
80 // Original clusters from SkTextBlob if present. Will be empty if not present.
81 const SkSpan<const uint32_t> fClusters;
82 // Possible RSXForm information
83 const SkSpan<const SkVector> fScaledRotations;
84 // Font for this run modified to have glyph encoding and left alignment.
85 SkFont fFont;
86 };
87
88 class GlyphRunList {
89 SkSpan<const GlyphRun> fGlyphRuns;
90
91 public:
92 // Blob maybe null.
93 GlyphRunList(const SkTextBlob* blob,
94 SkRect bounds,
95 SkPoint origin,
96 SkSpan<const GlyphRun> glyphRunList,
97 GlyphRunBuilder* builder);
98
99 GlyphRunList(const GlyphRun& glyphRun,
100 const SkRect& bounds,
101 SkPoint origin,
102 GlyphRunBuilder* builder);
103 uint64_t uniqueID() const;
104 bool anyRunsLCD() const;
105 void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const;
106
canCache()107 bool canCache() const { return fOriginalTextBlob != nullptr; }
runCount()108 size_t runCount() const { return fGlyphRuns.size(); }
totalGlyphCount()109 size_t totalGlyphCount() const {
110 size_t glyphCount = 0;
111 for (const GlyphRun& run : *this) {
112 glyphCount += run.runSize();
113 }
114 return glyphCount;
115 }
maxGlyphRunSize()116 size_t maxGlyphRunSize() const {
117 size_t size = 0;
118 for (const GlyphRun& run : *this) {
119 size = std::max(run.runSize(), size);
120 }
121 return size;
122 }
123
hasRSXForm()124 bool hasRSXForm() const {
125 for (const GlyphRun& run : *this) {
126 if (!run.scaledRotations().empty()) { return true; }
127 }
128 return false;
129 }
130
131 sk_sp<SkTextBlob> makeBlob() const;
132
origin()133 SkPoint origin() const { return fOrigin; }
sourceBounds()134 SkRect sourceBounds() const { return fSourceBounds; }
sourceBoundsWithOrigin()135 SkRect sourceBoundsWithOrigin() const { return fSourceBounds.makeOffset(fOrigin); }
blob()136 const SkTextBlob* blob() const { return fOriginalTextBlob; }
builder()137 GlyphRunBuilder* builder() const { return fBuilder; }
138 SkSubRunBuffers* buffers() const;
139
140 auto begin() -> decltype(fGlyphRuns.begin()) { return fGlyphRuns.begin(); }
141 auto end() -> decltype(fGlyphRuns.end()) { return fGlyphRuns.end(); }
142 auto begin() const -> decltype(std::cbegin(fGlyphRuns)) { return std::cbegin(fGlyphRuns); }
143 auto end() const -> decltype(std::cend(fGlyphRuns)) { return std::cend(fGlyphRuns); }
144 auto size() const -> decltype(fGlyphRuns.size()) { return fGlyphRuns.size(); }
145 auto empty() const -> decltype(fGlyphRuns.empty()) { return fGlyphRuns.empty(); }
146 auto operator [] (size_t i) const -> decltype(fGlyphRuns[i]) { return fGlyphRuns[i]; }
147
148 private:
149 // The text blob is needed to hook up the call back that the SkTextBlob destructor calls. It
150 // should be used for nothing else.
151 const SkTextBlob* fOriginalTextBlob{nullptr};
152 const SkRect fSourceBounds{SkRect::MakeEmpty()};
153 const SkPoint fOrigin = {0, 0};
154 GlyphRunBuilder* const fBuilder;
155 };
156
157 class GlyphRunBuilder {
158 public:
159 GlyphRunList makeGlyphRunList(const GlyphRun& run, const SkPaint& paint, SkPoint origin);
160 const GlyphRunList& textToGlyphRunList(const SkFont& font,
161 const SkPaint& paint,
162 const void* bytes,
163 size_t byteLength,
164 SkPoint origin,
165 SkTextEncoding encoding = SkTextEncoding::kUTF8);
166 const GlyphRunList& blobToGlyphRunList(const SkTextBlob& blob, SkPoint origin);
167 std::tuple<SkSpan<const SkPoint>, SkSpan<const SkVector>>
168 convertRSXForm(SkSpan<const SkRSXform> xforms);
169
empty()170 bool empty() const { return fGlyphRunListStorage.empty(); }
buffers()171 SkSubRunBuffers* buffers() { return &fSubRunBuffers; }
172
173 private:
174 void initialize(const SkTextBlob& blob);
175 void prepareBuffers(int positionCount, int RSXFormCount);
176
177 SkSpan<const SkGlyphID> textToGlyphIDs(
178 const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding);
179
180 void makeGlyphRun(
181 const SkFont& font,
182 SkSpan<const SkGlyphID> glyphIDs,
183 SkSpan<const SkPoint> positions,
184 SkSpan<const char> text,
185 SkSpan<const uint32_t> clusters,
186 SkSpan<const SkVector> scaledRotations);
187
188 const GlyphRunList& setGlyphRunList(
189 const SkTextBlob* blob, const SkRect& bounds, SkPoint origin);
190
191 int fMaxTotalRunSize{0};
192 skia_private::AutoTMalloc<SkPoint> fPositions;
193 int fMaxScaledRotations{0};
194 skia_private::AutoTMalloc<SkVector> fScaledRotations;
195
196 std::vector<GlyphRun> fGlyphRunListStorage;
197 std::optional<GlyphRunList> fGlyphRunList; // Defaults to no value;
198
199 // Used as a temporary for preparing using utfN text. This implies that only one run of
200 // glyph ids will ever be needed because blobs are already glyph based.
201 std::vector<SkGlyphID> fScratchGlyphIDs;
202
203 SkSubRunBuffers fSubRunBuffers;
204 };
buffers()205 inline SkSubRunBuffers* GlyphRunList::buffers() const { return fBuilder->buffers(); }
206 } // namespace sktext
207
208 #endif // SkGlyphRun_DEFINED
209