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