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