• 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 "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 &currentCgs, 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