Flutter Engine
paragraph_skia.cc
Go to the documentation of this file.
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_skia.h"
18 
19 #include <algorithm>
20 
21 namespace txt {
22 
23 namespace skt = skia::textlayout;
24 
25 namespace {
26 
27 // Convert SkFontStyle::Weight values (ranging from 100-900) to txt::FontWeight
28 // values (ranging from 0-8).
29 txt::FontWeight GetTxtFontWeight(int font_weight) {
30  int txt_weight = (font_weight - 100) / 100;
31  txt_weight = std::clamp(txt_weight, static_cast<int>(txt::FontWeight::w100),
32  static_cast<int>(txt::FontWeight::w900));
33  return static_cast<txt::FontWeight>(txt_weight);
34 }
35 
36 txt::FontStyle GetTxtFontStyle(SkFontStyle::Slant font_slant) {
37  return font_slant == SkFontStyle::Slant::kUpright_Slant
40 }
41 
42 TextStyle SkiaToTxt(const skt::TextStyle& skia) {
43  TextStyle txt;
44 
45  txt.color = skia.getColor();
46  txt.decoration = static_cast<TextDecoration>(skia.getDecorationType());
47  txt.decoration_color = skia.getDecorationColor();
48  txt.decoration_style =
49  static_cast<TextDecorationStyle>(skia.getDecorationStyle());
50  txt.decoration_thickness_multiplier =
51  SkScalarToDouble(skia.getDecorationThicknessMultiplier());
52  txt.font_weight = GetTxtFontWeight(skia.getFontStyle().weight());
53  txt.font_style = GetTxtFontStyle(skia.getFontStyle().slant());
54 
55  txt.text_baseline = static_cast<TextBaseline>(skia.getTextBaseline());
56 
57  for (const SkString& font_family : skia.getFontFamilies()) {
58  txt.font_families.emplace_back(font_family.c_str());
59  }
60 
61  txt.font_size = SkScalarToDouble(skia.getFontSize());
62  txt.letter_spacing = SkScalarToDouble(skia.getLetterSpacing());
63  txt.word_spacing = SkScalarToDouble(skia.getWordSpacing());
64  txt.height = SkScalarToDouble(skia.getHeight());
65 
66  txt.locale = skia.getLocale().c_str();
67  if (skia.hasBackground()) {
68  txt.background = skia.getBackground();
69  }
70  if (skia.hasForeground()) {
71  txt.foreground = skia.getForeground();
72  }
73 
74  txt.text_shadows.clear();
75  for (const skt::TextShadow& skia_shadow : skia.getShadows()) {
76  txt::TextShadow shadow;
77  shadow.offset = skia_shadow.fOffset;
78  shadow.blur_radius = skia_shadow.fBlurRadius;
79  shadow.color = skia_shadow.fColor;
80  txt.text_shadows.emplace_back(shadow);
81  }
82 
83  return txt;
84 }
85 
86 } // anonymous namespace
87 
88 ParagraphSkia::ParagraphSkia(std::unique_ptr<skt::Paragraph> paragraph)
89  : paragraph_(std::move(paragraph)) {}
90 
92  return SkScalarToDouble(paragraph_->getMaxWidth());
93 }
94 
96  return SkScalarToDouble(paragraph_->getHeight());
97 }
98 
100  return SkScalarToDouble(paragraph_->getLongestLine());
101 }
102 
103 std::vector<LineMetrics>& ParagraphSkia::GetLineMetrics() {
104  if (!line_metrics_) {
105  std::vector<skt::LineMetrics> metrics;
106  paragraph_->getLineMetrics(metrics);
107 
108  line_metrics_.emplace();
109  for (const skt::LineMetrics& skm : metrics) {
110  LineMetrics& txtm = line_metrics_->emplace_back(
111  skm.fStartIndex, skm.fEndIndex, skm.fEndExcludingWhitespaces,
112  skm.fEndIncludingNewline, skm.fHardBreak);
113  txtm.ascent = skm.fAscent;
114  txtm.descent = skm.fDescent;
115  txtm.unscaled_ascent = skm.fUnscaledAscent;
116  txtm.height = skm.fHeight;
117  txtm.width = skm.fWidth;
118  txtm.left = skm.fLeft;
119  txtm.baseline = skm.fBaseline;
120  txtm.line_number = skm.fLineNumber;
121 
122  for (const auto& sk_iter : skm.fLineMetrics) {
123  const skt::StyleMetrics& sk_style_metrics = sk_iter.second;
124  line_metrics_styles_.push_back(SkiaToTxt(*sk_style_metrics.text_style));
125  txtm.run_metrics.emplace(
126  std::piecewise_construct, std::forward_as_tuple(sk_iter.first),
127  std::forward_as_tuple(&line_metrics_styles_.back(),
128  sk_style_metrics.font_metrics));
129  }
130  }
131  }
132 
133  return line_metrics_.value();
134 }
135 
137  return SkScalarToDouble(paragraph_->getMinIntrinsicWidth());
138 }
139 
141  return SkScalarToDouble(paragraph_->getMaxIntrinsicWidth());
142 }
143 
145  return SkScalarToDouble(paragraph_->getAlphabeticBaseline());
146 }
147 
149  return SkScalarToDouble(paragraph_->getIdeographicBaseline());
150 }
151 
153  return paragraph_->didExceedMaxLines();
154 }
155 
157  paragraph_->layout(width);
158 }
159 
160 void ParagraphSkia::Paint(SkCanvas* canvas, double x, double y) {
161  paragraph_->paint(canvas, x, y);
162 }
163 
164 std::vector<Paragraph::TextBox> ParagraphSkia::GetRectsForRange(
165  size_t start,
166  size_t end,
167  RectHeightStyle rect_height_style,
168  RectWidthStyle rect_width_style) {
169  std::vector<skt::TextBox> skia_boxes = paragraph_->getRectsForRange(
170  start, end, static_cast<skt::RectHeightStyle>(rect_height_style),
171  static_cast<skt::RectWidthStyle>(rect_width_style));
172 
173  std::vector<Paragraph::TextBox> boxes;
174  for (const skt::TextBox skia_box : skia_boxes) {
175  boxes.emplace_back(skia_box.rect,
176  static_cast<TextDirection>(skia_box.direction));
177  }
178 
179  return boxes;
180 }
181 
182 std::vector<Paragraph::TextBox> ParagraphSkia::GetRectsForPlaceholders() {
183  std::vector<skt::TextBox> skia_boxes = paragraph_->getRectsForPlaceholders();
184 
185  std::vector<Paragraph::TextBox> boxes;
186  for (const skt::TextBox skia_box : skia_boxes) {
187  boxes.emplace_back(skia_box.rect,
188  static_cast<TextDirection>(skia_box.direction));
189  }
190 
191  return boxes;
192 }
193 
195  double dx,
196  double dy) {
197  skt::PositionWithAffinity skia_pos =
198  paragraph_->getGlyphPositionAtCoordinate(dx, dy);
199 
201  skia_pos.position, static_cast<Affinity>(skia_pos.affinity));
202 }
203 
205  skt::SkRange<size_t> range = paragraph_->getWordBoundary(offset);
206  return Paragraph::Range<size_t>(range.start, range.end);
207 }
208 
209 } // namespace txt
Range< size_t > GetWordBoundary(size_t offset) override
FontStyle
Definition: font_style.h:22
SkPoint offset
Definition: text_shadow.h:28
double GetMaxIntrinsicWidth() override
TextDecorationStyle
bool DidExceedMaxLines() override
double blur_radius
Definition: text_shadow.h:29
Definition: ref_ptr.h:252
FontWeight
Definition: font_weight.h:22
double GetLongestLine() override
std::vector< TextBox > GetRectsForRange(size_t start, size_t end, RectHeightStyle rect_height_style, RectWidthStyle rect_width_style) override
std::map< size_t, RunMetrics > run_metrics
Definition: line_metrics.h:68
std::vector< TextBox > GetRectsForPlaceholders() override
int32_t width
void Layout(double width) override
double GetHeight() override
TextBaseline
Definition: text_baseline.h:22
double GetMaxWidth() override
double GetAlphabeticBaseline() override
double GetIdeographicBaseline() override
TextDecoration
PositionWithAffinity GetGlyphPositionAtCoordinate(double dx, double dy) override
double unscaled_ascent
Definition: line_metrics.h:50
void Paint(SkCanvas *canvas, double x, double y) override
std::vector< LineMetrics > & GetLineMetrics() override
ParagraphSkia(std::unique_ptr< skia::textlayout::Paragraph > paragraph)
double GetMinIntrinsicWidth() override