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 <gmock/gmock.h> 17 #include <gtest/gtest.h> 18 19 #include "draw/canvas.h" 20 #include "text_flip_effect.h" 21 #include "typography_mock.h" 22 #include "typography.h" 23 #include "typography_create.h" 24 #include "font_collection.h" 25 26 using namespace testing; 27 using namespace testing::ext; 28 using namespace OHOS::Rosen; 29 30 class MockCanvas : public Drawing::Canvas { 31 public: 32 MOCK_METHOD(void, DrawTextBlob, (const Drawing::TextBlob* blob, const float x, const float y), (override)); 33 }; 34 35 class TextFlipEffectTest : public testing::Test { 36 public: SetUp()37 void SetUp() override 38 { 39 auto textEffect = TextEffectFactoryCreator::GetInstance().CreateTextEffect(TextEffectStrategy::FLIP); 40 effect_ = std::static_pointer_cast<TextFlipEffect>(textEffect); 41 ASSERT_NE(effect_, nullptr); 42 EXPECT_EQ(effect_->strategy_, TextEffectStrategy::FLIP); 43 mockTypography_ = std::make_shared<MockTypography>(); 44 mockCanvas_ = std::make_unique<MockCanvas>(); 45 } 46 TearDown()47 void TearDown() override 48 { 49 effect_.reset(); 50 mockTypography_.reset(); 51 mockCanvas_.reset(); 52 } 53 54 protected: 55 std::shared_ptr<TextFlipEffect> effect_{nullptr}; 56 std::shared_ptr<MockTypography> mockTypography_{nullptr}; 57 std::unique_ptr<MockCanvas> mockCanvas_{nullptr}; 58 CreateConfig()59 TypographyConfig CreateConfig() 60 { 61 return { mockTypography_, {0, 10} }; 62 } 63 }; 64 65 /* 66 * @tc.name: TextFlipEffectTest001 67 * @tc.desc: Test for UpdateEffectConfig action 68 * @tc.type: FUNC 69 */ 70 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest001, TestSize.Level0) 71 { 72 std::unordered_map<TextEffectAttribute, std::string> config1 = { 73 {TextEffectAttribute::FLIP_DIRECTION, "up"}, 74 {TextEffectAttribute::BLUR_ENABLE, "false"}, 75 }; 76 77 std::unordered_map<TextEffectAttribute, std::string> config2 = { 78 {TextEffectAttribute::FLIP_DIRECTION, "down"}, 79 {TextEffectAttribute::BLUR_ENABLE, "true"}, 80 }; 81 82 EXPECT_EQ(effect_->UpdateEffectConfig(config1), TEXT_EFFECT_SUCCESS); 83 EXPECT_EQ(effect_->UpdateEffectConfig(config2), TEXT_EFFECT_SUCCESS); 84 EXPECT_EQ(effect_->direction_, TextEffectFlipDirection::DOWN); 85 EXPECT_TRUE(effect_->blurEnable_); 86 87 std::unordered_map<TextEffectAttribute, std::string> invalidConfig = { 88 {TextEffectAttribute::FLIP_DIRECTION, "invalid"}, 89 {TextEffectAttribute::BLUR_ENABLE, "invalid"} 90 }; 91 EXPECT_EQ(effect_->UpdateEffectConfig(invalidConfig), TEXT_EFFECT_INVALID_INPUT); 92 EXPECT_EQ(effect_->direction_, TextEffectFlipDirection::DOWN); 93 EXPECT_TRUE(effect_->blurEnable_); 94 95 std::unordered_map<TextEffectAttribute, std::string> configEmpty; 96 EXPECT_EQ(effect_->UpdateEffectConfig(configEmpty), TEXT_EFFECT_SUCCESS); 97 } 98 99 /* 100 * @tc.name: TextFlipEffectTest002 101 * @tc.desc: Test for AppendTypography action 102 * @tc.type: FUNC 103 */ 104 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest002, TestSize.Level0) 105 { 106 TypographyConfig config = CreateConfig(); 107 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(true)).Times(1); 108 EXPECT_EQ(effect_->AppendTypography({config}), TEXT_EFFECT_SUCCESS); 109 EXPECT_EQ(effect_->typographyConfig_.typography, mockTypography_); 110 111 auto anotherTypography = std::make_shared<MockTypography>(); 112 TypographyConfig anotherConfig = { anotherTypography, {5, 15} }; 113 EXPECT_EQ(effect_->AppendTypography({anotherConfig}), TEXT_EFFECT_UNKNOWN); 114 115 EXPECT_EQ(effect_->AppendTypography({}), TEXT_EFFECT_INVALID_INPUT); 116 TypographyConfig nullptrConfig = { nullptr, {0, 0} }; 117 EXPECT_EQ(effect_->AppendTypography({nullptrConfig}), TEXT_EFFECT_INVALID_INPUT); 118 } 119 120 /* 121 * @tc.name: TextFlipEffectTest003 122 * @tc.desc: Test for UpdateTypography action 123 * @tc.type: FUNC 124 */ 125 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest003, TestSize.Level0) 126 { 127 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(true)).Times(2); 128 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(false)).Times(1); 129 effect_->AppendTypography({CreateConfig()}); 130 TypographyConfig newConfig = { mockTypography_, {5, 15} }; 131 std::vector<std::pair<TypographyConfig, TypographyConfig>> update = { 132 {CreateConfig(), newConfig} 133 }; 134 135 EXPECT_EQ(effect_->UpdateTypography(update), TEXT_EFFECT_SUCCESS); 136 EXPECT_EQ(effect_->typographyConfig_.rawTextRange.first, 5); 137 EXPECT_EQ(effect_->typographyConfig_.rawTextRange.second, 15); 138 139 TypographyConfig configNull = { nullptr, {5, 15} }; 140 std::vector<std::pair<TypographyConfig, TypographyConfig>> updateNull = { 141 {CreateConfig(), configNull} 142 }; 143 EXPECT_EQ(effect_->UpdateTypography(updateNull), TEXT_EFFECT_INVALID_INPUT); 144 145 std::vector<std::pair<TypographyConfig, TypographyConfig>> emptyUpdate; 146 EXPECT_EQ(effect_->UpdateTypography(emptyUpdate), TEXT_EFFECT_INVALID_INPUT); 147 148 auto anotherTypography = std::make_shared<MockTypography>(); 149 TypographyConfig anotherConfig = { anotherTypography, {5, 15} }; 150 std::vector<std::pair<TypographyConfig, TypographyConfig>> mismatchedUpdate = { 151 {anotherConfig, anotherConfig} 152 }; 153 EXPECT_EQ(effect_->UpdateTypography(mismatchedUpdate), TEXT_EFFECT_INVALID_INPUT); 154 effect_->typographyConfig_.typography = nullptr; 155 TypographyConfig invalidConfig = { nullptr, {5, 15} }; 156 std::vector<std::pair<TypographyConfig, TypographyConfig>> invalidUpdate = { 157 {invalidConfig, anotherConfig} 158 }; 159 EXPECT_EQ(effect_->UpdateTypography(invalidUpdate), TEXT_EFFECT_UNKNOWN); 160 } 161 162 /* 163 * @tc.name: TextFlipEffectTest004 164 * @tc.desc: Test for RemoveTypography action 165 * @tc.type: FUNC 166 */ 167 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest004, TestSize.Level0) 168 { 169 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(false)).Times(2); 170 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(true)).Times(2); 171 TypographyConfig config = CreateConfig(); 172 effect_->AppendTypography({config}); 173 effect_->RemoveTypography({config}); 174 175 EXPECT_EQ(effect_->typographyConfig_.typography, nullptr); 176 EXPECT_EQ(effect_->typographyConfig_.rawTextRange.first, 0); 177 EXPECT_EQ(effect_->typographyConfig_.rawTextRange.second, 0); 178 179 effect_->AppendTypography({CreateConfig()}); 180 auto anotherTypography = std::make_shared<MockTypography>(); 181 TypographyConfig anotherConfig = { anotherTypography, {5, 15} }; 182 effect_->RemoveTypography({anotherConfig}); 183 EXPECT_NE(effect_->typographyConfig_.typography, nullptr); 184 effect_->RemoveTypography({}); 185 EXPECT_EQ(effect_->typographyConfig_.typography, nullptr); 186 } 187 188 /* 189 * @tc.name: TextFlipEffectTest005 190 * @tc.desc: Test for StartEffect and StopEffect action 191 * @tc.type: FUNC 192 */ 193 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest005, TestSize.Level0) 194 { 195 OHOS::Rosen::TypographyStyle typographyStyle0; 196 typographyStyle0.enableAutoSpace = false; 197 std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection0 = 198 OHOS::Rosen::FontCollection::From(std::make_shared<txt::FontCollection>()); 199 std::unique_ptr<OHOS::Rosen::TypographyCreate> typographyCreate = 200 OHOS::Rosen::TypographyCreate::Create(typographyStyle0, fontCollection0); 201 std::u16string text = u"88"; 202 typographyCreate->AppendText(text); 203 std::unique_ptr<OHOS::Rosen::Typography> typography0 = typographyCreate->CreateTypography(); 204 double maxWidth = 1500; 205 typography0->Layout(maxWidth); 206 207 std::shared_ptr<Typography> typography(typography0.release()); 208 TypographyConfig config = { typography, {0, text.length()} }; 209 effect_->AppendTypography({config}); 210 effect_->StartEffect(mockCanvas_.get(), 100.0, 200.0); 211 effect_->StopEffect(); 212 TypographyConfig config1 = { typography, {0, text.length()} }; 213 effect_->AppendTypography({config1}); 214 typography->SetSkipTextBlobDrawing(true); 215 typography->Paint(mockCanvas_.get(), 100.0, 200.0); 216 effect_->StartEffect(mockCanvas_.get(), 100.0, 200.0); 217 EXPECT_FALSE(effect_->lastAllBlobGlyphIds_.empty()); 218 219 typography->SetSkipTextBlobDrawing(false); 220 effect_->StopEffect(); 221 EXPECT_TRUE(effect_->lastAllBlobGlyphIds_.empty()); 222 } 223 224 /* 225 * @tc.name: TextFlipEffectTest006 226 * @tc.desc: Test for DrawTextFlip action 227 * @tc.type: FUNC 228 */ 229 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest006, TestSize.Level0) 230 { 231 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(true)).Times(1); 232 EXPECT_CALL(*mockTypography_, GetAnimation()).Times(1); 233 TypographyConfig config = CreateConfig(); 234 effect_->AppendTypography({config}); 235 std::vector<TextBlobRecordInfo> records; 236 TextBlobRecordInfo record1 = {nullptr, {0.0f, 0.0f}, Drawing::Color::COLOR_BLACK}; 237 std::string info = "88"; 238 OHOS::Rosen::Drawing::Font font; 239 font.SetSize(24); 240 std::shared_ptr<Drawing::TextBlob> blob = Drawing::TextBlob::MakeFromString(info.c_str(), font); 241 TextBlobRecordInfo record2 = {blob, {0.0f, 0.0f}, Drawing::Color::COLOR_BLACK}; 242 records.emplace_back(record1); 243 records.emplace_back(record2); 244 double x = 0.0; 245 double y = 0.0; 246 effect_->DrawTextFlip(records, mockCanvas_.get(), x, y); 247 EXPECT_TRUE(effect_->lastAllBlobGlyphIds_.empty()); 248 } 249 250 /* 251 * @tc.name: TextFlipEffectTest007 252 * @tc.desc: Test for DrawResidualText action 253 * @tc.type: FUNC 254 */ 255 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest007, TestSize.Level0) 256 { 257 OHOS::Rosen::TypographyStyle typographyStyle0; 258 typographyStyle0.enableAutoSpace = false; 259 std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection0 = 260 OHOS::Rosen::FontCollection::From(std::make_shared<txt::FontCollection>()); 261 std::unique_ptr<OHOS::Rosen::TypographyCreate> typographyCreate = 262 OHOS::Rosen::TypographyCreate::Create(typographyStyle0, fontCollection0); 263 std::u16string text = u"88"; 264 typographyCreate->AppendText(text); 265 std::unique_ptr<OHOS::Rosen::Typography> typography0 = typographyCreate->CreateTypography(); 266 double maxWidth = 1500; 267 typography0->Layout(maxWidth); 268 std::shared_ptr<Typography> typography(typography0.release()); 269 TypographyConfig config = { typography, {0, text.length()} }; 270 effect_->AppendTypography({config}); 271 typography->SetSkipTextBlobDrawing(true); 272 typography->Paint(mockCanvas_.get(), 100.0, 200.0); 273 std::vector<TextBlobRecordInfo> records = typography->GetTextBlobRecordInfo(); 274 EXPECT_FALSE(records.empty()); 275 double height = records[0].blob->Bounds()->GetHeight(); 276 std::function<bool(const std::shared_ptr<TextEngine::SymbolAnimationConfig>&)> animationFunc = 277 typography->GetAnimation(); 278 effect_->currentGlyphIndex_ = 0; 279 effect_->lastAllBlobGlyphIds_.clear(); 280 effect_->lastAllBlobGlyphIds_.emplace_back(10); 281 effect_->lastAllBlobGlyphIds_.emplace_back(20); 282 effect_->DrawResidualText(mockCanvas_.get(), height, animationFunc); 283 EXPECT_FALSE(effect_->lastAllBlobGlyphIds_.empty()); 284 effect_->currentGlyphIndex_ = 2; 285 effect_->lastAllBlobGlyphIds_.clear(); 286 effect_->DrawResidualText(mockCanvas_.get(), height, animationFunc); 287 EXPECT_NE(effect_->currentGlyphIndex_, 0); 288 } 289 290 /* 291 * @tc.name: TextFlipEffectTest008 292 * @tc.desc: Test for DrawTextFlipElements action 293 * @tc.type: FUNC 294 */ 295 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest008, TestSize.Level0) 296 { 297 OHOS::Rosen::TypographyStyle typographyStyle0; 298 typographyStyle0.enableAutoSpace = false; 299 std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection0 = 300 OHOS::Rosen::FontCollection::From(std::make_shared<txt::FontCollection>()); 301 std::unique_ptr<OHOS::Rosen::TypographyCreate> typographyCreate = 302 OHOS::Rosen::TypographyCreate::Create(typographyStyle0, fontCollection0); 303 std::u16string text = u"88"; 304 typographyCreate->AppendText(text); 305 std::unique_ptr<OHOS::Rosen::Typography> typography0 = typographyCreate->CreateTypography(); 306 double maxWidth = 1500; 307 typography0->Layout(maxWidth); 308 std::shared_ptr<Typography> typography(typography0.release()); 309 TypographyConfig config = { typography, {0, text.length()} }; 310 effect_->AppendTypography({config}); 311 typography->SetSkipTextBlobDrawing(true); 312 typography->Paint(mockCanvas_.get(), 100.0, 200.0); 313 std::vector<TextBlobRecordInfo> records = typography->GetTextBlobRecordInfo(); 314 EXPECT_FALSE(records.empty()); 315 double height = records[0].blob->Bounds()->GetHeight(); 316 std::function<bool(const std::shared_ptr<TextEngine::SymbolAnimationConfig>&)> animationFunc = 317 typography->GetAnimation(); 318 std::vector<std::vector<TextEngine::TextEffectElement>> effectElements; 319 std::vector<TextEngine::TextEffectElement> unEffectElements; 320 std::vector<TextEngine::TextEffectElement> inEffectElements; 321 effectElements.emplace_back(unEffectElements); 322 effectElements.emplace_back(inEffectElements); 323 effect_->DrawTextFlipElements(mockCanvas_.get(), height, Drawing::Color::COLOR_BLACK, 324 animationFunc, effectElements); 325 EXPECT_EQ(effect_->currentGlyphIndex_, 0); 326 } 327 328 /* 329 * @tc.name: TextFlipEffectTest009 330 * @tc.desc: Test for ClearTypography action 331 * @tc.type: FUNC 332 */ 333 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest009, TestSize.Level0) 334 { 335 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(true)).Times(2); 336 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(false)).Times(1); 337 TypographyConfig config = CreateConfig(); 338 effect_->AppendTypography({config}); 339 effect_->ClearTypography(); 340 EXPECT_EQ(effect_->typographyConfig_.typography, nullptr); 341 effect_->AppendTypography({config}); 342 effect_->typographyConfig_.typography = nullptr; 343 effect_->ClearTypography(); 344 EXPECT_EQ(effect_->typographyConfig_.rawTextRange.second, 10); 345 } 346 347 /* 348 * @tc.name: TextFlipEffectTest010 349 * @tc.desc: Test for GenerateChangeElements action 350 * @tc.type: FUNC 351 */ 352 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest010, TestSize.Level0) 353 { 354 OHOS::Rosen::TypographyStyle typographyStyle0; 355 typographyStyle0.enableAutoSpace = false; 356 std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection0 = 357 OHOS::Rosen::FontCollection::From(std::make_shared<txt::FontCollection>()); 358 std::unique_ptr<OHOS::Rosen::TypographyCreate> typographyCreate0 = 359 OHOS::Rosen::TypographyCreate::Create(typographyStyle0, fontCollection0); 360 std::u16string text = u"88"; 361 typographyCreate0->AppendText(text); 362 std::unique_ptr<OHOS::Rosen::Typography> typography0 = typographyCreate0->CreateTypography(); 363 double maxWidth = 1500; 364 typography0->Layout(maxWidth); 365 std::shared_ptr<Typography> typographySharePtr0(typography0.release()); 366 TypographyConfig config0 = { typographySharePtr0, {0, text.length()} }; 367 effect_->AppendTypography({config0}); 368 double x = 100.0; 369 double y = 200.0; 370 effect_->StartEffect(mockCanvas_.get(), x, y); 371 372 OHOS::Rosen::TypographyStyle typographyStyle1; 373 typographyStyle1.enableAutoSpace = false; 374 std::shared_ptr<OHOS::Rosen::FontCollection> fontCollection1 = 375 OHOS::Rosen::FontCollection::From(std::make_shared<txt::FontCollection>()); 376 std::unique_ptr<OHOS::Rosen::TypographyCreate> typographyCreate1 = 377 OHOS::Rosen::TypographyCreate::Create(typographyStyle1, fontCollection1); 378 text = u"89"; 379 typographyCreate1->AppendText(text); 380 std::unique_ptr<OHOS::Rosen::Typography> typography1 = typographyCreate1->CreateTypography(); 381 typography1->Layout(maxWidth); 382 std::shared_ptr<Typography> typographySharePtr1(typography1.release()); 383 TypographyConfig config1 = { typographySharePtr1, {0, text.length()} }; 384 std::vector<std::pair<TypographyConfig, TypographyConfig>> typographyConfigs; 385 std::pair<TypographyConfig, TypographyConfig> typographyConfig(config0, config1); 386 typographyConfigs.emplace_back(typographyConfig); 387 effect_->UpdateTypography(typographyConfigs); 388 typographySharePtr1->SetSkipTextBlobDrawing(true); 389 typographySharePtr1->Paint(mockCanvas_.get(), x, y); 390 std::vector<TextBlobRecordInfo> records = typographySharePtr1->GetTextBlobRecordInfo(); 391 EXPECT_FALSE(records.empty()); 392 std::vector<std::vector<TextEngine::TextEffectElement>> effectElements; 393 for (auto& info : records) { 394 effectElements = effect_->GenerateChangeElements(info.blob, 395 x + info.offset.fX, y + info.offset.fY); 396 } 397 EXPECT_FALSE(effectElements.empty()); 398 } 399 400 /* 401 * @tc.name: TextFlipEffectTest011 402 * @tc.desc: Test for GenerateFlipConfig action 403 * @tc.type: FUNC 404 */ 405 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest011, TestSize.Level0) 406 { 407 effect_->blurEnable_ = true; 408 EXPECT_EQ(effect_->GenerateFlipConfig(15.0).size(), 2); 409 } 410 411 /* 412 * @tc.name: TextFlipEffectTest012 413 * @tc.desc: Test for NoEffect action 414 * @tc.type: FUNC 415 */ 416 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest012, TestSize.Level0) 417 { 418 double x = 100.0; 419 double y = 200.0; 420 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(true)).Times(1); 421 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(false)).Times(1); 422 EXPECT_CALL(*mockTypography_, HasSkipTextBlobDrawing()).Times(1); 423 EXPECT_CALL(*mockTypography_, SetSkipTextBlobDrawing(false)).Times(2); 424 EXPECT_CALL(*mockTypography_, Paint(mockCanvas_.get(), x, y)).Times(1); 425 426 TypographyConfig config = CreateConfig(); 427 effect_->AppendTypography({config}); 428 effect_->NoEffect(mockCanvas_.get(), x, y); 429 EXPECT_TRUE(effect_->lastAllBlobGlyphIds_.empty()); 430 431 effect_->RemoveTypography({config}); 432 effect_->NoEffect(mockCanvas_.get(), x, y); 433 EXPECT_EQ(effect_->typographyConfig_.typography, nullptr); 434 } 435 436 /* 437 * @tc.name: TextFlipEffectTest013 438 * @tc.desc: Test for no path ttf 439 * @tc.type: FUNC 440 */ 441 HWTEST_F(TextFlipEffectTest, TextFlipEffectTest013, TestSize.Level0) 442 { 443 double x = 100.0; 444 double y = 100.0; 445 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(true)).Times(1); 446 EXPECT_CALL(*mockTypography_, SetTextEffectAssociation(false)).Times(1); 447 EXPECT_CALL(*mockTypography_, GetAnimation()).Times(1); 448 449 const char* text = "\uffff"; 450 OHOS::Rosen::Drawing::Font font; 451 std::shared_ptr<Drawing::TextBlob> blob = Drawing::TextBlob::MakeFromString(text, font); 452 TypographyConfig config = CreateConfig(); 453 effect_->AppendTypography({config}); 454 EXPECT_CALL(*mockCanvas_, DrawTextBlob(blob.get(), x, y)).Times(1); 455 TextBlobRecordInfo blobInfo; 456 blobInfo.blob = blob; 457 std::vector<TextBlobRecordInfo> infos; 458 infos.emplace_back(blobInfo); 459 effect_->DrawTextFlip(infos, mockCanvas_.get(), x, y); 460 EXPECT_TRUE(effect_->lastAllBlobGlyphIds_.empty()); 461 effect_->DrawTextFlip(infos, nullptr, x, y); 462 effect_->RemoveTypography({config}); 463 EXPECT_EQ(effect_->typographyConfig_.typography, nullptr); 464 }