1 /*
2  * Copyright (c) 2021 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/clip/render_clip.h"
17 
18 #include "base/log/dump_log.h"
19 #include "base/log/event_report.h"
20 #include "core/components/box/render_box.h"
21 #include "core/components/clip/clip_component.h"
22 #include "core/components/display/render_display.h"
23 #include "core/components/transform/render_transform.h"
24 
25 namespace OHOS::Ace {
26 
Update(const RefPtr<Component> & component)27 void RenderClip::Update(const RefPtr<Component>& component)
28 {
29     const RefPtr<ClipComponent> clip = AceType::DynamicCast<ClipComponent>(component);
30     if (!clip) {
31         return;
32     }
33     clipWithShadow_ = clip->IsClipWithShadow();
34     followChildSize_ = clip->IsFollowChild();
35     width_ = NormalizeToPx(clip->GetWidth());
36     height_ = NormalizeToPx(clip->GetHeight());
37     offsetX_ = NormalizeToPx(clip->GetOffsetX());
38     offsetY_ = NormalizeToPx(clip->GetOffsetY());
39 
40     topLeftRadius_ = clip->GetTopLeftRadius();
41     topRightRadius_ = clip->GetTopRightRadius();
42     bottomLeftRadius_ = clip->GetBottomLeftRadius();
43     bottomRightRadius_ = clip->GetBottomRightRadius();
44 
45     MarkNeedLayout();
46 }
47 
PerformLayout()48 void RenderClip::PerformLayout()
49 {
50     if (GetChildren().empty()) {
51         LOGE("RenderClip: no child found in RenderClip!");
52         EventReport::SendRenderException(RenderExcepType::CLIP_ERR);
53         return;
54     }
55     auto child = GetChildren().front();
56     child->Layout(GetLayoutParam());
57     child->SetPosition(Offset::Zero());
58     if (followChildSize_) {
59         SetLayoutSize(child->GetLayoutSize());
60     } else {
61         SetLayoutSize(GetLayoutParam().GetMaxSize());
62     }
63 }
64 
GetFloatPropertySetterMap()65 FloatPropertyAnimatable::SetterMap RenderClip::GetFloatPropertySetterMap()
66 {
67     FloatPropertyAnimatable::SetterMap map;
68     auto weak = AceType::WeakClaim(this);
69     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak](float value) {
70         auto clip = weak.Upgrade();
71         if (!clip) {
72             LOGE("set width failed. clip is null.");
73             return;
74         }
75         clip->SetWidth(value);
76     };
77     map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak](float value) {
78         auto clip = weak.Upgrade();
79         if (!clip) {
80             LOGE("set height failed. clip is null.");
81             return;
82         }
83         clip->SetHeight(value);
84     };
85     map[PropertyAnimatableType::PROPERTY_OFFSET_X] = [weak](float value) {
86         auto clip = weak.Upgrade();
87         if (!clip) {
88             LOGE("set offsetX failed. clip is null.");
89             return;
90         }
91         clip->SetOffsetX(value);
92         clip->UpdateBoxForShadowAnimation();
93     };
94     map[PropertyAnimatableType::PROPERTY_OFFSET_Y] = [weak](float value) {
95         auto clip = weak.Upgrade();
96         if (!clip) {
97             LOGE("set offsetY failed. clip is null.");
98             return;
99         }
100         clip->SetOffsetY(value);
101         clip->UpdateBoxForShadowAnimation();
102     };
103     map[PropertyAnimatableType::PROPERTY_BORDER_RADIUS] = [weak](float value) {
104         auto clip = weak.Upgrade();
105         if (!clip) {
106             LOGE("set border radius failed. clip is null.");
107             return;
108         }
109         clip->SetClipRadius(Radius(value));
110     };
111     return map;
112 };
113 
GetFloatPropertyGetterMap()114 FloatPropertyAnimatable::GetterMap RenderClip::GetFloatPropertyGetterMap()
115 {
116     FloatPropertyAnimatable::GetterMap map;
117     auto weak = AceType::WeakClaim(this);
118     map[PropertyAnimatableType::PROPERTY_WIDTH] = [weak]() -> float {
119         auto clip = weak.Upgrade();
120         if (!clip) {
121             LOGE("get width failed. clip is null.");
122             return 0.0;
123         }
124         return clip->width_;
125     };
126     map[PropertyAnimatableType::PROPERTY_HEIGHT] = [weak]() -> float {
127         auto clip = weak.Upgrade();
128         if (!clip) {
129             LOGE("get height failed. clip is null.");
130             return 0.0;
131         }
132         return clip->height_;
133     };
134     map[PropertyAnimatableType::PROPERTY_OFFSET_X] = [weak]() -> float {
135         auto clip = weak.Upgrade();
136         if (!clip) {
137             LOGE("get offsetX failed. clip is null.");
138             return 0.0;
139         }
140         return clip->offsetX_;
141     };
142     map[PropertyAnimatableType::PROPERTY_OFFSET_Y] = [weak]() -> float {
143         auto clip = weak.Upgrade();
144         if (!clip) {
145             LOGE("get offsetY failed. clip is null.");
146             return 0.0;
147         }
148         return clip->offsetY_;
149     };
150 
151     map[PropertyAnimatableType::PROPERTY_BORDER_RADIUS] = [weak]() -> float {
152         auto clip = weak.Upgrade();
153         if (!clip) {
154             LOGE("get borer radius failed. clip is null.");
155             return 0.0f;
156         }
157         return clip->topLeftRadius_.GetX().Value();
158     };
159     return map;
160 };
161 
GetClipRect(const Offset & offset) const162 Rect RenderClip::GetClipRect(const Offset& offset) const
163 {
164     double clipWidth = 0.0;
165     if (!NearZero(width_)) {
166         clipWidth = width_;
167     } else {
168         clipWidth = GetTransitionPaintRect().Width();
169     }
170     double clipHeight = 0.0;
171     if (!NearZero(height_)) {
172         clipHeight = height_;
173     } else {
174         clipHeight = GetTransitionPaintRect().Height();
175     }
176     return Rect(offset.GetX() + offsetX_, offset.GetY() + offsetY_, clipWidth, clipHeight);
177 }
178 
UpdateBoxForShadowAnimation()179 void RenderClip::UpdateBoxForShadowAnimation()
180 {
181     if (!clipWithShadow_) {
182         return;
183     }
184 
185     // If clip is used for animation, then there will be existed display and transform.
186     auto renderTransform = AceType::DynamicCast<RenderTransform>(GetParent().Upgrade());
187     if (!renderTransform) {
188         return;
189     }
190     auto renderDisplay = AceType::DynamicCast<RenderDisplay>(renderTransform->GetParent().Upgrade());
191     if (!renderDisplay) {
192         return;
193     }
194     // There must be box for shadow animation.
195     auto renderBox = DynamicCast<RenderBox>(renderDisplay->GetParent().Upgrade());
196     if (renderBox) {
197         renderBox->SetPaintSize(GetLayoutSize() - Size(offsetX_, offsetY_));
198         renderBox->SetPosition(shadowBoxOffset_ + Offset(offsetX_, offsetY_));
199         renderBox->MarkNeedRender();
200         SetPosition(Offset(-offsetX_, -offsetY_));
201     }
202 }
203 
Dump()204 void RenderClip::Dump()
205 {
206     DumpLog::GetInstance().AddDesc(std::string("Clip HW: ").append(Size(width_, height_).ToString()));
207     DumpLog::GetInstance().AddDesc(std::string("Clip Offset: ").append(Offset(offsetX_, offsetY_).ToString()));
208 }
209 
210 } // namespace OHOS::Ace
211