| 1 | /* |
| 2 | * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions |
| 6 | * are met: |
| 7 | * |
| 8 | * 1. Redistributions of source code must retain the above |
| 9 | * copyright notice, this list of conditions and the following |
| 10 | * disclaimer. |
| 11 | * 2. Redistributions in binary form must reproduce the above |
| 12 | * copyright notice, this list of conditions and the following |
| 13 | * disclaimer in the documentation and/or other materials |
| 14 | * provided with the distribution. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 19 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| 20 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| 21 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| 23 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 25 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| 27 | * OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | */ |
| 29 | |
| 30 | #ifndef FloatRoundedRect_h |
| 31 | #define FloatRoundedRect_h |
| 32 | |
| 33 | #include "FloatRect.h" |
| 34 | #include "FloatSize.h" |
| 35 | #include "RoundedRect.h" |
| 36 | |
| 37 | namespace WebCore { |
| 38 | |
| 39 | class FloatRoundedRect { |
| 40 | WTF_MAKE_FAST_ALLOCATED; |
| 41 | public: |
| 42 | class Radii { |
| 43 | public: |
| 44 | Radii() { } |
| 45 | Radii(const FloatSize& topLeft, const FloatSize& topRight, const FloatSize& bottomLeft, const FloatSize& bottomRight) |
| 46 | : m_topLeft(topLeft) |
| 47 | , m_topRight(topRight) |
| 48 | , m_bottomLeft(bottomLeft) |
| 49 | , m_bottomRight(bottomRight) |
| 50 | { |
| 51 | } |
| 52 | |
| 53 | Radii(const RoundedRect::Radii& intRadii) |
| 54 | : m_topLeft(intRadii.topLeft()) |
| 55 | , m_topRight(intRadii.topRight()) |
| 56 | , m_bottomLeft(intRadii.bottomLeft()) |
| 57 | , m_bottomRight(intRadii.bottomRight()) |
| 58 | { |
| 59 | } |
| 60 | |
| 61 | explicit Radii(float uniformRadius) |
| 62 | : m_topLeft(uniformRadius, uniformRadius) |
| 63 | , m_topRight(uniformRadius, uniformRadius) |
| 64 | , m_bottomLeft(uniformRadius, uniformRadius) |
| 65 | , m_bottomRight(uniformRadius, uniformRadius) |
| 66 | { |
| 67 | } |
| 68 | |
| 69 | void setTopLeft(const FloatSize& size) { m_topLeft = size; } |
| 70 | void setTopRight(const FloatSize& size) { m_topRight = size; } |
| 71 | void setBottomLeft(const FloatSize& size) { m_bottomLeft = size; } |
| 72 | void setBottomRight(const FloatSize& size) { m_bottomRight = size; } |
| 73 | const FloatSize& topLeft() const { return m_topLeft; } |
| 74 | const FloatSize& topRight() const { return m_topRight; } |
| 75 | const FloatSize& bottomLeft() const { return m_bottomLeft; } |
| 76 | const FloatSize& bottomRight() const { return m_bottomRight; } |
| 77 | |
| 78 | bool isZero() const; |
| 79 | bool isUniformCornerRadius() const; // Including no radius. |
| 80 | |
| 81 | void scale(float factor); |
| 82 | void scale(float horizontalFactor, float verticalFactor); |
| 83 | void expand(float topWidth, float bottomWidth, float leftWidth, float rightWidth); |
| 84 | void expand(float size) { expand(size, size, size, size); } |
| 85 | void shrink(float topWidth, float bottomWidth, float leftWidth, float rightWidth) { expand(-topWidth, -bottomWidth, -leftWidth, -rightWidth); } |
| 86 | void shrink(float size) { shrink(size, size, size, size); } |
| 87 | |
| 88 | private: |
| 89 | FloatSize m_topLeft; |
| 90 | FloatSize m_topRight; |
| 91 | FloatSize m_bottomLeft; |
| 92 | FloatSize m_bottomRight; |
| 93 | }; |
| 94 | |
| 95 | WEBCORE_EXPORT explicit FloatRoundedRect(const FloatRect& = FloatRect(), const Radii& = Radii()); |
| 96 | explicit FloatRoundedRect(const RoundedRect&); |
| 97 | FloatRoundedRect(float x, float y, float width, float height); |
| 98 | FloatRoundedRect(const FloatRect&, const FloatSize& topLeft, const FloatSize& topRight, const FloatSize& bottomLeft, const FloatSize& bottomRight); |
| 99 | |
| 100 | const FloatRect& rect() const { return m_rect; } |
| 101 | const Radii& radii() const { return m_radii; } |
| 102 | bool isRounded() const { return !m_radii.isZero(); } |
| 103 | bool isEmpty() const { return m_rect.isEmpty(); } |
| 104 | |
| 105 | void setRect(const FloatRect& rect) { m_rect = rect; } |
| 106 | void setRadii(const Radii& radii) { m_radii = radii; } |
| 107 | |
| 108 | void move(const FloatSize& size) { m_rect.move(size); } |
| 109 | void inflate(float size) { m_rect.inflate(size); } |
| 110 | void expandRadii(float size) { m_radii.expand(size); } |
| 111 | void shrinkRadii(float size) { m_radii.shrink(size); } |
| 112 | void inflateWithRadii(float size); |
| 113 | void adjustRadii(); |
| 114 | |
| 115 | FloatRect topLeftCorner() const |
| 116 | { |
| 117 | return FloatRect(m_rect.x(), m_rect.y(), m_radii.topLeft().width(), m_radii.topLeft().height()); |
| 118 | } |
| 119 | FloatRect topRightCorner() const |
| 120 | { |
| 121 | return FloatRect(m_rect.maxX() - m_radii.topRight().width(), m_rect.y(), m_radii.topRight().width(), m_radii.topRight().height()); |
| 122 | } |
| 123 | FloatRect bottomLeftCorner() const |
| 124 | { |
| 125 | return FloatRect(m_rect.x(), m_rect.maxY() - m_radii.bottomLeft().height(), m_radii.bottomLeft().width(), m_radii.bottomLeft().height()); |
| 126 | } |
| 127 | FloatRect bottomRightCorner() const |
| 128 | { |
| 129 | return FloatRect(m_rect.maxX() - m_radii.bottomRight().width(), m_rect.maxY() - m_radii.bottomRight().height(), m_radii.bottomRight().width(), m_radii.bottomRight().height()); |
| 130 | } |
| 131 | |
| 132 | bool isRenderable() const; |
| 133 | bool xInterceptsAtY(float y, float& minXIntercept, float& maxXIntercept) const; |
| 134 | |
| 135 | bool intersectionIsRectangular(const FloatRect&) const; |
| 136 | |
| 137 | private: |
| 138 | FloatRect m_rect; |
| 139 | Radii m_radii; |
| 140 | }; |
| 141 | |
| 142 | inline bool operator==(const FloatRoundedRect::Radii& a, const FloatRoundedRect::Radii& b) |
| 143 | { |
| 144 | return a.topLeft() == b.topLeft() && a.topRight() == b.topRight() && a.bottomLeft() == b.bottomLeft() && a.bottomRight() == b.bottomRight(); |
| 145 | } |
| 146 | |
| 147 | inline bool operator!=(const FloatRoundedRect::Radii& a, const FloatRoundedRect::Radii& b) |
| 148 | { |
| 149 | return !(a == b); |
| 150 | } |
| 151 | |
| 152 | inline bool operator==(const FloatRoundedRect& a, const FloatRoundedRect& b) |
| 153 | { |
| 154 | return a.rect() == b.rect() && a.radii() == b.radii(); |
| 155 | } |
| 156 | |
| 157 | inline bool operator!=(const FloatRoundedRect& a, const FloatRoundedRect& b) |
| 158 | { |
| 159 | return !(a == b); |
| 160 | } |
| 161 | |
| 162 | inline float calcBorderRadiiConstraintScaleFor(const FloatRect& rect, const FloatRoundedRect::Radii& radii) |
| 163 | { |
| 164 | // Constrain corner radii using CSS3 rules: |
| 165 | // http://www.w3.org/TR/css3-background/#the-border-radius |
| 166 | |
| 167 | float factor = 1; |
| 168 | float radiiSum; |
| 169 | |
| 170 | // top |
| 171 | radiiSum = radii.topLeft().width() + radii.topRight().width(); // Casts to avoid integer overflow. |
| 172 | if (radiiSum > rect.width()) |
| 173 | factor = std::min(rect.width() / radiiSum, factor); |
| 174 | |
| 175 | // bottom |
| 176 | radiiSum = radii.bottomLeft().width() + radii.bottomRight().width(); |
| 177 | if (radiiSum > rect.width()) |
| 178 | factor = std::min(rect.width() / radiiSum, factor); |
| 179 | |
| 180 | // left |
| 181 | radiiSum = radii.topLeft().height() + radii.bottomLeft().height(); |
| 182 | if (radiiSum > rect.height()) |
| 183 | factor = std::min(rect.height() / radiiSum, factor); |
| 184 | |
| 185 | // right |
| 186 | radiiSum = radii.topRight().height() + radii.bottomRight().height(); |
| 187 | if (radiiSum > rect.height()) |
| 188 | factor = std::min(rect.height() / radiiSum, factor); |
| 189 | |
| 190 | ASSERT(factor <= 1); |
| 191 | return factor; |
| 192 | } |
| 193 | |
| 194 | WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const FloatRoundedRect&); |
| 195 | |
| 196 | } // namespace WebCore |
| 197 | |
| 198 | #endif // FloatRoundedRect_h |
| 199 | |