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 "char_groups.h"
17
18 #include <algorithm>
19 #include <cassert>
20
21 #include "texgine/utils/exlog.h"
22 #include "texgine_exception.h"
23
24 namespace OHOS {
25 namespace Rosen {
26 namespace TextEngine {
operator <<(std::ostream & os,const struct IndexRange & range)27 std::ostream &operator<<(std::ostream &os, const struct IndexRange &range)
28 {
29 os << "[" << range.start << ", " << range.end << ")";
30 return os;
31 }
32
CreateEmpty()33 CharGroups CharGroups::CreateEmpty()
34 {
35 CharGroups cgs;
36 cgs.pcgs_ = std::make_shared<std::vector<struct CharGroup>>();
37 cgs.range_ = {0, 0};
38 return cgs;
39 }
40
CreateWithInvalidRange(IndexRange range)41 CharGroups CharGroups::CreateWithInvalidRange(IndexRange range)
42 {
43 CharGroups cgs = CreateEmpty();
44 cgs.range_ = range;
45 return cgs;
46 }
47
GetNumberOfGlyph() const48 size_t CharGroups::GetNumberOfGlyph() const
49 {
50 if (!IsValid()) {
51 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
52 }
53
54 size_t sum = 0;
55 for (auto i = range_.start; i < range_.end; i++) {
56 sum += pcgs_->at(i).glyphs.size();
57 }
58 return sum;
59 }
60
GetNumberOfCharGroup() const61 size_t CharGroups::GetNumberOfCharGroup() const
62 {
63 if (!IsValid()) {
64 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
65 }
66
67 return range_.end - range_.start;
68 }
69
GetRange() const70 const IndexRange &CharGroups::GetRange() const
71 {
72 return range_;
73 }
74
GetBack() const75 CharGroup &CharGroups::GetBack() const
76 {
77 if (!IsValid()) {
78 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
79 }
80
81 if (GetSize() == 0) {
82 throw TEXGINE_EXCEPTION(OUT_OF_RANGE);
83 }
84
85 return *(pcgs_->begin() + range_.end - 1);
86 }
87
GetSize() const88 size_t CharGroups::GetSize() const
89 {
90 if (!IsValid()) {
91 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
92 }
93
94 return pcgs_->size();
95 }
96
IsValid() const97 bool CharGroups::IsValid() const
98 {
99 if (pcgs_ == nullptr) {
100 return false;
101 }
102
103 if (range_.start > range_.end || range_.start < 0 || range_.end < 0 ||
104 range_.end > static_cast<int>(pcgs_->size()) || range_.start > static_cast<int>(pcgs_->size())) {
105 return false;
106 }
107
108 return true;
109 }
110
IsSameCharGroups(const CharGroups & right) const111 bool CharGroups::IsSameCharGroups(const CharGroups &right) const
112 {
113 return pcgs_ == right.pcgs_;
114 }
115
IsIntersect(const CharGroups & right) const116 bool CharGroups::IsIntersect(const CharGroups &right) const
117 {
118 if (!IsValid()) {
119 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
120 }
121
122 try {
123 if (!right.IsValid()) {
124 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
125 }
126 } catch(const struct TexgineException &err) {
127 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
128 }
129
130 if (pcgs_ != right.pcgs_) {
131 return false;
132 }
133
134 return range_.start < right.range_.end && right.range_.start < range_.end;
135 }
136
GetSplit(const int & index) const137 CharGroupsPair CharGroups::GetSplit(const int &index) const
138 {
139 if (index < 0) {
140 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
141 }
142
143 return GetSplitAll(index + range_.start);
144 }
145
GetSplitAll(const int & index) const146 CharGroupsPair CharGroups::GetSplitAll(const int &index) const
147 {
148 if (!IsValid()) {
149 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
150 }
151
152 if (index <= range_.start || index >= range_.end) {
153 throw TEXGINE_EXCEPTION(OUT_OF_RANGE);
154 }
155 CharGroupsPair retval;
156 retval[0] = *this;
157 retval[0].range_.end = index;
158 retval[1] = *this;
159 retval[1].range_.start = index;
160 return retval;
161 }
162
GetSub(const int & start,const int & end) const163 CharGroups CharGroups::GetSub(const int &start, const int &end) const
164 {
165 if (!(0 <= start && start <= end)) {
166 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
167 }
168
169 return GetSubAll(start + range_.start, end + range_.start);
170 }
171
GetSubAll(const int & start,const int & end) const172 CharGroups CharGroups::GetSubAll(const int &start, const int &end) const
173 {
174 if (!IsValid()) {
175 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
176 }
177
178 if (!(0 <= start && start <= end && end <= static_cast<int>(GetSize()))) {
179 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
180 }
181
182 CharGroups cgs = *this;
183 cgs.range_ = {start, end};
184 return cgs;
185 }
186
GetSubFromU16RangeAll(const int & u16start,const int & u16end) const187 CharGroups CharGroups::GetSubFromU16RangeAll(const int &u16start, const int &u16end) const
188 {
189 if (!IsValid()) {
190 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
191 }
192
193 if (!(0 <= u16start && u16start <= u16end)) {
194 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
195 }
196
197 size_t sum = 0;
198 int startIndex = 0;
199 int endIndex = 1e9;
200 for (int i = -1; i <= static_cast<int>(pcgs_->size()); i++) {
201 if (static_cast<int>(sum) <= u16start) {
202 startIndex = std::max(startIndex, i);
203 }
204
205 if (0 <= i && i < static_cast<int>(pcgs_->size())) {
206 sum += pcgs_->at(i).chars.size();
207 }
208
209 if (static_cast<int>(sum) >= u16end) {
210 endIndex = std::min(endIndex, i);
211 }
212 }
213
214 return GetSubAll(startIndex, endIndex + 1);
215 }
216
GetIntersect(const CharGroups & right) const217 CharGroups CharGroups::GetIntersect(const CharGroups &right) const
218 {
219 if (!IsValid()) {
220 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
221 }
222
223 try {
224 if (!right.IsValid()) {
225 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
226 }
227 } catch(const TexgineException &err) {
228 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
229 }
230
231 if (!IsIntersect(right)) {
232 throw CustomException("these two cgs is not intersect");
233 }
234
235 CharGroups retval = *this;
236 retval.range_.start = std::max(range_.start, right.range_.start);
237 retval.range_.end = std::min(range_.end, right.range_.end);
238 return retval;
239 }
240
Get(const int32_t & index) const241 struct CharGroup &CharGroups::Get(const int32_t &index) const
242 {
243 if (index < 0) {
244 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
245 }
246
247 return GetAll(index + range_.start);
248 }
249
GetAll(const int32_t & index) const250 struct CharGroup &CharGroups::GetAll(const int32_t &index) const
251 {
252 if (!IsValid()) {
253 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
254 }
255
256 if (!(0 <= index && index < static_cast<int>(GetSize()))) {
257 throw TEXGINE_EXCEPTION(OUT_OF_RANGE);
258 }
259
260 return pcgs_->at(index);
261 }
262
ToUTF16() const263 std::vector<uint16_t> CharGroups::ToUTF16() const
264 {
265 if (!IsValid()) {
266 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
267 }
268
269 std::vector<uint16_t> u16;
270 for (auto i = range_.start; i < range_.end; i++) {
271 u16.insert(u16.end(), pcgs_->at(i).chars.begin(), pcgs_->at(i).chars.end());
272 }
273
274 return u16;
275 }
276
ToUTF16All() const277 std::vector<uint16_t> CharGroups::ToUTF16All() const
278 {
279 if (!IsValid()) {
280 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
281 }
282
283 std::vector<uint16_t> u16;
284 for (const auto &cg : *pcgs_) {
285 u16.insert(u16.end(), cg.chars.begin(), cg.chars.end());
286 }
287
288 return u16;
289 }
290
begin() const291 std::vector<struct CharGroup>::iterator CharGroups::begin() const
292 {
293 if (!IsValid()) {
294 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
295 }
296
297 return pcgs_->begin() + range_.start;
298 }
299
end() const300 std::vector<struct CharGroup>::iterator CharGroups::end() const
301 {
302 if (!IsValid()) {
303 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
304 }
305
306 return pcgs_->begin() + range_.end;
307 }
308
Clone() const309 CharGroups CharGroups::Clone() const
310 {
311 if (!IsValid()) {
312 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
313 }
314
315 auto ret = CharGroups::CreateEmpty();
316 *ret.pcgs_ = *pcgs_;
317 ret.range_ = range_;
318 return ret;
319 }
320
Merge(const CharGroups & right)321 void CharGroups::Merge(const CharGroups &right)
322 {
323 if (!IsValid()) {
324 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
325 }
326
327 try {
328 if (!right.IsValid()) {
329 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
330 }
331 } catch(const struct TexgineException &err) {
332 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
333 }
334
335 if (range_.end != right.range_.start) {
336 LOGEX_FUNC_LINE(ERROR) << "the right start not equal this end";
337 return;
338 }
339
340 range_.end += right.range_.end - right.range_.start;
341 }
342
PushBack(const struct CharGroup & cg)343 void CharGroups::PushBack(const struct CharGroup &cg)
344 {
345 if (!IsValid()) {
346 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
347 }
348
349 if (!(range_.start == 0 && range_.end == static_cast<int>(pcgs_->size()))) {
350 throw CustomException("incomplete CharGroups cannot revert");
351 }
352
353 pcgs_->push_back(cg);
354 range_.end++;
355 }
356
ReverseAll()357 void CharGroups::ReverseAll()
358 {
359 if (!IsValid()) {
360 throw TEXGINE_EXCEPTION(INVALID_CHAR_GROUPS);
361 }
362
363 if (!(range_.start == 0 && range_.end == static_cast<int>(pcgs_->size()))) {
364 throw CustomException("incomplete CharGroups cannot revert");
365 }
366
367 std::reverse(pcgs_->begin(), pcgs_->end());
368 }
369
CheckCodePoint() const370 bool CharGroups::CheckCodePoint() const
371 {
372 if (!GetSize()) {
373 return false;
374 }
375 for (auto &charGroup : *pcgs_) {
376 if (!charGroup.CheckCodePoint()) {
377 return false;
378 }
379 }
380 return true;
381 };
382
GetTypefaceName()383 std::string CharGroups::GetTypefaceName()
384 {
385 if (!IsValid()) {
386 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is null";
387 return "";
388 }
389
390 return (*pcgs_)[0].typeface->GetName();
391 }
392
GetAllCharWidth() const393 double CharGroups::GetAllCharWidth() const
394 {
395 double allCharWidth = 0.0;
396 if (!GetSize()) {
397 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is empty";
398 return allCharWidth;
399 }
400
401 for (const auto &charGroup : *pcgs_) {
402 allCharWidth += charGroup.GetWidth();
403 }
404 return allCharWidth;
405 }
406
GetCharWidth(const size_t index) const407 double CharGroups::GetCharWidth(const size_t index) const
408 {
409 if (!IsValid()) {
410 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is null";
411 return 0.0;
412 }
413 // size - 1 means last index of the array
414 if (index > (pcgs_->size() - 1)) {
415 LOGEX_FUNC_LINE(ERROR) << "the index is out of range, index = " << index << " pcgs_ size = " << pcgs_->size();
416 return 0.0;
417 }
418 return pcgs_->at(index).GetWidth();
419 }
420
GetCharsToU16(size_t start,size_t end,const SpacesModel & spacesModel)421 std::vector<uint16_t> CharGroups::GetCharsToU16(size_t start, size_t end, const SpacesModel &spacesModel)
422 {
423 if (pcgs_ == nullptr) {
424 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is null";
425 return {};
426 }
427 // size - 1 means last index of the array
428 size_t maxIndex = pcgs_->size() - 1;
429 if ((start > end) || (start > maxIndex) || (end > maxIndex)) {
430 LOGEX_FUNC_LINE(ERROR) << "invalid parameter, start = " << start <<
431 " end = " << end << " size = " << pcgs_->size();
432 return {};
433 }
434
435 switch (spacesModel) {
436 case SpacesModel::NORMAL:
437 break;
438 case SpacesModel::LEFT: {
439 if (!pcgs_->at(end).chars.empty() && u_isspace(pcgs_->at(end).chars.back())) {
440 pcgs_->at(end).chars.pop_back();
441 }
442 if (pcgs_->at(end).chars.empty()) {
443 end--;
444 }
445 break;
446 }
447 case SpacesModel::RIGHT: {
448 if (!pcgs_->at(start).chars.empty() && u_isspace(pcgs_->at(start).chars.front())) {
449 pcgs_->at(start).chars.erase(pcgs_->at(start).chars.begin());
450 }
451 if (pcgs_->at(start).chars.empty()) {
452 start++;
453 }
454 break;
455 }
456 default:
457 break;
458 }
459
460 std::vector<uint16_t> charData;
461 for (; start <= end; start++) {
462 charData.insert(charData.end(), pcgs_->at(start).chars.begin(), pcgs_->at(start).chars.end());
463 }
464 return charData;
465 }
466
IsSingleWord() const467 bool CharGroups::IsSingleWord() const
468 {
469 if (!IsValid()) {
470 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is null";
471 return false;
472 }
473 bool isSingleWord = true;
474 for (const auto &charGroup : *pcgs_) {
475 if (charGroup.HasWhitesSpace()) {
476 isSingleWord = false;
477 break;
478 }
479 }
480 return isSingleWord;
481 }
482
JudgeOnlyHardBreak() const483 bool CharGroups::JudgeOnlyHardBreak() const
484 {
485 if (!IsValid()) {
486 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is null";
487 return false;
488 }
489 bool onlyHardBreak = true;
490 for (auto i = range_.start; i < range_.end; i++) {
491 onlyHardBreak = pcgs_->at(i).JudgeOnlyHardBreak();
492 if (!onlyHardBreak) {
493 break;
494 }
495 }
496 return onlyHardBreak;
497 }
498
FindHardBreakPos() const499 int CharGroups::FindHardBreakPos() const
500 {
501 if (!IsValid()) {
502 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is null";
503 return -1;
504 }
505 int breakPos = -1;
506 for (auto i = range_.start; i < range_.end; i++) {
507 if (pcgs_->at(i).HasHardBreak()) {
508 breakPos = i;
509 break;
510 }
511 }
512 return breakPos;
513 }
514
GetSubCharsToU16(const int start,const int end)515 std::vector<uint16_t> CharGroups::GetSubCharsToU16(const int start, const int end)
516 {
517 if (!IsValid()) {
518 LOGEX_FUNC_LINE(ERROR) << "pcgs_ is null";
519 return {};
520 }
521 if ((start < range_.start) || (start >= range_.end) ||
522 (end < range_.start) || (end >= range_.end) || (start > end)) {
523 LOGEX_FUNC_LINE(ERROR) << "invalid parameter, start = " << start <<
524 " end = " << end << " range_.start = " << range_.start << " range_.end = " << range_.end;
525 return {};
526 }
527
528 std::vector<uint16_t> charData;
529 for (auto i = start; i <= end; i++) {
530 charData.insert(charData.end(), pcgs_->at(i).chars.begin(), pcgs_->at(i).chars.end());
531 }
532 return charData;
533 }
534 } // namespace TextEngine
535 } // namespace Rosen
536 } // namespace OHOS
537