• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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