1/*
2 * Copyright 2019 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "paragraph_builder_skia.h"
18#include "paragraph_skia.h"
19
20#include "third_party/skia/modules/skparagraph/include/ParagraphStyle.h"
21#include "third_party/skia/modules/skparagraph/include/TextStyle.h"
22#include "txt/paragraph_style.h"
23
24namespace skt = skia::textlayout;
25
26namespace txt {
27
28namespace {
29
30// Convert txt::FontWeight values (ranging from 0-8) to SkFontStyle::Weight
31// values (ranging from 100-900).
32SkFontStyle::Weight GetSkFontStyleWeight(txt::FontWeight font_weight) {
33 return static_cast<SkFontStyle::Weight>(static_cast<int>(font_weight) * 100 +
34 100);
35}
36
37SkFontStyle MakeSkFontStyle(txt::FontWeight font_weight,
38 txt::FontStyle font_style) {
39 return SkFontStyle(
40 GetSkFontStyleWeight(font_weight), SkFontStyle::Width::kNormal_Width,
41 font_style == txt::FontStyle::normal ? SkFontStyle::Slant::kUpright_Slant
42 : SkFontStyle::Slant::kItalic_Slant);
43}
44
45} // anonymous namespace
46
47ParagraphBuilderSkia::ParagraphBuilderSkia(
48 const ParagraphStyle& style,
49 std::shared_ptr<FontCollection> font_collection)
50 : base_style_(style.GetTextStyle()) {
51 builder_ = skt::ParagraphBuilder::make(
52 style: TxtToSkia(txt: style), fontCollection: font_collection->CreateSktFontCollection());
53}
54
55ParagraphBuilderSkia::~ParagraphBuilderSkia() = default;
56
57void ParagraphBuilderSkia::PushStyle(const TextStyle& style) {
58 builder_->pushStyle(style: TxtToSkia(txt: style));
59 txt_style_stack_.push(v: style);
60}
61
62void ParagraphBuilderSkia::Pop() {
63 builder_->pop();
64 txt_style_stack_.pop();
65}
66
67const TextStyle& ParagraphBuilderSkia::PeekStyle() {
68 return txt_style_stack_.empty() ? base_style_ : txt_style_stack_.top();
69}
70
71void ParagraphBuilderSkia::AddText(const std::u16string& text) {
72 builder_->addText(text);
73}
74
75void ParagraphBuilderSkia::AddPlaceholder(PlaceholderRun& span) {
76 skt::PlaceholderStyle placeholder_style;
77 placeholder_style.fHeight = span.height;
78 placeholder_style.fWidth = span.width;
79 placeholder_style.fBaseline = static_cast<skt::TextBaseline>(span.baseline);
80 placeholder_style.fBaselineOffset = span.baseline_offset;
81 placeholder_style.fAlignment =
82 static_cast<skt::PlaceholderAlignment>(span.alignment);
83
84 builder_->addPlaceholder(placeholderStyle: placeholder_style);
85}
86
87std::unique_ptr<Paragraph> ParagraphBuilderSkia::Build() {
88 return std::make_unique<ParagraphSkia>(args: builder_->Build(),
89 args: std::move(dl_paints_));
90}
91
92skt::ParagraphPainter::PaintID ParagraphBuilderSkia::CreatePaintID(
93 const flutter::DlPaint& dl_paint) {
94 dl_paints_.push_back(x: dl_paint);
95 return dl_paints_.size() - 1;
96}
97
98skt::ParagraphStyle ParagraphBuilderSkia::TxtToSkia(const ParagraphStyle& txt) {
99 skt::ParagraphStyle skia;
100 skt::TextStyle text_style;
101
102 // Convert the default color of an SkParagraph text style into a DlPaint.
103 flutter::DlPaint dl_paint;
104 dl_paint.setColor(text_style.getColor());
105 text_style.setForegroundPaintID(CreatePaintID(dl_paint));
106
107 text_style.setFontStyle(MakeSkFontStyle(font_weight: txt.font_weight, font_style: txt.font_style));
108 text_style.setFontSize(SkDoubleToScalar(txt.font_size));
109 text_style.setHeight(SkDoubleToScalar(txt.height));
110 text_style.setHeightOverride(txt.has_height_override);
111 text_style.setFontFamilies({SkString(txt.font_family.c_str())});
112 text_style.setLocale(SkString(txt.locale.c_str()));
113 skia.setTextStyle(text_style);
114
115 skt::StrutStyle strut_style;
116 strut_style.setFontStyle(
117 MakeSkFontStyle(font_weight: txt.strut_font_weight, font_style: txt.strut_font_style));
118 strut_style.setFontSize(SkDoubleToScalar(txt.strut_font_size));
119 strut_style.setHeight(SkDoubleToScalar(txt.strut_height));
120 strut_style.setHeightOverride(txt.strut_has_height_override);
121
122 std::vector<SkString> strut_fonts;
123 std::transform(first: txt.strut_font_families.begin(), last: txt.strut_font_families.end(),
124 result: std::back_inserter(x&: strut_fonts),
125 op: [](const std::string& f) { return SkString(f.c_str()); });
126 strut_style.setFontFamilies(strut_fonts);
127 strut_style.setLeading(txt.strut_leading);
128 strut_style.setForceStrutHeight(txt.force_strut_height);
129 strut_style.setStrutEnabled(txt.strut_enabled);
130 skia.setStrutStyle(strut_style);
131
132 skia.setTextAlign(static_cast<skt::TextAlign>(txt.text_align));
133 skia.setTextDirection(static_cast<skt::TextDirection>(txt.text_direction));
134 skia.setMaxLines(txt.max_lines);
135 skia.setEllipsis(txt.ellipsis);
136 skia.setTextHeightBehavior(
137 static_cast<skt::TextHeightBehavior>(txt.text_height_behavior));
138
139 skia.turnHintingOff();
140 skia.setReplaceTabCharacters(true);
141 skia.setApplyRoundingHack(txt.apply_rounding_hack);
142
143 return skia;
144}
145
146skt::TextStyle ParagraphBuilderSkia::TxtToSkia(const TextStyle& txt) {
147 skt::TextStyle skia;
148
149 skia.setColor(txt.color);
150 skia.setDecoration(static_cast<skt::TextDecoration>(txt.decoration));
151 skia.setDecorationColor(txt.decoration_color);
152 skia.setDecorationStyle(
153 static_cast<skt::TextDecorationStyle>(txt.decoration_style));
154 skia.setDecorationThicknessMultiplier(
155 SkDoubleToScalar(txt.decoration_thickness_multiplier));
156 skia.setFontStyle(MakeSkFontStyle(font_weight: txt.font_weight, font_style: txt.font_style));
157 skia.setTextBaseline(static_cast<skt::TextBaseline>(txt.text_baseline));
158
159 std::vector<SkString> skia_fonts;
160 std::transform(first: txt.font_families.begin(), last: txt.font_families.end(),
161 result: std::back_inserter(x&: skia_fonts),
162 op: [](const std::string& f) { return SkString(f.c_str()); });
163 skia.setFontFamilies(skia_fonts);
164
165 skia.setFontSize(SkDoubleToScalar(txt.font_size));
166 skia.setLetterSpacing(SkDoubleToScalar(txt.letter_spacing));
167 skia.setWordSpacing(SkDoubleToScalar(txt.word_spacing));
168 skia.setHeight(SkDoubleToScalar(txt.height));
169 skia.setHeightOverride(txt.has_height_override);
170 skia.setHalfLeading(txt.half_leading);
171
172 skia.setLocale(SkString(txt.locale.c_str()));
173 if (txt.background.has_value()) {
174 skia.setBackgroundPaintID(CreatePaintID(dl_paint: txt.background.value()));
175 }
176 if (txt.foreground.has_value()) {
177 skia.setForegroundPaintID(CreatePaintID(dl_paint: txt.foreground.value()));
178 } else {
179 flutter::DlPaint dl_paint;
180 dl_paint.setColor(txt.color);
181 skia.setForegroundPaintID(CreatePaintID(dl_paint));
182 }
183
184 skia.resetFontFeatures();
185 for (const auto& ff : txt.font_features.GetFontFeatures()) {
186 skia.addFontFeature(fontFeature: SkString(ff.first.c_str()), value: ff.second);
187 }
188
189 if (!txt.font_variations.GetAxisValues().empty()) {
190 std::vector<SkFontArguments::VariationPosition::Coordinate> coordinates;
191 for (const auto& it : txt.font_variations.GetAxisValues()) {
192 const std::string& axis = it.first;
193 if (axis.length() != 4) {
194 continue;
195 }
196 coordinates.push_back(x: {
197 .axis: SkSetFourByteTag(a: axis[0], b: axis[1], c: axis[2], d: axis[3]),
198 .value: it.second,
199 });
200 }
201 SkFontArguments::VariationPosition position = {
202 .coordinates: coordinates.data(), .coordinateCount: static_cast<int>(coordinates.size())};
203 skia.setFontArguments(
204 SkFontArguments().setVariationDesignPosition(position));
205 }
206
207 skia.resetShadows();
208 for (const txt::TextShadow& txt_shadow : txt.text_shadows) {
209 skt::TextShadow shadow;
210 shadow.fOffset = txt_shadow.offset;
211 shadow.fBlurSigma = txt_shadow.blur_sigma;
212 shadow.fColor = txt_shadow.color;
213 skia.addShadow(shadow);
214 }
215
216 return skia;
217}
218
219} // namespace txt
220

source code of flutter_engine/flutter/third_party/txt/src/skia/paragraph_builder_skia.cc