1 /*
2 * Copyright (c) 2025 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 <codecvt>
17 #include <cstdint>
18
19 #include "ani_common.h"
20 #include "ani_line_metrics_converter.h"
21 #include "ani_paragraph.h"
22 #include "ani_text_utils.h"
23 #include "canvas_ani/ani_canvas.h"
24 #include "font_collection.h"
25 #include "text/font_metrics.h"
26 #include "typography.h"
27 #include "typography_create.h"
28 #include "utils/text_log.h"
29
30 namespace OHOS::Text::ANI {
31 using namespace OHOS::Rosen;
SetTypography(ani_env * env,std::unique_ptr<OHOS::Rosen::Typography> & typography)32 ani_object AniParagraph::SetTypography(ani_env* env, std::unique_ptr<OHOS::Rosen::Typography>& typography)
33 {
34 ani_object pargraphObj = AniTextUtils::CreateAniObject(env, ANI_CLASS_PARAGRAPH, ":V");
35 Typography* typographyPtr = typography.release();
36 ani_status ret =
37 env->Object_SetFieldByName_Long(pargraphObj, "nativeObj", reinterpret_cast<ani_long>(typographyPtr));
38 if (ret != ANI_OK) {
39 TEXT_LOGE("Failed to create ani Paragraph obj");
40 delete typographyPtr;
41 typographyPtr = nullptr;
42 return AniTextUtils::CreateAniUndefined(env);
43 }
44 return pargraphObj;
45 }
46
AniInit(ani_vm * vm,uint32_t * result)47 ani_status AniParagraph::AniInit(ani_vm* vm, uint32_t* result)
48 {
49 ani_env* env;
50 ani_status ret = vm->GetEnv(ANI_VERSION_1, &env);
51 if (ret != ANI_OK) {
52 TEXT_LOGE("null env, ret %{public}d", ret);
53 return ANI_NOT_FOUND;
54 }
55
56 ani_class cls = nullptr;
57 ret = env->FindClass(ANI_CLASS_PARAGRAPH, &cls);
58 if (ret != ANI_OK) {
59 TEXT_LOGE("Failed to find class, ret %{public}d", ret);
60 return ANI_NOT_FOUND;
61 }
62
63 std::string paintSignature = std::string(ANI_CLASS_CANVAS) + "DD:V";
64 std::string paintOnPathSignature = std::string(ANI_CLASS_CANVAS) + std::string(ANI_CLASS_PATH) + "DD:V";
65 std::array methods = {
66 ani_native_function{"layoutSync", "D:V", reinterpret_cast<void*>(LayoutSync)},
67 ani_native_function{"paint", paintSignature.c_str(), reinterpret_cast<void*>(Paint)},
68 ani_native_function{"paintOnPath", paintOnPathSignature.c_str(), reinterpret_cast<void*>(PaintOnPath)},
69 ani_native_function{"getLongestLine", ":D", reinterpret_cast<void*>(GetLongestLine)},
70 ani_native_function{"getLineMetrics", ":Lescompat/Array;", reinterpret_cast<void*>(GetLineMetrics)},
71 ani_native_function{"nativeGetLineMetricsAt", "D:L@ohos/graphics/text/text/LineMetrics;",
72 reinterpret_cast<void*>(GetLineMetricsAt)},
73 };
74
75 ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
76 if (ret != ANI_OK) {
77 TEXT_LOGE("Failed to bind methods, ret %{public}d", ret);
78 return ANI_NOT_FOUND;
79 }
80 return ANI_OK;
81 }
82
LayoutSync(ani_env * env,ani_object object,ani_double width)83 void AniParagraph::LayoutSync(ani_env* env, ani_object object, ani_double width)
84 {
85 Typography* typography = AniTextUtils::GetNativeFromObj<Typography>(env, object);
86 if (typography == nullptr) {
87 TEXT_LOGE("Paragraph is null");
88 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
89 return;
90 }
91 typography->Layout(width);
92 }
93
Paint(ani_env * env,ani_object object,ani_object canvas,ani_double x,ani_double y)94 void AniParagraph::Paint(ani_env* env, ani_object object, ani_object canvas, ani_double x, ani_double y)
95 {
96 Typography* typography = AniTextUtils::GetNativeFromObj<Typography>(env, object);
97 if (typography == nullptr) {
98 TEXT_LOGE("Paragraph is null");
99 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
100 return;
101 }
102 Drawing::AniCanvas* aniCanvas = AniTextUtils::GetNativeFromObj<Drawing::AniCanvas>(env, canvas);
103 if (aniCanvas == nullptr || aniCanvas->GetCanvas() == nullptr) {
104 TEXT_LOGE("Canvas is null");
105 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "canvas unavailable.");
106 return;
107 }
108 typography->Paint(aniCanvas->GetCanvas(), x, y);
109 }
110
PaintOnPath(ani_env * env,ani_object object,ani_object canvas,ani_object path,ani_double hOffset,ani_double vOffset)111 void AniParagraph::PaintOnPath(
112 ani_env* env, ani_object object, ani_object canvas, ani_object path, ani_double hOffset, ani_double vOffset)
113 {
114 Typography* typography = AniTextUtils::GetNativeFromObj<Typography>(env, object);
115 if (typography == nullptr) {
116 TEXT_LOGE("Paragraph is null");
117 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
118 return;
119 }
120 Drawing::AniCanvas* aniCanvas = AniTextUtils::GetNativeFromObj<Drawing::AniCanvas>(env, canvas);
121 if (aniCanvas == nullptr || aniCanvas->GetCanvas() == nullptr) {
122 TEXT_LOGE("Canvas is null");
123 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Canvas unavailable.");
124 return;
125 }
126 Drawing::Path* pathInternal = AniTextUtils::GetNativeFromObj<Drawing::Path>(env, path);
127 if (pathInternal == nullptr) {
128 TEXT_LOGE("Path is null");
129 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Path unavailable.");
130 return;
131 }
132 typography->Paint(aniCanvas->GetCanvas(), pathInternal, hOffset, vOffset);
133 }
134
GetLongestLine(ani_env * env,ani_object object)135 ani_double AniParagraph::GetLongestLine(ani_env* env, ani_object object)
136 {
137 Typography* typography = AniTextUtils::GetNativeFromObj<Typography>(env, object);
138 if (typography == nullptr) {
139 TEXT_LOGE("Paragraph is null");
140 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
141 return 0;
142 }
143 return typography->GetActualWidth();
144 }
145
GetLineMetrics(ani_env * env,ani_object object)146 ani_ref AniParagraph::GetLineMetrics(ani_env* env, ani_object object)
147 {
148 ani_object arrayObj = AniTextUtils::CreateAniUndefined(env);
149 Typography* typography = AniTextUtils::GetNativeFromObj<Typography>(env, object);
150 if (typography == nullptr) {
151 TEXT_LOGE("Paragraph is null");
152 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
153 return arrayObj;
154 }
155 std::vector<LineMetrics> vectorLineMetrics = typography->GetLineMetrics();
156 arrayObj = AniTextUtils::CreateAniArray(env, vectorLineMetrics.size());
157 ani_boolean isUndefined;
158 env->Reference_IsUndefined(arrayObj, &isUndefined);
159 if (isUndefined) {
160 TEXT_LOGE("Failed to Create arrayObject");
161 return arrayObj;
162 }
163 ani_size index = 0;
164 for (const auto& lineMetrics : vectorLineMetrics) {
165 ani_object aniObj = AniLineMetricsConverter::ParseLineMetricsToAni(env, lineMetrics);
166 ani_status ret = env->Object_CallMethodByName_Void(arrayObj, "$_set", "ILstd/core/Object;:V", index, aniObj);
167 if (ret != ANI_OK) {
168 TEXT_LOGE("Failed to set lineMetrics item");
169 continue;
170 }
171 index++;
172 }
173 return arrayObj;
174 }
175
GetLineMetricsAt(ani_env * env,ani_object object,ani_double lineNumber)176 ani_object AniParagraph::GetLineMetricsAt(ani_env* env, ani_object object, ani_double lineNumber)
177 {
178 Typography* typography = AniTextUtils::GetNativeFromObj<Typography>(env, object);
179 if (typography == nullptr) {
180 TEXT_LOGE("Paragraph is null");
181 AniTextUtils::ThrowBusinessError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
182 return AniTextUtils::CreateAniUndefined(env);
183 }
184 LineMetrics lineMetrics;
185 if (!typography->GetLineMetricsAt(lineNumber, &lineMetrics)) {
186 TEXT_LOGE("Failed to get line metrics");
187 return AniTextUtils::CreateAniUndefined(env);
188 }
189 return AniLineMetricsConverter::ParseLineMetricsToAni(env, lineMetrics);
190 }
191 } // namespace OHOS::Text::ANI