Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2006, 2008, 2011 Apple Inc. All rights reserved.
      3  * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  *
     20 */
     21 
     22 #include "config.h"
     23 #include "core/rendering/HitTestLocation.h"
     24 
     25 #include "HTMLNames.h"
     26 #include "SVGNames.h"
     27 #include "XLinkNames.h"
     28 
     29 namespace WebCore {
     30 
     31 using namespace HTMLNames;
     32 
     33 HitTestLocation::HitTestLocation()
     34     : m_region(0)
     35     , m_isRectBased(false)
     36     , m_isRectilinear(true)
     37 {
     38 }
     39 
     40 HitTestLocation::HitTestLocation(const LayoutPoint& point)
     41     : m_point(point)
     42     , m_boundingBox(rectForPoint(point, 0, 0, 0, 0))
     43     , m_transformedPoint(point)
     44     , m_transformedRect(m_boundingBox)
     45     , m_region(0)
     46     , m_isRectBased(false)
     47     , m_isRectilinear(true)
     48 {
     49 }
     50 
     51 HitTestLocation::HitTestLocation(const FloatPoint& point)
     52     : m_point(flooredLayoutPoint(point))
     53     , m_boundingBox(rectForPoint(m_point, 0, 0, 0, 0))
     54     , m_transformedPoint(point)
     55     , m_transformedRect(m_boundingBox)
     56     , m_region(0)
     57     , m_isRectBased(false)
     58     , m_isRectilinear(true)
     59 {
     60 }
     61 
     62 HitTestLocation::HitTestLocation(const FloatPoint& point, const FloatQuad& quad)
     63     : m_transformedPoint(point)
     64     , m_transformedRect(quad)
     65     , m_region(0)
     66     , m_isRectBased(true)
     67 {
     68     m_point = flooredLayoutPoint(point);
     69     m_boundingBox = enclosingIntRect(quad.boundingBox());
     70     m_isRectilinear = quad.isRectilinear();
     71 }
     72 
     73 HitTestLocation::HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
     74     : m_point(centerPoint)
     75     , m_boundingBox(rectForPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding))
     76     , m_transformedPoint(centerPoint)
     77     , m_region(0)
     78     , m_isRectBased(topPadding || rightPadding || bottomPadding || leftPadding)
     79     , m_isRectilinear(true)
     80 {
     81     m_transformedRect = FloatQuad(m_boundingBox);
     82 }
     83 
     84 HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize& offset, RenderRegion* region)
     85     : m_point(other.m_point)
     86     , m_boundingBox(other.m_boundingBox)
     87     , m_transformedPoint(other.m_transformedPoint)
     88     , m_transformedRect(other.m_transformedRect)
     89     , m_region(region ? region : other.m_region)
     90     , m_isRectBased(other.m_isRectBased)
     91     , m_isRectilinear(other.m_isRectilinear)
     92 {
     93     move(offset);
     94 }
     95 
     96 HitTestLocation::HitTestLocation(const HitTestLocation& other)
     97     : m_point(other.m_point)
     98     , m_boundingBox(other.m_boundingBox)
     99     , m_transformedPoint(other.m_transformedPoint)
    100     , m_transformedRect(other.m_transformedRect)
    101     , m_region(other.m_region)
    102     , m_isRectBased(other.m_isRectBased)
    103     , m_isRectilinear(other.m_isRectilinear)
    104 {
    105 }
    106 
    107 HitTestLocation::~HitTestLocation()
    108 {
    109 }
    110 
    111 HitTestLocation& HitTestLocation::operator=(const HitTestLocation& other)
    112 {
    113     m_point = other.m_point;
    114     m_boundingBox = other.m_boundingBox;
    115     m_transformedPoint = other.m_transformedPoint;
    116     m_transformedRect = other.m_transformedRect;
    117     m_region = other.m_region;
    118     m_isRectBased = other.m_isRectBased;
    119     m_isRectilinear = other.m_isRectilinear;
    120 
    121     return *this;
    122 }
    123 
    124 void HitTestLocation::move(const LayoutSize& offset)
    125 {
    126     m_point.move(offset);
    127     m_transformedPoint.move(offset);
    128     m_transformedRect.move(offset);
    129     m_boundingBox = enclosingIntRect(m_transformedRect.boundingBox());
    130 }
    131 
    132 template<typename RectType>
    133 bool HitTestLocation::intersectsRect(const RectType& rect) const
    134 {
    135     // FIXME: When the hit test is not rect based we should use rect.contains(m_point).
    136     // That does change some corner case tests though.
    137 
    138     // First check if rect even intersects our bounding box.
    139     if (!rect.intersects(m_boundingBox))
    140         return false;
    141 
    142     // If the transformed rect is rectilinear the bounding box intersection was accurate.
    143     if (m_isRectilinear)
    144         return true;
    145 
    146     // If rect fully contains our bounding box, we are also sure of an intersection.
    147     if (rect.contains(m_boundingBox))
    148         return true;
    149 
    150     // Otherwise we need to do a slower quad based intersection test.
    151     return m_transformedRect.intersectsRect(rect);
    152 }
    153 
    154 bool HitTestLocation::intersects(const LayoutRect& rect) const
    155 {
    156     return intersectsRect(rect);
    157 }
    158 
    159 bool HitTestLocation::intersects(const FloatRect& rect) const
    160 {
    161     return intersectsRect(rect);
    162 }
    163 
    164 bool HitTestLocation::intersects(const RoundedRect& rect) const
    165 {
    166     return rect.intersectsQuad(m_transformedRect);
    167 }
    168 
    169 IntRect HitTestLocation::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
    170 {
    171     IntPoint actualPoint(flooredIntPoint(point));
    172     actualPoint -= IntSize(leftPadding, topPadding);
    173 
    174     IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding);
    175     // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1".
    176     // FIXME: Remove this once non-rect based hit-detection stops using IntRect:intersects.
    177     actualPadding += IntSize(1, 1);
    178 
    179     return IntRect(actualPoint, actualPadding);
    180 }
    181 
    182 } // namespace WebCore
    183