• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Google Inc. All rights reserved.
4  * Copyright (C) 2013 Xidorn Quan (quanxunzhen@gmail.com)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 #include "platform/geometry/RoundedRect.h"
30 
31 #include "wtf/Assertions.h"
32 #include <algorithm>
33 
34 namespace blink {
35 
isZero() const36 bool RoundedRect::Radii::isZero() const
37 {
38     return m_topLeft.isZero() && m_topRight.isZero() && m_bottomLeft.isZero() && m_bottomRight.isZero();
39 }
40 
scale(float factor)41 void RoundedRect::Radii::scale(float factor)
42 {
43     if (factor == 1)
44         return;
45 
46     // If either radius on a corner becomes zero, reset both radii on that corner.
47     m_topLeft.scale(factor);
48     if (!m_topLeft.width() || !m_topLeft.height())
49         m_topLeft = IntSize();
50     m_topRight.scale(factor);
51     if (!m_topRight.width() || !m_topRight.height())
52         m_topRight = IntSize();
53     m_bottomLeft.scale(factor);
54     if (!m_bottomLeft.width() || !m_bottomLeft.height())
55         m_bottomLeft = IntSize();
56     m_bottomRight.scale(factor);
57     if (!m_bottomRight.width() || !m_bottomRight.height())
58         m_bottomRight = IntSize();
59 
60 }
61 
expand(int topWidth,int bottomWidth,int leftWidth,int rightWidth)62 void RoundedRect::Radii::expand(int topWidth, int bottomWidth, int leftWidth, int rightWidth)
63 {
64     if (m_topLeft.width() > 0 && m_topLeft.height() > 0) {
65         m_topLeft.setWidth(std::max<int>(0, m_topLeft.width() + leftWidth));
66         m_topLeft.setHeight(std::max<int>(0, m_topLeft.height() + topWidth));
67     }
68     if (m_topRight.width() > 0 && m_topRight.height() > 0) {
69         m_topRight.setWidth(std::max<int>(0, m_topRight.width() + rightWidth));
70         m_topRight.setHeight(std::max<int>(0, m_topRight.height() + topWidth));
71     }
72     if (m_bottomLeft.width() > 0 && m_bottomLeft.height() > 0) {
73         m_bottomLeft.setWidth(std::max<int>(0, m_bottomLeft.width() + leftWidth));
74         m_bottomLeft.setHeight(std::max<int>(0, m_bottomLeft.height() + bottomWidth));
75     }
76     if (m_bottomRight.width() > 0 && m_bottomRight.height() > 0) {
77         m_bottomRight.setWidth(std::max<int>(0, m_bottomRight.width() + rightWidth));
78         m_bottomRight.setHeight(std::max<int>(0, m_bottomRight.height() + bottomWidth));
79     }
80 }
81 
inflateWithRadii(int size)82 void RoundedRect::inflateWithRadii(int size)
83 {
84     IntRect old = m_rect;
85 
86     m_rect.inflate(size);
87     // Considering the inflation factor of shorter size to scale the radii seems appropriate here
88     float factor;
89     if (m_rect.width() < m_rect.height())
90         factor = old.width() ? (float)m_rect.width() / old.width() : int(0);
91     else
92         factor = old.height() ? (float)m_rect.height() / old.height() : int(0);
93 
94     m_radii.scale(factor);
95 }
96 
includeLogicalEdges(const RoundedRect::Radii & edges,bool isHorizontal,bool includeLogicalLeftEdge,bool includeLogicalRightEdge)97 void RoundedRect::Radii::includeLogicalEdges(const RoundedRect::Radii& edges, bool isHorizontal, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
98 {
99     if (includeLogicalLeftEdge) {
100         if (isHorizontal)
101             m_bottomLeft = edges.bottomLeft();
102         else
103             m_topRight = edges.topRight();
104         m_topLeft = edges.topLeft();
105     }
106 
107     if (includeLogicalRightEdge) {
108         if (isHorizontal)
109             m_topRight = edges.topRight();
110         else
111             m_bottomLeft = edges.bottomLeft();
112         m_bottomRight = edges.bottomRight();
113     }
114 }
115 
excludeLogicalEdges(bool isHorizontal,bool excludeLogicalLeftEdge,bool excludeLogicalRightEdge)116 void RoundedRect::Radii::excludeLogicalEdges(bool isHorizontal, bool excludeLogicalLeftEdge, bool excludeLogicalRightEdge)
117 {
118     if (excludeLogicalLeftEdge) {
119         if (isHorizontal)
120             m_bottomLeft = IntSize();
121         else
122             m_topRight = IntSize();
123         m_topLeft = IntSize();
124     }
125 
126     if (excludeLogicalRightEdge) {
127         if (isHorizontal)
128             m_topRight = IntSize();
129         else
130             m_bottomLeft = IntSize();
131         m_bottomRight = IntSize();
132     }
133 }
134 
RoundedRect(int x,int y,int width,int height)135 RoundedRect::RoundedRect(int x, int y, int width, int height)
136     : m_rect(x, y, width, height)
137 {
138 }
139 
RoundedRect(const IntRect & rect,const Radii & radii)140 RoundedRect::RoundedRect(const IntRect& rect, const Radii& radii)
141     : m_rect(rect)
142     , m_radii(radii)
143 {
144 }
145 
RoundedRect(const IntRect & rect,const IntSize & topLeft,const IntSize & topRight,const IntSize & bottomLeft,const IntSize & bottomRight)146 RoundedRect::RoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight)
147     : m_rect(rect)
148     , m_radii(topLeft, topRight, bottomLeft, bottomRight)
149 {
150 }
151 
radiusCenterRect() const152 IntRect RoundedRect::radiusCenterRect() const
153 {
154     ASSERT(isRenderable());
155     int minX = m_rect.x() + std::max(m_radii.topLeft().width(), m_radii.bottomLeft().width());
156     int minY = m_rect.y() + std::max(m_radii.topLeft().height(), m_radii.topRight().height());
157     int maxX = m_rect.maxX() - std::max(m_radii.topRight().width(), m_radii.bottomRight().width());
158     int maxY = m_rect.maxY() - std::max(m_radii.bottomLeft().height(), m_radii.bottomRight().height());
159     return IntRect(minX, minY, maxX - minX, maxY - minY);
160 }
161 
includeLogicalEdges(const Radii & edges,bool isHorizontal,bool includeLogicalLeftEdge,bool includeLogicalRightEdge)162 void RoundedRect::includeLogicalEdges(const Radii& edges, bool isHorizontal, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
163 {
164     m_radii.includeLogicalEdges(edges, isHorizontal, includeLogicalLeftEdge, includeLogicalRightEdge);
165 }
166 
excludeLogicalEdges(bool isHorizontal,bool excludeLogicalLeftEdge,bool excludeLogicalRightEdge)167 void RoundedRect::excludeLogicalEdges(bool isHorizontal, bool excludeLogicalLeftEdge, bool excludeLogicalRightEdge)
168 {
169     m_radii.excludeLogicalEdges(isHorizontal, excludeLogicalLeftEdge, excludeLogicalRightEdge);
170 }
171 
isRenderable() const172 bool RoundedRect::isRenderable() const
173 {
174     return m_radii.topLeft().width() + m_radii.topRight().width() <= m_rect.width()
175         && m_radii.bottomLeft().width() + m_radii.bottomRight().width() <= m_rect.width()
176         && m_radii.topLeft().height() + m_radii.bottomLeft().height() <= m_rect.height()
177         && m_radii.topRight().height() + m_radii.bottomRight().height() <= m_rect.height();
178 }
179 
adjustRadii()180 void RoundedRect::adjustRadii()
181 {
182     int maxRadiusWidth = std::max(m_radii.topLeft().width() + m_radii.topRight().width(), m_radii.bottomLeft().width() + m_radii.bottomRight().width());
183     int maxRadiusHeight = std::max(m_radii.topLeft().height() + m_radii.bottomLeft().height(), m_radii.topRight().height() + m_radii.bottomRight().height());
184 
185     if (maxRadiusWidth <= 0 || maxRadiusHeight <= 0) {
186         m_radii.scale(0.0f);
187         return;
188     }
189     float widthRatio = static_cast<float>(m_rect.width()) / maxRadiusWidth;
190     float heightRatio = static_cast<float>(m_rect.height()) / maxRadiusHeight;
191     m_radii.scale(widthRatio < heightRatio ? widthRatio : heightRatio);
192 }
193 
intersectsQuad(const FloatQuad & quad) const194 bool RoundedRect::intersectsQuad(const FloatQuad& quad) const
195 {
196     FloatRect rect(m_rect);
197     if (!quad.intersectsRect(rect))
198         return false;
199 
200     const IntSize& topLeft = m_radii.topLeft();
201     if (!topLeft.isEmpty()) {
202         FloatRect rect(m_rect.x(), m_rect.y(), topLeft.width(), topLeft.height());
203         if (quad.intersectsRect(rect)) {
204             FloatPoint center(m_rect.x() + topLeft.width(), m_rect.y() + topLeft.height());
205             FloatSize size(topLeft.width(), topLeft.height());
206             if (!quad.intersectsEllipse(center, size))
207                 return false;
208         }
209     }
210 
211     const IntSize& topRight = m_radii.topRight();
212     if (!topRight.isEmpty()) {
213         FloatRect rect(m_rect.maxX() - topRight.width(), m_rect.y(), topRight.width(), topRight.height());
214         if (quad.intersectsRect(rect)) {
215             FloatPoint center(m_rect.maxX() - topRight.width(), m_rect.y() + topRight.height());
216             FloatSize size(topRight.width(), topRight.height());
217             if (!quad.intersectsEllipse(center, size))
218                 return false;
219         }
220     }
221 
222     const IntSize& bottomLeft = m_radii.bottomLeft();
223     if (!bottomLeft.isEmpty()) {
224         FloatRect rect(m_rect.x(), m_rect.maxY() - bottomLeft.height(), bottomLeft.width(), bottomLeft.height());
225         if (quad.intersectsRect(rect)) {
226             FloatPoint center(m_rect.x() + bottomLeft.width(), m_rect.maxY() - bottomLeft.height());
227             FloatSize size(bottomLeft.width(), bottomLeft.height());
228             if (!quad.intersectsEllipse(center, size))
229                 return false;
230         }
231     }
232 
233     const IntSize& bottomRight = m_radii.bottomRight();
234     if (!bottomRight.isEmpty()) {
235         FloatRect rect(m_rect.maxX() - bottomRight.width(), m_rect.maxY() - bottomRight.height(), bottomRight.width(), bottomRight.height());
236         if (quad.intersectsRect(rect)) {
237             FloatPoint center(m_rect.maxX() - bottomRight.width(), m_rect.maxY() - bottomRight.height());
238             FloatSize size(bottomRight.width(), bottomRight.height());
239             if (!quad.intersectsEllipse(center, size))
240                 return false;
241         }
242     }
243 
244     return true;
245 }
246 
247 } // namespace blink
248