1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "line_breaker.h"
17
18 #include "char_groups.h"
19 #include "floating.h"
20 #include "texgine/any_span.h"
21 #include "texgine_exception.h"
22 #include "texgine/utils/exlog.h"
23 #include "texgine/utils/trace.h"
24 #include "text_merger.h"
25 #include "text_span.h"
26
27 namespace OHOS {
28 namespace Rosen {
29 namespace TextEngine {
BreakLines(std::vector<VariantSpan> & spans,const TypographyStyle & tstyle,const double widthLimit)30 std::vector<LineMetrics> LineBreaker::BreakLines(std::vector<VariantSpan> &spans,
31 const TypographyStyle &tstyle, const double widthLimit)
32 {
33 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "BreakLines");
34 auto ss = GenerateScoreSpans(spans);
35 DoBreakLines(ss, widthLimit, tstyle);
36 auto lineBreaks = GenerateBreaks(ss);
37 return GenerateLineMetrics(spans, lineBreaks);
38 }
39
GenerateScoreSpans(const std::vector<VariantSpan> & spans)40 std::vector<struct ScoredSpan> LineBreaker::GenerateScoreSpans(const std::vector<VariantSpan> &spans)
41 {
42 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "GenerateScoreSpans");
43 std::vector<struct ScoredSpan> scoredSpans = {{}};
44 double offset = 0;
45 double preBreak = 0.0;
46 double postBreak = 0.0;
47 CharGroups lastcgs;
48 for (const auto &span : spans) {
49 if (span == nullptr) {
50 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
51 }
52
53 if (auto ts = span.TryToTextSpan(); ts != nullptr) {
54 if (lastcgs.IsSameCharGroups(ts->cgs_) == false) {
55 // not same word break
56 offset = scoredSpans.back().postBreak;
57 lastcgs = ts->cgs_;
58 }
59 preBreak = ts->GetPreBreak();
60 postBreak = ts->GetPostBreak();
61 }
62
63 if (auto as = span.TryToAnySpan(); as != nullptr) {
64 offset = scoredSpans.back().postBreak;
65 preBreak = as->GetWidth();
66 postBreak = preBreak;
67 // prevent after as is a SameCharGroups ts with before this as
68 lastcgs = {};
69 }
70
71 LOGEX_FUNC_LINE_DEBUG() << "[" << scoredSpans.size() << "]"
72 << ": offset: " << offset
73 << ", preBreak: " << preBreak
74 << ", postBreak: " << postBreak;
75 scoredSpans.push_back({
76 .span = span,
77 .preBreak = offset + preBreak,
78 .postBreak = offset + postBreak,
79 .score = 0,
80 .prev = 0,
81 });
82 }
83 scoredSpans.erase(scoredSpans.begin());
84 return scoredSpans;
85 }
86
DoBreakLines(std::vector<struct ScoredSpan> & scoredSpans,const double widthLimit,const TypographyStyle & tstyle)87 void LineBreaker::DoBreakLines(std::vector<struct ScoredSpan> &scoredSpans, const double widthLimit,
88 const TypographyStyle &tstyle)
89 {
90 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "UpadateLineBreaksData");
91 scoredSpans.emplace(scoredSpans.cbegin());
92 for (size_t i = 1; i < scoredSpans.size(); i++) {
93 auto &is = scoredSpans[i];
94 is.prev = scoredSpans[i - 1].prev;
95 LOGEX_FUNC_LINE_DEBUG() << "[" << i << "]: is.preBreak: " << is.preBreak
96 << ", prev.postBreak: " << scoredSpans[is.prev].postBreak;
97 if (FLOATING_GT(is.preBreak - scoredSpans[is.prev].postBreak, widthLimit)) {
98 is.prev = static_cast<int>(i - 1);
99 LOGEX_FUNC_LINE_DEBUG() << " -> [" << is.prev
100 << "]: prev.postBreak: " << scoredSpans[is.prev].postBreak;
101 }
102
103 if (tstyle.breakStrategy == BreakStrategy::GREEDY) {
104 continue;
105 }
106
107 LOGSCOPED(sl1, LOGEX_FUNC_LINE_DEBUG(), "algo");
108 double delta = widthLimit - (is.preBreak - scoredSpans[is.prev].postBreak);
109 is.score = delta * delta + scoredSpans[is.prev].score;
110
111 std::stringstream ss;
112 ss << i;
113 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), ss.str());
114 for (size_t j = 0; j < i; j++) {
115 const auto &js = scoredSpans[j];
116 double jdelta = widthLimit - (is.preBreak - js.postBreak);
117 if (jdelta < 0) {
118 continue;
119 }
120
121 double jscore = js.score + jdelta * jdelta;
122 LOGEX_FUNC_LINE_DEBUG() << "[" << j << "]"
123 << " s(" << jscore << ")" << " = js(" << js.score << ")"
124 << " + dd(" << jdelta * jdelta << ")" << " (jdelta: " << jdelta << ")";
125
126 if (jscore < is.score) {
127 is.score = jscore;
128 is.prev = static_cast<int>(j);
129 }
130 }
131 LOGEX_FUNC_LINE_DEBUG() << "[" << i << "] Any{" << is.prev << "<-" << " b(" << is.preBreak << ", "
132 << is.postBreak << ")" << " s(" << is.score << ")}";
133 }
134 scoredSpans.erase(scoredSpans.begin());
135 }
136
GenerateBreaks(const std::vector<struct ScoredSpan> & scoredSpans)137 std::vector<int32_t> LineBreaker::GenerateBreaks(const std::vector<struct ScoredSpan> &scoredSpans)
138 {
139 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "GenerateBreaks");
140
141 std::vector<int32_t> lineBreaks;
142 for (int i = static_cast<int>(scoredSpans.size()); i > 0; i = scoredSpans[i - 1].prev) {
143 if (scoredSpans[i - 1].prev >= i) {
144 throw TEXGINE_EXCEPTION(ERROR_STATUS);
145 }
146
147 LOGEX_FUNC_LINE_DEBUG() << "break at " << i;
148 lineBreaks.push_back(i);
149 }
150 std::reverse(lineBreaks.begin(), lineBreaks.end());
151 return lineBreaks;
152 }
153
GenerateLineMetrics(std::vector<VariantSpan> & spans,std::vector<int32_t> & breaks)154 std::vector<LineMetrics> LineBreaker::GenerateLineMetrics(std::vector<VariantSpan> &spans,
155 std::vector<int32_t> &breaks)
156 {
157 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "GenerateLineMetrics");
158 LOGEX_FUNC_LINE_DEBUG() << "breaks.size(): " << breaks.size();
159
160 std::vector<LineMetrics> lineMetrics;
161 auto prev = 0;
162 if (!breaks.empty() && breaks.back() > static_cast<int>(spans.size())) {
163 throw TEXGINE_EXCEPTION(OUT_OF_RANGE);
164 }
165
166 for (const auto &lb : breaks) {
167 if (lb <= prev) {
168 throw TEXGINE_EXCEPTION(ERROR_STATUS);
169 }
170
171 std::stringstream ss;
172 ss << "[" << prev << ", " << lb << ")";
173 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), ss.str());
174
175 std::vector<VariantSpan> vss;
176 for (int32_t i = prev; i < lb; i++) {
177 spans[i].Dump();
178 vss.push_back(spans[i]);
179 }
180
181 lineMetrics.push_back({
182 .lineSpans = vss,
183 });
184 prev = lb;
185 }
186
187 return lineMetrics;
188 }
189 } // namespace TextEngine
190 } // namespace Rosen
191 } // namespace OHOS
192