Line data Source code
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/. */
6 :
7 : #include "mozilla/ShapeUtils.h"
8 :
9 : #include <cstdlib>
10 :
11 : #include "nsCSSRendering.h"
12 : #include "nsMargin.h"
13 : #include "nsRuleNode.h"
14 : #include "nsStyleCoord.h"
15 : #include "nsStyleStruct.h"
16 : #include "SVGContentUtils.h"
17 :
18 : namespace mozilla {
19 :
20 : nscoord
21 0 : ShapeUtils::ComputeShapeRadius(const StyleShapeRadius aType,
22 : const nscoord aCenter,
23 : const nscoord aPosMin,
24 : const nscoord aPosMax)
25 : {
26 0 : nscoord dist1 = std::abs(aPosMin - aCenter);
27 0 : nscoord dist2 = std::abs(aPosMax - aCenter);
28 0 : nscoord length = 0;
29 0 : switch (aType) {
30 : case StyleShapeRadius::FarthestSide:
31 0 : length = dist1 > dist2 ? dist1 : dist2;
32 0 : break;
33 : case StyleShapeRadius::ClosestSide:
34 0 : length = dist1 > dist2 ? dist2 : dist1;
35 0 : break;
36 : }
37 0 : return length;
38 : }
39 :
40 : nsPoint
41 0 : ShapeUtils::ComputeCircleOrEllipseCenter(const StyleBasicShape* aBasicShape,
42 : const nsRect& aRefBox)
43 : {
44 0 : MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Circle ||
45 : aBasicShape->GetShapeType() == StyleBasicShapeType::Ellipse,
46 : "The basic shape must be circle() or ellipse!");
47 :
48 0 : nsPoint topLeft, anchor;
49 0 : nsSize size(aRefBox.Size());
50 0 : nsImageRenderer::ComputeObjectAnchorPoint(aBasicShape->GetPosition(),
51 : size, size,
52 0 : &topLeft, &anchor);
53 0 : return anchor + aRefBox.TopLeft();
54 : }
55 :
56 : nscoord
57 0 : ShapeUtils::ComputeCircleRadius(const StyleBasicShape* aBasicShape,
58 : const nsPoint& aCenter,
59 : const nsRect& aRefBox)
60 : {
61 0 : MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Circle,
62 : "The basic shape must be circle()!");
63 :
64 0 : const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
65 0 : MOZ_ASSERT(coords.Length() == 1, "wrong number of arguments");
66 0 : nscoord r = 0;
67 0 : if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
68 0 : const auto styleShapeRadius = coords[0].GetEnumValue<StyleShapeRadius>();
69 : nscoord horizontal =
70 0 : ComputeShapeRadius(styleShapeRadius, aCenter.x, aRefBox.x, aRefBox.XMost());
71 : nscoord vertical =
72 0 : ComputeShapeRadius(styleShapeRadius, aCenter.y, aRefBox.y, aRefBox.YMost());
73 0 : r = styleShapeRadius == StyleShapeRadius::FarthestSide
74 0 : ? std::max(horizontal, vertical)
75 0 : : std::min(horizontal, vertical);
76 : } else {
77 : // We resolve percent <shape-radius> value for circle() as defined here:
78 : // https://drafts.csswg.org/css-shapes/#funcdef-circle
79 : double referenceLength =
80 0 : SVGContentUtils::ComputeNormalizedHypotenuse(aRefBox.width,
81 0 : aRefBox.height);
82 0 : r = nsRuleNode::ComputeCoordPercentCalc(coords[0],
83 0 : NSToCoordRound(referenceLength));
84 : }
85 0 : return r;
86 : }
87 :
88 : nsSize
89 0 : ShapeUtils::ComputeEllipseRadii(const StyleBasicShape* aBasicShape,
90 : const nsPoint& aCenter,
91 : const nsRect& aRefBox)
92 : {
93 0 : MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Ellipse,
94 : "The basic shape must be ellipse()!");
95 :
96 0 : const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
97 0 : MOZ_ASSERT(coords.Length() == 2, "wrong number of arguments");
98 0 : nsSize radii;
99 :
100 0 : if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
101 0 : const StyleShapeRadius radiusX = coords[0].GetEnumValue<StyleShapeRadius>();
102 0 : radii.width = ComputeShapeRadius(radiusX, aCenter.x, aRefBox.x,
103 : aRefBox.XMost());
104 : } else {
105 0 : radii.width = nsRuleNode::ComputeCoordPercentCalc(coords[0], aRefBox.width);
106 : }
107 :
108 0 : if (coords[1].GetUnit() == eStyleUnit_Enumerated) {
109 0 : const StyleShapeRadius radiusY = coords[1].GetEnumValue<StyleShapeRadius>();
110 0 : radii.height = ComputeShapeRadius(radiusY, aCenter.y, aRefBox.y,
111 : aRefBox.YMost());
112 : } else {
113 0 : radii.height = nsRuleNode::ComputeCoordPercentCalc(coords[1], aRefBox.height);
114 : }
115 :
116 0 : return radii;
117 : }
118 :
119 : /* static */ nsRect
120 0 : ShapeUtils::ComputeInsetRect(const StyleBasicShape* aBasicShape,
121 : const nsRect& aRefBox)
122 : {
123 0 : MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Inset,
124 : "The basic shape must be inset()!");
125 :
126 0 : const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
127 0 : MOZ_ASSERT(coords.Length() == 4, "wrong number of arguments");
128 :
129 0 : nsMargin inset(nsRuleNode::ComputeCoordPercentCalc(coords[0], aRefBox.height),
130 0 : nsRuleNode::ComputeCoordPercentCalc(coords[1], aRefBox.width),
131 0 : nsRuleNode::ComputeCoordPercentCalc(coords[2], aRefBox.height),
132 0 : nsRuleNode::ComputeCoordPercentCalc(coords[3], aRefBox.width));
133 :
134 0 : nsRect insetRect(aRefBox);
135 0 : insetRect.Deflate(inset);
136 :
137 0 : return insetRect;
138 : }
139 :
140 : /* static */ bool
141 0 : ShapeUtils::ComputeInsetRadii(const StyleBasicShape* aBasicShape,
142 : const nsRect& aInsetRect,
143 : const nsRect& aRefBox,
144 : nscoord aRadii[8])
145 : {
146 0 : const nsStyleCorners& radius = aBasicShape->GetRadius();
147 0 : return nsIFrame::ComputeBorderRadii(radius, aInsetRect.Size(), aRefBox.Size(),
148 0 : Sides(), aRadii);
149 :
150 : }
151 :
152 : /* static */ nsTArray<nsPoint>
153 0 : ShapeUtils::ComputePolygonVertices(const StyleBasicShape* aBasicShape,
154 : const nsRect& aRefBox)
155 : {
156 0 : MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Polygon,
157 : "The basic shape must be polygon()!");
158 :
159 0 : const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
160 0 : MOZ_ASSERT(coords.Length() % 2 == 0 &&
161 : coords.Length() >= 2, "Wrong number of arguments!");
162 :
163 0 : nsTArray<nsPoint> vertices(coords.Length() / 2);
164 0 : for (size_t i = 0; i + 1 < coords.Length(); i += 2) {
165 0 : vertices.AppendElement(
166 0 : nsPoint(nsRuleNode::ComputeCoordPercentCalc(coords[i], aRefBox.width),
167 0 : nsRuleNode::ComputeCoordPercentCalc(coords[i + 1], aRefBox.height))
168 0 : + aRefBox.TopLeft());
169 : }
170 0 : return vertices;
171 : }
172 :
173 : } // namespace mozilla
|