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 #include "core/dom/DocumentMarkerController.h"
     29 #include "core/editing/FrameSelection.h"
     30 #include "core/html/HTMLAnchorElement.h"
     31 #include "core/html/HTMLImageElement.h"
     32 #include "core/html/HTMLInputElement.h"
     33 #include "core/html/HTMLMediaElement.h"
     34 #include "core/html/HTMLPlugInImageElement.h"
     35 #include "core/html/HTMLVideoElement.h"
     36 #include "core/html/parser/HTMLParserIdioms.h"
     37 #include "core/loader/cache/ImageResource.h"
     38 #include "core/page/Frame.h"
     39 #include "core/page/FrameTree.h"
     40 #include "core/platform/Scrollbar.h"
     41 #include "core/rendering/RenderBlock.h"
     42 #include "core/rendering/RenderImage.h"
     43 #include "core/rendering/RenderInline.h"
     44 
     45 namespace WebCore {
     46 
     47 using namespace HTMLNames;
     48 
     49 HitTestLocation::HitTestLocation()
     50     : m_region(0)
     51     , m_isRectBased(false)
     52     , m_isRectilinear(true)
     53 {
     54 }
     55 
     56 HitTestLocation::HitTestLocation(const LayoutPoint& point)
     57     : m_point(point)
     58     , m_boundingBox(rectForPoint(point, 0, 0, 0, 0))
     59     , m_transformedPoint(point)
     60     , m_transformedRect(m_boundingBox)
     61     , m_region(0)
     62     , m_isRectBased(false)
     63     , m_isRectilinear(true)
     64 {
     65 }
     66 
     67 HitTestLocation::HitTestLocation(const FloatPoint& point)
     68     : m_point(flooredLayoutPoint(point))
     69     , m_boundingBox(rectForPoint(m_point, 0, 0, 0, 0))
     70     , m_transformedPoint(point)
     71     , m_transformedRect(m_boundingBox)
     72     , m_region(0)
     73     , m_isRectBased(false)
     74     , m_isRectilinear(true)
     75 {
     76 }
     77 
     78 HitTestLocation::HitTestLocation(const FloatPoint& point, const FloatQuad& quad)
     79     : m_transformedPoint(point)
     80     , m_transformedRect(quad)
     81     , m_region(0)
     82     , m_isRectBased(true)
     83 {
     84     m_point = flooredLayoutPoint(point);
     85     m_boundingBox = enclosingIntRect(quad.boundingBox());
     86     m_isRectilinear = quad.isRectilinear();
     87 }
     88 
     89 HitTestLocation::HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
     90     : m_point(centerPoint)
     91     , m_boundingBox(rectForPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding))
     92     , m_transformedPoint(centerPoint)
     93     , m_region(0)
     94     , m_isRectBased(topPadding || rightPadding || bottomPadding || leftPadding)
     95     , m_isRectilinear(true)
     96 {
     97     m_transformedRect = FloatQuad(m_boundingBox);
     98 }
     99 
    100 HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize& offset, RenderRegion* region)
    101     : m_point(other.m_point)
    102     , m_boundingBox(other.m_boundingBox)
    103     , m_transformedPoint(other.m_transformedPoint)
    104     , m_transformedRect(other.m_transformedRect)
    105     , m_region(region ? region : other.m_region)
    106     , m_isRectBased(other.m_isRectBased)
    107     , m_isRectilinear(other.m_isRectilinear)
    108 {
    109     move(offset);
    110 }
    111 
    112 HitTestLocation::HitTestLocation(const HitTestLocation& other)
    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 }
    122 
    123 HitTestLocation::~HitTestLocation()
    124 {
    125 }
    126 
    127 HitTestLocation& HitTestLocation::operator=(const HitTestLocation& other)
    128 {
    129     m_point = other.m_point;
    130     m_boundingBox = other.m_boundingBox;
    131     m_transformedPoint = other.m_transformedPoint;
    132     m_transformedRect = other.m_transformedRect;
    133     m_region = other.m_region;
    134     m_isRectBased = other.m_isRectBased;
    135     m_isRectilinear = other.m_isRectilinear;
    136 
    137     return *this;
    138 }
    139 
    140 void HitTestLocation::move(const LayoutSize& offset)
    141 {
    142     m_point.move(offset);
    143     m_transformedPoint.move(offset);
    144     m_transformedRect.move(offset);
    145     m_boundingBox = enclosingIntRect(m_transformedRect.boundingBox());
    146 }
    147 
    148 template<typename RectType>
    149 bool HitTestLocation::intersectsRect(const RectType& rect) const
    150 {
    151     // FIXME: When the hit test is not rect based we should use rect.contains(m_point).
    152     // That does change some corner case tests though.
    153 
    154     // First check if rect even intersects our bounding box.
    155     if (!rect.intersects(m_boundingBox))
    156         return false;
    157 
    158     // If the transformed rect is rectilinear the bounding box intersection was accurate.
    159     if (m_isRectilinear)
    160         return true;
    161 
    162     // If rect fully contains our bounding box, we are also sure of an intersection.
    163     if (rect.contains(m_boundingBox))
    164         return true;
    165 
    166     // Otherwise we need to do a slower quad based intersection test.
    167     return m_transformedRect.intersectsRect(rect);
    168 }
    169 
    170 bool HitTestLocation::intersects(const LayoutRect& rect) const
    171 {
    172     return intersectsRect(rect);
    173 }
    174 
    175 bool HitTestLocation::intersects(const FloatRect& rect) const
    176 {
    177     return intersectsRect(rect);
    178 }
    179 
    180 bool HitTestLocation::intersects(const RoundedRect& rect) const
    181 {
    182     return rect.intersectsQuad(m_transformedRect);
    183 }
    184 
    185 IntRect HitTestLocation::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
    186 {
    187     IntPoint actualPoint(flooredIntPoint(point));
    188     actualPoint -= IntSize(leftPadding, topPadding);
    189 
    190     IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding);
    191     // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1".
    192     // FIXME: Remove this once non-rect based hit-detection stops using IntRect:intersects.
    193     actualPadding += IntSize(1, 1);
    194 
    195     return IntRect(actualPoint, actualPadding);
    196 }
    197 
    198 } // namespace WebCore
    199