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 "bidi_processer.h"
17 #include <unicode/ubidi.h>
18
19 #include "texgine_exception.h"
20 #include "texgine/utils/exlog.h"
21 #include "texgine/utils/trace.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 namespace TextEngine {
ProcessBidiText(const std::vector<VariantSpan> & spans,const TextDirection dir)26 std::vector<VariantSpan> BidiProcesser::ProcessBidiText(const std::vector<VariantSpan> &spans, const TextDirection dir)
27 {
28 ScopedTrace scope("BidiProcesser::ProcessBidiText");
29 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "ProcessBidiText");
30 std::vector<VariantSpan> newSpans;
31 for (auto const &span : spans) {
32 auto ts = span.TryToTextSpan();
33 if (ts == nullptr) {
34 newSpans.push_back(span);
35 continue;
36 }
37
38 span.Dump();
39 auto nsis = DoBidiProcess(ts->cgs_, dir);
40 for (auto const &nsi : nsis) {
41 ts->rtl_ = nsi.rtl;
42 VariantSpan vs(ts->CloneWithCharGroups(nsi.cgs));
43 vs.SetTextStyle(span.GetTextStyle());
44 newSpans.push_back(vs);
45 }
46 }
47
48 return newSpans;
49 }
50
DoBidiProcess(const CharGroups & cgs,const TextDirection dir)51 std::vector<NewSpanInfo> BidiProcesser::DoBidiProcess(const CharGroups &cgs, const TextDirection dir)
52 {
53 LOGSCOPED(sl, LOGEX_FUNC_LINE_DEBUG(), "BidiProcesser::doBidiProcess");
54 if (!cgs.IsValid() || cgs.GetSize() == 0) {
55 throw TEXGINE_EXCEPTION(INVALID_ARGUMENT);
56 }
57
58 auto deleter = [](UBiDi *p) {ubidi_close(p);};
59 std::unique_ptr<UBiDi, decltype(deleter)> bidi(ubidi_open(), deleter);
60 if (bidi == nullptr) {
61 throw APIFailedException("ubidi_open is failed");
62 }
63
64 auto u16vect = cgs.ToUTF16All();
65 auto status = U_ZERO_ERROR;
66 auto level = dir == TextDirection::RTL ? UBIDI_RTL : UBIDI_LTR;
67 ubidi_setPara(bidi.get(), reinterpret_cast<UChar *>(u16vect.data()),
68 u16vect.size(), level, nullptr, &status);
69 if (!U_SUCCESS(status)) {
70 throw APIFailedException("ubidi_setPara failed");
71 }
72
73 int size = ubidi_countRuns(bidi.get(), &status);
74 std::vector<NewSpanInfo> nsis;
75 for (auto i = 0; i < size; i++) {
76 NewSpanInfo nsi;
77 int start = -1;
78 int length = -1;
79 nsi.rtl = (ubidi_getVisualRun(bidi.get(), i, &start, &length) == UBIDI_RTL);
80 if (start < 0 || length < 0) {
81 throw APIFailedException("ubidi_getVisualRun is failed");
82 }
83
84 auto cc = cgs.GetSubFromU16RangeAll(start, start + length);
85 LOGEX_FUNC_LINE_DEBUG(Logger::SetToNoReturn) <<
86 "u16[" << start << ", " << start + length << ")" <<
87 " is " << (nsi.rtl ? "rtl" : "ltr") << " ";
88 if (cgs.IsIntersect(cc) == false) {
89 LOGCEX_DEBUG() << "not intersect";
90 continue;
91 }
92
93 auto ic = cgs.GetIntersect(cc);
94 LOGCEX_DEBUG() << "intersect at cgs" << ic.GetRange();
95 nsi.cgs = ic;
96 nsis.push_back(nsi);
97 }
98 return nsis;
99 }
100 } // namespace TextEngine
101 } // namespace Rosen
102 } // namespace OHOS
103