• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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