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 <vector>
13 
14 #include "SkFont.h"
15 #include "SkPaint.h"
16 #include "SkPoint.h"
17 #include "SkSpan.h"
18 #include "SkTemplates.h"
19 #include "SkTypes.h"
20 
21 class SkBaseDevice;
22 class SkGlyph;
23 class SkTextBlob;
24 
25 class SkGlyphRun {
26 public:
27     SkGlyphRun() = default;
28     SkGlyphRun(const SkFont& font,
29                SkSpan<const SkPoint> positions,
30                SkSpan<const SkGlyphID> glyphIDs,
31                SkSpan<const char> text,
32                SkSpan<const uint32_t> clusters);
33     SkGlyphRun(const SkGlyphRun& glyphRun, const SkFont& font);
34 
35     void filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions);
36 
runSize()37     size_t runSize() const { return fGlyphIDs.size(); }
positions()38     SkSpan<const SkPoint> positions() const { return fPositions.toConst(); }
glyphsIDs()39     SkSpan<const SkGlyphID> glyphsIDs() const { return fGlyphIDs; }
font()40     const SkFont& font() const { return fFont; }
clusters()41     SkSpan<const uint32_t> clusters() const { return fClusters; }
text()42     SkSpan<const char> text() const { return fText; }
43 
44 private:
45     // Positions of each glyph.
46     const SkSpan<const SkPoint> fPositions;
47     // This is temporary while converting from the old per glyph code to the bulk code.
48     const SkSpan<const SkGlyphID> fGlyphIDs;
49     // Original text from SkTextBlob if present. Will be empty of not present.
50     const SkSpan<const char> fText;
51     // Original clusters from SkTextBlob if present. Will be empty if not present.
52     const SkSpan<const uint32_t>   fClusters;
53     // Paint for this run modified to have glyph encoding and left alignment.
54     SkFont fFont;
55 };
56 
57 class SkGlyphRunList {
58     const SkPaint* fOriginalPaint{nullptr};  // This should be deleted soon.
59     // The text blob is needed to hookup the call back that the SkTextBlob destructor calls. It
60     // should be used for nothing else
61     const SkTextBlob*  fOriginalTextBlob{nullptr};
62     SkPoint fOrigin = {0, 0};
63     SkSpan<const SkGlyphRun> fGlyphRuns;
64 
65 public:
66     SkGlyphRunList();
67     // Blob maybe null.
68     SkGlyphRunList(
69             const SkPaint& paint,
70             const SkTextBlob* blob,
71             SkPoint origin,
72             SkSpan<const SkGlyphRun> glyphRunList);
73 
74     SkGlyphRunList(const SkGlyphRun& glyphRun, const SkPaint& paint);
75 
76     uint64_t uniqueID() const;
77     bool anyRunsLCD() const;
78     bool anyRunsSubpixelPositioned() const;
79     void temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const;
80 
canCache()81     bool canCache() const { return fOriginalTextBlob != nullptr; }
runCount()82     size_t runCount() const { return fGlyphRuns.size(); }
totalGlyphCount()83     size_t totalGlyphCount() const {
84         size_t glyphCount = 0;
85         for(const auto& run : fGlyphRuns) {
86             glyphCount += run.runSize();
87         }
88         return glyphCount;
89     }
90     bool allFontsFinite() const;
91 
origin()92     SkPoint origin() const { return fOrigin; }
paint()93     const SkPaint& paint() const { return *fOriginalPaint; }
blob()94     const SkTextBlob* blob() const { return fOriginalTextBlob; }
95 
96     auto begin() -> decltype(fGlyphRuns.begin())               { return fGlyphRuns.begin();  }
97     auto end()   -> decltype(fGlyphRuns.end())                 { return fGlyphRuns.end();    }
98     auto begin() const -> decltype(fGlyphRuns.cbegin())        { return fGlyphRuns.cbegin(); }
99     auto end()   const -> decltype(fGlyphRuns.cend())          { return fGlyphRuns.cend();   }
100     auto size()  const -> decltype(fGlyphRuns.size())          { return fGlyphRuns.size();   }
101     auto empty() const -> decltype(fGlyphRuns.empty())         { return fGlyphRuns.empty();  }
102     auto operator [] (size_t i) const -> decltype(fGlyphRuns[i]) { return fGlyphRuns[i];     }
103 };
104 
105 class SkGlyphIDSet {
106 public:
107     SkSpan<const SkGlyphID> uniquifyGlyphIDs(
108             uint32_t universeSize, SkSpan<const SkGlyphID> glyphIDs,
109             SkGlyphID* uniqueGlyphIDs, uint16_t* denseindices);
110 private:
111     size_t fUniverseToUniqueSize{0};
112     SkAutoTMalloc<uint16_t> fUniverseToUnique;
113 };
114 
115 class SkGlyphRunBuilder {
116 public:
117     void drawTextUTF8(
118         const SkPaint& paint, const SkFont&, const void* bytes, size_t byteLength, SkPoint origin);
119     void drawGlyphsWithPositions(
120             const SkPaint&, const SkFont&, SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos);
121     void drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin, SkBaseDevice*);
122 
123     const SkGlyphRunList& useGlyphRunList();
124 
empty()125     bool empty() const { return fGlyphRunListStorage.size() == 0; }
126 
127     static void DispatchBlob(SkGlyphRunBuilder* builder, const SkPaint& paint,
128                              const SkTextBlob& blob, SkPoint origin, SkBaseDevice* device);
129 
130 private:
131     void initialize(size_t totalRunSize);
132     SkSpan<const SkGlyphID> textToGlyphIDs(
133             const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding);
134 
135     void makeGlyphRun(
136             const SkFont& font,
137             SkSpan<const SkGlyphID> glyphIDs,
138             SkSpan<const SkPoint> positions,
139             SkSpan<const char> text,
140             SkSpan<const uint32_t> clusters);
141 
142     void makeGlyphRunList(const SkPaint& paint, const SkTextBlob* blob, SkPoint origin);
143 
144     void simplifyDrawText(
145             const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
146             SkPoint origin, SkPoint* positions,
147             SkSpan<const char> text = SkSpan<const char>{},
148             SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
149     void simplifyDrawPosTextH(
150             const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
151             const SkScalar* xpos, SkScalar constY, SkPoint* positions,
152             SkSpan<const char> text = SkSpan<const char>{},
153             SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
154     void simplifyDrawPosText(
155             const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
156             const SkPoint* pos,
157             SkSpan<const char> text = SkSpan<const char>{},
158             SkSpan<const uint32_t> clusters = SkSpan<const uint32_t>{});
159 
160     size_t fMaxTotalRunSize{0};
161     SkAutoTMalloc<SkPoint> fPositions;
162 
163     std::vector<SkGlyphRun> fGlyphRunListStorage;
164     SkGlyphRunList fGlyphRunList;
165 
166     // Used as a temporary for preparing using utfN text. This implies that only one run of
167     // glyph ids will ever be needed because blobs are already glyph based.
168     std::vector<SkGlyphID> fScratchGlyphIDs;
169 
170     // Used as temporary storage for calculating positions for drawText.
171     std::vector<SkPoint> fScratchAdvances;
172 
173     // Used for collecting the set of unique glyphs.
174     SkGlyphIDSet fGlyphIDSet;
175     SkAutoTMalloc<SkGlyphID> fUniqueGlyphIDs;
176     SkAutoTMalloc<uint16_t> fUniqueGlyphIDIndices;
177 };
178 
179 #endif  // SkGlyphRun_DEFINED
180