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/overlay/sheet_wrapper_paint_method.h"
17
18 #include "base/geometry/ng/offset_t.h"
19 #include "base/utils/utils.h"
20 #include "core/components/common/properties/shadow_config.h"
21 #include "core/components_ng/pattern/overlay/sheet_presentation_pattern.h"
22 #include "core/components_ng/pattern/overlay/sheet_style.h"
23 #include "core/components_ng/pattern/overlay/sheet_wrapper_pattern.h"
24 #include "core/components_ng/render/drawing.h"
25 #include "core/components_ng/render/drawing_prop_convertor.h"
26 #include "core/components_ng/render/paint_wrapper.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr Dimension ARROW_VERTICAL_P1_OFFSET_X = 8.0_vp;
32 constexpr Dimension ARROW_VERTICAL_P2_OFFSET_X = 1.5_vp;
33 constexpr Dimension ARROW_VERTICAL_P2_OFFSET_Y = 7.32_vp;
34 constexpr Dimension ARROW_VERTICAL_P4_OFFSET_X = 1.5_vp;
35 constexpr Dimension ARROW_VERTICAL_P4_OFFSET_Y = 7.32_vp;
36 constexpr Dimension ARROW_VERTICAL_P5_OFFSET_X = 8.0_vp;
37 constexpr Dimension ARROW_RADIUS = 2.0_vp;
38 constexpr float BLUR_MASK_FILTER = 0.55f;
39 constexpr float HALF = 0.5f;
40 } // namespace
41
PaintOuterBorder(RSCanvas & canvas,PaintWrapper * paintWrapper)42 void SheetWrapperPaintMethod::PaintOuterBorder(RSCanvas& canvas, PaintWrapper* paintWrapper)
43 {
44 CHECK_NULL_VOID(paintWrapper);
45 CHECK_EQUAL_VOID(IsDrawBorder(paintWrapper), false);
46 auto sheetNode = GetSheetNode(paintWrapper);
47 CHECK_NULL_VOID(sheetNode);
48 auto pipeline = sheetNode->GetContext();
49 CHECK_NULL_VOID(pipeline);
50 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
51 CHECK_NULL_VOID(sheetTheme);
52 RSPath path;
53 auto outerBorderWidth = sheetTheme->GetSheetOuterBorderWidth().ConvertToPx();
54 auto sheetPattern = DynamicCast<SheetPresentationPattern>(sheetNode->GetPattern());
55 CHECK_NULL_VOID(sheetPattern);
56 BorderRadiusProperty sheetRadius(sheetTheme->GetSheetRadius());
57 sheetPattern->CalculateSheetRadius(sheetRadius);
58 GetBorderDrawPath(path, sheetNode, sheetTheme, outerBorderWidth, sheetRadius);
59 RSPen pen;
60 SetBorderPenStyle(pen, sheetTheme->GetSheetOuterBorderWidth(), sheetTheme->GetSheetOuterBorderColor());
61 canvas.Save();
62 canvas.AttachPen(pen);
63 canvas.DrawPath(path);
64 canvas.DetachPen();
65 canvas.Restore();
66 path.Close();
67 }
68
GetSheetNode(PaintWrapper * paintWrapper)69 RefPtr<FrameNode> SheetWrapperPaintMethod::GetSheetNode(PaintWrapper* paintWrapper)
70 {
71 CHECK_NULL_RETURN(paintWrapper, nullptr);
72 auto renderContext = paintWrapper->GetRenderContext();
73 CHECK_NULL_RETURN(renderContext, nullptr);
74 auto host = renderContext->GetHost();
75 CHECK_NULL_RETURN(host, nullptr);
76 auto sheetNode = DynamicCast<FrameNode>(host->GetFirstChild());
77 CHECK_NULL_RETURN(sheetNode, nullptr);
78 return sheetNode;
79 }
80
GetBorderDrawPath(RSPath & path,const RefPtr<FrameNode> sheetNode,const RefPtr<SheetTheme> & sheetTheme,float borderWidth,const BorderRadiusProperty & sheetRadius)81 void SheetWrapperPaintMethod::GetBorderDrawPath(RSPath& path, const RefPtr<FrameNode> sheetNode,
82 const RefPtr<SheetTheme>& sheetTheme, float borderWidth, const BorderRadiusProperty& sheetRadius)
83 {
84 auto sheetPattern = DynamicCast<SheetPresentationPattern>(sheetNode->GetPattern());
85 CHECK_NULL_VOID(sheetPattern);
86 auto geometryNode = sheetNode->GetGeometryNode();
87 CHECK_NULL_VOID(geometryNode);
88 auto sheetSize = geometryNode->GetFrameSize();
89 auto radiusTopLeft = sheetRadius.radiusTopLeft->ConvertToPx();
90 auto radiusTopRight = sheetRadius.radiusTopRight->ConvertToPx();
91 auto radiusBottomRight = sheetRadius.radiusBottomRight->ConvertToPx();
92 auto radiusBottomLeft = sheetRadius.radiusBottomLeft->ConvertToPx();
93 auto borderOffset = borderWidth * HALF;
94 auto arrowOffset = sheetPattern->GetSheetArrowOffset().GetX();
95 auto targetOffsetX = sheetNode->GetPositionToParentWithTransform().GetX();
96 auto targetOffsetY = sheetNode->GetPositionToParentWithTransform().GetY();
97 auto arrowHeight = SHEET_ARROW_HEIGHT.ConvertToPx();
98 path.Reset();
99 path.MoveTo(targetOffsetX - borderOffset, arrowHeight + radiusTopLeft + targetOffsetY);
100 if (LessNotEqual(radiusTopLeft, sheetSize.Width() * HALF - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx())) {
101 // When radius is less than half the page width, draw radius and P1
102 path.ArcTo(radiusTopLeft + borderOffset, radiusTopLeft + borderOffset, 0.0f, RSPathDirection::CW_DIRECTION,
103 radiusTopLeft + targetOffsetX, arrowHeight + targetOffsetY - borderOffset);
104 path.LineTo(arrowOffset - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx() + targetOffsetX,
105 arrowHeight + targetOffsetY - borderOffset); // P1
106 } else {
107 // Change the end point of radius, skip P1 and draw P2 to P3 directly
108 path.ArcTo(radiusTopLeft + borderOffset, radiusTopLeft + borderOffset, 0.0f, RSPathDirection::CW_DIRECTION,
109 sheetSize.Width() * HALF - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx() + targetOffsetX,
110 arrowHeight + targetOffsetY - borderOffset);
111 }
112 path.LineTo(arrowOffset - ARROW_VERTICAL_P2_OFFSET_X.ConvertToPx() + targetOffsetX - borderOffset,
113 arrowHeight - ARROW_VERTICAL_P2_OFFSET_Y.ConvertToPx() + targetOffsetY); // P2
114 path.ArcTo(ARROW_RADIUS.ConvertToPx() + borderOffset, ARROW_RADIUS.ConvertToPx() + borderOffset, 0.0f,
115 RSPathDirection::CW_DIRECTION,
116 arrowOffset + ARROW_VERTICAL_P4_OFFSET_X.ConvertToPx() + targetOffsetX + borderOffset,
117 arrowHeight - ARROW_VERTICAL_P4_OFFSET_Y.ConvertToPx() + targetOffsetY); // P4
118 path.LineTo(arrowOffset + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx() + targetOffsetX,
119 arrowHeight + targetOffsetY - borderOffset); // P5
120 if (LessNotEqual(radiusTopRight, sheetSize.Width() * HALF - ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx())) {
121 // When radius is less than half the page width, draw P5
122 path.LineTo(sheetSize.Width() - radiusTopRight + targetOffsetX, arrowHeight + targetOffsetY - borderOffset);
123 }
124 path.ArcTo(radiusTopRight + borderOffset, radiusTopRight + borderOffset, 0.0f, RSPathDirection::CW_DIRECTION,
125 sheetSize.Width() + targetOffsetX + borderOffset, arrowHeight + radiusTopRight + targetOffsetY);
126 path.LineTo(
127 sheetSize.Width() + targetOffsetX + borderOffset, sheetSize.Height() - radiusBottomRight + targetOffsetY);
128 path.ArcTo(radiusBottomRight + borderOffset, radiusBottomRight + borderOffset, 0.0f, RSPathDirection::CW_DIRECTION,
129 sheetSize.Width() - radiusBottomRight + targetOffsetX, sheetSize.Height() + targetOffsetY + borderOffset);
130 path.LineTo(radiusBottomLeft + targetOffsetX, sheetSize.Height() + targetOffsetY + borderOffset);
131 path.ArcTo(radiusBottomLeft + borderOffset, radiusBottomLeft + borderOffset, 0.0f, RSPathDirection::CW_DIRECTION,
132 targetOffsetX - borderOffset, sheetSize.Height() - radiusBottomLeft + targetOffsetY);
133 path.LineTo(targetOffsetX - borderOffset, arrowHeight + radiusTopLeft + targetOffsetY);
134 }
135
PaintInnerBorder(RSCanvas & canvas,PaintWrapper * paintWrapper)136 void SheetWrapperPaintMethod::PaintInnerBorder(RSCanvas& canvas, PaintWrapper* paintWrapper)
137 {
138 CHECK_NULL_VOID(paintWrapper);
139 CHECK_EQUAL_VOID(IsDrawBorder(paintWrapper), false);
140 auto sheetNode = GetSheetNode(paintWrapper);
141 CHECK_NULL_VOID(sheetNode);
142 auto pipeline = sheetNode->GetContext();
143 CHECK_NULL_VOID(pipeline);
144 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
145 CHECK_NULL_VOID(sheetTheme);
146 RSPath path;
147 auto innerBorderWidth = -(sheetTheme->GetSheetInnerBorderWidth().ConvertToPx());
148 auto sheetPattern = DynamicCast<SheetPresentationPattern>(sheetNode->GetPattern());
149 CHECK_NULL_VOID(sheetPattern);
150 BorderRadiusProperty sheetRadius(sheetTheme->GetSheetRadius());
151 sheetPattern->CalculateSheetRadius(sheetRadius);
152 GetBorderDrawPath(path, sheetNode, sheetTheme, innerBorderWidth, sheetRadius);
153 RSPen pen;
154 SetBorderPenStyle(pen, sheetTheme->GetSheetInnerBorderWidth(), sheetTheme->GetSheetInnerBorderColor());
155 canvas.Save();
156 canvas.AttachPen(pen);
157 canvas.DrawPath(path);
158 canvas.DetachPen();
159 canvas.Restore();
160 path.Close();
161 }
162
SetBorderPenStyle(RSPen & pen,const Dimension & borderWidth,const Color & borderColor)163 void SheetWrapperPaintMethod::SetBorderPenStyle(RSPen& pen, const Dimension& borderWidth, const Color& borderColor)
164 {
165 RSFilter filter;
166 filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter(RSBlurType::SOLID, BLUR_MASK_FILTER));
167 pen.SetFilter(filter);
168 pen.SetAntiAlias(true);
169 pen.SetWidth(borderWidth.ConvertToPx());
170 pen.SetColor(borderColor.GetValue());
171 }
172
IsDrawBorder(PaintWrapper * paintWrapper)173 bool SheetWrapperPaintMethod::IsDrawBorder(PaintWrapper* paintWrapper)
174 {
175 auto sheetNode = GetSheetNode(paintWrapper);
176 CHECK_NULL_RETURN(sheetNode, false);
177 auto sheetPattern = DynamicCast<SheetPresentationPattern>(sheetNode->GetPattern());
178 CHECK_NULL_RETURN(sheetPattern, false);
179 auto sheetType = sheetPattern->GetSheetType();
180 auto pipeline = sheetNode->GetContext();
181 CHECK_NULL_RETURN(pipeline, false);
182 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
183 CHECK_NULL_RETURN(sheetTheme, false);
184 auto layoutProperty = sheetNode->GetLayoutProperty<SheetPresentationProperty>();
185 CHECK_NULL_RETURN(layoutProperty, false);
186 auto sheetStyle = layoutProperty->GetSheetStyleValue();
187 if (sheetTheme->IsOuterBorderEnable() && sheetType == SheetType::SHEET_POPUP &&
188 !sheetStyle.borderWidth.has_value()) {
189 return true;
190 }
191 return false;
192 }
193
194 } // namespace OHOS::Ace::NG
195