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