97498e81f99566c254605dbf4902314c986068e8
[WebKit-https.git] / Source / WebCore / rendering / HitTestResult.cpp
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 "HitTestResult.h"
24
25 #include "CachedImage.h"
26 #include "DocumentMarkerController.h"
27 #include "Editor.h"
28 #include "File.h"
29 #include "Frame.h"
30 #include "FrameSelection.h"
31 #include "FrameTree.h"
32 #include "HTMLAnchorElement.h"
33 #include "HTMLAreaElement.h"
34 #include "HTMLAttachmentElement.h"
35 #include "HTMLAudioElement.h"
36 #include "HTMLImageElement.h"
37 #include "HTMLInputElement.h"
38 #include "HTMLMediaElement.h"
39 #include "HTMLNames.h"
40 #include "HTMLParserIdioms.h"
41 #include "HTMLPlugInImageElement.h"
42 #include "HTMLTextAreaElement.h"
43 #include "HTMLVideoElement.h"
44 #include "HitTestLocation.h"
45 #include "PseudoElement.h"
46 #include "RenderBlockFlow.h"
47 #include "RenderImage.h"
48 #include "RenderInline.h"
49 #include "SVGAElement.h"
50 #include "SVGImageElement.h"
51 #include "SVGNames.h"
52 #include "Scrollbar.h"
53 #include "ShadowRoot.h"
54 #include "TextIterator.h"
55 #include "UserGestureIndicator.h"
56 #include "VisibleUnits.h"
57 #include "XLinkNames.h"
58
59 namespace WebCore {
60
61 using namespace HTMLNames;
62
63 HitTestResult::HitTestResult()
64     : m_isOverWidget(false)
65 {
66 }
67
68 HitTestResult::HitTestResult(const LayoutPoint& point)
69     : m_hitTestLocation(point)
70     , m_pointInInnerNodeFrame(point)
71     , m_isOverWidget(false)
72 {
73 }
74
75 HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
76     : m_hitTestLocation(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding)
77     , m_pointInInnerNodeFrame(centerPoint)
78     , m_isOverWidget(false)
79 {
80 }
81
82 HitTestResult::HitTestResult(const HitTestLocation& other)
83     : m_hitTestLocation(other)
84     , m_pointInInnerNodeFrame(m_hitTestLocation.point())
85     , m_isOverWidget(false)
86 {
87 }
88
89 HitTestResult::HitTestResult(const HitTestResult& other)
90     : m_hitTestLocation(other.m_hitTestLocation)
91     , m_innerNode(other.innerNode())
92     , m_innerNonSharedNode(other.innerNonSharedNode())
93     , m_pointInInnerNodeFrame(other.m_pointInInnerNodeFrame)
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 NodeSet in case of rect hit test.
100     m_rectBasedTestResult = other.m_rectBasedTestResult ? std::make_unique<NodeSet>(*other.m_rectBasedTestResult) : nullptr;
101 }
102
103 HitTestResult::~HitTestResult()
104 {
105 }
106
107 HitTestResult& HitTestResult::operator=(const HitTestResult& other)
108 {
109     m_hitTestLocation = other.m_hitTestLocation;
110     m_innerNode = other.innerNode();
111     m_innerNonSharedNode = other.innerNonSharedNode();
112     m_pointInInnerNodeFrame = other.m_pointInInnerNodeFrame;
113     m_localPoint = other.localPoint();
114     m_innerURLElement = other.URLElement();
115     m_scrollbar = other.scrollbar();
116     m_isOverWidget = other.isOverWidget();
117
118     // Only copy the NodeSet in case of rect hit test.
119     m_rectBasedTestResult = other.m_rectBasedTestResult ? std::make_unique<NodeSet>(*other.m_rectBasedTestResult) : nullptr;
120
121     return *this;
122 }
123
124 void HitTestResult::setToNonShadowAncestor()
125 {
126     Node* node = innerNode();
127     if (node)
128         node = node->document().ancestorInThisScope(node);
129     setInnerNode(node);
130     node = innerNonSharedNode();
131     if (node)
132         node = node->document().ancestorInThisScope(node);
133     setInnerNonSharedNode(node);
134 }
135
136 void HitTestResult::setInnerNode(Node* node)
137 {
138     if (is<PseudoElement>(node))
139         node = downcast<PseudoElement>(*node).hostElement();
140     m_innerNode = node;
141 }
142     
143 void HitTestResult::setInnerNonSharedNode(Node* node)
144 {
145     if (is<PseudoElement>(node))
146         node = downcast<PseudoElement>(*node).hostElement();
147     m_innerNonSharedNode = node;
148 }
149
150 void HitTestResult::setURLElement(Element* n) 
151
152     m_innerURLElement = n; 
153 }
154
155 void HitTestResult::setScrollbar(Scrollbar* s)
156 {
157     m_scrollbar = s;
158 }
159
160 Frame* HitTestResult::innerNodeFrame() const
161 {
162     if (m_innerNonSharedNode)
163         return m_innerNonSharedNode->document().frame();
164     if (m_innerNode)
165         return m_innerNode->document().frame();
166     return 0;
167 }
168
169 Frame* HitTestResult::targetFrame() const
170 {
171     if (!m_innerURLElement)
172         return 0;
173
174     Frame* frame = m_innerURLElement->document().frame();
175     if (!frame)
176         return 0;
177
178     return frame->tree().find(m_innerURLElement->target());
179 }
180
181 bool HitTestResult::isSelected() const
182 {
183     if (!m_innerNonSharedNode)
184         return false;
185
186     Frame* frame = m_innerNonSharedNode->document().frame();
187     if (!frame)
188         return false;
189
190     return frame->selection().contains(m_hitTestLocation.point());
191 }
192
193 String HitTestResult::selectedText() const
194 {
195     if (!m_innerNonSharedNode)
196         return emptyString();
197
198     Frame* frame = m_innerNonSharedNode->document().frame();
199     if (!frame)
200         return emptyString();
201
202     // Look for a character that's not just a separator.
203     for (TextIterator it(frame->selection().toNormalizedRange().get()); !it.atEnd(); it.advance()) {
204         int length = it.text().length();
205         for (int i = 0; i < length; ++i) {
206             if (!(U_GET_GC_MASK(it.text()[i]) & U_GC_Z_MASK))
207                 return frame->displayStringModifiedByEncoding(frame->editor().selectedText());
208         }
209     }
210     return emptyString();
211 }
212
213 String HitTestResult::spellingToolTip(TextDirection& dir) const
214 {
215     dir = LTR;
216     // Return the tool tip string associated with this point, if any. Only markers associated with bad grammar
217     // currently supply strings, but maybe someday markers associated with misspelled words will also.
218     if (!m_innerNonSharedNode)
219         return String();
220     
221     DocumentMarker* marker = m_innerNonSharedNode->document().markers().markerContainingPoint(m_hitTestLocation.point(), DocumentMarker::Grammar);
222     if (!marker)
223         return String();
224
225     if (auto renderer = m_innerNonSharedNode->renderer())
226         dir = renderer->style().direction();
227     return marker->description();
228 }
229
230 String HitTestResult::replacedString() const
231 {
232     // Return the replaced string associated with this point, if any. This marker is created when a string is autocorrected, 
233     // and is used for generating a contextual menu item that allows it to easily be changed back if desired.
234     if (!m_innerNonSharedNode)
235         return String();
236     
237     DocumentMarker* marker = m_innerNonSharedNode->document().markers().markerContainingPoint(m_hitTestLocation.point(), DocumentMarker::Replacement);
238     if (!marker)
239         return String();
240     
241     return marker->description();
242 }    
243     
244 String HitTestResult::title(TextDirection& dir) const
245 {
246     dir = LTR;
247     // Find the title in the nearest enclosing DOM node.
248     // For <area> tags in image maps, walk the tree for the <area>, not the <img> using it.
249     for (Node* titleNode = m_innerNode.get(); titleNode; titleNode = titleNode->parentNode()) {
250         if (is<Element>(*titleNode)) {
251             Element& titleElement = downcast<Element>(*titleNode);
252             String title = titleElement.title();
253             if (!title.isEmpty()) {
254                 if (auto renderer = titleElement.renderer())
255                     dir = renderer->style().direction();
256                 return title;
257             }
258         }
259     }
260     return String();
261 }
262
263 String HitTestResult::innerTextIfTruncated(TextDirection& dir) const
264 {
265     for (Node* truncatedNode = m_innerNode.get(); truncatedNode; truncatedNode = truncatedNode->parentNode()) {
266         if (!is<Element>(*truncatedNode))
267             continue;
268
269         if (auto renderer = downcast<Element>(*truncatedNode).renderer()) {
270             if (is<RenderBlockFlow>(*renderer)) {
271                 RenderBlockFlow& block = downcast<RenderBlockFlow>(*renderer);
272                 if (block.style().textOverflow()) {
273                     for (RootInlineBox* line = block.firstRootBox(); line; line = line->nextRootBox()) {
274                         if (line->hasEllipsisBox()) {
275                             dir = block.style().direction();
276                             return downcast<Element>(*truncatedNode).innerText();
277                         }
278                     }
279                 }
280                 break;
281             }
282         }
283     }
284
285     dir = LTR;
286     return String();
287 }
288
289 String displayString(const String& string, const Node* node)
290 {
291     if (!node)
292         return string;
293     return node->document().displayStringModifiedByEncoding(string);
294 }
295
296 String HitTestResult::altDisplayString() const
297 {
298     if (!m_innerNonSharedNode)
299         return String();
300     
301     if (is<HTMLImageElement>(*m_innerNonSharedNode)) {
302         HTMLImageElement& image = downcast<HTMLImageElement>(*m_innerNonSharedNode);
303         return displayString(image.fastGetAttribute(altAttr), m_innerNonSharedNode.get());
304     }
305     
306     if (is<HTMLInputElement>(*m_innerNonSharedNode)) {
307         HTMLInputElement& input = downcast<HTMLInputElement>(*m_innerNonSharedNode);
308         return displayString(input.alt(), m_innerNonSharedNode.get());
309     }
310
311     return String();
312 }
313
314 Image* HitTestResult::image() const
315 {
316     if (!m_innerNonSharedNode)
317         return nullptr;
318     
319     auto* renderer = m_innerNonSharedNode->renderer();
320     if (is<RenderImage>(renderer)) {
321         auto& image = downcast<RenderImage>(*renderer);
322         if (image.cachedImage() && !image.cachedImage()->errorOccurred())
323             return image.cachedImage()->imageForRenderer(&image);
324     }
325
326     return nullptr;
327 }
328
329 IntRect HitTestResult::imageRect() const
330 {
331     if (!image())
332         return IntRect();
333     return m_innerNonSharedNode->renderBox()->absoluteContentQuad().enclosingBoundingBox();
334 }
335
336 #if ENABLE(ATTACHMENT_ELEMENT)
337 URL HitTestResult::absoluteAttachmentURL() const
338 {
339     if (!m_innerNonSharedNode)
340         return URL();
341     
342     if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isAttachment()))
343         return URL();
344     
345     if (!is<HTMLAttachmentElement>(*m_innerNonSharedNode))
346         return URL();
347     File* attachmentFile = downcast<HTMLAttachmentElement>(*m_innerNonSharedNode).file();
348     if (!attachmentFile)
349         return URL();
350     
351     return URL::fileURLWithFileSystemPath(attachmentFile->path());
352 }
353 #endif
354
355 URL HitTestResult::absoluteImageURL() const
356 {
357     if (!m_innerNonSharedNode)
358         return URL();
359
360     if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isImage()))
361         return URL();
362
363     AtomicString urlString;
364     if (is<HTMLEmbedElement>(*m_innerNonSharedNode)
365         || is<HTMLImageElement>(*m_innerNonSharedNode)
366         || is<HTMLInputElement>(*m_innerNonSharedNode)
367         || is<HTMLObjectElement>(*m_innerNonSharedNode)
368         || is<SVGImageElement>(*m_innerNonSharedNode)) {
369         urlString = downcast<Element>(*m_innerNonSharedNode).imageSourceURL();
370     } else
371         return URL();
372
373     return m_innerNonSharedNode->document().completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
374 }
375
376 URL HitTestResult::absolutePDFURL() const
377 {
378     if (!m_innerNonSharedNode)
379         return URL();
380
381     if (!is<HTMLEmbedElement>(*m_innerNonSharedNode) && !is<HTMLObjectElement>(*m_innerNonSharedNode))
382         return URL();
383
384     HTMLPlugInImageElement& element = downcast<HTMLPlugInImageElement>(*m_innerNonSharedNode);
385     URL url = m_innerNonSharedNode->document().completeURL(stripLeadingAndTrailingHTMLSpaces(element.url()));
386     if (!url.isValid())
387         return URL();
388
389     if (element.serviceType() == "application/pdf" || (element.serviceType().isEmpty() && url.path().endsWith(".pdf", false)))
390         return url;
391     return URL();
392 }
393
394 URL HitTestResult::absoluteMediaURL() const
395 {
396 #if ENABLE(VIDEO)
397     if (HTMLMediaElement* mediaElt = mediaElement())
398         return mediaElt->currentSrc();
399     return URL();
400 #else
401     return URL();
402 #endif
403 }
404
405 bool HitTestResult::mediaSupportsFullscreen() const
406 {
407 #if ENABLE(VIDEO)
408     HTMLMediaElement* mediaElt(mediaElement());
409     return is<HTMLVideoElement>(mediaElt) && mediaElt->supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard);
410 #else
411     return false;
412 #endif
413 }
414
415 #if ENABLE(VIDEO)
416 HTMLMediaElement* HitTestResult::mediaElement() const
417 {
418     if (!m_innerNonSharedNode)
419         return nullptr;
420
421     if (!(m_innerNonSharedNode->renderer() && m_innerNonSharedNode->renderer()->isMedia()))
422         return nullptr;
423
424     if (is<HTMLMediaElement>(*m_innerNonSharedNode))
425         return downcast<HTMLMediaElement>(m_innerNonSharedNode.get());
426     return nullptr;
427 }
428 #endif
429
430 void HitTestResult::toggleMediaControlsDisplay() const
431 {
432 #if ENABLE(VIDEO)
433     if (HTMLMediaElement* mediaElt = mediaElement())
434         mediaElt->setControls(!mediaElt->controls());
435 #endif
436 }
437
438 void HitTestResult::toggleMediaLoopPlayback() const
439 {
440 #if ENABLE(VIDEO)
441     if (HTMLMediaElement* mediaElt = mediaElement())
442         mediaElt->setLoop(!mediaElt->loop());
443 #endif
444 }
445
446 bool HitTestResult::mediaIsInFullscreen() const
447 {
448 #if ENABLE(VIDEO)
449     if (HTMLMediaElement* mediaElement = this->mediaElement())
450         return mediaElement->isVideo() && mediaElement->isFullscreen();
451 #endif
452     return false;
453 }
454
455 void HitTestResult::toggleMediaFullscreenState() const
456 {
457 #if ENABLE(VIDEO)
458     if (HTMLMediaElement* mediaElement = this->mediaElement()) {
459         if (mediaElement->isVideo() && mediaElement->supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard)) {
460             UserGestureIndicator indicator(DefinitelyProcessingUserGesture, &mediaElement->document());
461             mediaElement->toggleFullscreenState();
462         }
463     }
464 #endif
465 }
466
467 void HitTestResult::enterFullscreenForVideo() const
468 {
469 #if ENABLE(VIDEO)
470     HTMLMediaElement* mediaElement(this->mediaElement());
471     if (is<HTMLVideoElement>(mediaElement)) {
472         HTMLVideoElement& videoElement = downcast<HTMLVideoElement>(*mediaElement);
473         if (!videoElement.isFullscreen() && mediaElement->supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard)) {
474             UserGestureIndicator indicator(DefinitelyProcessingUserGesture, &mediaElement->document());
475             videoElement.enterFullscreen();
476         }
477     }
478 #endif
479 }
480
481 bool HitTestResult::mediaControlsEnabled() const
482 {
483 #if ENABLE(VIDEO)
484     if (HTMLMediaElement* mediaElement = this->mediaElement())
485         return mediaElement->controls();
486 #endif
487     return false;
488 }
489
490 bool HitTestResult::mediaLoopEnabled() const
491 {
492 #if ENABLE(VIDEO)
493     if (HTMLMediaElement* mediaElt = mediaElement())
494         return mediaElt->loop();
495 #endif
496     return false;
497 }
498
499 bool HitTestResult::mediaPlaying() const
500 {
501 #if ENABLE(VIDEO)
502     if (HTMLMediaElement* mediaElt = mediaElement())
503         return !mediaElt->paused();
504 #endif
505     return false;
506 }
507
508 void HitTestResult::toggleMediaPlayState() const
509 {
510 #if ENABLE(VIDEO)
511     if (HTMLMediaElement* mediaElt = mediaElement())
512         mediaElt->togglePlayState();
513 #endif
514 }
515
516 bool HitTestResult::mediaHasAudio() const
517 {
518 #if ENABLE(VIDEO)
519     if (HTMLMediaElement* mediaElt = mediaElement())
520         return mediaElt->hasAudio();
521 #endif
522     return false;
523 }
524
525 bool HitTestResult::mediaIsVideo() const
526 {
527 #if ENABLE(VIDEO)
528     if (HTMLMediaElement* mediaElt = mediaElement())
529         return is<HTMLVideoElement>(*mediaElt);
530 #endif
531     return false;
532 }
533
534 bool HitTestResult::mediaMuted() const
535 {
536 #if ENABLE(VIDEO)
537     if (HTMLMediaElement* mediaElt = mediaElement())
538         return mediaElt->muted();
539 #endif
540     return false;
541 }
542
543 void HitTestResult::toggleMediaMuteState() const
544 {
545 #if ENABLE(VIDEO)
546     if (HTMLMediaElement* mediaElt = mediaElement())
547         mediaElt->setMuted(!mediaElt->muted());
548 #endif
549 }
550
551 bool HitTestResult::isDownloadableMedia() const
552 {
553 #if ENABLE(VIDEO)
554     if (HTMLMediaElement* mediaElt = mediaElement())
555         return mediaElt->canSaveMediaData();
556 #endif
557
558     return false;
559 }
560
561 bool HitTestResult::isOverTextInsideFormControlElement() const
562 {
563     Node* node = innerNode();
564     if (!node)
565         return false;
566
567     if (!is<HTMLTextFormControlElement>(*node))
568         return false;
569
570     Frame* frame = node->document().frame();
571     if (!frame)
572         return false;
573
574     IntPoint framePoint = roundedPointInInnerNodeFrame();
575     if (!frame->rangeForPoint(framePoint))
576         return false;
577
578     VisiblePosition position = frame->visiblePositionForPoint(framePoint);
579     if (position.isNull())
580         return false;
581
582     RefPtr<Range> wordRange = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionForward);
583     if (!wordRange)
584         return false;
585
586     return !wordRange->text().isEmpty();
587 }
588
589 bool HitTestResult::allowsCopy() const
590 {
591     Node* node = innerNode();
592     if (!node)
593         return false;
594
595     RenderObject* renderer = node->renderer();
596     if (!renderer)
597         return false;
598
599     bool isUserSelectNone = renderer->style().userSelect() == SELECT_NONE;
600     bool isPasswordField = is<HTMLInputElement>(node) && downcast<HTMLInputElement>(*node).isPasswordField();
601     return !isPasswordField && !isUserSelectNone;
602 }
603
604 URL HitTestResult::absoluteLinkURL() const
605 {
606     if (m_innerURLElement)
607         return m_innerURLElement->absoluteLinkURL();
608     return URL();
609 }
610
611 bool HitTestResult::isOverLink() const
612 {
613     return m_innerURLElement && m_innerURLElement->isLink();
614 }
615
616 String HitTestResult::titleDisplayString() const
617 {
618     if (!m_innerURLElement)
619         return String();
620     
621     return displayString(m_innerURLElement->title(), m_innerURLElement.get());
622 }
623
624 String HitTestResult::textContent() const
625 {
626     if (!m_innerURLElement)
627         return String();
628     return m_innerURLElement->textContent();
629 }
630
631 // FIXME: This function needs a better name and may belong in a different class. It's not
632 // really isContentEditable(); it's more like needsEditingContextMenu(). In many ways, this
633 // function would make more sense in the ContextMenu class, except that WebElementDictionary 
634 // hooks into it. Anyway, we should architect this better. 
635 bool HitTestResult::isContentEditable() const
636 {
637     if (!m_innerNonSharedNode)
638         return false;
639
640     if (is<HTMLTextAreaElement>(*m_innerNonSharedNode))
641         return true;
642
643     if (is<HTMLInputElement>(*m_innerNonSharedNode))
644         return downcast<HTMLInputElement>(*m_innerNonSharedNode).isTextField();
645
646     return m_innerNonSharedNode->hasEditableStyle();
647 }
648
649 bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestRequest& request, const HitTestLocation& locationInContainer, const LayoutRect& rect)
650 {
651     // If it is not a rect-based hit test, this method has to be no-op.
652     // Return false, so the hit test stops.
653     if (!isRectBasedTest())
654         return false;
655
656     // If node is null, return true so the hit test can continue.
657     if (!node)
658         return true;
659
660     if (request.disallowsShadowContent())
661         node = node->document().ancestorInThisScope(node);
662
663     mutableRectBasedTestResult().add(node);
664
665     bool regionFilled = rect.contains(locationInContainer.boundingBox());
666     return !regionFilled;
667 }
668
669 bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestRequest& request, const HitTestLocation& locationInContainer, const FloatRect& rect)
670 {
671     // If it is not a rect-based hit test, this method has to be no-op.
672     // Return false, so the hit test stops.
673     if (!isRectBasedTest())
674         return false;
675
676     // If node is null, return true so the hit test can continue.
677     if (!node)
678         return true;
679
680     if (request.disallowsShadowContent())
681         node = node->document().ancestorInThisScope(node);
682
683     mutableRectBasedTestResult().add(node);
684
685     bool regionFilled = rect.contains(locationInContainer.boundingBox());
686     return !regionFilled;
687 }
688
689 void HitTestResult::append(const HitTestResult& other)
690 {
691     ASSERT(isRectBasedTest() && other.isRectBasedTest());
692
693     if (!m_innerNode && other.innerNode()) {
694         m_innerNode = other.innerNode();
695         m_innerNonSharedNode = other.innerNonSharedNode();
696         m_localPoint = other.localPoint();
697         m_pointInInnerNodeFrame = other.m_pointInInnerNodeFrame;
698         m_innerURLElement = other.URLElement();
699         m_scrollbar = other.scrollbar();
700         m_isOverWidget = other.isOverWidget();
701     }
702
703     if (other.m_rectBasedTestResult) {
704         NodeSet& set = mutableRectBasedTestResult();
705         for (NodeSet::const_iterator it = other.m_rectBasedTestResult->begin(), last = other.m_rectBasedTestResult->end(); it != last; ++it)
706             set.add(it->get());
707     }
708 }
709
710 const HitTestResult::NodeSet& HitTestResult::rectBasedTestResult() const
711 {
712     if (!m_rectBasedTestResult)
713         m_rectBasedTestResult = std::make_unique<NodeSet>();
714     return *m_rectBasedTestResult;
715 }
716
717 HitTestResult::NodeSet& HitTestResult::mutableRectBasedTestResult()
718 {
719     if (!m_rectBasedTestResult)
720         m_rectBasedTestResult = std::make_unique<NodeSet>();
721     return *m_rectBasedTestResult;
722 }
723
724 Vector<String> HitTestResult::dictationAlternatives() const
725 {
726     // Return the dictation context handle if the text at this point has DictationAlternative marker, which means this text is
727     if (!m_innerNonSharedNode)
728         return Vector<String>();
729
730     DocumentMarker* marker = m_innerNonSharedNode->document().markers().markerContainingPoint(pointInInnerNodeFrame(), DocumentMarker::DictationAlternatives);
731     if (!marker)
732         return Vector<String>();
733
734     Frame* frame = innerNonSharedNode()->document().frame();
735     if (!frame)
736         return Vector<String>();
737
738     return frame->editor().dictationAlternativesForMarker(marker);
739 }
740
741 Node* HitTestResult::targetNode() const
742 {
743     Node* node = innerNode();
744     if (!node)
745         return 0;
746     if (node->inDocument())
747         return node;
748
749     Element* element = node->parentElement();
750     if (element && element->inDocument())
751         return element;
752
753     return node;
754 }
755
756 Element* HitTestResult::innerElement() const
757 {
758     Node* node = m_innerNode.get();
759     if (!node)
760         return nullptr;
761     if (is<Element>(*node))
762         return downcast<Element>(node);
763     return node->parentElement();
764 }
765
766 Element* HitTestResult::innerNonSharedElement() const
767 {
768     Node* node = m_innerNonSharedNode.get();
769     if (!node)
770         return nullptr;
771     if (is<Element>(*node))
772         return downcast<Element>(node);
773     return node->parentElement();
774 }
775
776 #if USE(APPLE_INTERNAL_SDK)
777 #include <WebKitAdditions/HitTestResultAdditions.cpp>
778 #else
779 bool HitTestResult::mediaSupportsEnhancedFullscreen() const
780 {
781     return false;
782 }
783
784 bool HitTestResult::mediaIsInEnhancedFullscreen() const
785 {
786     return false;
787 }
788
789 void HitTestResult::toggleEnhancedFullscreenForVideo() const
790 {
791 }
792 #endif
793
794 } // namespace WebCore