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