1
2 /*
3 * Copyright (c) 2024 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "drawing_text_line.h"
18
19 #include <string>
20
21 #include "array_mgr.h"
22 #include "drawing_rect.h"
23 #include "skia_txt/run_impl.h"
24 #include "skia_txt/text_line_base.h"
25 #include "skia/txt/paragraph.h"
26 #include "utils/text_log.h"
27
28 using namespace OHOS::Rosen;
29
30 typedef OHOS::Rosen::AdapterTxt::TextLineBaseImpl LineImpl;
31 typedef OHOS::Rosen::AdapterTxt::RunImpl RunImpl;
32
OH_Drawing_TypographyGetTextLines(OH_Drawing_Typography * typography)33 OH_Drawing_Array* OH_Drawing_TypographyGetTextLines(OH_Drawing_Typography* typography)
34 {
35 if (typography == nullptr) {
36 TEXT_LOGE("Null typography");
37 return nullptr;
38 }
39
40 auto paragraph = reinterpret_cast<Typography*>(typography)->GetParagraph();
41 if (paragraph == nullptr) {
42 TEXT_LOGE("Failed to get paragraph");
43 return nullptr;
44 }
45
46 auto textLines = reinterpret_cast<SPText::Paragraph*>(paragraph)->GetTextLines();
47 if (textLines.size() == 0) {
48 TEXT_LOGE("Failed to get text lines");
49 return nullptr;
50 }
51
52 LineObject* lineObjectArr = new (std::nothrow) LineObject[textLines.size()];
53 if (lineObjectArr == nullptr) {
54 TEXT_LOGE("Failed to create line object");
55 return nullptr;
56 }
57 for (size_t i = 0; i < textLines.size(); ++i) {
58 auto textLine = new (std::nothrow) LineImpl(std::move(textLines[i]));
59 if (textLine == nullptr) {
60 TEXT_LOGE("Failed to create line impl");
61 for (size_t j = 0; j < i; ++j) {
62 delete reinterpret_cast<LineImpl*>(lineObjectArr[j].line);
63 lineObjectArr[j].line = nullptr;
64 }
65 delete[] lineObjectArr;
66 return nullptr;
67 }
68
69 lineObjectArr[i].line = reinterpret_cast<void*>(textLine);
70 lineObjectArr[i].isArray = true;
71 }
72
73 ObjectArray* array = new (std::nothrow) ObjectArray();
74 if (array == nullptr) {
75 TEXT_LOGE("Failed to create array");
76 for (size_t i = 0; i < textLines.size(); ++i) {
77 delete reinterpret_cast<LineImpl*>(lineObjectArr[i].line);
78 }
79 delete[] lineObjectArr;
80 return nullptr;
81 }
82 array->addr = lineObjectArr;
83 array->num = textLines.size();
84 array->type = TEXT_LINE;
85
86 return reinterpret_cast<OH_Drawing_Array*>(array);
87 }
88
OH_Drawing_DestroyTextLines(OH_Drawing_Array * lines)89 void OH_Drawing_DestroyTextLines(OH_Drawing_Array* lines)
90 {
91 if (lines == nullptr) {
92 TEXT_LOGE("Null lines");
93 return;
94 }
95
96 auto arrayLines = reinterpret_cast<ObjectArray*>(lines);
97 if (arrayLines != nullptr && arrayLines->type == TEXT_LINE && arrayLines->num > 0) {
98 LineObject* lineObjectArr = reinterpret_cast<LineObject*>(arrayLines->addr);
99 if (lineObjectArr != nullptr) {
100 for (size_t i = 0; i < arrayLines->num; ++i) {
101 delete reinterpret_cast<LineImpl*>(lineObjectArr[i].line);
102 lineObjectArr[i].line = nullptr;
103 }
104 delete[] lineObjectArr;
105 arrayLines->addr = nullptr;
106 }
107 arrayLines->num = 0;
108 arrayLines->type = INVALID;
109 delete arrayLines;
110 }
111 }
112
OH_Drawing_DestroyTextLine(OH_Drawing_TextLine * line)113 void OH_Drawing_DestroyTextLine(OH_Drawing_TextLine* line)
114 {
115 if (line == nullptr) {
116 TEXT_LOGE("Null line");
117 return;
118 }
119
120 LineObject* lineObject = reinterpret_cast<LineObject*>(line);
121 if (!lineObject->isArray) {
122 delete reinterpret_cast<LineImpl*>(lineObject->line);
123 lineObject->line = nullptr;
124 delete lineObject;
125 }
126 }
127
OH_Drawing_GetTextLineByIndex(OH_Drawing_Array * lines,size_t index)128 OH_Drawing_TextLine* OH_Drawing_GetTextLineByIndex(OH_Drawing_Array* lines, size_t index)
129 {
130 if (lines == nullptr) {
131 TEXT_LOGE("Null lines");
132 return nullptr;
133 }
134
135 auto arrayLines = reinterpret_cast<ObjectArray*>(lines);
136 if (arrayLines != nullptr && arrayLines->addr != nullptr &&
137 arrayLines->type == TEXT_LINE && index < arrayLines->num) {
138 LineObject* lineObjectArr = reinterpret_cast<LineObject*>(arrayLines->addr);
139 return reinterpret_cast<OH_Drawing_TextLine*>(&lineObjectArr[index]);
140 }
141
142 return nullptr;
143 }
144
OH_Drawing_TextLineGetGlyphCount(OH_Drawing_TextLine * line)145 double OH_Drawing_TextLineGetGlyphCount(OH_Drawing_TextLine* line)
146 {
147 if (line == nullptr) {
148 TEXT_LOGE("Null line");
149 return 0.0;
150 }
151
152 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
153 if (lineImpl == nullptr) {
154 TEXT_LOGE("Failed to get line");
155 return 0.0;
156 }
157
158 return lineImpl->GetGlyphCount();
159 }
160
OH_Drawing_TextLineGetTextRange(OH_Drawing_TextLine * line,size_t * start,size_t * end)161 void OH_Drawing_TextLineGetTextRange(OH_Drawing_TextLine* line, size_t* start, size_t* end)
162 {
163 if (line == nullptr || start == nullptr || end == nullptr) {
164 TEXT_LOGE("Param is nullptr");
165 return;
166 }
167
168 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
169 if (lineImpl == nullptr) {
170 TEXT_LOGE("Failed to get line");
171 return;
172 }
173
174 Boundary range = lineImpl->GetTextRange();
175 *start = range.leftIndex;
176 *end = range.rightIndex;
177 }
178
OH_Drawing_TextLineGetGlyphRuns(OH_Drawing_TextLine * line)179 OH_Drawing_Array* OH_Drawing_TextLineGetGlyphRuns(OH_Drawing_TextLine* line)
180 {
181 if (line == nullptr) {
182 TEXT_LOGE("Null line");
183 return nullptr;
184 }
185
186 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
187 if (lineImpl == nullptr) {
188 TEXT_LOGE("Failed to get line");
189 return nullptr;
190 }
191
192 auto spTextLines = lineImpl->GetSpTextLineBase();
193 if (spTextLines == nullptr) {
194 TEXT_LOGE("Failed to get sp text line");
195 return nullptr;
196 }
197
198 auto runs = reinterpret_cast<SPText::TextLineBase*>(spTextLines)->GetGlyphRuns();
199 if (runs.size() == 0) {
200 TEXT_LOGE("Failed to get glyph runs");
201 return nullptr;
202 }
203
204 RunImpl* runsArr = new (std::nothrow) RunImpl[runs.size()];
205 if (runsArr == nullptr) {
206 TEXT_LOGE("Failed to create run impl");
207 return nullptr;
208 }
209 for (size_t i = 0; i < runs.size(); ++i) {
210 runsArr[i].SetSpRunBase(runs[i]);
211 }
212
213 ObjectArray* array = new (std::nothrow) ObjectArray();
214 if (array == nullptr) {
215 TEXT_LOGE("Failed to create array");
216 delete[] runsArr;
217 return nullptr;
218 }
219 array->addr = runsArr;
220 array->num = runs.size();
221 array->type = TEXT_RUN;
222
223 return reinterpret_cast<OH_Drawing_Array*>(array);
224 }
225
OH_Drawing_DestroyRuns(OH_Drawing_Array * runs)226 void OH_Drawing_DestroyRuns(OH_Drawing_Array* runs)
227 {
228 if (runs == nullptr) {
229 TEXT_LOGE("Null runs");
230 return;
231 }
232
233 auto arrayRuns = reinterpret_cast<ObjectArray*>(runs);
234 if (arrayRuns != nullptr && arrayRuns->type == TEXT_RUN && arrayRuns->num > 0) {
235 RunImpl* runsArr = reinterpret_cast<RunImpl*>(arrayRuns->addr);
236 if (runsArr != nullptr) {
237 delete[] runsArr;
238 arrayRuns->addr = nullptr;
239 }
240 arrayRuns->num = 0;
241 arrayRuns->type = INVALID;
242 delete arrayRuns;
243 }
244 }
245
OH_Drawing_GetRunByIndex(OH_Drawing_Array * runs,size_t index)246 OH_Drawing_Run* OH_Drawing_GetRunByIndex(OH_Drawing_Array* runs, size_t index)
247 {
248 if (runs == nullptr) {
249 TEXT_LOGE("Null runs");
250 return nullptr;
251 }
252
253 auto arrayRuns = reinterpret_cast<ObjectArray*>(runs);
254 if (arrayRuns != nullptr && arrayRuns->addr != nullptr &&
255 arrayRuns->type == TEXT_RUN && index < arrayRuns->num) {
256 RunImpl* run = reinterpret_cast<RunImpl*>(arrayRuns->addr);
257 return reinterpret_cast<OH_Drawing_Run*>(&run[index]);
258 }
259
260 return nullptr;
261 }
262
OH_Drawing_TextLinePaint(OH_Drawing_TextLine * line,OH_Drawing_Canvas * canvas,double x,double y)263 void OH_Drawing_TextLinePaint(OH_Drawing_TextLine* line, OH_Drawing_Canvas* canvas, double x, double y)
264 {
265 if (line == nullptr || canvas == nullptr) {
266 TEXT_LOGE("Invalid parameter");
267 return;
268 }
269
270 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
271 if (lineImpl == nullptr) {
272 TEXT_LOGE("Failed to get line");
273 return;
274 }
275
276 lineImpl->Paint(reinterpret_cast<OHOS::Rosen::Drawing::Canvas*>(canvas), x, y);
277 }
278
OH_Drawing_TextLineCreateTruncatedLine(OH_Drawing_TextLine * line,double width,int mode,const char * ellipsis)279 OH_Drawing_TextLine* OH_Drawing_TextLineCreateTruncatedLine(OH_Drawing_TextLine* line, double width, int mode,
280 const char* ellipsis)
281 {
282 if (line == nullptr || ellipsis == nullptr) {
283 TEXT_LOGE("Invalid parameter");
284 return nullptr;
285 }
286
287 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
288 if (lineImpl == nullptr) {
289 TEXT_LOGE("Failed to get line");
290 return nullptr;
291 }
292
293 auto spTextLines = lineImpl->GetSpTextLineBase();
294 if (spTextLines == nullptr) {
295 TEXT_LOGE("Failed to get sp text line");
296 return nullptr;
297 }
298
299 std::string ellipsisStr(ellipsis);
300 auto truncatedTextLine = reinterpret_cast<SPText::TextLineBase*>(spTextLines)->CreateTruncatedLine(
301 width, static_cast<OHOS::Rosen::SPText::EllipsisModal>(mode), ellipsisStr);
302 if (truncatedTextLine == nullptr) {
303 TEXT_LOGE("Failed to create truncated line");
304 return nullptr;
305 }
306
307 auto truncatedLine = new (std::nothrow) LineImpl(std::move(truncatedTextLine));
308 if (truncatedLine == nullptr) {
309 TEXT_LOGE("Failed to create line impl");
310 return nullptr;
311 }
312
313 LineObject* lineObject = new (std::nothrow) LineObject();
314 if (lineObject == nullptr) {
315 TEXT_LOGE("Failed to create array");
316 delete truncatedLine;
317 return nullptr;
318 }
319
320 lineObject->line = reinterpret_cast<void*>(truncatedLine);
321 lineObject->isArray = false;
322
323 return reinterpret_cast<OH_Drawing_TextLine*>(lineObject);
324 }
325
OH_Drawing_TextLineGetTypographicBounds(OH_Drawing_TextLine * line,double * ascent,double * descent,double * leading)326 double OH_Drawing_TextLineGetTypographicBounds(OH_Drawing_TextLine* line, double* ascent, double* descent,
327 double* leading)
328 {
329 if (line == nullptr || ascent == nullptr || descent == nullptr || leading == nullptr) {
330 TEXT_LOGE("Invalid parameter");
331 return 0.0;
332 }
333
334 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
335 if (lineImpl == nullptr) {
336 TEXT_LOGE("Failed to get line");
337 return 0.0;
338 }
339
340 return lineImpl->GetTypographicBounds(ascent, descent, leading);
341 }
342
OH_Drawing_TextLineGetImageBounds(OH_Drawing_TextLine * line)343 OH_Drawing_Rect* OH_Drawing_TextLineGetImageBounds(OH_Drawing_TextLine* line)
344 {
345 if (line == nullptr) {
346 TEXT_LOGE("Null line");
347 return nullptr;
348 }
349
350 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
351 if (lineImpl == nullptr) {
352 TEXT_LOGE("Failed to get line");
353 return nullptr;
354 }
355
356 auto skRect = lineImpl->GetImageBounds();
357 return OH_Drawing_RectCreate(skRect.GetLeft(), skRect.GetTop(), skRect.GetRight(), skRect.GetBottom());
358 }
359
OH_Drawing_TextLineGetTrailingSpaceWidth(OH_Drawing_TextLine * line)360 double OH_Drawing_TextLineGetTrailingSpaceWidth(OH_Drawing_TextLine* line)
361 {
362 if (line == nullptr) {
363 TEXT_LOGE("Null line");
364 return 0.0;
365 }
366
367 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
368 if (lineImpl == nullptr) {
369 TEXT_LOGE("Failed to get line");
370 return 0.0;
371 }
372
373 return lineImpl->GetTrailingSpaceWidth();
374 }
375
OH_Drawing_TextLineGetStringIndexForPosition(OH_Drawing_TextLine * line,OH_Drawing_Point * point)376 int32_t OH_Drawing_TextLineGetStringIndexForPosition(OH_Drawing_TextLine* line, OH_Drawing_Point* point)
377 {
378 if (line == nullptr || point == nullptr) {
379 TEXT_LOGE("Invalid parameter");
380 return 0;
381 }
382
383 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
384 if (lineImpl == nullptr) {
385 TEXT_LOGE("Failed to get line");
386 return 0;
387 }
388
389 return lineImpl->GetStringIndexForPosition(*reinterpret_cast<SkPoint*>(point));
390 }
391
OH_Drawing_TextLineGetOffsetForStringIndex(OH_Drawing_TextLine * line,int32_t index)392 double OH_Drawing_TextLineGetOffsetForStringIndex(OH_Drawing_TextLine* line, int32_t index)
393 {
394 if (line == nullptr) {
395 TEXT_LOGE("Null line");
396 return 0.0;
397 }
398
399 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
400 if (lineImpl == nullptr) {
401 TEXT_LOGE("Failed to get line");
402 return 0.0;
403 }
404
405 return lineImpl->GetOffsetForStringIndex(index);
406 }
407
OH_Drawing_TextLineEnumerateCaretOffsets(OH_Drawing_TextLine * line,Drawing_CaretOffsetsCallback callback)408 void OH_Drawing_TextLineEnumerateCaretOffsets(OH_Drawing_TextLine* line, Drawing_CaretOffsetsCallback callback)
409 {
410 if (line == nullptr || callback == nullptr) {
411 TEXT_LOGE("Invalid parameter");
412 return;
413 }
414
415 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
416 if (lineImpl == nullptr) {
417 TEXT_LOGE("Failed to get line");
418 return;
419 }
420
421 bool isHardBreak = false;
422 std::map<int32_t, double> offsetMap = lineImpl->GetIndexAndOffsets(isHardBreak);
423 double leftOffset = 0.0;
424 const size_t twoNum = 2;
425 for (auto it = offsetMap.begin(); it != offsetMap.end(); ++it) {
426 for (size_t i = 0; i < twoNum; i++) {
427 double offset = (i == 0) ? leftOffset: it->second;
428 bool leadingEdge = (i == 0) ? true : false;
429 if (callback(offset, it->first, leadingEdge)) {
430 return;
431 }
432 }
433 leftOffset = it->second;
434 }
435 if (isHardBreak && offsetMap.size() > 0) {
436 if (!callback(leftOffset, offsetMap.rbegin()->first + 1, true)) {
437 callback(leftOffset, offsetMap.rbegin()->first + 1, false);
438 }
439 }
440 }
441
OH_Drawing_TextLineGetAlignmentOffset(OH_Drawing_TextLine * line,double alignmentFactor,double alignmentWidth)442 double OH_Drawing_TextLineGetAlignmentOffset(OH_Drawing_TextLine* line, double alignmentFactor, double alignmentWidth)
443 {
444 if (line == nullptr) {
445 TEXT_LOGE("Null line");
446 return 0.0;
447 }
448
449 auto lineImpl = reinterpret_cast<LineImpl*>(reinterpret_cast<LineObject*>(line)->line);
450 if (lineImpl == nullptr) {
451 TEXT_LOGE("Failed to get line");
452 return 0.0;
453 }
454
455 return lineImpl->GetAlignmentOffset(alignmentFactor, alignmentWidth);
456 }