Coverage Report

Created: 2018-09-25 14:53

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