1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "flutter/lib/ui/text/paragraph.h" |
6 | |
7 | #include "flutter/common/settings.h" |
8 | #include "flutter/common/task_runners.h" |
9 | #include "flutter/fml/logging.h" |
10 | #include "flutter/fml/task_runner.h" |
11 | #include "third_party/tonic/converter/dart_converter.h" |
12 | #include "third_party/tonic/dart_args.h" |
13 | #include "third_party/tonic/dart_binding_macros.h" |
14 | #include "third_party/tonic/dart_library_natives.h" |
15 | |
16 | using tonic::ToDart; |
17 | |
18 | namespace flutter { |
19 | |
20 | IMPLEMENT_WRAPPERTYPEINFO(ui, Paragraph); |
21 | |
22 | #define FOR_EACH_BINDING(V) \ |
23 | V(Paragraph, width) \ |
24 | V(Paragraph, height) \ |
25 | V(Paragraph, longestLine) \ |
26 | V(Paragraph, minIntrinsicWidth) \ |
27 | V(Paragraph, maxIntrinsicWidth) \ |
28 | V(Paragraph, alphabeticBaseline) \ |
29 | V(Paragraph, ideographicBaseline) \ |
30 | V(Paragraph, didExceedMaxLines) \ |
31 | V(Paragraph, layout) \ |
32 | V(Paragraph, paint) \ |
33 | V(Paragraph, getWordBoundary) \ |
34 | V(Paragraph, getLineBoundary) \ |
35 | V(Paragraph, getRectsForRange) \ |
36 | V(Paragraph, getRectsForPlaceholders) \ |
37 | V(Paragraph, getPositionForOffset) \ |
38 | V(Paragraph, computeLineMetrics) |
39 | |
40 | DART_BIND_ALL(Paragraph, FOR_EACH_BINDING) |
41 | |
42 | Paragraph::Paragraph(std::unique_ptr<txt::Paragraph> paragraph) |
43 | : m_paragraph(std::move(paragraph)) {} |
44 | |
45 | Paragraph::~Paragraph() = default; |
46 | |
47 | size_t Paragraph::GetAllocationSize() const { |
48 | // We don't have an accurate accounting of the paragraph's memory consumption, |
49 | // so return a fixed size to indicate that its impact is more than the size |
50 | // of the Paragraph class. |
51 | return 2000; |
52 | } |
53 | |
54 | double Paragraph::width() { |
55 | return m_paragraph->GetMaxWidth(); |
56 | } |
57 | |
58 | double Paragraph::height() { |
59 | return m_paragraph->GetHeight(); |
60 | } |
61 | |
62 | double Paragraph::longestLine() { |
63 | return m_paragraph->GetLongestLine(); |
64 | } |
65 | |
66 | double Paragraph::minIntrinsicWidth() { |
67 | return m_paragraph->GetMinIntrinsicWidth(); |
68 | } |
69 | |
70 | double Paragraph::maxIntrinsicWidth() { |
71 | return m_paragraph->GetMaxIntrinsicWidth(); |
72 | } |
73 | |
74 | double Paragraph::alphabeticBaseline() { |
75 | return m_paragraph->GetAlphabeticBaseline(); |
76 | } |
77 | |
78 | double Paragraph::ideographicBaseline() { |
79 | return m_paragraph->GetIdeographicBaseline(); |
80 | } |
81 | |
82 | bool Paragraph::didExceedMaxLines() { |
83 | return m_paragraph->DidExceedMaxLines(); |
84 | } |
85 | |
86 | void Paragraph::layout(double width) { |
87 | m_paragraph->Layout(width); |
88 | } |
89 | |
90 | void Paragraph::paint(Canvas* canvas, double x, double y) { |
91 | SkCanvas* sk_canvas = canvas->canvas(); |
92 | if (!sk_canvas) { |
93 | return; |
94 | } |
95 | m_paragraph->Paint(sk_canvas, x, y); |
96 | } |
97 | |
98 | static tonic::Float32List EncodeTextBoxes( |
99 | const std::vector<txt::Paragraph::TextBox>& boxes) { |
100 | // Layout: |
101 | // First value is the number of values. |
102 | // Then there are boxes.size() groups of 5 which are LTRBD, where D is the |
103 | // text direction index. |
104 | tonic::Float32List result( |
105 | Dart_NewTypedData(Dart_TypedData_kFloat32, boxes.size() * 5)); |
106 | uint64_t position = 0; |
107 | for (uint64_t i = 0; i < boxes.size(); i++) { |
108 | const txt::Paragraph::TextBox& box = boxes[i]; |
109 | result[position++] = box.rect.fLeft; |
110 | result[position++] = box.rect.fTop; |
111 | result[position++] = box.rect.fRight; |
112 | result[position++] = box.rect.fBottom; |
113 | result[position++] = static_cast<float>(box.direction); |
114 | } |
115 | return result; |
116 | } |
117 | |
118 | tonic::Float32List Paragraph::getRectsForRange(unsigned start, |
119 | unsigned end, |
120 | unsigned boxHeightStyle, |
121 | unsigned boxWidthStyle) { |
122 | std::vector<txt::Paragraph::TextBox> boxes = m_paragraph->GetRectsForRange( |
123 | start, end, static_cast<txt::Paragraph::RectHeightStyle>(boxHeightStyle), |
124 | static_cast<txt::Paragraph::RectWidthStyle>(boxWidthStyle)); |
125 | return EncodeTextBoxes(boxes); |
126 | } |
127 | |
128 | tonic::Float32List Paragraph::getRectsForPlaceholders() { |
129 | std::vector<txt::Paragraph::TextBox> boxes = |
130 | m_paragraph->GetRectsForPlaceholders(); |
131 | return EncodeTextBoxes(boxes); |
132 | } |
133 | |
134 | Dart_Handle Paragraph::getPositionForOffset(double dx, double dy) { |
135 | Dart_Handle result = Dart_NewListOf(Dart_CoreType_Int, 2); |
136 | txt::Paragraph::PositionWithAffinity pos = |
137 | m_paragraph->GetGlyphPositionAtCoordinate(dx, dy); |
138 | Dart_ListSetAt(result, 0, ToDart(pos.position)); |
139 | Dart_ListSetAt(result, 1, ToDart(static_cast<int>(pos.affinity))); |
140 | return result; |
141 | } |
142 | |
143 | Dart_Handle Paragraph::getWordBoundary(unsigned offset) { |
144 | txt::Paragraph::Range<size_t> point = m_paragraph->GetWordBoundary(offset); |
145 | Dart_Handle result = Dart_NewListOf(Dart_CoreType_Int, 2); |
146 | Dart_ListSetAt(result, 0, ToDart(point.start)); |
147 | Dart_ListSetAt(result, 1, ToDart(point.end)); |
148 | return result; |
149 | } |
150 | |
151 | Dart_Handle Paragraph::getLineBoundary(unsigned offset) { |
152 | std::vector<txt::LineMetrics> metrics = m_paragraph->GetLineMetrics(); |
153 | int line_start = -1; |
154 | int line_end = -1; |
155 | for (txt::LineMetrics& line : metrics) { |
156 | if (offset >= line.start_index && offset <= line.end_index) { |
157 | line_start = line.start_index; |
158 | line_end = line.end_index; |
159 | break; |
160 | } |
161 | } |
162 | Dart_Handle result = Dart_NewListOf(Dart_CoreType_Int, 2); |
163 | Dart_ListSetAt(result, 0, ToDart(line_start)); |
164 | Dart_ListSetAt(result, 1, ToDart(line_end)); |
165 | return result; |
166 | } |
167 | |
168 | tonic::Float64List Paragraph::computeLineMetrics() { |
169 | std::vector<txt::LineMetrics> metrics = m_paragraph->GetLineMetrics(); |
170 | |
171 | // Layout: |
172 | // boxes.size() groups of 9 which are the line metrics |
173 | // properties |
174 | tonic::Float64List result( |
175 | Dart_NewTypedData(Dart_TypedData_kFloat64, metrics.size() * 9)); |
176 | uint64_t position = 0; |
177 | for (uint64_t i = 0; i < metrics.size(); i++) { |
178 | const txt::LineMetrics& line = metrics[i]; |
179 | result[position++] = static_cast<double>(line.hard_break); |
180 | result[position++] = line.ascent; |
181 | result[position++] = line.descent; |
182 | result[position++] = line.unscaled_ascent; |
183 | // We add then round to get the height. The |
184 | // definition of height here is different |
185 | // than the one in LibTxt. |
186 | result[position++] = round(line.ascent + line.descent); |
187 | result[position++] = line.width; |
188 | result[position++] = line.left; |
189 | result[position++] = line.baseline; |
190 | result[position++] = static_cast<double>(line.line_number); |
191 | } |
192 | |
193 | return result; |
194 | } |
195 | |
196 | } // namespace flutter |
197 | |