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
16using tonic::ToDart;
17
18namespace flutter {
19
20IMPLEMENT_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
40DART_BIND_ALL(Paragraph, FOR_EACH_BINDING)
41
42Paragraph::Paragraph(std::unique_ptr<txt::Paragraph> paragraph)
43 : m_paragraph(std::move(paragraph)) {}
44
45Paragraph::~Paragraph() = default;
46
47size_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
54double Paragraph::width() {
55 return m_paragraph->GetMaxWidth();
56}
57
58double Paragraph::height() {
59 return m_paragraph->GetHeight();
60}
61
62double Paragraph::longestLine() {
63 return m_paragraph->GetLongestLine();
64}
65
66double Paragraph::minIntrinsicWidth() {
67 return m_paragraph->GetMinIntrinsicWidth();
68}
69
70double Paragraph::maxIntrinsicWidth() {
71 return m_paragraph->GetMaxIntrinsicWidth();
72}
73
74double Paragraph::alphabeticBaseline() {
75 return m_paragraph->GetAlphabeticBaseline();
76}
77
78double Paragraph::ideographicBaseline() {
79 return m_paragraph->GetIdeographicBaseline();
80}
81
82bool Paragraph::didExceedMaxLines() {
83 return m_paragraph->DidExceedMaxLines();
84}
85
86void Paragraph::layout(double width) {
87 m_paragraph->Layout(width);
88}
89
90void 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
98static 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
118tonic::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
128tonic::Float32List Paragraph::getRectsForPlaceholders() {
129 std::vector<txt::Paragraph::TextBox> boxes =
130 m_paragraph->GetRectsForPlaceholders();
131 return EncodeTextBoxes(boxes);
132}
133
134Dart_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
143Dart_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
151Dart_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
168tonic::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