• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19 */
20 
21 #include "config.h"
22 #include "HitTestResult.h"
23 
24 #include "DocumentMarkerController.h"
25 #include "Frame.h"
26 #include "FrameTree.h"
27 #include "HTMLAnchorElement.h"
28 #include "HTMLVideoElement.h"
29 #include "HTMLImageElement.h"
30 #include "HTMLInputElement.h"
31 #include "HTMLMediaElement.h"
32 #include "HTMLNames.h"
33 #include "HTMLParserIdioms.h"
34 #include "RenderImage.h"
35 #include "RenderInline.h"
36 #include "Scrollbar.h"
37 #include "SelectionController.h"
38 
39 #if ENABLE(SVG)
40 #include "SVGNames.h"
41 #include "XLinkNames.h"
42 #endif
43 
44 #if ENABLE(WML)
45 #include "WMLImageElement.h"
46 #include "WMLNames.h"
47 #endif
48 
49 namespace WebCore {
50 
51 using namespace HTMLNames;
52 
HitTestResult()53 HitTestResult::HitTestResult()
54     : m_isOverWidget(false)
55     , m_isRectBased(false)
56     , m_topPadding(0)
57     , m_rightPadding(0)
58     , m_bottomPadding(0)
59     , m_leftPadding(0)
60 {
61 }
62 
HitTestResult(const IntPoint & point)63 HitTestResult::HitTestResult(const IntPoint& point)
64     : m_point(point)
65     , m_isOverWidget(false)
66     , m_isRectBased(false)
67     , m_topPadding(0)
68     , m_rightPadding(0)
69     , m_bottomPadding(0)
70     , m_leftPadding(0)
71 {
72 }
73 
HitTestResult(const IntPoint & centerPoint,unsigned topPadding,unsigned rightPadding,unsigned bottomPadding,unsigned leftPadding)74 HitTestResult::HitTestResult(const IntPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
75     : m_point(centerPoint)
76     , m_isOverWidget(false)
77     , m_topPadding(topPadding)
78     , m_rightPadding(rightPadding)
79     , m_bottomPadding(bottomPadding)
80     , m_leftPadding(leftPadding)
81 {
82     // If all padding values passed in are zero then it is not a rect based hit test.
83     m_isRectBased = topPadding || rightPadding || bottomPadding || leftPadding;
84 
85     // Make sure all padding values are clamped to zero if it is not a rect hit test.
86     if (!m_isRectBased)
87         m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0;
88 }
89 
HitTestResult(const HitTestResult & other)90 HitTestResult::HitTestResult(const HitTestResult& other)
91     : m_innerNode(other.innerNode())
92     , m_innerNonSharedNode(other.innerNonSharedNode())
93     , m_point(other.point())
94     , m_localPoint(other.localPoint())
95     , m_innerURLElement(other.URLElement())
96     , m_scrollbar(other.scrollbar())
97     , m_isOverWidget(other.isOverWidget())
98 {
99     // Only copy the padding and NodeSet in case of rect hit test.
100     // Copying the later is rather expensive.
101     if ((m_isRectBased = other.isRectBasedTest())) {
102         m_topPadding = other.m_topPadding;
103         m_rightPadding = other.m_rightPadding;
104         m_bottomPadding = other.m_bottomPadding;
105         m_leftPadding = other.m_leftPadding;
106     } else
107         m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0;
108 
109     m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0);
110 }
111 
~HitTestResult()112 HitTestResult::~HitTestResult()
113 {
114 }
115 
operator =(const HitTestResult & other)116 HitTestResult& HitTestResult::operator=(const HitTestResult& other)
117 {
118     m_innerNode = other.innerNode();
119     m_innerNonSharedNode = other.innerNonSharedNode();
120     m_point = other.point();
121     m_localPoint = other.localPoint();
122     m_innerURLElement = other.URLElement();
123     m_scrollbar = other.scrollbar();
124     m_isOverWidget = other.isOverWidget();
125     // Only copy the padding and NodeSet in case of rect hit test.
126     // Copying the later is rather expensive.
127     if ((m_isRectBased = other.isRectBasedTest())) {
128         m_topPadding = other.m_topPadding;
129         m_rightPadding = other.m_rightPadding;
130         m_bottomPadding = other.m_bottomPadding;
131         m_leftPadding = other.m_leftPadding;
132     } else
133         m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0;
134 
135     m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0);
136     return *this;
137 }
138 
setToNonShadowAncestor()139 void HitTestResult::setToNonShadowAncestor()
140 {
141     Node* node = innerNode();
142     if (node)
143         node = node->shadowAncestorNode();
144     setInnerNode(node);
145     node = innerNonSharedNode();
146     if (node)
147         node = node->shadowAncestorNode();
148     setInnerNonSharedNode(node);
149 }
150 
setInnerNode(Node * n)151 void HitTestResult::setInnerNode(Node* n)
152 {
153     m_innerNode = n;
154 }
155 
setInnerNonSharedNode(Node * n)156 void HitTestResult::setInnerNonSharedNode(Node* n)
157 {
158     m_innerNonSharedNode = n;
159 }
160 
setURLElement(Element * n)161 void HitTestResult::setURLElement(Element* n)
162 {
163     m_innerURLElement = n;
164 }
165 
setScrollbar(Scrollbar * s)166 void HitTestResult::setScrollbar(Scrollbar* s)
167 {
168     m_scrollbar = s;
169 }
170 
targetFrame() const171 Frame* HitTestResult::targetFrame() const
172 {
173     if (!m_innerURLElement)
174         return 0;
175 
176     Frame* frame = m_innerURLElement->document()->frame();
177     if (!frame)
178         return 0;
179 
180     return frame->tree()->find(m_innerURLElement->target());
181 }
182 
isSelected() const183 bool HitTestResult::isSelected() const
184 {
185     if (!m_innerNonSharedNode)
186         return false;
187 
188     Frame* frame = m_innerNonSharedNode->document()->frame();
189     if (!frame)
190         return false;
191 
192     return frame->selection()->contains(m_point);
193 }
194 
spellingToolTip(TextDirection & dir) const195 String HitTestResult::spellingToolTip(TextDirection& dir) const
196 {
197     dir = LTR;
198     // Return the tool tip string associated with this point, if any. Only markers associated with bad grammar
199     // currently supply strings, but maybe someday markers associated with misspelled words will also.
200     if (!m_innerNonSharedNode)
201         return String();
202 
203     DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(m_point, DocumentMarker::Grammar);
204     if (!marker)
205         return String();
206 
207     if (RenderObject* renderer = m_innerNonSharedNode->renderer())
208         dir = renderer->style()->direction();
209     return marker->description;
210 }
211 
replacedString() const212 String HitTestResult::replacedString() const
213 {
214     // Return the replaced string associated with this point, if any. This marker is created when a string is autocorrected,
215     // and is used for generating a contextual menu item that allows it to easily be changed back if desired.
216     if (!m_innerNonSharedNode)
217         return String();
218 
219     DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(m_point, DocumentMarker::Replacement);
220     if (!marker)
221         return String();
222 
223     return marker->description;
224 }
225 
title(TextDirection & dir) const226 String HitTestResult::title(TextDirection& dir) const
227 {
228     dir = LTR;
229     // Find the title in the nearest enclosing DOM node.
230     // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
231     for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentNode()) {
232         if (titleNode->isElementNode()) {
233             String title = static_cast<Element*>(titleNode)->title();
234             if (!title.isEmpty()) {
235                 if (RenderObject* renderer = titleNode->renderer())
236                     dir = renderer->style()->direction();
237                 return title;
238             }
239         }
240     }
241     return String();
242 }
243 
displayString(const String & string,const Node * node)244 String displayString(const String& string, const Node* node)
245 {
246     if (!node)
247         return string;
248     return node->document()->displayStringModifiedByEncoding(string);
249 }
250 
altDisplayString() const251 String HitTestResult::altDisplayString() const
252 {
253     if (!m_innerNonSharedNode)
254         return String();
255 
256     if (m_innerNonSharedNode->hasTagName(imgTag)) {
257         HTMLImageElement* image = static_cast<HTMLImageElement*>(m_innerNonSharedNode.get());
258         return displayString(image->getAttribute(altAttr), m_innerNonSharedNode.get());
259     }
260 
261     if (m_innerNonSharedNode->hasTagName(inputTag)) {
262         HTMLInputElement* input = static_cast<HTMLInputElement*>(m_innerNonSharedNode.get());
263         return displayString(input->alt(), m_innerNonSharedNode.get());
264     }
265 
266 #if ENABLE(WML)
267     if (m_innerNonSharedNode->hasTagName(WMLNames::imgTag)) {
268         WMLImageElement* image = static_cast<WMLImageElement*>(m_innerNonSharedNode.get());
269         return displayString(image->altText(), m_innerNonSharedNode.get());
270     }
271 #endif
272 
273     return String();
274 }
275 
image() const276 Image* HitTestResult::image() const
277 {
278     if (!m_innerNonSharedNode)
279         return 0;
280 
281     RenderObject* renderer = m_innerNonSharedNode->renderer();
282     if (renderer && renderer->isImage()) {
283         RenderImage* image = static_cast<WebCore::RenderImage*>(renderer);
284         if (image->cachedImage() && !image->cachedImage()->errorOccurred())
285             return image->cachedImage()->image();
286     }
287 
288     return 0;
289 }
290 
imageRect() const291 IntRect HitTestResult::imageRect() const
292 {
293     if (!image())
294         return IntRect();
295     return m_innerNonSharedNode->renderBox()->absoluteContentQuad().enclosingBoundingBox();
296 }
297 
absoluteImageURL() const298 KURL HitTestResult::absoluteImageURL() const
299 {
300     if (!(m_innerNonSharedNode && m_innerNonSharedNode->document()))
301         return KURL();
302 
303     if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isImage()))
304         return KURL();
305 
306     AtomicString urlString;
307     if (m_innerNonSharedNode->hasTagName(embedTag)
308         || m_innerNonSharedNode->hasTagName(imgTag)
309         || m_innerNonSharedNode->hasTagName(inputTag)
310         || m_innerNonSharedNode->hasTagName(objectTag)
311 #if ENABLE(SVG)
312         || m_innerNonSharedNode->hasTagName(SVGNames::imageTag)
313 #endif
314 #if ENABLE(WML)
315         || m_innerNonSharedNode->hasTagName(WMLNames::imgTag)
316 #endif
317        ) {
318         Element* element = static_cast<Element*>(m_innerNonSharedNode.get());
319         urlString = element->getAttribute(element->imageSourceAttributeName());
320     } else
321         return KURL();
322 
323     return m_innerNonSharedNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
324 }
325 
absoluteMediaURL() const326 KURL HitTestResult::absoluteMediaURL() const
327 {
328 #if ENABLE(VIDEO)
329     if (HTMLMediaElement* mediaElt = mediaElement())
330         return m_innerNonSharedNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(mediaElt->currentSrc()));
331     return KURL();
332 #else
333     return KURL();
334 #endif
335 }
336 
mediaSupportsFullscreen() const337 bool HitTestResult::mediaSupportsFullscreen() const
338 {
339 #if ENABLE(VIDEO)
340     HTMLMediaElement* mediaElt(mediaElement());
341     return (mediaElt && mediaElt->hasTagName(HTMLNames::videoTag) && mediaElt->supportsFullscreen());
342 #else
343     return false;
344 #endif
345 }
346 
347 #if ENABLE(VIDEO)
mediaElement() const348 HTMLMediaElement* HitTestResult::mediaElement() const
349 {
350     if (!(m_innerNonSharedNode && m_innerNonSharedNode->document()))
351         return 0;
352 
353     if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isMedia()))
354         return 0;
355 
356     if (m_innerNonSharedNode->hasTagName(HTMLNames::videoTag) || m_innerNonSharedNode->hasTagName(HTMLNames::audioTag))
357         return static_cast<HTMLMediaElement*>(m_innerNonSharedNode.get());
358     return 0;
359 }
360 #endif
361 
toggleMediaControlsDisplay() const362 void HitTestResult::toggleMediaControlsDisplay() const
363 {
364 #if ENABLE(VIDEO)
365     if (HTMLMediaElement* mediaElt = mediaElement())
366         mediaElt->setControls(!mediaElt->controls());
367 #endif
368 }
369 
toggleMediaLoopPlayback() const370 void HitTestResult::toggleMediaLoopPlayback() const
371 {
372 #if ENABLE(VIDEO)
373     if (HTMLMediaElement* mediaElt = mediaElement())
374         mediaElt->setLoop(!mediaElt->loop());
375 #endif
376 }
377 
enterFullscreenForVideo() const378 void HitTestResult::enterFullscreenForVideo() const
379 {
380 #if ENABLE(VIDEO)
381     HTMLMediaElement* mediaElt(mediaElement());
382     if (mediaElt && mediaElt->hasTagName(HTMLNames::videoTag)) {
383         HTMLVideoElement* videoElt = static_cast<HTMLVideoElement*>(mediaElt);
384         if (!videoElt->isFullscreen() && mediaElt->supportsFullscreen())
385             videoElt->enterFullscreen();
386     }
387 #endif
388 }
389 
mediaControlsEnabled() const390 bool HitTestResult::mediaControlsEnabled() const
391 {
392 #if ENABLE(VIDEO)
393     if (HTMLMediaElement* mediaElt = mediaElement())
394         return mediaElt->controls();
395 #endif
396     return false;
397 }
398 
mediaLoopEnabled() const399 bool HitTestResult::mediaLoopEnabled() const
400 {
401 #if ENABLE(VIDEO)
402     if (HTMLMediaElement* mediaElt = mediaElement())
403         return mediaElt->loop();
404 #endif
405     return false;
406 }
407 
mediaPlaying() const408 bool HitTestResult::mediaPlaying() const
409 {
410 #if ENABLE(VIDEO)
411     if (HTMLMediaElement* mediaElt = mediaElement())
412         return !mediaElt->paused();
413 #endif
414     return false;
415 }
416 
toggleMediaPlayState() const417 void HitTestResult::toggleMediaPlayState() const
418 {
419 #if ENABLE(VIDEO)
420     if (HTMLMediaElement* mediaElt = mediaElement())
421         mediaElt->togglePlayState();
422 #endif
423 }
424 
mediaHasAudio() const425 bool HitTestResult::mediaHasAudio() const
426 {
427 #if ENABLE(VIDEO)
428     if (HTMLMediaElement* mediaElt = mediaElement())
429         return mediaElt->hasAudio();
430 #endif
431     return false;
432 }
433 
mediaIsVideo() const434 bool HitTestResult::mediaIsVideo() const
435 {
436 #if ENABLE(VIDEO)
437     if (HTMLMediaElement* mediaElt = mediaElement())
438         return mediaElt->hasTagName(HTMLNames::videoTag);
439 #endif
440     return false;
441 }
442 
mediaMuted() const443 bool HitTestResult::mediaMuted() const
444 {
445 #if ENABLE(VIDEO)
446     if (HTMLMediaElement* mediaElt = mediaElement())
447         return mediaElt->muted();
448 #endif
449     return false;
450 }
451 
toggleMediaMuteState() const452 void HitTestResult::toggleMediaMuteState() const
453 {
454 #if ENABLE(VIDEO)
455     if (HTMLMediaElement* mediaElt = mediaElement())
456         mediaElt->setMuted(!mediaElt->muted());
457 #endif
458 }
459 
absoluteLinkURL() const460 KURL HitTestResult::absoluteLinkURL() const
461 {
462     if (!(m_innerURLElement && m_innerURLElement->document()))
463         return KURL();
464 
465     AtomicString urlString;
466     if (m_innerURLElement->hasTagName(aTag) || m_innerURLElement->hasTagName(areaTag) || m_innerURLElement->hasTagName(linkTag))
467         urlString = m_innerURLElement->getAttribute(hrefAttr);
468 #if ENABLE(SVG)
469     else if (m_innerURLElement->hasTagName(SVGNames::aTag))
470         urlString = m_innerURLElement->getAttribute(XLinkNames::hrefAttr);
471 #endif
472 #if ENABLE(WML)
473     else if (m_innerURLElement->hasTagName(WMLNames::aTag))
474         urlString = m_innerURLElement->getAttribute(hrefAttr);
475 #endif
476     else
477         return KURL();
478 
479     return m_innerURLElement->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
480 }
481 
isLiveLink() const482 bool HitTestResult::isLiveLink() const
483 {
484     if (!(m_innerURLElement && m_innerURLElement->document()))
485         return false;
486 
487     if (m_innerURLElement->hasTagName(aTag))
488         return static_cast<HTMLAnchorElement*>(m_innerURLElement.get())->isLiveLink();
489 #if ENABLE(SVG)
490     if (m_innerURLElement->hasTagName(SVGNames::aTag))
491         return m_innerURLElement->isLink();
492 #endif
493 #if ENABLE(WML)
494     if (m_innerURLElement->hasTagName(WMLNames::aTag))
495         return m_innerURLElement->isLink();
496 #endif
497 
498     return false;
499 }
500 
titleDisplayString() const501 String HitTestResult::titleDisplayString() const
502 {
503     if (!m_innerURLElement)
504         return String();
505 
506     return displayString(m_innerURLElement->title(), m_innerURLElement.get());
507 }
508 
textContent() const509 String HitTestResult::textContent() const
510 {
511     if (!m_innerURLElement)
512         return String();
513     return m_innerURLElement->textContent();
514 }
515 
516 // FIXME: This function needs a better name and may belong in a different class. It's not
517 // really isContentEditable(); it's more like needsEditingContextMenu(). In many ways, this
518 // function would make more sense in the ContextMenu class, except that WebElementDictionary
519 // hooks into it. Anyway, we should architect this better.
isContentEditable() const520 bool HitTestResult::isContentEditable() const
521 {
522     if (!m_innerNonSharedNode)
523         return false;
524 
525     if (m_innerNonSharedNode->hasTagName(textareaTag) || m_innerNonSharedNode->hasTagName(isindexTag))
526         return true;
527 
528     if (m_innerNonSharedNode->hasTagName(inputTag))
529         return static_cast<HTMLInputElement*>(m_innerNonSharedNode.get())->isTextField();
530 
531     return m_innerNonSharedNode->rendererIsEditable();
532 }
533 
addNodeToRectBasedTestResult(Node * node,int x,int y,const IntRect & rect)534 bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const IntRect& rect)
535 {
536     // If it is not a rect-based hit test, this method has to be no-op.
537     // Return false, so the hit test stops.
538     if (!isRectBasedTest())
539         return false;
540 
541     // If node is null, return true so the hit test can continue.
542     if (!node)
543         return true;
544 
545     node = node->shadowAncestorNode();
546     mutableRectBasedTestResult().add(node);
547 
548     if (node->renderer()->isInline()) {
549         for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) {
550             if (!curr->isRenderInline())
551                 break;
552 
553             // We need to make sure the nodes for culled inlines get included.
554             RenderInline* currInline = toRenderInline(curr);
555             if (currInline->alwaysCreateLineBoxes())
556                 break;
557 
558             if (currInline->visibleToHitTesting() && currInline->node())
559                 mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode());
560         }
561     }
562     return !rect.contains(rectForPoint(x, y));
563 }
564 
addNodeToRectBasedTestResult(Node * node,int x,int y,const FloatRect & rect)565 bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const FloatRect& rect)
566 {
567     // If it is not a rect-based hit test, this method has to be no-op.
568     // Return false, so the hit test stops.
569     if (!isRectBasedTest())
570         return false;
571 
572     // If node is null, return true so the hit test can continue.
573     if (!node)
574         return true;
575 
576     node = node->shadowAncestorNode();
577     mutableRectBasedTestResult().add(node);
578 
579     if (node->renderer()->isInline()) {
580         for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) {
581             if (!curr->isRenderInline())
582                 break;
583 
584             // We need to make sure the nodes for culled inlines get included.
585             RenderInline* currInline = toRenderInline(curr);
586             if (currInline->alwaysCreateLineBoxes())
587                 break;
588 
589             if (currInline->visibleToHitTesting() && currInline->node())
590                 mutableRectBasedTestResult().add(currInline->node()->shadowAncestorNode());
591         }
592     }
593     return !rect.contains(rectForPoint(x, y));
594 }
595 
append(const HitTestResult & other)596 void HitTestResult::append(const HitTestResult& other)
597 {
598     ASSERT(isRectBasedTest() && other.isRectBasedTest());
599 
600     if (!m_innerNode && other.innerNode()) {
601         m_innerNode = other.innerNode();
602         m_innerNonSharedNode = other.innerNonSharedNode();
603         m_localPoint = other.localPoint();
604         m_innerURLElement = other.URLElement();
605         m_scrollbar = other.scrollbar();
606         m_isOverWidget = other.isOverWidget();
607     }
608 
609     if (other.m_rectBasedTestResult) {
610         NodeSet& set = mutableRectBasedTestResult();
611         for (NodeSet::const_iterator it = other.m_rectBasedTestResult->begin(), last = other.m_rectBasedTestResult->end(); it != last; ++it)
612             set.add(it->get());
613     }
614 }
615 
rectForPoint(const IntPoint & point,unsigned topPadding,unsigned rightPadding,unsigned bottomPadding,unsigned leftPadding)616 IntRect HitTestResult::rectForPoint(const IntPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
617 {
618     IntPoint actualPoint(point);
619     actualPoint -= IntSize(leftPadding, topPadding);
620 
621     IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding);
622     // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1".
623     actualPadding += IntSize(1, 1);
624 
625     return IntRect(actualPoint, actualPadding);
626 }
627 
rectBasedTestResult() const628 const HitTestResult::NodeSet& HitTestResult::rectBasedTestResult() const
629 {
630     if (!m_rectBasedTestResult)
631         m_rectBasedTestResult = adoptPtr(new NodeSet);
632     return *m_rectBasedTestResult;
633 }
634 
mutableRectBasedTestResult()635 HitTestResult::NodeSet& HitTestResult::mutableRectBasedTestResult()
636 {
637     if (!m_rectBasedTestResult)
638         m_rectBasedTestResult = adoptPtr(new NodeSet);
639     return *m_rectBasedTestResult;
640 }
641 
642 } // namespace WebCore
643