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 "text_breaker.h"
17
18 #include <cassert>
19
20 #include "measurer.h"
21 #include "texgine/any_span.h"
22 #include "texgine_exception.h"
23 #include "text_span.h"
24 #include "texgine/utils/exlog.h"
25 #include "texgine/utils/trace.h"
26 #include "text_converter.h"
27 #include "word_breaker.h"
28
29 namespace OHOS {
30 namespace Rosen {
31 namespace TextEngine {
WordBreak(std::vector<VariantSpan> & spans,const TypographyStyle & ys,const std::shared_ptr<FontProviders> & fontProviders)32 int TextBreaker::WordBreak(std::vector<VariantSpan> &spans, const TypographyStyle &ys,
33 const std::shared_ptr<FontProviders> &fontProviders)
34 {
35 ScopedTrace scope("TextBreaker::WordBreak");
36 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "WordBreak");
37 std::vector<VariantSpan> visitingSpans;
38 std::swap(visitingSpans, spans);
39 for (const auto &vspan : visitingSpans) {
40 auto span = vspan.TryToTextSpan();
41 if (span == nullptr) {
42 spans.push_back(vspan);
43 continue;
44 }
45
46 auto xs = vspan.GetTextStyle();
47 auto fontCollection = GenerateFontCollection(ys, xs, fontProviders);
48 if (fontCollection == nullptr) {
49 // WordBreak failed
50 return 1;
51 }
52
53 CharGroups cgs;
54 std::vector<Boundary> boundaries;
55 auto ret = Measure(xs, span->u16vect_, *fontCollection, cgs, boundaries);
56 if (ret) {
57 return 1;
58 }
59
60 LOGSCOPED(sl2, LOGEX_FUNC_LINE_DEBUG(), "TextBreaker::doWordBreak algo");
61 preBreak_ = 0;
62 postBreak_ = 0;
63 for (auto &[start, end] : boundaries) {
64 const auto &wordcgs = cgs.GetSubFromU16RangeAll(start, end);
65 std::stringstream ss;
66 ss << "u16range: [" << start << ", " << end << "), range: " << wordcgs.GetRange();
67 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), ss.str());
68 BreakWord(wordcgs, ys, xs, spans);
69 }
70 }
71 // WordBreak successed
72 return 0;
73 }
74
GenerateFontCollection(const TypographyStyle & ys,const TextStyle & xs,const std::shared_ptr<FontProviders> & fontProviders)75 std::shared_ptr<FontCollection> TextBreaker::GenerateFontCollection(const TypographyStyle &ys,
76 const TextStyle &xs, const std::shared_ptr<FontProviders> &fontProviders) noexcept(false)
77 {
78 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "TextBreaker::GenerateFontCollection");
79 auto families = xs.fontFamilies;
80 if (families.empty()) {
81 families = ys.fontFamilies;
82 }
83
84 if (fontProviders == nullptr) {
85 LOGEX_FUNC_LINE(ERROR) << "fontProviders is nullptr";
86 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
87 }
88
89 return fontProviders->GenerateFontCollection(families);
90 }
91
Measure(const TextStyle & xs,const std::vector<uint16_t> & u16vect,const FontCollection & fontCollection,CharGroups & cgs,std::vector<Boundary> & boundaries)92 int TextBreaker::Measure(const TextStyle &xs, const std::vector<uint16_t> &u16vect,
93 const FontCollection &fontCollection, CharGroups &cgs, std::vector<Boundary> &boundaries) noexcept(false)
94 {
95 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "TextBreaker::doMeasure");
96 auto measurer = Measurer::Create(u16vect, fontCollection);
97 if (measurer == nullptr) {
98 LOGEX_FUNC_LINE(ERROR) << "Measurer::Create return nullptr";
99 throw TEXGINE_EXCEPTION(API_FAILED);
100 }
101
102 measurer->SetLocale(xs.locale);
103 measurer->SetRTL(false);
104 measurer->SetSize(xs.fontSize);
105 FontStyles style(xs.fontWeight, xs.fontStyle);
106 measurer->SetFontStyle(style);
107 measurer->SetRange(0, u16vect.size());
108 measurer->SetSpacing(xs.letterSpacing, xs.wordSpacing);
109 auto ret = measurer->Measure(cgs);
110 if (ret != 0) {
111 LOGEX_FUNC_LINE(ERROR) << "Measure failed!";
112 return ret;
113 }
114 boundaries = measurer->GetWordBoundary();
115 if (boundaries.size() == 0) {
116 LOGEX_FUNC_LINE(ERROR) << "Measurer GetWordBoundary failed!";
117 return 1;
118 }
119 return 0;
120 }
121
BreakWord(const CharGroups & wordcgs,const TypographyStyle & ys,const TextStyle & xs,std::vector<VariantSpan> & spans)122 void TextBreaker::BreakWord(const CharGroups &wordcgs, const TypographyStyle &ys,
123 const TextStyle &xs, std::vector<VariantSpan> &spans)
124 {
125 size_t rangeOffset = 0;
126 for (size_t i = 0; i < wordcgs.GetNumberOfCharGroup(); i++) {
127 const auto &cg = wordcgs.Get(i);
128 postBreak_ += cg.GetWidth();
129 if (u_isWhitespace(cg.chars[0]) == 0) {
130 // not white space
131 preBreak_ = postBreak_;
132 }
133
134 LOGEX_FUNC_LINE_DEBUG() << "Now: [" << i << "] '" << TextConverter::ToStr(cg.chars) << "'"
135 << " preBreak_: " << preBreak_ << ", postBreak_: " << postBreak_;
136
137 const auto &breakType = ys.wordBreakType;
138 bool isBreakAll = (breakType == WordBreakType::BREAK_ALL);
139 bool isBreakWord = (breakType == WordBreakType::BREAK_WORD);
140 bool isFinalCharGroup = (i == wordcgs.GetNumberOfCharGroup() - 1);
141 bool needGenerateSpan = isBreakAll;
142 needGenerateSpan = needGenerateSpan || (isBreakWord && isFinalCharGroup);
143 if (needGenerateSpan == false) {
144 continue;
145 }
146
147 auto currentCgs = wordcgs.GetSub(rangeOffset, i + 1);
148 GenerateSpan(currentCgs, ys, xs, spans);
149 rangeOffset = i + 1;
150 }
151 }
152
GenerateSpan(const CharGroups & currentCgs,const TypographyStyle & ys,const TextStyle & xs,std::vector<VariantSpan> & spans)153 void TextBreaker::GenerateSpan(const CharGroups ¤tCgs, const TypographyStyle &ys,
154 const TextStyle &xs, std::vector<VariantSpan> &spans)
155 {
156 if (!currentCgs.IsValid() || currentCgs.GetSize() == 0) {
157 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
158 }
159
160 LOGEX_FUNC_LINE_DEBUG(Logger::SetToNoReturn) << "AddWord " << spans.size()
161 << " " << currentCgs.GetRange() << ": \033[40m'";
162 LOGCEX_DEBUG() << TextConverter::ToStr(currentCgs.ToUTF16()) << "'\033[0m";
163 auto newSpan = std::make_shared<TextSpan>();
164 newSpan->cgs_ = currentCgs;
165 newSpan->postBreak_ = postBreak_;
166 newSpan->preBreak_ = preBreak_;
167 newSpan->typeface_ = currentCgs.Get(0).typeface;
168
169 for ([[maybe_unused]] const auto &cg : currentCgs) {
170 assert(cg.typeface == newSpan->typeface_);
171 }
172 VariantSpan vs(newSpan);
173 vs.SetTextStyle(xs);
174 spans.push_back(vs);
175 }
176 } // namespace TextEngine
177 } // namespace Rosen
178 } // namespace OHOS
179