Home | History | Annotate | Download | only in shapes
      1 /*
      2  * Copyright (C) 2012 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 "core/rendering/shapes/RectangleShape.h"
     32 
     33 #include "wtf/MathExtras.h"
     34 
     35 namespace WebCore {
     36 
     37 static inline float ellipseXIntercept(float y, float rx, float ry)
     38 {
     39     ASSERT(ry > 0);
     40     return rx * sqrt(1 - (y * y) / (ry * ry));
     41 }
     42 
     43 static inline float ellipseYIntercept(float x, float rx, float ry)
     44 {
     45     ASSERT(rx > 0);
     46     return ry * sqrt(1 - (x * x) / (rx * rx));
     47 }
     48 
     49 FloatRoundedRect FloatRoundedRect::paddingBounds(float padding) const
     50 {
     51     ASSERT(padding >= 0);
     52     if (!padding || isEmpty())
     53         return *this;
     54 
     55     float boundsX = x() + std::min(width() / 2, padding);
     56     float boundsY = y() + std::min(height() / 2, padding);
     57     float boundsWidth = std::max(0.0f, width() - padding * 2);
     58     float boundsHeight = std::max(0.0f, height() - padding * 2);
     59     float boundsRadiusX = std::max(0.0f, rx() - padding);
     60     float boundsRadiusY = std::max(0.0f, ry() - padding);
     61     return FloatRoundedRect(FloatRect(boundsX, boundsY, boundsWidth, boundsHeight), FloatSize(boundsRadiusX, boundsRadiusY));
     62 }
     63 
     64 FloatRoundedRect FloatRoundedRect::marginBounds(float margin) const
     65 {
     66     ASSERT(margin >= 0);
     67     if (!margin)
     68         return *this;
     69 
     70     float boundsX = x() - margin;
     71     float boundsY = y() - margin;
     72     float boundsWidth = width() + margin * 2;
     73     float boundsHeight = height() + margin * 2;
     74     float boundsRadiusX = rx() + margin;
     75     float boundsRadiusY = ry() + margin;
     76     return FloatRoundedRect(FloatRect(boundsX, boundsY, boundsWidth, boundsHeight), FloatSize(boundsRadiusX, boundsRadiusY));
     77 }
     78 
     79 FloatPoint FloatRoundedRect::cornerInterceptForWidth(float widthAtIntercept) const
     80 {
     81     float xi = (width() - widthAtIntercept) / 2;
     82     float yi = ry() - ellipseYIntercept(rx() - xi, rx(), ry());
     83     return FloatPoint(xi, yi);
     84 }
     85 
     86 FloatRoundedRect RectangleShape::shapePaddingBounds() const
     87 {
     88     if (!m_haveInitializedPaddingBounds) {
     89         m_haveInitializedPaddingBounds = true;
     90         m_paddingBounds = m_bounds.paddingBounds(shapePadding());
     91     }
     92     return m_paddingBounds;
     93 }
     94 
     95 FloatRoundedRect RectangleShape::shapeMarginBounds() const
     96 {
     97     if (!m_haveInitializedMarginBounds) {
     98         m_haveInitializedMarginBounds = true;
     99         m_marginBounds = m_bounds.marginBounds(shapeMargin());
    100     }
    101     return m_marginBounds;
    102 }
    103 
    104 void RectangleShape::getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
    105 {
    106     const FloatRoundedRect& bounds = shapeMarginBounds();
    107     if (bounds.isEmpty())
    108         return;
    109 
    110     float y1 = logicalTop;
    111     float y2 = logicalTop + logicalHeight;
    112 
    113     if (y2 < bounds.y() || y1 >= bounds.maxY())
    114         return;
    115 
    116     float x1 = bounds.x();
    117     float x2 = bounds.maxX();
    118 
    119     if (bounds.ry() > 0) {
    120         if (y2 < bounds.y() + bounds.ry()) {
    121             float yi = y2 - bounds.y() - bounds.ry();
    122             float xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
    123             x1 = bounds.x() + bounds.rx() - xi;
    124             x2 = bounds.maxX() - bounds.rx() + xi;
    125         } else if (y1 > bounds.maxY() - bounds.ry()) {
    126             float yi =  y1 - (bounds.maxY() - bounds.ry());
    127             float xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
    128             x1 = bounds.x() + bounds.rx() - xi;
    129             x2 = bounds.maxX() - bounds.rx() + xi;
    130         }
    131     }
    132 
    133     result.append(LineSegment(x1, x2));
    134 }
    135 
    136 void RectangleShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
    137 {
    138     const FloatRoundedRect& bounds = shapePaddingBounds();
    139     if (bounds.isEmpty())
    140         return;
    141 
    142     float y1 = logicalTop;
    143     float y2 = logicalTop + logicalHeight;
    144 
    145     if (y1 < bounds.y() || y2 > bounds.maxY())
    146         return;
    147 
    148     float x1 = bounds.x();
    149     float x2 = bounds.maxX();
    150 
    151     if (bounds.ry() > 0) {
    152         bool y1InterceptsCorner = y1 < bounds.y() + bounds.ry();
    153         bool y2InterceptsCorner = y2 > bounds.maxY() - bounds.ry();
    154         float xi = 0;
    155 
    156         if (y1InterceptsCorner && y2InterceptsCorner) {
    157             if  (y1 < bounds.height() + 2 * bounds.y() - y2) {
    158                 float yi = y1 - bounds.y() - bounds.ry();
    159                 xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
    160             } else {
    161                 float yi =  y2 - (bounds.maxY() - bounds.ry());
    162                 xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
    163             }
    164         } else if (y1InterceptsCorner) {
    165             float yi = y1 - bounds.y() - bounds.ry();
    166             xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
    167         } else if (y2InterceptsCorner) {
    168             float yi =  y2 - (bounds.maxY() - bounds.ry());
    169             xi = ellipseXIntercept(yi, bounds.rx(), bounds.ry());
    170         }
    171 
    172         if (y1InterceptsCorner || y2InterceptsCorner) {
    173             x1 = bounds.x() + bounds.rx() - xi;
    174             x2 = bounds.maxX() - bounds.rx() + xi;
    175         }
    176     }
    177 
    178     result.append(LineSegment(x1, x2));
    179 }
    180 
    181 bool RectangleShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const
    182 {
    183     float minIntervalTop = minLogicalIntervalTop;
    184     float minIntervalHeight = minLogicalIntervalSize.height();
    185     float minIntervalWidth = minLogicalIntervalSize.width();
    186 
    187     const FloatRoundedRect& bounds = shapePaddingBounds();
    188     if (bounds.isEmpty() || minIntervalWidth > bounds.width())
    189         return false;
    190 
    191     float minY = std::max(bounds.y(), minIntervalTop);
    192     float maxY = minY + minIntervalHeight;
    193 
    194     if (maxY > bounds.maxY())
    195         return false;
    196 
    197     bool intervalOverlapsMinCorner = minY < bounds.y() + bounds.ry();
    198     bool intervalOverlapsMaxCorner = maxY > bounds.maxY() - bounds.ry();
    199 
    200     if (!intervalOverlapsMinCorner && !intervalOverlapsMaxCorner) {
    201         result = minY;
    202         return true;
    203     }
    204 
    205     float centerY = bounds.y() + bounds.height() / 2;
    206     bool minCornerDefinesX = fabs(centerY - minY) > fabs(centerY - maxY);
    207     bool intervalFitsWithinCorners = minIntervalWidth + 2 * bounds.rx() <= bounds.width();
    208     FloatPoint cornerIntercept = bounds.cornerInterceptForWidth(minIntervalWidth);
    209 
    210     if (intervalOverlapsMinCorner && (!intervalOverlapsMaxCorner || minCornerDefinesX)) {
    211         if (intervalFitsWithinCorners || bounds.y() + cornerIntercept.y() < minY) {
    212             result = minY;
    213             return true;
    214         }
    215         if (minIntervalHeight < bounds.height() - (2 * cornerIntercept.y())) {
    216             result = LayoutUnit::fromFloatCeil(bounds.y() + cornerIntercept.y());
    217             return true;
    218         }
    219     }
    220 
    221     if (intervalOverlapsMaxCorner && (!intervalOverlapsMinCorner || !minCornerDefinesX)) {
    222         if (intervalFitsWithinCorners || minY <=  bounds.maxY() - cornerIntercept.y() - minIntervalHeight) {
    223             result = minY;
    224             return true;
    225         }
    226     }
    227 
    228     return false;
    229 }
    230 
    231 } // namespace WebCore
    232