1 /*
2 * Copyright (c) 2022-2023 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 <algorithm>
17 #include <cstddef>
18 #include <optional>
19 #include <utility>
20
21 #include "base/image/image_source.h"
22 #include "base/image/pixel_map.h"
23 #include "gtest/gtest.h"
24
25 #define protected public
26 #define private public
27 #include "core/components_ng/pattern/canvas/canvas_event_hub.h"
28 #include "core/components_ng/pattern/canvas/canvas_layout_algorithm.h"
29 #include "core/components_ng/pattern/canvas/canvas_model.h"
30 #include "core/components_ng/pattern/canvas/canvas_model_ng.h"
31 #include "core/components_ng/pattern/canvas/canvas_modifier.h"
32 #include "core/components_ng/pattern/canvas/canvas_paint_method.h"
33 #include "core/components_ng/pattern/canvas/canvas_paint_op.h"
34 #include "core/components_ng/pattern/canvas/canvas_pattern.h"
35 #include "core/components_ng/pattern/canvas/custom_paint_paint_method.h"
36 #include "core/components_ng/pattern/canvas/custom_paint_util.h"
37 #include "core/components_ng/pattern/canvas/offscreen_canvas_paint_method.h"
38 #include "core/components_ng/pattern/canvas/offscreen_canvas_pattern.h"
39 #undef private
40 #undef protected
41
42 using namespace testing;
43 using namespace testing::ext;
44
45 namespace OHOS::Ace::NG {
46
47 class CanvasTestNg : public testing::Test {
48 public:
49 static void SetUpTestCase();
50 static void TearDownTestCase();
51 };
52
SetUpTestCase()53 void CanvasTestNg::SetUpTestCase() {}
54
TearDownTestCase()55 void CanvasTestNg::TearDownTestCase() {}
56
57 /**
58 * @tc.name: CanvasPatternTest001
59 * @tc.desc: Test the function 'IsPercentStr' of the class 'CustomPaintPaintMethod'.
60 * @tc.type: FUNC
61 */
62 HWTEST_F(CanvasTestNg, CanvasPatternTest001, TestSize.Level1)
63 {
64 /**
65 * @tc.steps1: initialize parameters.
66 * @tc.expected: All pointer is non-null.
67 */
68 auto paintMethod = AceType::MakeRefPtr<OffscreenCanvasPaintMethod>();
69 ASSERT_NE(paintMethod, nullptr);
70
71 /**
72 * @tc.steps2: Call the function IsPercentStr with percent string.
73 * @tc.expected: The return value is true and the '%' of percent string is droped.
74 */
75 const std::string exceptedresult("50");
76
77 std::string percentStr("50%");
78 EXPECT_TRUE(paintMethod->IsPercentStr(percentStr));
79 EXPECT_STREQ(percentStr.c_str(), exceptedresult.c_str());
80
81 /**
82 * @tc.steps3: Call the function IsPercentStr with non-percent string.
83 * @tc.expected: The return value is false and the non-percent string is not changed.
84 */
85 std::string nonPercentStr("50");
86 EXPECT_FALSE(paintMethod->IsPercentStr(nonPercentStr));
87 EXPECT_STREQ(nonPercentStr.c_str(), exceptedresult.c_str());
88 }
89
90 /**
91 * @tc.name: CanvasPatternTest002
92 * @tc.desc: CanvasPattern::OnSizeChanged
93 * @tc.type: FUNC
94 */
95 HWTEST_F(CanvasTestNg, CanvasPatternTest002, TestSize.Level1)
96 {
97 auto* stack = ViewStackProcessor::GetInstance();
98 auto nodeId = stack->ClaimNodeId();
99 auto frameNode = FrameNode::GetOrCreateFrameNode(
__anonef3f1d760102() 100 V2::CANVAS_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<CanvasPattern>(); });
101 RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
102 geometryNode->SetContentSize(SizeF(100.0f, 100.0f));
103 geometryNode->SetContentOffset(OffsetF(0.0f, 0.0f));
104 auto pattern = frameNode->GetPattern<CanvasPattern>();
105 RefPtr<LayoutAlgorithm> layoutAlgorithm = AceType::MakeRefPtr<LayoutAlgorithm>();
106 auto layoutAlgorithmWrapper = AceType::MakeRefPtr<LayoutAlgorithmWrapper>(layoutAlgorithm, false);
107 auto layoutWrapper = AceType::MakeRefPtr<LayoutWrapperNode>(frameNode, geometryNode, nullptr);
108 layoutWrapper->SetLayoutAlgorithm(layoutAlgorithmWrapper);
109 DirtySwapConfig config;
110 bool needReset;
111
112 /**
113 * @tc.steps: step1. needReset = false; dirtyPixelGridRoundSize_ = { 0, 0 }
114 */
115 needReset = false;
116 pattern->contentModifier_ = AceType::MakeRefPtr<CanvasModifier>();
117 pattern->dirtyPixelGridRoundSize_ = { -1, -1 };
118 pattern->OnSizeChanged(config, needReset);
119 ASSERT_NE(pattern->contentModifier_, nullptr);
120 auto contentModifier1 = pattern->contentModifier_;
121 EXPECT_FALSE(contentModifier1->needResetSurface_);
122
123 /**
124 * @tc.steps: step2. needReset = false; dirtyPixelGridRoundSize_ = { 1, 1 };
125 */
126 needReset = false;
127 config.frameSizeChange = false;
128 config.contentSizeChange = false;
129 pattern->contentModifier_ = AceType::MakeRefPtr<CanvasModifier>();
130 pattern->dirtyPixelGridRoundSize_ = { 1, 1 };
131 pattern->OnSizeChanged(config, needReset);
132 ASSERT_NE(pattern->contentModifier_, nullptr);
133 auto contentModifier2 = pattern->contentModifier_;
134 EXPECT_FALSE(contentModifier2->needResetSurface_);
135
136 /**
137 * @tc.steps: step3. needReset = true; dirtyPixelGridRoundSize_ = { 1, 1 };
138 */
139 needReset = false;
140 config.frameSizeChange = true;
141 config.contentSizeChange = true;
142 pattern->contentModifier_ = AceType::MakeRefPtr<CanvasModifier>();
143 pattern->dirtyPixelGridRoundSize_ = { 1, 1 };
144 pattern->OnSizeChanged(config, needReset);
145 ASSERT_NE(pattern->contentModifier_, nullptr);
146 auto contentModifier3 = pattern->contentModifier_;
147 EXPECT_FALSE(contentModifier3->needResetSurface_);
148
149 /**
150 * @tc.steps: step4. needReset = true; config.frameSizeChange = false; config.contentSizeChange = false;
151 */
152 needReset = true;
153 config.frameSizeChange = false;
154 config.contentSizeChange = false;
155 pattern->contentModifier_ = AceType::MakeRefPtr<CanvasModifier>();
156 pattern->dirtyPixelGridRoundSize_ = { -1, -1 };
157 pattern->OnSizeChanged(config, needReset);
158 ASSERT_NE(pattern->contentModifier_, nullptr);
159 auto contentModifier4 = pattern->contentModifier_;
160 EXPECT_FALSE(contentModifier4->needResetSurface_);
161
162 /**
163 * @tc.steps: step5. needReset = true; config.frameSizeChange = true; config.contentSizeChange = false;
164 */
165 needReset = true;
166 config.frameSizeChange = true;
167 config.contentSizeChange = false;
168 pattern->contentModifier_ = AceType::MakeRefPtr<CanvasModifier>();
169 pattern->dirtyPixelGridRoundSize_ = { -1, -1 };
170 pattern->OnSizeChanged(config, needReset);
171 ASSERT_NE(pattern->contentModifier_, nullptr);
172 auto contentModifier5 = pattern->contentModifier_;
173 EXPECT_TRUE(contentModifier5->needResetSurface_);
174
175 /**
176 * @tc.steps: step6. needReset = true; config.frameSizeChange = false; config.contentSizeChange = true;
177 */
178 needReset = true;
179 config.frameSizeChange = false;
180 config.contentSizeChange = true;
181 pattern->contentModifier_ = AceType::MakeRefPtr<CanvasModifier>();
182 pattern->dirtyPixelGridRoundSize_ = { -1, -1 };
183 pattern->OnSizeChanged(config, needReset);
184 ASSERT_NE(pattern->contentModifier_, nullptr);
185 auto contentModifier6 = pattern->contentModifier_;
186 EXPECT_TRUE(contentModifier6->needResetSurface_);
187 }
188
189 /**
190 * @tc.name: CanvasPatternTest003
191 * @tc.desc: CanvasPattern::EnableAnalyzer
192 * @tc.type: FUNC
193 */
194 HWTEST_F(CanvasTestNg, CanvasPatternTest003, TestSize.Level1)
195 {
196 auto* stack = ViewStackProcessor::GetInstance();
197 auto nodeId = stack->ClaimNodeId();
198 auto frameNode = FrameNode::GetOrCreateFrameNode(
__anonef3f1d760202() 199 V2::CANVAS_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<CanvasPattern>(); });
200 RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
201 geometryNode->SetContentSize(SizeF(100.0f, 100.0f));
202 geometryNode->SetContentOffset(OffsetF(0.0f, 0.0f));
203 auto pattern = frameNode->GetPattern<CanvasPattern>();
204
205 /**
206 * @tc.steps: step1. enable = false;
207 */
208 pattern->EnableAnalyzer(false);
209 EXPECT_FALSE(pattern->imageAnalyzerManager_);
210
211 /**
212 * @tc.steps: step1. enable = true;
213 */
214 pattern->EnableAnalyzer(true);
215 EXPECT_TRUE(pattern->imageAnalyzerManager_);
216 }
217
218 /**
219 * @tc.name: CanvasPatternTest004
220 * @tc.desc: CanvasPattern::UpdateTextDefaultDirection
221 * @tc.type: FUNC
222 */
223 HWTEST_F(CanvasTestNg, CanvasPatternTest004, TestSize.Level1)
224 {
225 auto* stack = ViewStackProcessor::GetInstance();
226 auto nodeId = stack->ClaimNodeId();
227 auto frameNode = FrameNode::GetOrCreateFrameNode(
__anonef3f1d760302() 228 V2::CANVAS_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<CanvasPattern>(); });
229 RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
230 geometryNode->SetContentSize(SizeF(100.0f, 100.0f));
231 geometryNode->SetContentOffset(OffsetF(0.0f, 0.0f));
232 auto pattern = frameNode->GetPattern<CanvasPattern>();
233
234 /**
235 * @tc.steps: step1. TextDirection::AUTO;
236 */
237 pattern->currentSetTextDirection_ = TextDirection::AUTO;
238 pattern->UpdateTextDefaultDirection();
239 EXPECT_EQ(pattern->currentSetTextDirection_, TextDirection::AUTO);
240 }
241
242 /**
243 * @tc.name: CanvasPatternTest005
244 * @tc.desc: CanvasLayoutAlgorithm::MeasureContent
245 * @tc.type: FUNC
246 */
247 HWTEST_F(CanvasTestNg, CanvasPatternTest005, TestSize.Level1)
248 {
249 auto* stack = ViewStackProcessor::GetInstance();
250 auto nodeId = stack->ClaimNodeId();
251 auto frameNode = FrameNode::GetOrCreateFrameNode(
__anonef3f1d760402() 252 V2::CANVAS_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<CanvasPattern>(); });
253 RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
254 geometryNode->SetContentSize(SizeF(100.0f, 100.0f));
255 geometryNode->SetContentOffset(OffsetF(0.0f, 0.0f));
256 auto pattern = frameNode->GetPattern<CanvasPattern>();
257
258 RefPtr<CanvasLayoutAlgorithm> canvasLayoutAlgorithm = AceType::MakeRefPtr<CanvasLayoutAlgorithm>();
259 LayoutConstraintF layoutConstraint;
260 LayoutWrapperNode layoutWrapper = LayoutWrapperNode(frameNode, geometryNode, frameNode->GetLayoutProperty());
261
262 /**
263 * @tc.steps: step1. IsValid() == false;
264 */
265 layoutConstraint.maxSize.SetWidth(1000.0f);
266 layoutConstraint.maxSize.SetHeight(1000.0f);
267 canvasLayoutAlgorithm->MeasureContent(layoutConstraint, &layoutWrapper);
268 EXPECT_EQ(pattern->canvasSize_->width_, 1000.0f);
269 EXPECT_EQ(pattern->canvasSize_->height_, 1000.0f);
270
271 /**
272 * @tc.steps: step1. IsValid() == true;
273 */
274 layoutConstraint.selfIdealSize.SetWidth(960.0f);
275 layoutConstraint.selfIdealSize.SetHeight(960.0f);
276 canvasLayoutAlgorithm->MeasureContent(layoutConstraint, &layoutWrapper);
277 EXPECT_EQ(pattern->canvasSize_->width_, 960.0f);
278 EXPECT_EQ(pattern->canvasSize_->height_, 960.0f);
279 }
280
281 /**
282 * @tc.name: CanvasPatternTest006
283 * @tc.desc: GetQuality
284 * @tc.type: FUNC
285 */
286 HWTEST_F(CanvasTestNg, CanvasPatternTest006, TestSize.Level1)
287 {
288 double dRet = 0.0;
289 std::string strRet = "";
290
291 /**
292 * @tc.steps: step1. GetQuality:type != IMAGE_JPEG && type != IMAGE_WEBP, quality > 0.0 || quality < 1.0
293 */
294 dRet = GetQuality("", 0.8);
295 EXPECT_EQ(dRet, DEFAULT_QUALITY * QUALITY_COEFFICIENT);
296
297 /**
298 * @tc.steps: step2. GetQuality:type != IMAGE_JPEG && type != IMAGE_WEBP, quality > 0.0 || quality < 1.0
299 */
300 dRet = GetQuality(IMAGE_PNG, 0.8);
301 EXPECT_EQ(dRet, DEFAULT_QUALITY * QUALITY_COEFFICIENT);
302
303 /**
304 * @tc.steps: step4. GetQuality:mimeType == IMAGE_JPEG, quality > 0.0 || quality < 1.0
305 */
306 dRet = GetQuality(IMAGE_JPEG, 0.8);
307 EXPECT_EQ(dRet, 0.8 * QUALITY_COEFFICIENT);
308
309 /**
310 * @tc.steps: step5. GetQuality:mimeType == IMAGE_WEBP, quality > 0.0 || quality < 1.0
311 */
312 dRet = GetQuality(IMAGE_WEBP, 0.8);
313 EXPECT_EQ(dRet, 0.8 * QUALITY_COEFFICIENT);
314
315 /**
316 * @tc.steps: step6. mimeType == IMAGE_WEBP, GetQuality:quality > 1.0
317 */
318 dRet = GetQuality(IMAGE_WEBP, 1.1);
319 EXPECT_EQ(dRet, DEFAULT_QUALITY * QUALITY_COEFFICIENT);
320
321 /**
322 * @tc.steps: step7. mimeType == IMAGE_WEBP, GetQuality:quality < 0.0
323 */
324 dRet = GetQuality(IMAGE_WEBP, -1.1);
325 EXPECT_EQ(dRet, DEFAULT_QUALITY * QUALITY_COEFFICIENT);
326 }
327
328 /**
329 * @tc.name: CanvasPatternTest007
330 * @tc.desc: OffscreenCanvasPattern::SetTextDirection && UpdateTextDefaultDirection
331 * @tc.type: FUNC
332 */
333 HWTEST_F(CanvasTestNg, CanvasPatternTest007, TestSize.Level1)
334 {
335 auto* stack = ViewStackProcessor::GetInstance();
336 auto nodeId = stack->ClaimNodeId();
337 auto frameNode = FrameNode::GetOrCreateFrameNode(
__anonef3f1d760502() 338 V2::CANVAS_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<OffscreenCanvasPattern>(100, 100); });
339 RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
340 geometryNode->SetContentSize(SizeF(100.0f, 100.0f));
341 geometryNode->SetContentOffset(OffsetF(0.0f, 0.0f));
342 auto offPattern = frameNode->GetPattern<OffscreenCanvasPattern>();
343
344 /**
345 * @tc.steps: step1. SetTextDirection : TextDirection::AUTO;
346 */
347 offPattern->SetTextDirection(TextDirection::AUTO);
348 EXPECT_EQ(offPattern->offscreenPaintMethod_->state_.fillState.textDirection_, TextDirection::AUTO);
349 /**
350 * @tc.steps: step2. SetTextDirection : TextDirection::INHERIT;
351 */
352 offPattern->SetTextDirection(TextDirection::INHERIT);
353 EXPECT_EQ(offPattern->offscreenPaintMethod_->state_.fillState.textDirection_, TextDirection::LTR);
354 /**
355 * @tc.steps: step3. UpdateTextDefaultDirection : TextDirection::INHERIT;
356 */
357 offPattern->currentSetTextDirection_ = TextDirection::AUTO;
358 offPattern->UpdateTextDefaultDirection();
359 EXPECT_EQ(offPattern->offscreenPaintMethod_->state_.fillState.textDirection_, TextDirection::LTR);
360 /**
361 * @tc.steps: step4. UpdateTextDefaultDirection : TextDirection::INHERIT;
362 */
363 offPattern->currentSetTextDirection_ = TextDirection::INHERIT;
364 offPattern->UpdateTextDefaultDirection();
365 EXPECT_EQ(offPattern->offscreenPaintMethod_->state_.fillState.textDirection_, TextDirection::LTR);
366 }
367
368 /**
369 * @tc.name: CanvasPatternTest008
370 * @tc.desc: CustomPaintPaintMethod::FillText && StrokeText
371 * @tc.type: FUNC
372 */
373 HWTEST_F(CanvasTestNg, CanvasPatternTest008, TestSize.Level1)
374 {
375 auto* stack = ViewStackProcessor::GetInstance();
376 auto nodeId = stack->ClaimNodeId();
377 auto frameNode = FrameNode::GetOrCreateFrameNode(
__anonef3f1d760602() 378 V2::CANVAS_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<OffscreenCanvasPattern>(100, 100); });
379 RefPtr<GeometryNode> geometryNode = AceType::MakeRefPtr<GeometryNode>();
380 geometryNode->SetContentSize(SizeF(100.0f, 100.0f));
381 geometryNode->SetContentOffset(OffsetF(0.0f, 0.0f));
382 auto offPattern = frameNode->GetPattern<OffscreenCanvasPattern>();
383
384 /**
385 * @tc.steps: step1. FillText : ret == false
386 */
387 offPattern->offscreenPaintMethod_->FillText("test", 0.0, 0.0, 50);
388 EXPECT_FALSE(offPattern->offscreenPaintMethod_->UpdateFillParagraph("test"));
389
390 /**
391 * @tc.steps: step2. StrokeText : HasShadow() == false
392 */
393 Shadow shadow1 = Shadow(5.0f, Offset(0.0, 0.0), Color(0x32000000), ShadowStyle::OuterDefaultXS);
394 Shadow shadow2 = Shadow(5.0f, Offset(10.0, 10.0), Color(0x32000000), ShadowStyle::OuterDefaultXS);
395 offPattern->offscreenPaintMethod_->state_.shadow = shadow1;
396 EXPECT_FALSE(offPattern->offscreenPaintMethod_->HasShadow());
397 offPattern->offscreenPaintMethod_->StrokeText("test", 0.0, 0.0, 50);
398 /**
399 * @tc.steps: step3. StrokeText : HasShadow() == true
400 */
401 offPattern->offscreenPaintMethod_->state_.shadow = shadow2;
402 EXPECT_TRUE(offPattern->offscreenPaintMethod_->HasShadow());
403 offPattern->offscreenPaintMethod_->FillText("test", 0.0, 0.0, 50);
404 }
405
406 } // namespace OHOS::Ace::NG
407