• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
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 #include "include/core/SkFont.h"
9 #include "include/core/SkFontMetrics.h"
10 #include "include/core/SkFontMgr.h"
11 #include "include/core/SkString.h"
12 #include "include/core/SkTypeface.h"
13 #include "include/private/SkTFitsIn.h"
14 #include "modules/skshaper/include/SkShaper.h"
15 #include "src/core/SkMakeUnique.h"
16 #include "src/core/SkTextBlobPriv.h"
17 #include "src/utils/SkUTF.h"
18 
19 #include <limits.h>
20 #include <string.h>
21 #include <locale>
22 #include <string>
23 #include <utility>
24 
Make(sk_sp<SkFontMgr> fontmgr)25 std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fontmgr) {
26 #ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
27     std::unique_ptr<SkShaper> shaper = SkShaper::MakeShaperDrivenWrapper(std::move(fontmgr));
28     if (shaper) {
29         return shaper;
30     }
31 #endif
32     return SkShaper::MakePrimitive();
33 }
34 
SkShaper()35 SkShaper::SkShaper() {}
~SkShaper()36 SkShaper::~SkShaper() {}
37 
38 /** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
utf8_next(const char ** ptr,const char * end)39 static inline SkUnichar utf8_next(const char** ptr, const char* end) {
40     SkUnichar val = SkUTF::NextUTF8(ptr, end);
41     return val < 0 ? 0xFFFD : val;
42 }
43 
44 class FontMgrRunIterator final : public SkShaper::FontRunIterator {
45 public:
FontMgrRunIterator(const char * utf8,size_t utf8Bytes,const SkFont & font,sk_sp<SkFontMgr> fallbackMgr)46     FontMgrRunIterator(const char* utf8, size_t utf8Bytes, const SkFont& font,
47                        sk_sp<SkFontMgr> fallbackMgr)
48         : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
49         , fFallbackMgr(std::move(fallbackMgr))
50         , fFont(font)
51         , fFallbackFont(fFont)
52         , fCurrentFont(nullptr)
53     {
54         fFont.setTypeface(font.refTypefaceOrDefault());
55         fFallbackFont.setTypeface(nullptr);
56     }
consume()57     void consume() override {
58         SkASSERT(fCurrent < fEnd);
59         SkUnichar u = utf8_next(&fCurrent, fEnd);
60         // If the starting typeface can handle this character, use it.
61         if (fFont.unicharToGlyph(u)) {
62             fCurrentFont = &fFont;
63         // If the current fallback can handle this character, use it.
64         } else if (fFallbackFont.getTypeface() && fFallbackFont.unicharToGlyph(u)) {
65             fCurrentFont = &fFallbackFont;
66         // If not, try to find a fallback typeface
67         } else {
68             sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
69                 nullptr, fFont.getTypeface()->fontStyle(), nullptr, 0, u));
70             if (candidate) {
71                 fFallbackFont.setTypeface(std::move(candidate));
72                 fCurrentFont = &fFallbackFont;
73             } else {
74                 fCurrentFont = &fFont;
75             }
76         }
77 
78         while (fCurrent < fEnd) {
79             const char* prev = fCurrent;
80             u = utf8_next(&fCurrent, fEnd);
81 
82             // End run if not using initial typeface and initial typeface has this character.
83             if (fCurrentFont->getTypeface() != fFont.getTypeface() && fFont.unicharToGlyph(u)) {
84                 fCurrent = prev;
85                 return;
86             }
87 
88             // End run if current typeface does not have this character and some other font does.
89             if (!fCurrentFont->unicharToGlyph(u)) {
90                 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
91                     nullptr, fFont.getTypeface()->fontStyle(), nullptr, 0, u));
92                 if (candidate) {
93                     fCurrent = prev;
94                     return;
95                 }
96             }
97         }
98     }
endOfCurrentRun() const99     size_t endOfCurrentRun() const override {
100         return fCurrent - fBegin;
101     }
atEnd() const102     bool atEnd() const override {
103         return fCurrent == fEnd;
104     }
105 
currentFont() const106     const SkFont& currentFont() const override {
107         return *fCurrentFont;
108     }
109 
110 private:
111     char const * fCurrent;
112     char const * const fBegin;
113     char const * const fEnd;
114     sk_sp<SkFontMgr> fFallbackMgr;
115     SkFont fFont;
116     SkFont fFallbackFont;
117     SkFont* fCurrentFont;
118 };
119 
120 std::unique_ptr<SkShaper::FontRunIterator>
MakeFontMgrRunIterator(const char * utf8,size_t utf8Bytes,const SkFont & font,sk_sp<SkFontMgr> fallback)121 SkShaper::MakeFontMgrRunIterator(const char* utf8, size_t utf8Bytes,
122                                  const SkFont& font, sk_sp<SkFontMgr> fallback)
123 {
124     return skstd::make_unique<FontMgrRunIterator>(utf8, utf8Bytes, font, std::move(fallback));
125 }
126 
127 std::unique_ptr<SkShaper::LanguageRunIterator>
MakeStdLanguageRunIterator(const char * utf8,size_t utf8Bytes)128 SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) {
129     return skstd::make_unique<TrivialLanguageRunIterator>(std::locale().name().c_str(), utf8Bytes);
130 }
131 
beginLine()132 void SkTextBlobBuilderRunHandler::beginLine() {
133     fCurrentPosition = fOffset;
134     fMaxRunAscent = 0;
135     fMaxRunDescent = 0;
136     fMaxRunLeading = 0;
137 }
runInfo(const RunInfo & info)138 void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) {
139     SkFontMetrics metrics;
140     info.fFont.getMetrics(&metrics);
141     fMaxRunAscent = SkTMin(fMaxRunAscent, metrics.fAscent);
142     fMaxRunDescent = SkTMax(fMaxRunDescent, metrics.fDescent);
143     fMaxRunLeading = SkTMax(fMaxRunLeading, metrics.fLeading);
144 }
145 
commitRunInfo()146 void SkTextBlobBuilderRunHandler::commitRunInfo() {
147     fCurrentPosition.fY -= fMaxRunAscent;
148 }
149 
runBuffer(const RunInfo & info)150 SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::runBuffer(const RunInfo& info) {
151     int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX;
152     int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX;
153 
154     const auto& runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(&fBuilder, info.fFont, glyphCount,
155                                                                    utf8RangeSize, SkString());
156     if (runBuffer.utf8text && fUtf8Text) {
157         memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
158     }
159     fClusters = runBuffer.clusters;
160     fGlyphCount = glyphCount;
161     fClusterOffset = info.utf8Range.begin();
162 
163     return { runBuffer.glyphs,
164              runBuffer.points(),
165              nullptr,
166              runBuffer.clusters,
167              fCurrentPosition };
168 }
169 
commitRunBuffer(const RunInfo & info)170 void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) {
171     SkASSERT(0 <= fClusterOffset);
172     for (int i = 0; i < fGlyphCount; ++i) {
173         SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
174         fClusters[i] -= fClusterOffset;
175     }
176     fCurrentPosition += info.fAdvance;
177 }
commitLine()178 void SkTextBlobBuilderRunHandler::commitLine() {
179     fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
180 }
181 
makeBlob()182 sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
183     return fBuilder.make();
184 }
185