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