• 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 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_paint_method.h"
16 
17 #include "core/components/select/select_theme.h"
18 #include "core/components_ng/pattern/menu/menu_paint_property.h"
19 #include "core/components_ng/render/drawing_prop_convertor.h"
20 #include "core/components_ng/pattern/menu/menu_theme.h"
21 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.h"
22 #include "core/components_ng/render/drawing.h"
23 #include "core/components_ng/render/node_paint_method.h"
24 #include "core/components_ng/render/paint_wrapper.h"
25 
26 namespace OHOS::Ace::NG {
27 namespace {
28 constexpr int32_t RADIUS_MIDPOINT = 2;
29 constexpr float BORDER_MULTIPLES = 2.0f;
30 constexpr Dimension ARROW_RADIUS = 2.0_vp;
31 constexpr Dimension ARROW_P1_OFFSET_X = 8.0_vp;
32 constexpr Dimension ARROW_P2_OFFSET_X = 1.5_vp;
33 constexpr Dimension ARROW_P1_OFFSET_Y = 8.0_vp;
34 constexpr Dimension ARROW_P2_OFFSET_Y = 0.68_vp;
35 
GetMenuThemeFromPaintWrapper(PaintWrapper * paintWrapper)36 RefPtr<MenuTheme> GetMenuThemeFromPaintWrapper(PaintWrapper* paintWrapper)
37 {
38     CHECK_NULL_RETURN(paintWrapper, nullptr);
39     auto renderContext = paintWrapper->GetRenderContext();
40     CHECK_NULL_RETURN(renderContext, nullptr);
41     auto host = renderContext->GetHost();
42     CHECK_NULL_RETURN(host, nullptr);
43     auto pipelineContext = host->GetContextRefPtr();
44     CHECK_NULL_RETURN(pipelineContext, nullptr);
45     return pipelineContext->GetTheme<MenuTheme>();
46 }
47 
GetMenuWrapperPatternFromPaintWrapper(PaintWrapper * paintWrapper)48 RefPtr<MenuWrapperPattern> GetMenuWrapperPatternFromPaintWrapper(PaintWrapper* paintWrapper)
49 {
50     CHECK_NULL_RETURN(paintWrapper, nullptr);
51     auto renderContext = paintWrapper->GetRenderContext();
52     CHECK_NULL_RETURN(renderContext, nullptr);
53     auto host = renderContext->GetHost();
54     CHECK_NULL_RETURN(host, nullptr);
55     return host->GetPattern<MenuWrapperPattern>();
56 }
57 }
58 
GetOverlayDrawFunction(PaintWrapper * paintWrapper)59 CanvasDrawFunction MenuWrapperPaintMethod::GetOverlayDrawFunction(PaintWrapper* paintWrapper)
60 {
61     return [weak = WeakClaim(this), paintWrapper](RSCanvas& canvas) {
62         if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
63             return;
64         }
65         auto menuTheme = GetMenuThemeFromPaintWrapper(paintWrapper);
66         CHECK_NULL_VOID(menuTheme);
67         auto wrapperPattern = GetMenuWrapperPatternFromPaintWrapper(paintWrapper);
68         CHECK_NULL_VOID(wrapperPattern);
69         if (!menuTheme->GetDoubleBorderEnable() && !wrapperPattern->GetHasCustomOutlineWidth()) {
70             return;
71         }
72         auto paintMethod = weak.Upgrade();
73         if (paintMethod) {
74             paintMethod->PaintDoubleBorder(canvas, paintWrapper);
75         }
76     };
77 }
78 
PaintDoubleBorder(RSCanvas & canvas,PaintWrapper * paintWrapper)79 void MenuWrapperPaintMethod::PaintDoubleBorder(RSCanvas& canvas, PaintWrapper* paintWrapper)
80 {
81     CHECK_NULL_VOID(paintWrapper);
82     auto renderContext = paintWrapper->GetRenderContext();
83     CHECK_NULL_VOID(renderContext);
84     auto host = renderContext->GetHost();
85     CHECK_NULL_VOID(host);
86     auto wrapperPattern = host->GetPattern<MenuWrapperPattern>();
87     CHECK_NULL_VOID(wrapperPattern);
88     if (wrapperPattern->GetMenuStatus() != MenuStatus::SHOW) {
89         return;
90     }
91     auto children = host->GetChildren();
92     if (children.empty()) {
93         return;
94     }
95     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
96         auto& child = *iter;
97         if (!child || child->GetTag() != V2::MENU_ETS_TAG) {
98             continue;
99         }
100         auto frameNode = AceType::DynamicCast<FrameNode>(child);
101         CHECK_NULL_VOID(frameNode);
102         auto renderContext = frameNode->GetRenderContext();
103         CHECK_NULL_VOID(renderContext);
104         auto opacity = renderContext->GetOpacity().value_or(1.0);
105         if (!NearEqual(opacity, 1.0)) {
106             continue;
107         }
108         auto pattern = frameNode->GetPattern<MenuPattern>();
109         CHECK_NULL_VOID(pattern);
110         auto params = pattern->GetMenuPathParams();
111         if (params.has_value()) {
112             PaintInnerBorderAndClipSinglePath(canvas, paintWrapper, params.value());
113             PaintOuterBorderAndClipSinglePath(canvas, paintWrapper, params.value());
114         }
115     }
116 }
117 
PaintInnerBorderAndClipSinglePath(RSCanvas & canvas,PaintWrapper * paintWrapper,const MenuPathParams & params)118 void MenuWrapperPaintMethod::PaintInnerBorderAndClipSinglePath(
119     RSCanvas& canvas, PaintWrapper* paintWrapper, const MenuPathParams& params)
120 {
121     RSPath rsPath;
122     BuildCompletePath(rsPath, params);
123     canvas.Save();
124     if (!params.didNeedArrow) {
125         canvas.ClipPath(rsPath, RSClipOp::DIFFERENCE, true);
126         return;
127     }
128     RSPen paint;
129     paint.SetAntiAlias(true);
130     auto menuTheme = GetMenuThemeFromPaintWrapper(paintWrapper);
131     CHECK_NULL_VOID(menuTheme);
132     // Because the canvas is cut by the ContentDrawFunction method, only half of the width can be drawn
133     paint.SetWidth(menuTheme->GetInnerBorderWidth() * BORDER_MULTIPLES);
134     paint.SetColor(menuTheme->GetInnerBorderColor().GetValue());
135     canvas.AttachPen(paint);
136     canvas.ClipPath(rsPath, RSClipOp::INTERSECT, true);
137     canvas.DrawPath(rsPath);
138     canvas.DetachPen();
139     canvas.Restore();
140 }
141 
CanvasDrawOutline(RSCanvas & canvas,const RSPen & paint,const RSPath & rsPathEdge)142 void CanvasDrawOutline(RSCanvas& canvas, const RSPen& paint, const RSPath& rsPathEdge)
143 {
144     canvas.Save();
145     canvas.AttachPen(paint);
146     canvas.DrawPath(rsPathEdge);
147     canvas.DetachPen();
148 }
149 
PaintEdgeOuterBorder(const MenuPathParams & params,RSCanvas & canvas,const MenuParam & menuParam)150 void MenuWrapperPaintMethod::PaintEdgeOuterBorder(
151     const MenuPathParams& params, RSCanvas& canvas, const MenuParam& menuParam)
152 {
153     RSPath rsPathTop;
154     RSPath rsPathRight;
155     RSPath rsPathBottom;
156     RSPath rsPathLeft;
157     RSPen paint;
158     paint.SetAntiAlias(true);
159     auto maxWidth =
160         std::max({ menuParam.outlineWidth->leftDimen->ConvertToPx(), menuParam.outlineWidth->topDimen->ConvertToPx(),
161             menuParam.outlineWidth->rightDimen->ConvertToPx(), menuParam.outlineWidth->bottomDimen->ConvertToPx() });
162     paint.SetWidth(maxWidth * BORDER_MULTIPLES);
163     rsPathTop.MoveTo(
164         params.childOffset.GetX() + params.radiusTopLeftPx - params.radiusTopLeftPx / sqrt(RADIUS_MIDPOINT),
165         params.childOffset.GetY() + params.radiusTopLeftPx - params.radiusTopLeftPx / sqrt(RADIUS_MIDPOINT));
166     BuildTopLinePath(rsPathTop, params);
167     paint.SetColor(menuParam.outlineColor->topColor->GetValue());
168     CanvasDrawOutline(canvas, paint, rsPathTop);
169 
170     rsPathRight.MoveTo(params.childOffset.GetX() + params.frameSize.Width() - params.radiusTopRightPx +
171                            params.radiusTopRightPx / sqrt(RADIUS_MIDPOINT),
172         params.childOffset.GetY() + params.radiusTopRightPx - params.radiusTopRightPx / sqrt(RADIUS_MIDPOINT));
173     BuildRightLinePath(rsPathRight, params);
174     paint.SetColor(menuParam.outlineColor->rightColor->GetValue());
175     CanvasDrawOutline(canvas, paint, rsPathRight);
176 
177     rsPathBottom.MoveTo(params.childOffset.GetX() + params.frameSize.Width() - params.radiusBottomRightPx +
178                             params.radiusBottomRightPx / sqrt(RADIUS_MIDPOINT),
179         params.childOffset.GetY() + params.frameSize.Height() - params.radiusBottomRightPx +
180             params.radiusBottomRightPx / sqrt(RADIUS_MIDPOINT));
181     BuildBottomLinePath(rsPathBottom, params);
182     paint.SetColor(menuParam.outlineColor->bottomColor->GetValue());
183     CanvasDrawOutline(canvas, paint, rsPathBottom);
184 
185     rsPathLeft.MoveTo(
186         params.childOffset.GetX() + params.radiusBottomLeftPx - params.radiusBottomLeftPx / sqrt(RADIUS_MIDPOINT),
187         params.childOffset.GetY() + params.frameSize.Height() - params.radiusBottomLeftPx +
188             params.radiusBottomLeftPx / sqrt(RADIUS_MIDPOINT));
189     BuildLeftLinePath(rsPathLeft, params);
190     paint.SetColor(menuParam.outlineColor->leftColor->GetValue());
191     CanvasDrawOutline(canvas, paint, rsPathLeft);
192 }
193 
PaintOuterBorderAndClipSinglePath(RSCanvas & canvas,PaintWrapper * paintWrapper,const MenuPathParams & params)194 void MenuWrapperPaintMethod::PaintOuterBorderAndClipSinglePath(
195     RSCanvas& canvas, PaintWrapper* paintWrapper, const MenuPathParams& params)
196 {
197     CHECK_NULL_VOID(paintWrapper);
198     auto wrapperPattern = GetMenuWrapperPatternFromPaintWrapper(paintWrapper);
199     CHECK_NULL_VOID(wrapperPattern);
200     RSPath rsPath;
201     MenuParam menuParam = wrapperPattern->GetMenuParam();
202     BuildCompletePath(rsPath, params);
203     canvas.Save();
204     if (!params.didNeedArrow) {
205         canvas.ClipPath(rsPath, RSClipOp::DIFFERENCE, true);
206         return;
207     }
208     RSPen paint;
209     paint.SetAntiAlias(true);
210     auto menuTheme = GetMenuThemeFromPaintWrapper(paintWrapper);
211     CHECK_NULL_VOID(menuTheme);
212     if (!wrapperPattern->GetHasCustomOutlineWidth()) {
213         paint.SetWidth(menuTheme->GetOuterBorderWidth() * BORDER_MULTIPLES);
214         paint.SetColor(menuTheme->GetOuterBorderColor().GetValue());
215         CanvasDrawOutline(canvas, paint, rsPath);
216     } else {
217         canvas.Save();
218         auto rsOutlinePath = BuildOutlinePath(params, menuParam);
219         canvas.ClipPath(rsOutlinePath, RSClipOp::INTERSECT, true);
220         canvas.ClipPath(rsPath, RSClipOp::DIFFERENCE, true);
221         PaintEdgeOuterBorder(params, canvas, menuParam);
222     }
223 }
224 
BuildOutlinePath(const MenuPathParams & params,const MenuParam & menuParam)225 RSPath MenuWrapperPaintMethod::BuildOutlinePath(const MenuPathParams& params, const MenuParam& menuParam)
226 {
227     auto rsOutlineParam = params;
228     rsOutlineParam.childOffset.SetX(params.childOffset.GetX() - menuParam.outlineWidth->leftDimen->ConvertToPx());
229     rsOutlineParam.childOffset.SetY(params.childOffset.GetY() - menuParam.outlineWidth->topDimen->ConvertToPx());
230     rsOutlineParam.frameSize.SetWidth(params.frameSize.Width() + menuParam.outlineWidth->leftDimen->ConvertToPx() +
231                                       menuParam.outlineWidth->rightDimen->ConvertToPx());
232     rsOutlineParam.frameSize.SetHeight(params.frameSize.Height() + menuParam.outlineWidth->topDimen->ConvertToPx() +
233                                        menuParam.outlineWidth->bottomDimen->ConvertToPx());
234     arrowOutlineOffset_.top = menuParam.outlineWidth->topDimen->ConvertToPx();
235     arrowOutlineOffset_.left = menuParam.outlineWidth->leftDimen->ConvertToPx();
236     arrowOutlineOffset_.right = menuParam.outlineWidth->rightDimen->ConvertToPx();
237     arrowOutlineOffset_.bottom = menuParam.outlineWidth->bottomDimen->ConvertToPx();
238     RSPath rsOutlinePath;
239     BuildCompletePath(rsOutlinePath, rsOutlineParam);
240     arrowOutlineOffset_.Reset();
241     return rsOutlinePath;
242 }
243 
BuildCompletePath(RSPath & rsPath,const MenuPathParams & params)244 void MenuWrapperPaintMethod::BuildCompletePath(RSPath& rsPath, const MenuPathParams& params)
245 {
246     rsPath.MoveTo(params.childOffset.GetX() + params.radiusTopLeftPx - params.radiusTopLeftPx / sqrt(RADIUS_MIDPOINT),
247         params.childOffset.GetY() + params.radiusTopLeftPx - params.radiusTopLeftPx / sqrt(RADIUS_MIDPOINT));
248     BuildTopLinePath(rsPath, params);
249     BuildRightLinePath(rsPath, params);
250     BuildBottomLinePath(rsPath, params);
251     BuildLeftLinePath(rsPath, params);
252 }
253 
BuildTopLinePath(RSPath & rsPath,const MenuPathParams & params)254 void MenuWrapperPaintMethod::BuildTopLinePath(RSPath& rsPath, const MenuPathParams& params)
255 {
256     rsPath.ArcTo(params.radiusTopLeftPx, params.radiusTopLeftPx, 0.0f, RSPathDirection::CW_DIRECTION,
257         params.childOffset.GetX() + params.radiusTopLeftPx, params.childOffset.GetY());
258     if (params.didNeedArrow) {
259         switch (params.arrowPlacement) {
260             case Placement::BOTTOM:
261             case Placement::BOTTOM_LEFT:
262             case Placement::BOTTOM_RIGHT:
263                 BuildBottomArrowPath(rsPath, params.arrowPosition.GetX(), params.arrowPosition.GetY());
264                 break;
265             default:
266                 break;
267         }
268     }
269     rsPath.LineTo(
270         params.childOffset.GetX() + params.frameSize.Width() - params.radiusTopRightPx, params.childOffset.GetY());
271     rsPath.ArcTo(params.radiusTopRightPx, params.radiusTopRightPx, 0.0f, RSPathDirection::CW_DIRECTION,
272         params.childOffset.GetX() + params.frameSize.Width() - params.radiusTopRightPx +
273             params.radiusTopRightPx / sqrt(RADIUS_MIDPOINT),
274         params.childOffset.GetY() + params.radiusTopRightPx - params.radiusTopRightPx / sqrt(RADIUS_MIDPOINT));
275 }
276 
BuildRightLinePath(RSPath & rsPath,const MenuPathParams & params)277 void MenuWrapperPaintMethod::BuildRightLinePath(RSPath& rsPath, const MenuPathParams& params)
278 {
279     rsPath.ArcTo(params.radiusTopRightPx, params.radiusTopRightPx, 0.0f, RSPathDirection::CW_DIRECTION,
280         params.childOffset.GetX() + params.frameSize.Width(), params.childOffset.GetY() + params.radiusTopRightPx);
281     if (params.didNeedArrow) {
282         switch (params.arrowPlacement) {
283             case Placement::LEFT:
284             case Placement::LEFT_TOP:
285             case Placement::LEFT_BOTTOM:
286                 BuildLeftArrowPath(rsPath, params.arrowPosition.GetX(), params.arrowPosition.GetY());
287                 break;
288             default:
289                 break;
290         }
291     }
292     rsPath.LineTo(params.childOffset.GetX() + params.frameSize.Width(),
293         params.childOffset.GetY() + params.frameSize.Height() - params.radiusBottomRightPx);
294     rsPath.ArcTo(params.radiusBottomRightPx, params.radiusBottomRightPx, 0.0f, RSPathDirection::CW_DIRECTION,
295         params.childOffset.GetX() + params.frameSize.Width() - params.radiusBottomRightPx +
296             params.radiusBottomRightPx / sqrt(RADIUS_MIDPOINT),
297         params.childOffset.GetY() + params.frameSize.Height() - params.radiusBottomRightPx +
298             params.radiusBottomRightPx / sqrt(RADIUS_MIDPOINT));
299 }
300 
BuildBottomLinePath(RSPath & rsPath,const MenuPathParams & params)301 void MenuWrapperPaintMethod::BuildBottomLinePath(RSPath& rsPath, const MenuPathParams& params)
302 {
303     rsPath.ArcTo(params.radiusBottomRightPx, params.radiusBottomRightPx, 0.0f, RSPathDirection::CW_DIRECTION,
304         params.childOffset.GetX() + params.frameSize.Width() - params.radiusBottomRightPx,
305         params.childOffset.GetY() + params.frameSize.Height());
306     if (params.didNeedArrow) {
307         switch (params.arrowPlacement) {
308             case Placement::TOP:
309             case Placement::TOP_LEFT:
310             case Placement::TOP_RIGHT:
311                 BuildTopArrowPath(rsPath, params.arrowPosition.GetX(), params.arrowPosition.GetY());
312                 break;
313             default:
314                 break;
315         }
316     }
317     rsPath.LineTo(
318         params.childOffset.GetX() + params.radiusBottomLeftPx, params.childOffset.GetY() + params.frameSize.Height());
319     rsPath.ArcTo(params.radiusBottomLeftPx, params.radiusBottomLeftPx, 0.0f, RSPathDirection::CW_DIRECTION,
320         params.childOffset.GetX() + params.radiusBottomLeftPx - params.radiusBottomLeftPx / sqrt(RADIUS_MIDPOINT),
321         params.childOffset.GetY() + params.frameSize.Height() - params.radiusBottomLeftPx +
322             params.radiusBottomLeftPx / sqrt(RADIUS_MIDPOINT));
323 }
324 
BuildLeftLinePath(RSPath & rsPath,const MenuPathParams & params)325 void MenuWrapperPaintMethod::BuildLeftLinePath(RSPath& rsPath, const MenuPathParams& params)
326 {
327     rsPath.ArcTo(params.radiusBottomLeftPx, params.radiusBottomLeftPx, 0.0f, RSPathDirection::CW_DIRECTION,
328         params.childOffset.GetX(), params.childOffset.GetY() + params.frameSize.Height() - params.radiusBottomLeftPx);
329     if (params.didNeedArrow) {
330         switch (params.arrowPlacement) {
331             case Placement::RIGHT:
332             case Placement::RIGHT_TOP:
333             case Placement::RIGHT_BOTTOM:
334                 BuildRightArrowPath(rsPath, params.arrowPosition.GetX(), params.arrowPosition.GetY());
335                 break;
336             default:
337                 break;
338         }
339     }
340     rsPath.LineTo(params.childOffset.GetX(), params.childOffset.GetY() + params.radiusTopLeftPx);
341     rsPath.ArcTo(params.radiusTopLeftPx, params.radiusTopLeftPx, 0.0f, RSPathDirection::CW_DIRECTION,
342         params.childOffset.GetX() + params.radiusTopLeftPx - params.radiusTopLeftPx / sqrt(RADIUS_MIDPOINT),
343         params.childOffset.GetY() + params.radiusTopLeftPx - params.radiusTopLeftPx / sqrt(RADIUS_MIDPOINT));
344 }
345 
BuildBottomArrowPath(RSPath & rsPath,float arrowX,float arrowY)346 void MenuWrapperPaintMethod::BuildBottomArrowPath(RSPath& rsPath, float arrowX, float arrowY)
347 {
348     rsPath.LineTo(arrowX - ARROW_P1_OFFSET_X.ConvertToPx(),
349         arrowY + ARROW_P1_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.top); // P1
350     rsPath.LineTo(arrowX - ARROW_P2_OFFSET_X.ConvertToPx(),
351         arrowY + ARROW_P2_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.top); // P2
352     rsPath.ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, RSPathDirection::CW_DIRECTION,
353         arrowX + ARROW_P2_OFFSET_X.ConvertToPx(),
354         arrowY + ARROW_P2_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.top); // P4
355     rsPath.LineTo(arrowX + ARROW_P1_OFFSET_X.ConvertToPx(),
356         arrowY + ARROW_P1_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.top); // P5
357 }
358 
BuildTopArrowPath(RSPath & rsPath,float arrowX,float arrowY)359 void MenuWrapperPaintMethod::BuildTopArrowPath(RSPath& rsPath, float arrowX, float arrowY)
360 {
361     rsPath.LineTo(arrowX + ARROW_P1_OFFSET_X.ConvertToPx(),
362         arrowY - ARROW_P1_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.bottom); // P1
363     rsPath.LineTo(arrowX + ARROW_P2_OFFSET_X.ConvertToPx(),
364         arrowY - ARROW_P2_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.bottom); // P2
365     rsPath.ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, RSPathDirection::CW_DIRECTION,
366         arrowX - ARROW_P2_OFFSET_X.ConvertToPx(),
367         arrowY - ARROW_P2_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.bottom); // P4
368     rsPath.LineTo(arrowX - ARROW_P1_OFFSET_X.ConvertToPx(),
369         arrowY - ARROW_P1_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.bottom); // P5
370 }
371 
BuildRightArrowPath(RSPath & rsPath,float arrowX,float arrowY)372 void MenuWrapperPaintMethod::BuildRightArrowPath(RSPath& rsPath, float arrowX, float arrowY)
373 {
374     rsPath.LineTo(arrowX + ARROW_P1_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.left,
375         arrowY + ARROW_P1_OFFSET_X.ConvertToPx()); // P1
376     rsPath.LineTo(arrowX + ARROW_P2_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.left,
377         arrowY + ARROW_P2_OFFSET_X.ConvertToPx()); // P2
378     rsPath.ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, RSPathDirection::CW_DIRECTION,
379         arrowX + ARROW_P2_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.left,
380         arrowY - ARROW_P2_OFFSET_X.ConvertToPx()); // P4
381     rsPath.LineTo(arrowX + ARROW_P1_OFFSET_Y.ConvertToPx() - arrowOutlineOffset_.left,
382         arrowY - ARROW_P1_OFFSET_X.ConvertToPx()); // P5
383 }
384 
BuildLeftArrowPath(RSPath & rsPath,float arrowX,float arrowY)385 void MenuWrapperPaintMethod::BuildLeftArrowPath(RSPath& rsPath, float arrowX, float arrowY)
386 {
387     rsPath.LineTo(arrowX - ARROW_P1_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.right,
388         arrowY - ARROW_P1_OFFSET_X.ConvertToPx()); // P1
389     rsPath.LineTo(arrowX - ARROW_P2_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.right,
390         arrowY - ARROW_P2_OFFSET_X.ConvertToPx()); // P2
391     rsPath.ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, RSPathDirection::CW_DIRECTION,
392         arrowX - ARROW_P2_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.right,
393         arrowY + ARROW_P2_OFFSET_X.ConvertToPx()); // P4
394     rsPath.LineTo(arrowX - ARROW_P1_OFFSET_Y.ConvertToPx() + arrowOutlineOffset_.right,
395         arrowY + ARROW_P1_OFFSET_X.ConvertToPx()); // P5
396 }
397 } // namespace OHOS::Ace::NG
398