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 "FloatRoundedRect.h"
30
31#include <algorithm>
32
33namespace WebCore {
34
35FloatRoundedRect::FloatRoundedRect(float x, float y, float width, float height)
36 : m_rect(x, y, width, height)
37{
38}
39
40FloatRoundedRect::FloatRoundedRect(const FloatRect& rect, const Radii& radii)
41 : m_rect(rect)
42 , m_radii(radii)
43{
44}
45
46FloatRoundedRect::FloatRoundedRect(const FloatRect& rect, const FloatSize& topLeft, const FloatSize& topRight, const FloatSize& bottomLeft, const FloatSize& bottomRight)
47 : m_rect(rect)
48 , m_radii(topLeft, topRight, bottomLeft, bottomRight)
49{
50}
51
52bool FloatRoundedRect::Radii::isZero() const
53{
54 return m_topLeft.isZero() && m_topRight.isZero() && m_bottomLeft.isZero() && m_bottomRight.isZero();
55}
56
57void FloatRoundedRect::Radii::scale(float factor)
58{
59 if (factor == 1)
60 return;
61
62 // If either radius on a corner becomes zero, reset both radii on that corner.
63 m_topLeft.scale(factor);
64 if (!m_topLeft.width() || !m_topLeft.height())
65 m_topLeft = FloatSize();
66 m_topRight.scale(factor);
67 if (!m_topRight.width() || !m_topRight.height())
68 m_topRight = FloatSize();
69 m_bottomLeft.scale(factor);
70 if (!m_bottomLeft.width() || !m_bottomLeft.height())
71 m_bottomLeft = FloatSize();
72 m_bottomRight.scale(factor);
73 if (!m_bottomRight.width() || !m_bottomRight.height())
74 m_bottomRight = FloatSize();
75
76}
77
78void FloatRoundedRect::Radii::expand(float topWidth, float bottomWidth, float leftWidth, float rightWidth)
79{
80 if (m_topLeft.width() > 0 && m_topLeft.height() > 0) {
81 m_topLeft.setWidth(std::max<float>(0, m_topLeft.width() + leftWidth));
82 m_topLeft.setHeight(std::max<float>(0, m_topLeft.height() + topWidth));
83 }
84 if (m_topRight.width() > 0 && m_topRight.height() > 0) {
85 m_topRight.setWidth(std::max<float>(0, m_topRight.width() + rightWidth));
86 m_topRight.setHeight(std::max<float>(0, m_topRight.height() + topWidth));
87 }
88 if (m_bottomLeft.width() > 0 && m_bottomLeft.height() > 0) {
89 m_bottomLeft.setWidth(std::max<float>(0, m_bottomLeft.width() + leftWidth));
90 m_bottomLeft.setHeight(std::max<float>(0, m_bottomLeft.height() + bottomWidth));
91 }
92 if (m_bottomRight.width() > 0 && m_bottomRight.height() > 0) {
93 m_bottomRight.setWidth(std::max<float>(0, m_bottomRight.width() + rightWidth));
94 m_bottomRight.setHeight(std::max<float>(0, m_bottomRight.height() + bottomWidth));
95 }
96}
97
98static inline float cornerRectIntercept(float y, const FloatRect& cornerRect)
99{
100 ASSERT(cornerRect.height() > 0);
101 return cornerRect.width() * sqrt(1 - (y * y) / (cornerRect.height() * cornerRect.height()));
102}
103
104bool FloatRoundedRect::xInterceptsAtY(float y, float& minXIntercept, float& maxXIntercept) const
105{
106 if (y < rect().y() || y >= rect().maxY())
107 return false;
108
109 const FloatRect& topLeftRect = topLeftCorner();
110 const FloatRect& bottomLeftRect = bottomLeftCorner();
111
112 if (y >= topLeftRect.y() && y < topLeftRect.maxY())
113 minXIntercept = topLeftRect.maxX() - cornerRectIntercept(topLeftRect.maxY() - y, topLeftRect);
114 else if (y >= bottomLeftRect.y() && y < bottomLeftRect.maxY())
115 minXIntercept = bottomLeftRect.maxX() - cornerRectIntercept(y - bottomLeftRect.y(), bottomLeftRect);
116 else
117 minXIntercept = m_rect.x();
118
119 const FloatRect& topRightRect = topRightCorner();
120 const FloatRect& bottomRightRect = bottomRightCorner();
121
122 if (y >= topRightRect.y() && y < topRightRect.maxY())
123 maxXIntercept = topRightRect.x() + cornerRectIntercept(topRightRect.maxY() - y, topRightRect);
124 else if (y >= bottomRightRect.y() && y < bottomRightRect.maxY())
125 maxXIntercept = bottomRightRect.x() + cornerRectIntercept(y - bottomRightRect.y(), bottomRightRect);
126 else
127 maxXIntercept = m_rect.maxX();
128
129 return true;
130}
131
132} // namespace WebCore