blob: 673240c8a213e5f67b2f1229f247762ea2c710c0 [file] [log] [blame]
Florin Malita9867f612018-12-12 10:54:49 -05001/*
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
Ben Wagner1383a382019-04-03 17:53:53 -04008#include "SkFont.h"
Ben Wagner3bdb69c2019-04-01 19:01:09 -04009#include "SkFontMetrics.h"
Ben Wagner1383a382019-04-03 17:53:53 -040010#include "SkFontMgr.h"
11#include "SkMakeUnique.h"
12#include "SkShaper.h"
13#include "SkString.h"
14#include "SkTFitsIn.h"
15#include "SkTextBlobPriv.h"
16#include "SkTypeface.h"
17#include "SkUTF.h"
18
19#include <limits.h>
20#include <string.h>
21#include <locale>
22#include <string>
23#include <utility>
Florin Malita9867f612018-12-12 10:54:49 -050024
Ben Wagnerb0591942019-02-15 14:46:18 -050025std::unique_ptr<SkShaper> SkShaper::Make() {
26#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
27 std::unique_ptr<SkShaper> shaper = SkShaper::MakeHarfBuzz();
28 if (shaper) {
29 return shaper;
30 }
31#endif
32 return SkShaper::MakePrimitive();
33}
34
35SkShaper::SkShaper() {}
36SkShaper::~SkShaper() {}
37
Ben Wagner1383a382019-04-03 17:53:53 -040038/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
39static 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
44class FontMgrRunIterator final : public SkShaper::FontRunIterator {
45public:
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 }
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 }
99 size_t endOfCurrentRun() const override {
100 return fCurrent - fBegin;
101 }
102 bool atEnd() const override {
103 return fCurrent == fEnd;
104 }
105
106 const SkFont& currentFont() const override {
107 return *fCurrentFont;
108 }
109
110private:
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
120std::unique_ptr<SkShaper::FontRunIterator>
121SkShaper::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
127class StdLanguageRunIterator final : public SkShaper::LanguageRunIterator {
128public:
129 StdLanguageRunIterator(const char* utf8, size_t utf8Bytes)
130 : fCurrent(utf8), fBegin(utf8), fEnd(fCurrent + utf8Bytes)
131 , fLanguage(std::locale().name().c_str())
132 { }
133 void consume() override {
134 // Ideally something like cld2/3 could be used, or user signals.
135 SkASSERT(fCurrent < fEnd);
136 fCurrent = fEnd;
137 }
138 size_t endOfCurrentRun() const override {
139 return fCurrent - fBegin;
140 }
141 bool atEnd() const override {
142 return fCurrent == fEnd;
143 }
144
145 const char* currentLanguage() const override {
146 return fLanguage.c_str();
147 }
148private:
149 char const * fCurrent;
150 char const * const fBegin;
151 char const * const fEnd;
152 const SkString fLanguage;
153};
154
155std::unique_ptr<SkShaper::LanguageRunIterator>
156SkShaper::MakeStdLanguageRunIterator(const char* utf8, size_t utf8Bytes) {
157 return skstd::make_unique<StdLanguageRunIterator>(utf8, utf8Bytes);
158}
159
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400160void SkTextBlobBuilderRunHandler::beginLine() {
161 fCurrentPosition = fOffset;
162 fMaxRunAscent = 0;
163 fMaxRunDescent = 0;
164 fMaxRunLeading = 0;
165}
166void SkTextBlobBuilderRunHandler::runInfo(const RunInfo& info) {
167 SkFontMetrics metrics;
168 info.fFont.getMetrics(&metrics);
169 fMaxRunAscent = SkTMin(fMaxRunAscent, metrics.fAscent);
170 fMaxRunDescent = SkTMax(fMaxRunDescent, metrics.fDescent);
171 fMaxRunLeading = SkTMax(fMaxRunLeading, metrics.fLeading);
172}
173
174void SkTextBlobBuilderRunHandler::commitRunInfo() {
175 fCurrentPosition.fY -= fMaxRunAscent;
176}
177
178SkShaper::RunHandler::Buffer SkTextBlobBuilderRunHandler::runBuffer(const RunInfo& info) {
179 int glyphCount = SkTFitsIn<int>(info.glyphCount) ? info.glyphCount : INT_MAX;
180 int utf8RangeSize = SkTFitsIn<int>(info.utf8Range.size()) ? info.utf8Range.size() : INT_MAX;
181
182 const auto& runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(&fBuilder, info.fFont, glyphCount,
183 utf8RangeSize, SkString());
Ben Wagner454e5fb2019-02-08 17:46:38 -0500184 if (runBuffer.utf8text && fUtf8Text) {
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400185 memcpy(runBuffer.utf8text, fUtf8Text + info.utf8Range.begin(), utf8RangeSize);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500186 }
187 fClusters = runBuffer.clusters;
188 fGlyphCount = glyphCount;
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400189 fClusterOffset = info.utf8Range.begin();
Ben Wagner454e5fb2019-02-08 17:46:38 -0500190
Florin Malita9867f612018-12-12 10:54:49 -0500191 return { runBuffer.glyphs,
Mike Reed22451cc2019-01-01 15:40:28 -0500192 runBuffer.points(),
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400193 nullptr,
194 runBuffer.clusters,
195 fCurrentPosition };
Florin Malita9867f612018-12-12 10:54:49 -0500196}
197
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400198void SkTextBlobBuilderRunHandler::commitRunBuffer(const RunInfo& info) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500199 SkASSERT(0 <= fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500200 for (int i = 0; i < fGlyphCount; ++i) {
Ben Wagner18ea3c72019-02-15 16:35:48 -0500201 SkASSERT(fClusters[i] >= (unsigned)fClusterOffset);
Ben Wagner454e5fb2019-02-08 17:46:38 -0500202 fClusters[i] -= fClusterOffset;
203 }
Ben Wagner3bdb69c2019-04-01 19:01:09 -0400204 fCurrentPosition += info.fAdvance;
205}
206void SkTextBlobBuilderRunHandler::commitLine() {
207 fOffset += { 0, fMaxRunDescent + fMaxRunLeading - fMaxRunAscent };
Ben Wagner454e5fb2019-02-08 17:46:38 -0500208}
209
Florin Malita950243d2019-01-11 11:08:35 -0500210sk_sp<SkTextBlob> SkTextBlobBuilderRunHandler::makeBlob() {
Florin Malita9867f612018-12-12 10:54:49 -0500211 return fBuilder.make();
212}