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