1 /*
2  * Copyright (c) 2024 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/scrollable/scrollable_paint_method.h"
17 
18 #include "core/components_ng/base/frame_node.h"
19 #include "core/components_ng/base/geometry_node.h"
20 #include "core/components_ng/pattern/scrollable/scrollable_paint_property.h"
21 
22 namespace OHOS::Ace::NG {
23 
24 constexpr double PERCENT_100 = 100.0;
25 constexpr float LINEAR_GRADIENT_ANGLE = 90.0f;
26 constexpr float LINEAR_GRADIENT_DIRECTION_ANGLE = 270.0f;
27 namespace {
CreatePercentGradientColor(float percent,Color color)28 GradientColor CreatePercentGradientColor(float percent, Color color)
29 {
30     NG::GradientColor gredient = GradientColor(color);
31     gredient.SetDimension(CalcDimension(percent * PERCENT_100, DimensionUnit::PERCENT));
32     return gredient;
33 }
34 } // namespace
35 
UpdateFadingGradient(const RefPtr<RenderContext> & renderContext)36 void ScrollablePaintMethod::UpdateFadingGradient(const RefPtr<RenderContext>& renderContext)
37 {
38     if (!hasFadingEdge_) {
39         return;
40     }
41     CHECK_NULL_VOID(renderContext);
42     CHECK_NULL_VOID(overlayRenderContext_);
43     NG::Gradient gradient;
44     gradient.CreateGradientWithType(NG::GradientType::LINEAR);
45     if (isVerticalReverse_) {
46         bool tempFadingValue = isFadingTop_;
47         isFadingTop_ = isFadingBottom_;
48         isFadingBottom_ = tempFadingValue;
49     }
50     if (isFadingTop_) {
51         gradient.AddColor(CreatePercentGradientColor(startPercent_, Color::TRANSPARENT));
52         gradient.AddColor(CreatePercentGradientColor(startPercent_ + percentFading_, Color::WHITE));
53     }
54     if (isFadingBottom_) {
55         gradient.AddColor(CreatePercentGradientColor(endPercent_ - percentFading_, Color::WHITE));
56         gradient.AddColor(CreatePercentGradientColor(endPercent_, Color::TRANSPARENT));
57     }
58     if (vertical_) {
59         gradient.GetLinearGradient()->angle = isReverse_
60                                                   ? CalcDimension(LINEAR_GRADIENT_DIRECTION_ANGLE, DimensionUnit::PX)
61                                                   : CalcDimension(LINEAR_GRADIENT_ANGLE, DimensionUnit::PX);
62     }
63     renderContext->UpdateBackBlendApplyType(BlendApplyType::OFFSCREEN);
64 
65     overlayRenderContext_->UpdateZIndex(INT32_MAX);
66     overlayRenderContext_->UpdateLinearGradient(gradient);
67     if (!isFadingTop_ && !isFadingBottom_) {
68         overlayRenderContext_->UpdateBackBlendMode(BlendMode::SRC_OVER);
69         renderContext->UpdateBackBlendMode(BlendMode::NONE);
70     } else {
71         overlayRenderContext_->UpdateBackBlendMode(BlendMode::DST_IN);
72         renderContext->UpdateBackBlendMode(BlendMode::SRC_OVER);
73     }
74     overlayRenderContext_->UpdateBackBlendApplyType(BlendApplyType::OFFSCREEN);
75 }
76 
TryContentClip(PaintWrapper * wrapper)77 bool ScrollablePaintMethod::TryContentClip(PaintWrapper* wrapper)
78 {
79     CHECK_NULL_RETURN(wrapper, false);
80     auto props = DynamicCast<ScrollablePaintProperty>(wrapper->GetPaintProperty());
81     CHECK_NULL_RETURN(props, false);
82     auto&& clip = props->GetContentClip();
83     if (clip.has_value()) {
84         auto renderContext = wrapper->GetRenderContext();
85         renderContext->SetClipToFrame(false);
86         renderContext->SetClipToBounds(false);
87 
88         auto mode = clip->first;
89         if (mode == ContentClipMode::DEFAULT) {
90             mode = props->GetDefaultContentClip();
91         }
92         auto&& geo = wrapper->GetGeometryNode();
93         switch (mode) {
94             case ContentClipMode::CUSTOM:
95                 renderContext->SetContentClip(clip->second);
96                 break;
97             case ContentClipMode::CONTENT_ONLY: {
98                 auto rect = geo->GetPaddingRect();
99                 rect.SetOffset(rect.GetOffset() - geo->GetFrameOffset());
100                 renderContext->SetContentClip(rect);
101                 break;
102             }
103             case ContentClipMode::SAFE_AREA: {
104                 auto host = renderContext->GetHost();
105                 CHECK_NULL_RETURN(host, false);
106                 const auto safeAreaPad = host->GetAccumulatedSafeAreaExpand(true);
107 
108                 auto size = geo->GetPaddingSize();
109                 AddPaddingToSize(safeAreaPad, size);
110 
111                 auto offset = geo->GetPaddingOffset() - geo->GetFrameOffset();
112                 offset -= OffsetF(safeAreaPad.left.value_or(0.0f), safeAreaPad.top.value_or(0.0f));
113                 renderContext->SetContentClip(RectF { offset, size });
114                 break;
115             }
116             case ContentClipMode::BOUNDARY: {
117                 auto rect = geo->GetFrameRect();
118                 rect.SetOffset({ 0.0f, 0.0f });
119                 renderContext->SetContentClip(rect);
120                 break;
121             }
122             default:
123                 break;
124         }
125         return true;
126     }
127     return false;
128 }
129 } // namespace OHOS::Ace::NG