• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HitTestLocation()33 HitTestLocation::HitTestLocation()
34     : m_region(0)
35     , m_isRectBased(false)
36     , m_isRectilinear(true)
37 {
38 }
39 
HitTestLocation(const LayoutPoint & point)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 
HitTestLocation(const FloatPoint & point)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 
HitTestLocation(const FloatPoint & point,const FloatQuad & quad)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 
HitTestLocation(const LayoutPoint & centerPoint,unsigned topPadding,unsigned rightPadding,unsigned bottomPadding,unsigned leftPadding)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 
HitTestLocation(const HitTestLocation & other,const LayoutSize & offset,RenderRegion * region)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 
HitTestLocation(const HitTestLocation & other)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 
~HitTestLocation()107 HitTestLocation::~HitTestLocation()
108 {
109 }
110 
operator =(const HitTestLocation & other)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 
move(const LayoutSize & offset)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>
intersectsRect(const RectType & rect) const133 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 
intersects(const LayoutRect & rect) const154 bool HitTestLocation::intersects(const LayoutRect& rect) const
155 {
156     return intersectsRect(rect);
157 }
158 
intersects(const FloatRect & rect) const159 bool HitTestLocation::intersects(const FloatRect& rect) const
160 {
161     return intersectsRect(rect);
162 }
163 
intersects(const RoundedRect & rect) const164 bool HitTestLocation::intersects(const RoundedRect& rect) const
165 {
166     return rect.intersectsQuad(m_transformedRect);
167 }
168 
rectForPoint(const LayoutPoint & point,unsigned topPadding,unsigned rightPadding,unsigned bottomPadding,unsigned leftPadding)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