1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ShapeUtils.h"
11 #include "nsCSSRendering.h"
13 #include "nsStyleStruct.h"
14 #include "mozilla/SVGContentUtils.h"
18 nscoord
ShapeUtils::ComputeShapeRadius(const StyleShapeRadius
& aType
,
19 const nscoord aCenter
,
20 const nscoord aPosMin
,
21 const nscoord aPosMax
) {
22 MOZ_ASSERT(aType
.IsFarthestSide() || aType
.IsClosestSide());
23 nscoord dist1
= std::abs(aPosMin
- aCenter
);
24 nscoord dist2
= std::abs(aPosMax
- aCenter
);
26 if (aType
.IsFarthestSide()) {
27 length
= dist1
> dist2
? dist1
: dist2
;
29 length
= dist1
> dist2
? dist2
: dist1
;
34 nsPoint
ShapeUtils::ComputeCircleOrEllipseCenter(
35 const StyleBasicShape
& aBasicShape
, const nsRect
& aRefBox
) {
36 MOZ_ASSERT(aBasicShape
.IsCircle() || aBasicShape
.IsEllipse(),
37 "The basic shape must be circle() or ellipse!");
39 const auto& position
= aBasicShape
.IsCircle()
40 ? aBasicShape
.AsCircle().position
41 : aBasicShape
.AsEllipse().position
;
43 nsPoint topLeft
, anchor
;
44 nsSize
size(aRefBox
.Size());
45 nsImageRenderer::ComputeObjectAnchorPoint(position
, size
, size
, &topLeft
,
47 return anchor
+ aRefBox
.TopLeft();
50 nscoord
ShapeUtils::ComputeCircleRadius(const StyleBasicShape
& aBasicShape
,
51 const nsPoint
& aCenter
,
52 const nsRect
& aRefBox
) {
53 MOZ_ASSERT(aBasicShape
.IsCircle(), "The basic shape must be circle()!");
54 const auto& radius
= aBasicShape
.AsCircle().radius
;
55 if (radius
.IsLength()) {
56 return radius
.AsLength().Resolve([&] {
57 // We resolve percent <shape-radius> value for circle() as defined here:
58 // https://drafts.csswg.org/css-shapes/#funcdef-circle
59 double referenceLength
= SVGContentUtils::ComputeNormalizedHypotenuse(
60 aRefBox
.width
, aRefBox
.height
);
61 return NSToCoordRound(referenceLength
);
66 ComputeShapeRadius(radius
, aCenter
.x
, aRefBox
.x
, aRefBox
.XMost());
68 ComputeShapeRadius(radius
, aCenter
.y
, aRefBox
.y
, aRefBox
.YMost());
69 return radius
.IsFarthestSide() ? std::max(horizontal
, vertical
)
70 : std::min(horizontal
, vertical
);
73 nsSize
ShapeUtils::ComputeEllipseRadii(const StyleBasicShape
& aBasicShape
,
74 const nsPoint
& aCenter
,
75 const nsRect
& aRefBox
) {
76 MOZ_ASSERT(aBasicShape
.IsEllipse(), "The basic shape must be ellipse()!");
77 const auto& ellipse
= aBasicShape
.AsEllipse();
79 if (ellipse
.semiaxis_x
.IsLength()) {
80 radii
.width
= ellipse
.semiaxis_x
.AsLength().Resolve(aRefBox
.width
);
82 radii
.width
= ComputeShapeRadius(ellipse
.semiaxis_x
, aCenter
.x
, aRefBox
.x
,
86 if (ellipse
.semiaxis_y
.IsLength()) {
87 radii
.height
= ellipse
.semiaxis_y
.AsLength().Resolve(aRefBox
.height
);
89 radii
.height
= ComputeShapeRadius(ellipse
.semiaxis_y
, aCenter
.y
, aRefBox
.y
,
97 nsRect
ShapeUtils::ComputeInsetRect(const StyleBasicShape
& aBasicShape
,
98 const nsRect
& aRefBox
) {
99 MOZ_ASSERT(aBasicShape
.IsInset(), "The basic shape must be inset()!");
100 const auto& rect
= aBasicShape
.AsInset().rect
;
102 rect
._0
.Resolve(aRefBox
.Height()), rect
._1
.Resolve(aRefBox
.Width()),
103 rect
._2
.Resolve(aRefBox
.Height()), rect
._3
.Resolve(aRefBox
.Width()));
105 nscoord x
= aRefBox
.X() + inset
.left
;
106 nscoord width
= aRefBox
.Width() - inset
.LeftRight();
107 nscoord y
= aRefBox
.Y() + inset
.top
;
108 nscoord height
= aRefBox
.Height() - inset
.TopBottom();
110 // Invert left and right, if necessary.
116 // Invert top and bottom, if necessary.
122 return nsRect(x
, y
, width
, height
);
126 bool ShapeUtils::ComputeInsetRadii(const StyleBasicShape
& aBasicShape
,
127 const nsRect
& aRefBox
,
128 const nsRect
& aInsetRect
,
130 const auto& radius
= aBasicShape
.AsInset().round
;
131 return nsIFrame::ComputeBorderRadii(radius
, aRefBox
.Size(), aInsetRect
.Size(),
136 nsTArray
<nsPoint
> ShapeUtils::ComputePolygonVertices(
137 const StyleBasicShape
& aBasicShape
, const nsRect
& aRefBox
) {
138 MOZ_ASSERT(aBasicShape
.IsPolygon(), "The basic shape must be polygon()!");
140 auto coords
= aBasicShape
.AsPolygon().coordinates
.AsSpan();
141 nsTArray
<nsPoint
> vertices(coords
.Length());
142 for (const StylePolygonCoord
<LengthPercentage
>& point
: coords
) {
143 vertices
.AppendElement(nsPoint(point
._0
.Resolve(aRefBox
.width
),
144 point
._1
.Resolve(aRefBox
.height
)) +
150 } // namespace mozilla