1/*
2 * Copyright (c) 2022 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 "common/spannable_string.h"
17#include "font/ui_font.h"
18#include "gfx_utils/graphic_log.h"
19#include "securec.h"
20namespace OHOS {
21namespace {
22constexpr uint16_t DEFAULT_IS_SPANNABLE_LEN = 10;
23constexpr uint16_t DEFAULT_EXPAND_EDGE = 1024;
24constexpr uint16_t DEFAULT_EXPAND_TIMES = 2;
25constexpr uint16_t DEFAULT_EXPAND_OFFSET = 1;
26} // namespace
27
28SpannableString::SpannableString() : isSpannableLen_(0), isSpannable_(nullptr) {}
29
30SpannableString::~SpannableString()
31{
32    Reset();
33}
34
35void SpannableString::SetTextStyle(TextStyle inputTextStyle, uint16_t startIndex, uint16_t endIndex)
36{
37    StyleSpan* style = new StyleSpan(inputTextStyle, startIndex, endIndex);
38    styleList_.PushBack(style);
39    SetSpannable(true, startIndex, endIndex);
40}
41bool SpannableString::GetTextStyle(uint16_t index, TextStyle& textStyle)
42{
43    bool hasFind = false;
44    ListNode<StyleSpan*>* tempSpan = styleList_.Begin();
45    for (; tempSpan != styleList_.End(); tempSpan = tempSpan->next_) {
46        uint16_t tempStart = tempSpan->data_->start_;
47        uint16_t tempEnd = tempSpan->data_->end_;
48        if ((tempStart <= index) && (index < tempEnd)) {
49            textStyle = tempSpan->data_->textStyle_;
50            hasFind = true;
51            break;
52        }
53    }
54    return hasFind;
55}
56
57void SpannableString::Reset()
58{
59    if (isSpannable_ != nullptr) {
60        UIFree(isSpannable_);
61    }
62    isSpannable_ = nullptr;
63    isSpannableLen_ = 0;
64    if (styleList_.Size() > 0) {
65        for (auto iter = styleList_.Begin(); iter != styleList_.End(); iter = iter->next_) {
66            delete iter->data_;
67            iter->data_ = nullptr;
68        }
69        styleList_.Clear();
70    }
71    if (sizeList_.Size() > 0) {
72        sizeList_.Clear();
73    }
74    if (fontIdList_.Size() > 0) {
75        fontIdList_.Clear();
76    }
77    if (heightList_.Size() > 0) {
78        heightList_.Clear();
79    }
80    if (backgroundColorList_.Size() > 0) {
81        backgroundColorList_.Clear();
82    }
83    if (foregroundColorList_.Size() > 0) {
84        foregroundColorList_.Clear();
85    }
86    if (lineBackgroundColorList_.Size() > 0) {
87        lineBackgroundColorList_.Clear();
88    }
89}
90
91void SpannableString::SetSpannableString(const SpannableString* input)
92{
93    Reset();
94    SetSpannable(true, 0, DEFAULT_IS_SPANNABLE_LEN);
95
96    ListNode<FontSizeSpan>* node = input->sizeList_.Begin();
97    while (node != input->sizeList_.End()) {
98        SetFontSize(node->data_.fontSize, node->data_.start, node->data_.end);
99        node = node->next_;
100    }
101    ListNode<FontIdSpan>* node_id = input->fontIdList_.Begin();
102    while (node_id != input->fontIdList_.End()) {
103        SetFontId(node_id->data_.fontId, node_id->data_.start, node_id->data_.end);
104        node_id = node_id->next_;
105    }
106    ListNode<LetterHeightSpan>* node_height = input->heightList_.Begin();
107    while (node_height != input->heightList_.End()) {
108        SetFontHeight(node_height->data_.height, node_height->data_.start, node_height->data_.end);
109        node_height = node_height->next_;
110    }
111    ListNode<StyleSpan*>* node_span = input->styleList_.Begin();
112    while (node_span != input->styleList_.End()) {
113        SetTextStyle(node_span->data_->textStyle_, node_span->data_->start_, node_span->data_->end_);
114        node_span = node_span->next_;
115    }
116    ListNode<BackgroundColorSpan>* node_backColor = input->backgroundColorList_.Begin();
117    while (node_backColor != input->backgroundColorList_.End()) {
118        SetBackgroundColor(node_backColor->data_.backgroundColor,
119                           node_backColor->data_.start,
120                           node_backColor->data_.end);
121        node_backColor = node_backColor->next_;
122    }
123    ListNode<ForegroundColorSpan>* node_foreColor = input->foregroundColorList_.Begin();
124    while (node_foreColor != input->foregroundColorList_.End()) {
125        SetForegroundColor(node_foreColor->data_.fontColor, node_foreColor->data_.start, node_foreColor->data_.end);
126        node_foreColor = node_foreColor->next_;
127    }
128    ListNode<LineBackgroundColorSpan>* node_lineBackColor = input->lineBackgroundColorList_.Begin();
129    while (node_lineBackColor != input->lineBackgroundColorList_.End()) {
130        SetLineBackgroundColor(node_lineBackColor->data_.linebackgroundColor,
131                               node_lineBackColor->data_.start,
132                               node_lineBackColor->data_.end);
133        node_lineBackColor = node_lineBackColor->next_;
134    }
135}
136
137bool SpannableString::ExpandSpannableLen(uint16_t index)
138{
139    if (isSpannableLen_ < index) {
140        uint16_t preLens = isSpannableLen_;
141        while (isSpannableLen_ < index && isSpannableLen_ != 0 && isSpannableLen_ < DEFAULT_EXPAND_EDGE) {
142            isSpannableLen_ = isSpannableLen_ * DEFAULT_EXPAND_TIMES + DEFAULT_EXPAND_OFFSET;
143        }
144        bool* tempIsSpannable_ = static_cast<bool*>(UIMalloc(isSpannableLen_ * sizeof(bool)));
145        if (tempIsSpannable_ == nullptr) {
146            GRAPHIC_LOGE("SpannableString::InitSpannable() isSpannable_ == nullptr");
147            return false;
148        }
149        if (isSpannable_ != nullptr) {
150            if (memcpy_s(tempIsSpannable_, isSpannableLen_, isSpannable_, isSpannableLen_) != EOK) {
151                UIFree(tempIsSpannable_);
152                tempIsSpannable_ = nullptr;
153                return false;
154            }
155            UIFree(isSpannable_);
156            isSpannable_ = nullptr;
157        }
158        for (uint16_t i = preLens; i < isSpannableLen_; i++) {
159            tempIsSpannable_[i] = false;
160        }
161        isSpannable_ = tempIsSpannable_;
162    }
163    return true;
164}
165
166bool SpannableString::SetSpannable(bool value, uint16_t startIndex, uint16_t endIndex)
167{
168    if (isSpannable_ == nullptr) {
169        isSpannableLen_ = DEFAULT_IS_SPANNABLE_LEN;
170        isSpannable_ = static_cast<bool*>(UIMalloc(isSpannableLen_ * sizeof(bool)));
171        for (uint16_t i = 0; i < isSpannableLen_; i++) {
172            isSpannable_[i] = false;
173        }
174    }
175    bool isSuccess = ExpandSpannableLen(endIndex);
176    if (isSuccess && (isSpannable_ != nullptr)) {
177        for (uint16_t i = startIndex; ((i < endIndex) && (i < isSpannableLen_)); i++) {
178            isSpannable_[i] = value;
179        }
180        isSuccess = true;
181    }
182    return isSuccess;
183}
184
185bool SpannableString::GetSpannable(uint16_t index)
186{
187    bool result = false;
188    if ((isSpannable_ != nullptr) && (index < isSpannableLen_)) {
189        result = isSpannable_[index];
190    }
191    return result;
192}
193
194/*
195 * this function merge samge value when add node
196 */
197void SpannableString::SetFontSize(uint8_t inputFontSize, uint16_t startIndex, uint16_t endIndex)
198{
199    if (sizeList_.IsEmpty()) {
200        FontSizeSpan inputSpan;
201        inputSpan.start = startIndex;
202        inputSpan.end =  endIndex;
203        inputSpan.fontSize = inputFontSize;
204        sizeList_.PushFront(inputSpan);
205        SetSpannable(true, startIndex, endIndex);
206        return;
207    } else {
208        ListNode<FontSizeSpan>* tempSpan = sizeList_.Begin();
209        for (; tempSpan != sizeList_.End(); tempSpan = tempSpan->next_) {
210            bool needAddNode = true;
211            uint16_t tempStart = tempSpan->data_.start;
212            uint16_t tempEnd = tempSpan->data_.end;
213            uint8_t tempSize = tempSpan->data_.fontSize;
214            if (inputFontSize == tempSize) {
215                needAddNode = EqualInsert<FontSizeSpan>(startIndex, endIndex, tempStart, tempEnd, &tempSpan, sizeList_);
216            } else {
217                FontSizeSpan tempLeft;
218                tempLeft.start = tempStart;
219                tempLeft.end = startIndex;
220                tempLeft.fontSize = tempSize;
221                FontSizeSpan tempRight;
222                tempRight.start = endIndex;
223                tempRight.end = tempEnd;
224                tempRight.fontSize = tempSize;
225                needAddNode = UnequalInsert<FontSizeSpan>(startIndex, endIndex, tempStart, tempEnd, &tempSpan,
226                                                          sizeList_, tempLeft, tempRight);
227            }
228            if (needAddNode) {
229                FontSizeSpan inputSpan;
230                inputSpan.start = startIndex;
231                inputSpan.end = endIndex;
232                inputSpan.fontSize = inputFontSize;
233                sizeList_.PushBack(inputSpan);
234                SetSpannable(true, startIndex, endIndex);
235            }
236        }
237    }
238}
239
240bool SpannableString::GetFontSize(uint16_t index, uint8_t& outputSize)
241{
242    bool hasFind = false;
243    ListNode<FontSizeSpan>* tempSpan = sizeList_.Begin();
244    for (; tempSpan != sizeList_.End(); tempSpan = tempSpan->next_) {
245        uint16_t tempStart = tempSpan->data_.start;
246        uint16_t tempEnd = tempSpan->data_.end;
247        if ((tempStart <= index) && (index < tempEnd)) {
248            outputSize = tempSpan->data_.fontSize;
249            hasFind = true;
250            break;
251        }
252    }
253    return hasFind;
254}
255
256void SpannableString::SetFontId(uint16_t inputFontId, uint16_t startIndex, uint16_t endIndex)
257{
258    if (fontIdList_.IsEmpty()) {
259        FontIdSpan inputSpan;
260        inputSpan.start = startIndex;
261        inputSpan.end = endIndex;
262        inputSpan.fontId =  inputFontId;
263        fontIdList_.PushFront(inputSpan);
264        SetSpannable(true, startIndex, endIndex);
265        return;
266    }
267    ListNode<FontIdSpan>* tempSpan = fontIdList_.Begin();
268    for (; tempSpan != fontIdList_.End(); tempSpan = tempSpan->next_) {
269        bool needAddNode = true;
270        uint16_t tempStart = tempSpan->data_.start;
271        uint16_t tempEnd = tempSpan->data_.end;
272        uint16_t tempId = tempSpan->data_.fontId;
273        if (inputFontId == tempId) {
274            needAddNode = EqualInsert<FontIdSpan>(startIndex, endIndex, tempStart, tempEnd, &tempSpan, fontIdList_);
275        } else {
276            FontIdSpan tempLeft;
277            tempLeft.start = tempStart;
278            tempLeft.end = startIndex;
279            tempLeft.fontId = tempId;
280            FontIdSpan tempRight;
281            tempRight.start = endIndex;
282            tempRight.end = tempEnd;
283            tempRight.fontId = tempId;
284            needAddNode = UnequalInsert<FontIdSpan>(startIndex, endIndex, tempStart, tempEnd, &tempSpan, fontIdList_,
285                                                    tempLeft, tempRight);
286        }
287        if (needAddNode) {
288            FontIdSpan inputSpan;
289            inputSpan.start = startIndex;
290            inputSpan.end = endIndex;
291            inputSpan.fontId = inputFontId;
292            fontIdList_.PushBack(inputSpan);
293            SetSpannable(true, startIndex, endIndex);
294        }
295    }
296}
297
298bool SpannableString::GetFontId(uint16_t index, uint16_t& outputFontId)
299{
300    bool hasFind = false;
301    ListNode<FontIdSpan>* tempSpan = fontIdList_.Begin();
302    for (; tempSpan != fontIdList_.End(); tempSpan = tempSpan->next_) {
303        uint16_t tempStart = tempSpan->data_.start;
304        uint16_t tempEnd = tempSpan->data_.end;
305        if ((tempStart <= index) && (index < tempEnd)) {
306            outputFontId = tempSpan->data_.fontId;
307            hasFind = true;
308            break;
309        }
310    }
311    return hasFind;
312}
313
314void SpannableString::SetFontHeight(int16_t inputHeight, uint16_t startIndex, uint16_t endIndex)
315{
316    if (heightList_.IsEmpty()) {
317        LetterHeightSpan inputSpan;
318        inputSpan.start = startIndex;
319        inputSpan.end = endIndex;
320        inputSpan.height = inputHeight;
321        heightList_.PushFront(inputSpan);
322        SetSpannable(true, startIndex, endIndex);
323        return;
324    }
325    ListNode<LetterHeightSpan>* tempSpan = heightList_.Begin();
326    for (; tempSpan != heightList_.End(); tempSpan = tempSpan->next_) {
327        bool needAddNode = true;
328        uint16_t tempStart = tempSpan->data_.start;
329        uint16_t tempEnd = tempSpan->data_.end;
330        int16_t tempHeight = tempSpan->data_.height;
331        if (inputHeight == tempHeight) {
332            needAddNode =
333                EqualInsert<LetterHeightSpan>(startIndex, endIndex, tempStart, tempEnd, &tempSpan, heightList_);
334        } else {
335            LetterHeightSpan tempLeft;
336            tempLeft.start = tempStart;
337            tempLeft.end = startIndex;
338            tempLeft.height = tempHeight;
339            LetterHeightSpan tempRight;
340            tempRight.start = endIndex;
341            tempRight.end = tempEnd;
342            tempRight.height = tempHeight;
343            needAddNode = UnequalInsert<LetterHeightSpan>(startIndex, endIndex, tempStart, tempEnd, &tempSpan,
344                                                          heightList_, tempLeft, tempRight);
345        }
346        if (needAddNode) {
347            LetterHeightSpan inputSpan;
348            inputSpan.start = startIndex;
349            inputSpan.end = endIndex;
350            inputSpan.height = inputHeight;
351            heightList_.PushBack(inputSpan);
352            SetSpannable(true, startIndex, endIndex);
353        }
354    }
355}
356
357bool SpannableString::GetFontHeight(uint16_t index,
358                                    int16_t& outputHeight,
359                                    uint16_t& defaultFontId,
360                                    uint8_t defaultFontSize)
361{
362    bool hasFind = false;
363    ListNode<LetterHeightSpan>* tempSpan = heightList_.Begin();
364    for (; tempSpan != heightList_.End(); tempSpan = tempSpan->next_) {
365        uint16_t tempStart = tempSpan->data_.start;
366        uint16_t tempEnd = tempSpan->data_.end;
367        if ((tempStart <= index) && (index < tempEnd)) {
368            hasFind = true;
369            outputHeight = tempSpan->data_.height;
370            break;
371        }
372    }
373    if (!hasFind) {
374        GetFontId(index, defaultFontId);
375        GetFontSize(index, defaultFontSize);
376        UIFont* uifont = UIFont::GetInstance();
377        outputHeight = uifont->GetHeight(defaultFontId, defaultFontSize);
378        SetFontHeight(outputHeight, index, index + 1);
379    }
380    return hasFind;
381}
382
383void SpannableString::SetBackgroundColor(ColorType inputBackgroundColor, uint16_t startIndex, uint16_t endIndex)
384{
385    if (backgroundColorList_.IsEmpty()) {
386        BackgroundColorSpan inputSpan;
387        inputSpan.start = startIndex;
388        inputSpan.end =  endIndex;
389        inputSpan.backgroundColor.full = inputBackgroundColor.full;
390        backgroundColorList_.PushFront(inputSpan);
391        SetSpannable(true, startIndex, endIndex);
392        return;
393    } else {
394        ListNode<BackgroundColorSpan>* tempSpan = backgroundColorList_.Begin();
395        for (; tempSpan != backgroundColorList_.End(); tempSpan = tempSpan->next_) {
396            bool needAddNode = true;
397            uint16_t tempStart = tempSpan->data_.start;
398            uint16_t tempEnd = tempSpan->data_.end;
399            ColorType tempSize;
400            tempSize.full = tempSpan->data_.backgroundColor.full;
401            if (inputBackgroundColor.full == tempSize.full) {
402                needAddNode = EqualInsert<BackgroundColorSpan>(
403                    startIndex, endIndex, tempStart, tempEnd, &tempSpan,
404                    backgroundColorList_);
405            } else {
406                BackgroundColorSpan tempLeft;
407                tempLeft.start = tempStart;
408                tempLeft.end = startIndex;
409                tempLeft.backgroundColor.full = tempSize.full;
410                BackgroundColorSpan tempRight;
411                tempRight.start = endIndex;
412                tempRight.end = tempEnd;
413                tempRight.backgroundColor.full = tempSize.full;
414                needAddNode = UnequalInsert<BackgroundColorSpan>(
415                    startIndex, endIndex, tempStart, tempEnd, &tempSpan,
416                    backgroundColorList_, tempLeft, tempRight);
417            }
418            if (needAddNode) {
419                BackgroundColorSpan inputSpan;
420                inputSpan.start = startIndex;
421                inputSpan.end = endIndex;
422                inputSpan.backgroundColor.full = inputBackgroundColor.full;
423                backgroundColorList_.PushBack(inputSpan);
424                SetSpannable(true, startIndex, endIndex);
425            }
426        }
427    }
428}
429
430bool SpannableString::GetBackgroundColor(uint16_t index, ColorType& outputBackgroundColor)
431{
432    bool hasFind = false;
433    ListNode<BackgroundColorSpan>* tempSpan = backgroundColorList_.Begin();
434    for (; tempSpan != backgroundColorList_.End(); tempSpan = tempSpan->next_) {
435        uint16_t tempStart = tempSpan->data_.start;
436        uint16_t tempEnd = tempSpan->data_.end;
437        if ((tempStart <= index) && (index < tempEnd)) {
438            outputBackgroundColor.full = tempSpan->data_.backgroundColor.full;
439            hasFind = true;
440            break;
441        }
442    }
443    return hasFind;
444}
445
446void SpannableString::SetForegroundColor(ColorType inputForegroundColor, uint16_t startIndex, uint16_t endIndex)
447{
448    if (foregroundColorList_.IsEmpty()) {
449        ForegroundColorSpan inputSpan;
450        inputSpan.start = startIndex;
451        inputSpan.end =  endIndex;
452        inputSpan.fontColor.full = inputForegroundColor.full;
453        foregroundColorList_.PushFront(inputSpan);
454        SetSpannable(true, startIndex, endIndex);
455        return;
456    } else {
457        ListNode<ForegroundColorSpan>* tempSpan = foregroundColorList_.Begin();
458        for (; tempSpan != foregroundColorList_.End(); tempSpan = tempSpan->next_) {
459            bool needAddNode = true;
460            uint16_t tempStart = tempSpan->data_.start;
461            uint16_t tempEnd = tempSpan->data_.end;
462            ColorType tempSize;
463            tempSize.full= tempSpan->data_.fontColor.full;
464            if (inputForegroundColor.full == tempSize.full) {
465                needAddNode = EqualInsert<ForegroundColorSpan>(
466                    startIndex, endIndex, tempStart, tempEnd, &tempSpan,
467                    foregroundColorList_);
468            } else {
469                ForegroundColorSpan tempLeft;
470                tempLeft.start = tempStart;
471                tempLeft.end = startIndex;
472                tempLeft.fontColor.full = tempSize.full;
473                ForegroundColorSpan tempRight;
474                tempRight.start = endIndex;
475                tempRight.end = tempEnd;
476                tempRight.fontColor.full = tempSize.full;
477                needAddNode = UnequalInsert<ForegroundColorSpan>(startIndex, endIndex, tempStart, tempEnd, &tempSpan,
478                                                          foregroundColorList_, tempLeft, tempRight);
479            }
480            if (needAddNode) {
481                ForegroundColorSpan inputSpan;
482                inputSpan.start = startIndex;
483                inputSpan.end = endIndex;
484                inputSpan.fontColor.full = inputForegroundColor.full;
485                foregroundColorList_.PushBack(inputSpan);
486                SetSpannable(true, startIndex, endIndex);
487            }
488        }
489    }
490}
491
492bool SpannableString::GetForegroundColor(uint16_t index, ColorType& outputForegroundColor)
493{
494    bool hasFind = false;
495    ListNode<ForegroundColorSpan>* tempSpan = foregroundColorList_.Begin();
496    for (; tempSpan != foregroundColorList_.End(); tempSpan = tempSpan->next_) {
497        uint16_t tempStart = tempSpan->data_.start;
498        uint16_t tempEnd = tempSpan->data_.end;
499        if ((tempStart <= index) && (index < tempEnd)) {
500            outputForegroundColor.full = tempSpan->data_.fontColor.full;
501            hasFind = true;
502            break;
503        }
504    }
505    return hasFind;
506}
507
508void SpannableString::SetLineBackgroundColor(ColorType inputLineBackgroundColor, uint16_t startIndex, uint16_t endIndex)
509{
510    if (lineBackgroundColorList_.IsEmpty()) {
511        LineBackgroundColorSpan inputSpan;
512        inputSpan.start = startIndex;
513        inputSpan.end =  endIndex;
514        inputSpan.linebackgroundColor.full = inputLineBackgroundColor.full;
515        lineBackgroundColorList_.PushFront(inputSpan);
516        SetSpannable(true, startIndex, endIndex);
517        return;
518    } else {
519        ListNode<LineBackgroundColorSpan>* tempSpan = lineBackgroundColorList_.Begin();
520        for (; tempSpan != lineBackgroundColorList_.End(); tempSpan = tempSpan->next_) {
521            bool needAddNode = true;
522            uint16_t tempStart = tempSpan->data_.start;
523            uint16_t tempEnd = tempSpan->data_.end;
524            ColorType tempSize;
525            tempSize.full = tempSpan->data_.linebackgroundColor.full;
526            if (inputLineBackgroundColor.full == tempSize.full) {
527                needAddNode = EqualInsert<LineBackgroundColorSpan>(
528                    startIndex, endIndex, tempStart, tempEnd, &tempSpan,
529                    lineBackgroundColorList_);
530            } else {
531                LineBackgroundColorSpan tempLeft;
532                tempLeft.start = tempStart;
533                tempLeft.end = startIndex;
534                tempLeft.linebackgroundColor.full = tempSize.full;
535                LineBackgroundColorSpan tempRight;
536                tempRight.start = endIndex;
537                tempRight.end = tempEnd;
538                tempRight.linebackgroundColor.full = tempSize.full;
539                needAddNode = UnequalInsert<LineBackgroundColorSpan>(
540                    startIndex, endIndex, tempStart, tempEnd, &tempSpan,
541                    lineBackgroundColorList_, tempLeft, tempRight);
542            }
543            if (needAddNode) {
544                LineBackgroundColorSpan inputSpan;
545                inputSpan.start = startIndex;
546                inputSpan.end = endIndex;
547                inputSpan.linebackgroundColor.full = inputLineBackgroundColor.full;
548                lineBackgroundColorList_.PushBack(inputSpan);
549                SetSpannable(true, startIndex, endIndex);
550            }
551        }
552    }
553}
554
555bool SpannableString::GetLineBackgroundColor(uint16_t index, ColorType& outputLineBackgroundColor)
556{
557    bool hasFind = false;
558    ListNode<LineBackgroundColorSpan>* tempSpan = lineBackgroundColorList_.Begin();
559    for (; tempSpan != lineBackgroundColorList_.End(); tempSpan = tempSpan->next_) {
560        uint16_t tempStart = tempSpan->data_.start;
561        uint16_t tempEnd = tempSpan->data_.end;
562        if ((tempStart <= index) && (index < tempEnd)) {
563            outputLineBackgroundColor.full = tempSpan->data_.linebackgroundColor.full;
564            hasFind = true;
565            break;
566        }
567    }
568    return hasFind;
569}
570} // namespace OHOS
571