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