1 /*
2  * Copyright (c) 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 "core/components_ng/pattern/image/image_modifier.h"
17 
18 #include <cstdlib>
19 
20 namespace OHOS::Ace::NG {
ImageModifier()21 ImageModifier::ImageModifier()
22 {
23     imageFit_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
24     flag_ = AceType::MakeRefPtr<PropertyBool>(false);
25     AttachProperty(imageFit_);
26     AttachProperty(flag_);
27 }
28 
onDraw(DrawingContext & context)29 void ImageModifier::onDraw(DrawingContext& context)
30 {
31     auto canvas = canvasImage_.Upgrade();
32     CHECK_NULL_VOID(canvas);
33     if (isAltImage_) {
34         DrawImageWithoutAnimation(context);
35         return;
36     }
37     if (isFirst_) {
38         DrawImageWithoutAnimation(context);
39         isFirst_ = false;
40     } else {
41         auto&& config = canvas->GetPaintConfig();
42         if (config.isSvg_) {
43             DrawImageWithoutAnimation(context);
44         } else {
45             DrawImageWithAnimation(context);
46         }
47     }
48 }
49 
SetImageFit(ImageFit imagefit)50 void ImageModifier::SetImageFit(ImageFit imagefit)
51 {
52     if (imagefit != endImageFit_) {
53         startImageFit_ = endImageFit_;
54         endImageFit_ = imagefit;
55     } else {
56         imageFit_->Set(static_cast<float>(startImageFit_));
57     }
58     imageFit_->Set(static_cast<float>(imagefit));
59 }
60 
UpdateImageData(const WeakPtr<CanvasImage> & canvasImage,const OffsetF & offset,const SizeF & contentSize)61 void ImageModifier::UpdateImageData(
62     const WeakPtr<CanvasImage>& canvasImage, const OffsetF& offset, const SizeF& contentSize)
63 {
64     canvasImage_ = canvasImage;
65     offset_ = offset;
66     contentSize_ = contentSize;
67     auto canvas = canvasImage_.Upgrade();
68     CHECK_NULL_VOID(canvas);
69     auto&& config = canvas->GetPaintConfig();
70     // update srcRect
71     startSrcRect_ = endSrcRect_;
72     endSrcRect_ = config.srcRect_;
73     // update dstRect
74     startDstRect_ = endDstRect_;
75     endDstRect_ = config.dstRect_;
76 }
77 
Modify()78 void ImageModifier::Modify()
79 {
80     flag_->Set(!flag_->Get());
81 }
82 
SetIsAltImage(bool isAltImage)83 void ImageModifier::SetIsAltImage(bool isAltImage)
84 {
85     isAltImage_ = isAltImage;
86 }
87 
GetValue(float value) const88 float ImageModifier::GetValue(float value) const
89 {
90     return std::max(value, 0.0f);
91 }
92 
DrawImageWithAnimation(DrawingContext & context)93 void ImageModifier::DrawImageWithAnimation(DrawingContext& context)
94 {
95     float difference = static_cast<float>(endImageFit_) - static_cast<float>(startImageFit_);
96     float ratio = 1.0f;
97     if (!NearZero(difference)) {
98         // ratio goes from 0 to 1
99         ratio = std::abs((imageFit_->Get() - static_cast<float>(startImageFit_)) / difference);
100     }
101     UpdatePaintConfig(ratio);
102     auto canvas = canvasImage_.Upgrade();
103     CHECK_NULL_VOID(canvas);
104     canvas->SetIsDrawAnimate(!NearEqual(ANIMATION_END, ratio, EPSILON));
105     ImagePainter imagePainter(canvas);
106     imagePainter.DrawImage(context.canvas, offset_, contentSize_);
107 }
108 
DrawImageWithoutAnimation(DrawingContext & context) const109 void ImageModifier::DrawImageWithoutAnimation(DrawingContext& context) const
110 {
111     auto canvas = canvasImage_.Upgrade();
112     CHECK_NULL_VOID(canvas);
113     ImagePainter imagePainter(canvas);
114     imagePainter.DrawImage(context.canvas, offset_, contentSize_);
115 }
116 
UpdatePaintConfig(float ratio)117 void ImageModifier::UpdatePaintConfig(float ratio)
118 {
119     // use ratio to calculate new dstRect and srcRect
120     auto canvas = canvasImage_.Upgrade();
121     CHECK_NULL_VOID(canvas);
122     auto&& config = canvas->GetPaintConfig();
123     if (NearEqual(ANIMATION_END, ratio, EPSILON)) {
124         config.dstRect_.SetRect(endDstRect_.GetOffset(), endDstRect_.GetSize());
125         config.srcRect_.SetRect(endSrcRect_.GetOffset(), endSrcRect_.GetSize());
126     } else {
127         // calculate new dstRect
128         auto x = startDstRect_.GetX() + (endDstRect_.GetX() - startDstRect_.GetX()) * ratio;
129         auto y = startDstRect_.GetY() + (endDstRect_.GetY() - startDstRect_.GetY()) * ratio;
130         auto width = contentSize_.Width() - TWICE * x;
131         auto height = contentSize_.Height() - TWICE * y;
132         config.dstRect_.SetRect(GetValue(x), GetValue(y), GetValue(width), GetValue(height));
133         // calculate new srcRect
134         auto startImageWidth = TWICE * startSrcRect_.GetX() + startSrcRect_.Width();
135         auto startImageHeight = TWICE * startSrcRect_.GetY() + startSrcRect_.Height();
136         auto endImageWidth = TWICE * endSrcRect_.GetX() + endSrcRect_.Width();
137         auto endImageHeight = TWICE * endSrcRect_.GetY() + endSrcRect_.Height();
138 
139         x = endSrcRect_.GetX() * ratio +
140             (startSrcRect_.GetX() / (startImageWidth / endImageWidth)) * (ANIMATION_END - ratio);
141         y = endSrcRect_.GetY() * ratio +
142             (startSrcRect_.GetY() / (startImageHeight / endImageHeight)) * (ANIMATION_END - ratio);
143         // calculate new width & height
144         width = endImageWidth - TWICE * x;
145         height = endImageHeight - TWICE * y;
146         config.srcRect_.SetRect(GetValue(x), GetValue(y), GetValue(width), GetValue(height));
147     }
148 }
149 } // namespace OHOS::Ace::NG
150