|
1 /* |
|
2 * This file is part of the HTML rendering engine for KDE. |
|
3 * |
|
4 * Copyright (C) 2006 Apple Computer, Inc. |
|
5 * |
|
6 * This library is free software; you can redistribute it and/or |
|
7 * modify it under the terms of the GNU Library General Public |
|
8 * License as published by the Free Software Foundation; either |
|
9 * version 2 of the License, or (at your option) any later version. |
|
10 * |
|
11 * This library is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 * Library General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU Library General Public License |
|
17 * along with this library; see the file COPYING.LIB. If not, write to |
|
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
19 * Boston, MA 02110-1301, USA. |
|
20 * |
|
21 */ |
|
22 |
|
23 #include "config.h" |
|
24 #include "HitTestResult.h" |
|
25 |
|
26 #include "CSSHelper.h" |
|
27 #include "Document.h" |
|
28 #include "Frame.h" |
|
29 #include "FrameTree.h" |
|
30 #include "HTMLAnchorElement.h" |
|
31 #include "HTMLElement.h" |
|
32 #include "HTMLImageElement.h" |
|
33 #include "HTMLInputElement.h" |
|
34 #include "HTMLNames.h" |
|
35 #include "KURL.h" |
|
36 #include "PlatformScrollBar.h" |
|
37 #include "RenderImage.h" |
|
38 #include "RenderObject.h" |
|
39 #include "SelectionController.h" |
|
40 |
|
41 #if ENABLE(SVG) |
|
42 #include "SVGNames.h" |
|
43 #include "XLinkNames.h" |
|
44 #endif |
|
45 |
|
46 namespace WebCore { |
|
47 |
|
48 using namespace HTMLNames; |
|
49 |
|
50 HitTestResult::HitTestResult(const IntPoint& point) |
|
51 : m_point(point) |
|
52 { |
|
53 } |
|
54 |
|
55 HitTestResult::HitTestResult(const HitTestResult& other) |
|
56 : m_innerNode(other.innerNode()) |
|
57 , m_innerNonSharedNode(other.innerNonSharedNode()) |
|
58 , m_point(other.point()) |
|
59 , m_localPoint(other.localPoint()) |
|
60 , m_innerURLElement(other.URLElement()) |
|
61 , m_scrollbar(other.scrollbar()) |
|
62 { |
|
63 } |
|
64 |
|
65 HitTestResult::~HitTestResult() |
|
66 { |
|
67 } |
|
68 |
|
69 HitTestResult& HitTestResult::operator=(const HitTestResult& other) |
|
70 { |
|
71 m_innerNode = other.innerNode(); |
|
72 m_innerNonSharedNode = other.innerNonSharedNode(); |
|
73 m_point = other.point(); |
|
74 m_innerURLElement = other.URLElement(); |
|
75 m_scrollbar = other.scrollbar(); |
|
76 return *this; |
|
77 } |
|
78 |
|
79 void HitTestResult::setToNonShadowAncestor() |
|
80 { |
|
81 Node* node = innerNode(); |
|
82 if (node) |
|
83 node = node->shadowAncestorNode(); |
|
84 setInnerNode(node); |
|
85 node = innerNonSharedNode(); |
|
86 if (node) |
|
87 node = node->shadowAncestorNode(); |
|
88 setInnerNonSharedNode(node); |
|
89 } |
|
90 |
|
91 void HitTestResult::setInnerNode(Node* n) |
|
92 { |
|
93 m_innerNode = n; |
|
94 } |
|
95 |
|
96 void HitTestResult::setInnerNonSharedNode(Node* n) |
|
97 { |
|
98 m_innerNonSharedNode = n; |
|
99 } |
|
100 |
|
101 void HitTestResult::setURLElement(Element* n) |
|
102 { |
|
103 m_innerURLElement = n; |
|
104 } |
|
105 |
|
106 void HitTestResult::setScrollbar(PlatformScrollbar* s) |
|
107 { |
|
108 m_scrollbar = s; |
|
109 } |
|
110 |
|
111 Frame* HitTestResult::targetFrame() const |
|
112 { |
|
113 if (!m_innerURLElement) |
|
114 return 0; |
|
115 |
|
116 Frame* frame = m_innerURLElement->document()->frame(); |
|
117 if (!frame) |
|
118 return 0; |
|
119 |
|
120 return frame->tree()->find(m_innerURLElement->target()); |
|
121 } |
|
122 |
|
123 IntRect HitTestResult::boundingBox() const |
|
124 { |
|
125 if (m_innerNonSharedNode) { |
|
126 RenderObject* renderer = m_innerNonSharedNode->renderer(); |
|
127 if (renderer) |
|
128 return renderer->absoluteBoundingBoxRect(); |
|
129 } |
|
130 |
|
131 return IntRect(); |
|
132 } |
|
133 |
|
134 bool HitTestResult::isSelected() const |
|
135 { |
|
136 if (!m_innerNonSharedNode) |
|
137 return false; |
|
138 |
|
139 Frame* frame = m_innerNonSharedNode->document()->frame(); |
|
140 if (!frame) |
|
141 return false; |
|
142 |
|
143 return frame->selectionController()->contains(m_point); |
|
144 } |
|
145 |
|
146 String HitTestResult::spellingToolTip() const |
|
147 { |
|
148 // Return the tool tip string associated with this point, if any. Only markers associated with bad grammar |
|
149 // currently supply strings, but maybe someday markers associated with misspelled words will also. |
|
150 if (!m_innerNonSharedNode) |
|
151 return String(); |
|
152 |
|
153 DocumentMarker* marker = m_innerNonSharedNode->document()->markerContainingPoint(m_point, DocumentMarker::Grammar); |
|
154 if (!marker) |
|
155 return String(); |
|
156 |
|
157 return marker->description; |
|
158 } |
|
159 |
|
160 String HitTestResult::title() const |
|
161 { |
|
162 // Find the title in the nearest enclosing DOM node. |
|
163 // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it. |
|
164 for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentNode()) { |
|
165 if (titleNode->isElementNode()) { |
|
166 String title = static_cast<Element*>(titleNode)->title(); |
|
167 if (!title.isEmpty()) |
|
168 return title; |
|
169 } |
|
170 } |
|
171 return String(); |
|
172 } |
|
173 |
|
174 String displayString(const String& string, const Node* node) |
|
175 { |
|
176 if (!node) |
|
177 return string; |
|
178 String copy(string); |
|
179 copy.replace('\\', node->document()->backslashAsCurrencySymbol()); |
|
180 return copy; |
|
181 } |
|
182 |
|
183 String HitTestResult::altDisplayString() const |
|
184 { |
|
185 if (!m_innerNonSharedNode) |
|
186 return String(); |
|
187 |
|
188 if (m_innerNonSharedNode->hasTagName(imgTag)) { |
|
189 HTMLImageElement* image = static_cast<HTMLImageElement*>(m_innerNonSharedNode.get()); |
|
190 return displayString(image->alt(), m_innerNonSharedNode.get()); |
|
191 } |
|
192 |
|
193 if (m_innerNonSharedNode->hasTagName(inputTag)) { |
|
194 HTMLInputElement* input = static_cast<HTMLInputElement*>(m_innerNonSharedNode.get()); |
|
195 return displayString(input->alt(), m_innerNonSharedNode.get()); |
|
196 } |
|
197 |
|
198 return String(); |
|
199 } |
|
200 |
|
201 Image* HitTestResult::image() const |
|
202 { |
|
203 if (!m_innerNonSharedNode) |
|
204 return 0; |
|
205 |
|
206 RenderObject* renderer = m_innerNonSharedNode->renderer(); |
|
207 if (renderer && renderer->isImage()) { |
|
208 RenderImage* image = static_cast<WebCore::RenderImage*>(renderer); |
|
209 if (image->cachedImage() && !image->cachedImage()->errorOccurred()) |
|
210 return image->cachedImage()->image(); |
|
211 } |
|
212 |
|
213 return 0; |
|
214 } |
|
215 |
|
216 IntRect HitTestResult::imageRect() const |
|
217 { |
|
218 if (!image()) |
|
219 return IntRect(); |
|
220 return m_innerNonSharedNode->renderer()->absoluteContentBox(); |
|
221 } |
|
222 |
|
223 KURL HitTestResult::absoluteImageURL() const |
|
224 { |
|
225 if (!(m_innerNonSharedNode && m_innerNonSharedNode->document())) |
|
226 return KURL(); |
|
227 |
|
228 if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isImage())) |
|
229 return KURL(); |
|
230 |
|
231 AtomicString urlString; |
|
232 if (m_innerNonSharedNode->hasTagName(imgTag) || m_innerNonSharedNode->hasTagName(inputTag)) |
|
233 urlString = static_cast<Element*>(m_innerNonSharedNode.get())->getAttribute(srcAttr); |
|
234 #if ENABLE(SVG) |
|
235 else if (m_innerNonSharedNode->hasTagName(SVGNames::imageTag)) |
|
236 urlString = static_cast<Element*>(m_innerNonSharedNode.get())->getAttribute(XLinkNames::hrefAttr); |
|
237 #endif |
|
238 else if (m_innerNonSharedNode->hasTagName(objectTag)) |
|
239 urlString = static_cast<Element*>(m_innerNonSharedNode.get())->getAttribute(dataAttr); |
|
240 else |
|
241 return KURL(); |
|
242 |
|
243 return KURL(m_innerNonSharedNode->document()->completeURL(parseURL(urlString).deprecatedString())); |
|
244 } |
|
245 |
|
246 KURL HitTestResult::absoluteLinkURL() const |
|
247 { |
|
248 if (!(m_innerURLElement && m_innerURLElement->document())) |
|
249 return KURL(); |
|
250 |
|
251 AtomicString urlString; |
|
252 if (m_innerURLElement->hasTagName(aTag) || m_innerURLElement->hasTagName(areaTag) || m_innerURLElement->hasTagName(linkTag)) |
|
253 urlString = m_innerURLElement->getAttribute(hrefAttr); |
|
254 #if ENABLE(SVG) |
|
255 else if (m_innerURLElement->hasTagName(SVGNames::aTag)) |
|
256 urlString = m_innerURLElement->getAttribute(XLinkNames::hrefAttr); |
|
257 #endif |
|
258 else |
|
259 return KURL(); |
|
260 |
|
261 return KURL(m_innerURLElement->document()->completeURL(parseURL(urlString).deprecatedString())); |
|
262 } |
|
263 |
|
264 bool HitTestResult::isLiveLink() const |
|
265 { |
|
266 if (!(m_innerURLElement && m_innerURLElement->document())) |
|
267 return false; |
|
268 |
|
269 if (m_innerURLElement->hasTagName(aTag)) |
|
270 return static_cast<HTMLAnchorElement*>(m_innerURLElement.get())->isLiveLink(); |
|
271 #if ENABLE(SVG) |
|
272 if (m_innerURLElement->hasTagName(SVGNames::aTag)) |
|
273 return m_innerURLElement->isLink(); |
|
274 #endif |
|
275 |
|
276 return false; |
|
277 } |
|
278 |
|
279 String HitTestResult::titleDisplayString() const |
|
280 { |
|
281 if (!m_innerURLElement) |
|
282 return String(); |
|
283 |
|
284 return displayString(m_innerURLElement->title(), m_innerURLElement.get()); |
|
285 } |
|
286 |
|
287 String HitTestResult::textContent() const |
|
288 { |
|
289 if (!m_innerURLElement) |
|
290 return String(); |
|
291 return m_innerURLElement->textContent(); |
|
292 } |
|
293 |
|
294 // FIXME: This function needs a better name and may belong in a different class. It's not |
|
295 // really isContentEditable(); it's more like needsEditingContextMenu(). In many ways, this |
|
296 // function would make more sense in the ContextMenu class, except that WebElementDictionary |
|
297 // hooks into it. Anyway, we should architect this better. |
|
298 bool HitTestResult::isContentEditable() const |
|
299 { |
|
300 if (!m_innerNonSharedNode) |
|
301 return false; |
|
302 |
|
303 if (m_innerNonSharedNode->hasTagName(textareaTag) || m_innerNonSharedNode->hasTagName(isindexTag)) |
|
304 return true; |
|
305 |
|
306 if (m_innerNonSharedNode->hasTagName(inputTag)) |
|
307 return static_cast<HTMLInputElement*>(m_innerNonSharedNode.get())->isTextField(); |
|
308 |
|
309 return m_innerNonSharedNode->isContentEditable(); |
|
310 } |
|
311 |
|
312 } // namespace WebCore |