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
16namespace flutter {
17
18IMPLEMENT_WRAPPERTYPEINFO(ui, Paragraph);
19
20Paragraph::Paragraph(std::unique_ptr<txt::Paragraph> paragraph)
21 : m_paragraph(std::move(paragraph)) {}
22
23Paragraph::~Paragraph() = default;
24
25double Paragraph::width() {
26 return m_paragraph->GetMaxWidth();
27}
28
29double Paragraph::height() {
30 return m_paragraph->GetHeight();
31}
32
33double Paragraph::longestLine() {
34 return m_paragraph->GetLongestLine();
35}
36
37double Paragraph::minIntrinsicWidth() {
38 return m_paragraph->GetMinIntrinsicWidth();
39}
40
41double Paragraph::maxIntrinsicWidth() {
42 return m_paragraph->GetMaxIntrinsicWidth();
43}
44
45double Paragraph::alphabeticBaseline() {
46 return m_paragraph->GetAlphabeticBaseline();
47}
48
49double Paragraph::ideographicBaseline() {
50 return m_paragraph->GetIdeographicBaseline();
51}
52
53bool Paragraph::didExceedMaxLines() {
54 return m_paragraph->DidExceedMaxLines();
55}
56
57void Paragraph::layout(double width) {
58 m_paragraph->Layout(width);
59}
60
61void Paragraph::paint(Canvas* canvas, double x, double y) {
62 if (!m_paragraph || !canvas) {
63 // disposed.
64 return;
65 }
66
67 DisplayListBuilder* builder = canvas->builder();
68 if (builder) {
69 m_paragraph->Paint(builder, x, y);
70 }
71}
72
73static tonic::Float32List EncodeTextBoxes(
74 const std::vector<txt::Paragraph::TextBox>& boxes) {
75 // Layout:
76 // First value is the number of values.
77 // Then there are boxes.size() groups of 5 which are LTRBD, where D is the
78 // text direction index.
79 tonic::Float32List result(
80 Dart_NewTypedData(type: Dart_TypedData_kFloat32, length: boxes.size() * 5));
81 uint64_t position = 0;
82 for (uint64_t i = 0; i < boxes.size(); i++) {
83 const txt::Paragraph::TextBox& box = boxes[i];
84 result[position++] = box.rect.fLeft;
85 result[position++] = box.rect.fTop;
86 result[position++] = box.rect.fRight;
87 result[position++] = box.rect.fBottom;
88 result[position++] = static_cast<float>(box.direction);
89 }
90 return result;
91}
92
93tonic::Float32List Paragraph::getRectsForRange(unsigned start,
94 unsigned end,
95 unsigned boxHeightStyle,
96 unsigned boxWidthStyle) {
97 std::vector<txt::Paragraph::TextBox> boxes = m_paragraph->GetRectsForRange(
98 start, end, rect_height_style: static_cast<txt::Paragraph::RectHeightStyle>(boxHeightStyle),
99 rect_width_style: static_cast<txt::Paragraph::RectWidthStyle>(boxWidthStyle));
100 return EncodeTextBoxes(boxes);
101}
102
103tonic::Float32List Paragraph::getRectsForPlaceholders() {
104 std::vector<txt::Paragraph::TextBox> boxes =
105 m_paragraph->GetRectsForPlaceholders();
106 return EncodeTextBoxes(boxes);
107}
108
109Dart_Handle Paragraph::getPositionForOffset(double dx, double dy) {
110 txt::Paragraph::PositionWithAffinity pos =
111 m_paragraph->GetGlyphPositionAtCoordinate(dx, dy);
112 std::vector<size_t> result = {
113 pos.position, // size_t already
114 static_cast<size_t>(pos.affinity) // affinity (enum)
115 };
116 return tonic::DartConverter<decltype(result)>::ToDart(val: result);
117}
118
119Dart_Handle Paragraph::getWordBoundary(unsigned offset) {
120 txt::Paragraph::Range<size_t> point = m_paragraph->GetWordBoundary(offset);
121 std::vector<size_t> result = {point.start, point.end};
122 return tonic::DartConverter<decltype(result)>::ToDart(val: result);
123}
124
125Dart_Handle Paragraph::getLineBoundary(unsigned offset) {
126 std::vector<txt::LineMetrics> metrics = m_paragraph->GetLineMetrics();
127 int line_start = -1;
128 int line_end = -1;
129 for (txt::LineMetrics& line : metrics) {
130 if (offset >= line.start_index && offset <= line.end_index) {
131 line_start = line.start_index;
132 line_end = line.end_index;
133 break;
134 }
135 }
136 std::vector<int> result = {line_start, line_end};
137 return tonic::DartConverter<decltype(result)>::ToDart(val: result);
138}
139
140tonic::Float64List Paragraph::computeLineMetrics() {
141 std::vector<txt::LineMetrics> metrics = m_paragraph->GetLineMetrics();
142
143 // Layout:
144 // boxes.size() groups of 9 which are the line metrics
145 // properties
146 tonic::Float64List result(
147 Dart_NewTypedData(type: Dart_TypedData_kFloat64, length: metrics.size() * 9));
148 uint64_t position = 0;
149 for (uint64_t i = 0; i < metrics.size(); i++) {
150 const txt::LineMetrics& line = metrics[i];
151 result[position++] = static_cast<double>(line.hard_break);
152 result[position++] = line.ascent;
153 result[position++] = line.descent;
154 result[position++] = line.unscaled_ascent;
155 // We add then round to get the height. The
156 // definition of height here is different
157 // than the one in LibTxt.
158 result[position++] = round(x: line.ascent + line.descent);
159 result[position++] = line.width;
160 result[position++] = line.left;
161 result[position++] = line.baseline;
162 result[position++] = static_cast<double>(line.line_number);
163 }
164
165 return result;
166}
167
168void Paragraph::dispose() {
169 m_paragraph.reset();
170 ClearDartWrapper();
171}
172
173} // namespace flutter
174

source code of flutter_engine/flutter/lib/ui/text/paragraph.cc