Home | History | Annotate | Download | only in geometry
      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 blink {
     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 blink
    141