Combine ActionMenuHitTestResult with WebHitTestResult
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / mac / WebPageMac.mm
1 /*
2  * Copyright (C) 2010, 2011, 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WebPage.h"
28
29 #if PLATFORM(MAC)
30
31 #import "AttributedString.h"
32 #import "DataReference.h"
33 #import "DictionaryPopupInfo.h"
34 #import "EditingRange.h"
35 #import "EditorState.h"
36 #import "InjectedBundleHitTestResult.h"
37 #import "PDFKitImports.h"
38 #import "PageBanner.h"
39 #import "PluginView.h"
40 #import "PrintInfo.h"
41 #import "UserData.h"
42 #import "WKAccessibilityWebPageObjectMac.h"
43 #import "WebCoreArgumentCoders.h"
44 #import "WebEvent.h"
45 #import "WebEventConversion.h"
46 #import "WebFrame.h"
47 #import "WebHitTestResult.h"
48 #import "WebImage.h"
49 #import "WebInspector.h"
50 #import "WebPageOverlay.h"
51 #import "WebPageProxyMessages.h"
52 #import "WebPasteboardOverrides.h"
53 #import "WebPreferencesStore.h"
54 #import "WebProcess.h"
55 #import <PDFKit/PDFKit.h>
56 #import <QuartzCore/QuartzCore.h>
57 #import <WebCore/AXObjectCache.h>
58 #import <WebCore/BackForwardController.h>
59 #import <WebCore/DataDetection.h>
60 #import <WebCore/DataDetectorsSPI.h>
61 #import <WebCore/DictionaryLookup.h>
62 #import <WebCore/EventHandler.h>
63 #import <WebCore/FocusController.h>
64 #import <WebCore/FrameLoader.h>
65 #import <WebCore/FrameView.h>
66 #import <WebCore/GraphicsContext.h>
67 #import <WebCore/HTMLConverter.h>
68 #import <WebCore/HitTestResult.h>
69 #import <WebCore/KeyboardEvent.h>
70 #import <WebCore/MIMETypeRegistry.h>
71 #import <WebCore/MainFrame.h>
72 #import <WebCore/NetworkingContext.h>
73 #import <WebCore/Page.h>
74 #import <WebCore/PageOverlayController.h>
75 #import <WebCore/PlatformKeyboardEvent.h>
76 #import <WebCore/PluginDocument.h>
77 #import <WebCore/RenderElement.h>
78 #import <WebCore/RenderObject.h>
79 #import <WebCore/RenderStyle.h>
80 #import <WebCore/RenderView.h>
81 #import <WebCore/ResourceHandle.h>
82 #import <WebCore/ScrollView.h>
83 #import <WebCore/StyleInheritedData.h>
84 #import <WebCore/TextIterator.h>
85 #import <WebCore/VisibleUnits.h>
86 #import <WebCore/WindowsKeyboardCodes.h>
87 #import <WebCore/htmlediting.h>
88 #import <WebKitSystemInterface.h>
89
90 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
91 #include <WebCore/MediaPlaybackTarget.h>
92 #endif
93
94 using namespace WebCore;
95
96 namespace WebKit {
97
98 void WebPage::platformInitialize()
99 {
100 #if USE(CFNETWORK)
101     m_page->addSchedulePair(SchedulePair::create([[NSRunLoop currentRunLoop] getCFRunLoop], kCFRunLoopCommonModes));
102 #else
103     m_page->addSchedulePair(SchedulePair::create([NSRunLoop currentRunLoop], kCFRunLoopCommonModes));
104 #endif
105
106     WKAccessibilityWebPageObject* mockAccessibilityElement = [[[WKAccessibilityWebPageObject alloc] init] autorelease];
107
108     // Get the pid for the starting process.
109     pid_t pid = WebProcess::singleton().presenterApplicationPid();
110     WKAXInitializeElementWithPresenterPid(mockAccessibilityElement, pid);
111     [mockAccessibilityElement setWebPage:this];
112     
113     // send data back over
114     NSData* remoteToken = (NSData *)WKAXRemoteTokenForElement(mockAccessibilityElement); 
115     IPC::DataReference dataToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]);
116     send(Messages::WebPageProxy::RegisterWebProcessAccessibilityToken(dataToken));
117     m_mockAccessibilityElement = mockAccessibilityElement;
118 }
119
120 void WebPage::platformDetach()
121 {
122     [m_mockAccessibilityElement setWebPage:nullptr];
123 }
124
125 void WebPage::platformEditorState(Frame& frame, EditorState& result) const
126 {
127 }
128
129 NSObject *WebPage::accessibilityObjectForMainFramePlugin()
130 {
131     if (!m_page)
132         return 0;
133     
134     if (PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()))
135         return pluginView->accessibilityObject();
136
137     return 0;
138 }
139
140 void WebPage::platformPreferencesDidChange(const WebPreferencesStore& store)
141 {
142 }
143
144 bool WebPage::shouldUsePDFPlugin() const
145 {
146     return pdfPluginEnabled() && classFromPDFKit(@"PDFLayerController");
147 }
148
149 typedef HashMap<String, String> SelectorNameMap;
150
151 // Map selectors into Editor command names.
152 // This is not needed for any selectors that have the same name as the Editor command.
153 static const SelectorNameMap* createSelectorExceptionMap()
154 {
155     SelectorNameMap* map = new HashMap<String, String>;
156
157     map->add("insertNewlineIgnoringFieldEditor:", "InsertNewline");
158     map->add("insertParagraphSeparator:", "InsertNewline");
159     map->add("insertTabIgnoringFieldEditor:", "InsertTab");
160     map->add("pageDown:", "MovePageDown");
161     map->add("pageDownAndModifySelection:", "MovePageDownAndModifySelection");
162     map->add("pageUp:", "MovePageUp");
163     map->add("pageUpAndModifySelection:", "MovePageUpAndModifySelection");
164
165     return map;
166 }
167
168 static String commandNameForSelectorName(const String& selectorName)
169 {
170     // Check the exception map first.
171     static const SelectorNameMap* exceptionMap = createSelectorExceptionMap();
172     SelectorNameMap::const_iterator it = exceptionMap->find(selectorName);
173     if (it != exceptionMap->end())
174         return it->value;
175
176     // Remove the trailing colon.
177     // No need to capitalize the command name since Editor command names are not case sensitive.
178     size_t selectorNameLength = selectorName.length();
179     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
180         return String();
181     return selectorName.left(selectorNameLength - 1);
182 }
183
184 static Frame* frameForEvent(KeyboardEvent* event)
185 {
186     Node* node = event->target()->toNode();
187     ASSERT(node);
188     Frame* frame = node->document().frame();
189     ASSERT(frame);
190     return frame;
191 }
192
193 bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>& commands, KeyboardEvent* event)
194 {
195     Frame& frame = event ? *frameForEvent(event) : m_page->focusController().focusedOrMainFrame();
196     ASSERT(frame.page() == corePage());
197
198     bool eventWasHandled = false;
199     for (size_t i = 0; i < commands.size(); ++i) {
200         if (commands[i].commandName == "insertText:") {
201             if (frame.editor().hasComposition()) {
202                 eventWasHandled = true;
203                 frame.editor().confirmComposition(commands[i].text);
204             } else {
205                 if (!frame.editor().canEdit())
206                     continue;
207
208                 // An insertText: might be handled by other responders in the chain if we don't handle it.
209                 // One example is space bar that results in scrolling down the page.
210                 eventWasHandled |= frame.editor().insertText(commands[i].text, event);
211             }
212         } else {
213             Editor::Command command = frame.editor().command(commandNameForSelectorName(commands[i].commandName));
214             if (command.isSupported()) {
215                 bool commandExecutedByEditor = command.execute(event);
216                 eventWasHandled |= commandExecutedByEditor;
217                 if (!commandExecutedByEditor) {
218                     bool performedNonEditingBehavior = event->keyEvent()->type() == PlatformEvent::RawKeyDown && performNonEditingBehaviorForSelector(commands[i].commandName, event);
219                     eventWasHandled |= performedNonEditingBehavior;
220                 }
221             } else {
222                 bool commandWasHandledByUIProcess = false;
223                 WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPageProxy::ExecuteSavedCommandBySelector(commands[i].commandName),
224                     Messages::WebPageProxy::ExecuteSavedCommandBySelector::Reply(commandWasHandledByUIProcess), m_pageID);
225                 eventWasHandled |= commandWasHandledByUIProcess;
226             }
227         }
228     }
229     return eventWasHandled;
230 }
231
232 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event)
233 {
234     Frame* frame = frameForEvent(event);
235     
236     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
237     if (!platformEvent)
238         return false;
239     const Vector<KeypressCommand>& commands = event->keypressCommands();
240
241     ASSERT(!platformEvent->macEvent()); // Cannot have a native event in WebProcess.
242
243     // Don't handle Esc while handling keydown event, we need to dispatch a keypress first.
244     if (platformEvent->type() != PlatformEvent::Char && platformEvent->windowsVirtualKeyCode() == VK_ESCAPE && commands.size() == 1 && commandNameForSelectorName(commands[0].commandName) == "cancelOperation")
245         return false;
246
247     bool eventWasHandled = false;
248
249     // Are there commands that could just cause text insertion if executed via Editor?
250     // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
251     // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
252     // (e.g. Tab that inserts a Tab character, or Enter).
253     bool haveTextInsertionCommands = false;
254     for (auto& command : commands) {
255         if (frame->editor().command(commandNameForSelectorName(command.commandName)).isTextInsertion())
256             haveTextInsertionCommands = true;
257     }
258     // If there are no text insertion commands, default keydown handler is the right time to execute the commands.
259     // Keypress (Char event) handler is the latest opportunity to execute.
260     if (!haveTextInsertionCommands || platformEvent->type() == PlatformEvent::Char) {
261         eventWasHandled = executeKeypressCommandsInternal(event->keypressCommands(), event);
262         event->keypressCommands().clear();
263     }
264
265     return eventWasHandled;
266 }
267
268 void WebPage::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
269 {
270     for (auto* pluginView : m_pluginViews) {
271         if (pluginView->sendComplexTextInput(pluginComplexTextInputIdentifier, textInput))
272             break;
273     }
274 }
275
276 #if !USE(ASYNC_NSTEXTINPUTCLIENT)
277
278 void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, const EditingRange& selectionRange, const EditingRange& replacementEditingRange, EditorState& newState)
279 {
280     Frame& frame = m_page->focusController().focusedOrMainFrame();
281
282     if (frame.selection().selection().isContentEditable()) {
283         RefPtr<Range> replacementRange;
284         if (replacementEditingRange.location != notFound) {
285             replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
286             frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
287         }
288
289         frame.editor().setComposition(text, underlines, selectionRange.location, selectionRange.location + selectionRange.length);
290     }
291
292     newState = editorState();
293 }
294
295 void WebPage::confirmComposition(EditorState& newState)
296 {
297     Frame& frame = m_page->focusController().focusedOrMainFrame();
298     frame.editor().confirmComposition();
299     newState = editorState();
300 }
301
302 void WebPage::insertText(const String& text, const EditingRange& replacementEditingRange, bool& handled, EditorState& newState)
303 {
304     Frame& frame = m_page->focusController().focusedOrMainFrame();
305
306     if (replacementEditingRange.location != notFound) {
307         RefPtr<Range> replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
308         if (replacementRange)
309             frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
310     }
311
312     if (!frame.editor().hasComposition()) {
313         // An insertText: might be handled by other responders in the chain if we don't handle it.
314         // One example is space bar that results in scrolling down the page.
315         handled = frame.editor().insertText(text, nullptr);
316     } else {
317         handled = true;
318         frame.editor().confirmComposition(text);
319     }
320
321     newState = editorState();
322 }
323
324 void WebPage::insertDictatedText(const String& text, const EditingRange& replacementEditingRange, const Vector<WebCore::DictationAlternative>& dictationAlternativeLocations, bool& handled, EditorState& newState)
325 {
326     Frame& frame = m_page->focusController().focusedOrMainFrame();
327
328     if (replacementEditingRange.location != notFound) {
329         RefPtr<Range> replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
330         if (replacementRange)
331             frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
332     }
333
334     ASSERT(!frame.editor().hasComposition());
335     handled = frame.editor().insertDictatedText(text, dictationAlternativeLocations, nullptr);
336     newState = editorState();
337 }
338
339 void WebPage::getMarkedRange(EditingRange& result)
340 {
341     Frame& frame = m_page->focusController().focusedOrMainFrame();
342
343     RefPtr<Range> range = frame.editor().compositionRange();
344     size_t locationSize;
345     size_t lengthSize;
346     if (range && TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range.get(), locationSize, lengthSize))
347         result = EditingRange(static_cast<uint64_t>(locationSize), static_cast<uint64_t>(lengthSize));
348     else
349         result = EditingRange();
350 }
351
352 void WebPage::getSelectedRange(EditingRange& result)
353 {
354     Frame& frame = m_page->focusController().focusedOrMainFrame();
355
356     size_t locationSize;
357     size_t lengthSize;
358     RefPtr<Range> range = frame.selection().toNormalizedRange();
359     if (range && TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range.get(), locationSize, lengthSize))
360         result = EditingRange(static_cast<uint64_t>(locationSize), static_cast<uint64_t>(lengthSize));
361     else
362         result = EditingRange();
363 }
364
365 void WebPage::getAttributedSubstringFromRange(const EditingRange& editingRange, AttributedString& result)
366 {
367     Frame& frame = m_page->focusController().focusedOrMainFrame();
368
369     const VisibleSelection& selection = frame.selection().selection();
370     if (selection.isNone() || !selection.isContentEditable() || selection.isInPasswordField())
371         return;
372
373     RefPtr<Range> range = rangeFromEditingRange(frame, editingRange);
374     if (!range)
375         return;
376
377     result.string = editingAttributedStringFromRange(*range);
378     NSAttributedString* attributedString = result.string.get();
379     
380     // WebCore::editingAttributedStringFromRange() insists on inserting a trailing
381     // whitespace at the end of the string which breaks the ATOK input method.  <rdar://problem/5400551>
382     // To work around this we truncate the resultant string to the correct length.
383     if ([attributedString length] > editingRange.length) {
384         ASSERT([attributedString length] == editingRange.length + 1);
385         ASSERT([[attributedString string] characterAtIndex:editingRange.length] == '\n' || [[attributedString string] characterAtIndex:editingRange.length] == ' ');
386         result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, editingRange.length)];
387     }
388 }
389
390 void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index)
391 {
392     index = notFound;
393
394     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(point);
395     Frame* frame = result.innerNonSharedNode() ? result.innerNodeFrame() : &m_page->focusController().focusedOrMainFrame();
396     
397     RefPtr<Range> range = frame->rangeForPoint(result.roundedPointInInnerNodeFrame());
398     if (!range)
399         return;
400
401     size_t location;
402     size_t length;
403     if (TextIterator::getLocationAndLengthFromRange(frame->selection().rootEditableElementOrDocumentElement(), range.get(), location, length))
404         index = static_cast<uint64_t>(location);
405 }
406     
407 void WebPage::firstRectForCharacterRange(const EditingRange& editingRange, WebCore::IntRect& resultRect)
408 {
409     Frame& frame = m_page->focusController().focusedOrMainFrame();
410     resultRect.setLocation(IntPoint(0, 0));
411     resultRect.setSize(IntSize(0, 0));
412     
413     RefPtr<Range> range = rangeFromEditingRange(frame, editingRange);
414     if (!range)
415         return;
416     
417     ASSERT(range->startContainer());
418     ASSERT(range->endContainer());
419      
420     IntRect rect = frame.editor().firstRectForRange(range.get());
421     resultRect = frame.view()->contentsToWindow(rect);
422 }
423
424 void WebPage::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands, bool& handled, EditorState& newState)
425 {
426     handled = executeKeypressCommandsInternal(commands, nullptr);
427     newState = editorState();
428 }
429
430 void WebPage::cancelComposition(EditorState& newState)
431 {
432     Frame& frame = m_page->focusController().focusedOrMainFrame();
433     frame.editor().cancelComposition();
434     newState = editorState();
435 }
436
437 #endif // !USE(ASYNC_NSTEXTINPUTCLIENT)
438
439 void WebPage::insertDictatedTextAsync(const String& text, const EditingRange& replacementEditingRange, const Vector<WebCore::DictationAlternative>& dictationAlternativeLocations, bool registerUndoGroup)
440 {
441     Frame& frame = m_page->focusController().focusedOrMainFrame();
442
443     if (replacementEditingRange.location != notFound) {
444         RefPtr<Range> replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
445         if (replacementRange)
446             frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
447     }
448
449     if (registerUndoGroup)
450         send(Messages::WebPageProxy::RegisterInsertionUndoGrouping());
451     
452     ASSERT(!frame.editor().hasComposition());
453     frame.editor().insertDictatedText(text, dictationAlternativeLocations, nullptr);
454 }
455
456 void WebPage::attributedSubstringForCharacterRangeAsync(const EditingRange& editingRange, uint64_t callbackID)
457 {
458     AttributedString result;
459
460     Frame& frame = m_page->focusController().focusedOrMainFrame();
461
462     const VisibleSelection& selection = frame.selection().selection();
463     if (selection.isNone() || !selection.isContentEditable() || selection.isInPasswordField()) {
464         send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(), callbackID));
465         return;
466     }
467
468     RefPtr<Range> range = rangeFromEditingRange(frame, editingRange);
469     if (!range) {
470         send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(), callbackID));
471         return;
472     }
473
474     result.string = editingAttributedStringFromRange(*range);
475     NSAttributedString* attributedString = result.string.get();
476     
477     // WebCore::editingAttributedStringFromRange() insists on inserting a trailing
478     // whitespace at the end of the string which breaks the ATOK input method.  <rdar://problem/5400551>
479     // To work around this we truncate the resultant string to the correct length.
480     if ([attributedString length] > editingRange.length) {
481         ASSERT([attributedString length] == editingRange.length + 1);
482         ASSERT([[attributedString string] characterAtIndex:editingRange.length] == '\n' || [[attributedString string] characterAtIndex:editingRange.length] == ' ');
483         result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, editingRange.length)];
484     }
485
486     send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(editingRange.location, [result.string length]), callbackID));
487 }
488
489 void WebPage::fontAtSelection(uint64_t callbackID)
490 {
491     String fontName;
492     double fontSize = 0;
493     bool selectionHasMultipleFonts = false;
494     Frame& frame = m_page->focusController().focusedOrMainFrame();
495     
496     if (!frame.selection().selection().isNone()) {
497         const Font* font = frame.editor().fontForSelection(selectionHasMultipleFonts);
498         NSFont *nsFont = font ? font->getNSFont() : nil;
499         if (nsFont) {
500             fontName = nsFont.fontName;
501             fontSize = nsFont.pointSize;
502         }
503     }
504     send(Messages::WebPageProxy::FontAtSelectionCallback(fontName, fontSize, selectionHasMultipleFonts, callbackID));
505 }
506     
507 void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint)
508 {
509     if (PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame())) {
510         if (pluginView->performDictionaryLookupAtLocation(floatPoint))
511             return;
512     }
513
514     // Find the frame the point is over.
515     IntPoint point = roundedIntPoint(floatPoint);
516     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(m_page->mainFrame().view()->windowToContents(point));
517     Frame* frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document().frame() : &m_page->focusController().focusedOrMainFrame();
518     NSDictionary *options = nil;
519     RefPtr<Range> range = rangeForDictionaryLookupAtHitTestResult(result, &options);
520     if (!range)
521         return;
522
523     performDictionaryLookupForRange(frame, *range, options, TextIndicatorPresentationTransition::Bounce);
524 }
525
526 void WebPage::performDictionaryLookupForSelection(Frame* frame, const VisibleSelection& selection, TextIndicatorPresentationTransition presentationTransition)
527 {
528     NSDictionary *options = nil;
529     RefPtr<Range> selectedRange = rangeForDictionaryLookupForSelection(selection, &options);
530     if (selectedRange)
531         performDictionaryLookupForRange(frame, *selectedRange, options, presentationTransition);
532 }
533
534 void WebPage::performDictionaryLookupOfCurrentSelection()
535 {
536     Frame* frame = &m_page->focusController().focusedOrMainFrame();
537     performDictionaryLookupForSelection(frame, frame->selection().selection(), TextIndicatorPresentationTransition::BounceAndCrossfade);
538 }
539
540 DictionaryPopupInfo WebPage::dictionaryPopupInfoForRange(Frame* frame, Range& range, NSDictionary **options, TextIndicatorPresentationTransition presentationTransition)
541 {
542     DictionaryPopupInfo dictionaryPopupInfo;
543     if (range.text().stripWhiteSpace().isEmpty())
544         return dictionaryPopupInfo;
545     
546     RenderObject* renderer = range.startContainer()->renderer();
547     const RenderStyle& style = renderer->style();
548
549     Vector<FloatQuad> quads;
550     range.textQuads(quads);
551     if (quads.isEmpty())
552         return dictionaryPopupInfo;
553
554     IntRect rangeRect = frame->view()->contentsToWindow(quads[0].enclosingBoundingBox());
555
556     dictionaryPopupInfo.origin = FloatPoint(rangeRect.x(), rangeRect.y() + (style.fontMetrics().ascent() * pageScaleFactor()));
557     dictionaryPopupInfo.options = (CFDictionaryRef)*options;
558
559     NSAttributedString *nsAttributedString = editingAttributedStringFromRange(range, IncludeImagesInAttributedString::No);
560
561     RetainPtr<NSMutableAttributedString> scaledNSAttributedString = adoptNS([[NSMutableAttributedString alloc] initWithString:[nsAttributedString string]]);
562
563     NSFontManager *fontManager = [NSFontManager sharedFontManager];
564
565     [nsAttributedString enumerateAttributesInRange:NSMakeRange(0, [nsAttributedString length]) options:0 usingBlock:^(NSDictionary *attributes, NSRange range, BOOL *stop) {
566         RetainPtr<NSMutableDictionary> scaledAttributes = adoptNS([attributes mutableCopy]);
567
568         NSFont *font = [scaledAttributes objectForKey:NSFontAttributeName];
569         if (font) {
570             font = [fontManager convertFont:font toSize:[font pointSize] * pageScaleFactor()];
571             [scaledAttributes setObject:font forKey:NSFontAttributeName];
572         }
573
574         [scaledNSAttributedString addAttributes:scaledAttributes.get() range:range];
575     }];
576
577     RefPtr<TextIndicator> textIndicator = TextIndicator::createWithRange(range, presentationTransition);
578     if (!textIndicator)
579         return dictionaryPopupInfo;
580
581     dictionaryPopupInfo.textIndicator = textIndicator->data();
582     dictionaryPopupInfo.attributedString.string = scaledNSAttributedString;
583
584     return dictionaryPopupInfo;
585 }
586
587 void WebPage::performDictionaryLookupForRange(Frame* frame, Range& range, NSDictionary *options, TextIndicatorPresentationTransition presentationTransition)
588 {
589     DictionaryPopupInfo dictionaryPopupInfo = dictionaryPopupInfoForRange(frame, range, &options, presentationTransition);
590     send(Messages::WebPageProxy::DidPerformDictionaryLookup(dictionaryPopupInfo));
591 }
592
593 bool WebPage::performNonEditingBehaviorForSelector(const String& selector, KeyboardEvent* event)
594 {
595     // First give accessibility a chance to handle the event.
596     Frame* frame = frameForEvent(event);
597     frame->eventHandler().handleKeyboardSelectionMovementForAccessibility(event);
598     if (event->defaultHandled())
599         return true;
600
601     // FIXME: All these selectors have corresponding Editor commands, but the commands only work in editable content.
602     // Should such non-editing behaviors be implemented in Editor or EventHandler::defaultArrowEventHandler() perhaps?
603     
604     bool didPerformAction = false;
605
606     if (selector == "moveUp:")
607         didPerformAction = scroll(m_page.get(), ScrollUp, ScrollByLine);
608     else if (selector == "moveToBeginningOfParagraph:")
609         didPerformAction = scroll(m_page.get(), ScrollUp, ScrollByPage);
610     else if (selector == "moveToBeginningOfDocument:") {
611         didPerformAction = scroll(m_page.get(), ScrollUp, ScrollByDocument);
612         didPerformAction |= scroll(m_page.get(), ScrollLeft, ScrollByDocument);
613     } else if (selector == "moveDown:")
614         didPerformAction = scroll(m_page.get(), ScrollDown, ScrollByLine);
615     else if (selector == "moveToEndOfParagraph:")
616         didPerformAction = scroll(m_page.get(), ScrollDown, ScrollByPage);
617     else if (selector == "moveToEndOfDocument:") {
618         didPerformAction = scroll(m_page.get(), ScrollDown, ScrollByDocument);
619         didPerformAction |= scroll(m_page.get(), ScrollLeft, ScrollByDocument);
620     } else if (selector == "moveLeft:")
621         didPerformAction = scroll(m_page.get(), ScrollLeft, ScrollByLine);
622     else if (selector == "moveWordLeft:")
623         didPerformAction = scroll(m_page.get(), ScrollLeft, ScrollByPage);
624     else if (selector == "moveToLeftEndOfLine:")
625         didPerformAction = m_page->backForward().goBack();
626     else if (selector == "moveRight:")
627         didPerformAction = scroll(m_page.get(), ScrollRight, ScrollByLine);
628     else if (selector == "moveWordRight:")
629         didPerformAction = scroll(m_page.get(), ScrollRight, ScrollByPage);
630     else if (selector == "moveToRightEndOfLine:")
631         didPerformAction = m_page->backForward().goForward();
632
633     return didPerformAction;
634 }
635
636 #if ENABLE(SERVICE_CONTROLS)
637 static String& replaceSelectionPasteboardName()
638 {
639     static NeverDestroyed<String> string("ReplaceSelectionPasteboard");
640     return string;
641 }
642
643 void WebPage::replaceSelectionWithPasteboardData(const Vector<String>& types, const IPC::DataReference& data)
644 {
645     for (auto& type : types)
646         WebPasteboardOverrides::sharedPasteboardOverrides().addOverride(replaceSelectionPasteboardName(), type, data.vector());
647
648     bool result;
649     readSelectionFromPasteboard(replaceSelectionPasteboardName(), result);
650
651     for (auto& type : types)
652         WebPasteboardOverrides::sharedPasteboardOverrides().removeOverride(replaceSelectionPasteboardName(), type);
653 }
654 #endif
655
656 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&)
657 {
658     return false;
659 }
660
661 void WebPage::registerUIProcessAccessibilityTokens(const IPC::DataReference& elementToken, const IPC::DataReference& windowToken)
662 {
663     NSData* elementTokenData = [NSData dataWithBytes:elementToken.data() length:elementToken.size()];
664     NSData* windowTokenData = [NSData dataWithBytes:windowToken.data() length:windowToken.size()];
665     id remoteElement = WKAXRemoteElementForToken(elementTokenData);
666     id remoteWindow = WKAXRemoteElementForToken(windowTokenData);
667     WKAXSetWindowForRemoteElement(remoteWindow, remoteElement);
668     
669     [accessibilityRemoteObject() setRemoteParent:remoteElement];
670 }
671
672 void WebPage::readSelectionFromPasteboard(const String& pasteboardName, bool& result)
673 {
674     Frame& frame = m_page->focusController().focusedOrMainFrame();
675     if (frame.selection().isNone()) {
676         result = false;
677         return;
678     }
679     frame.editor().readSelectionFromPasteboard(pasteboardName);
680     result = true;
681 }
682
683 void WebPage::getStringSelectionForPasteboard(String& stringValue)
684 {
685     Frame& frame = m_page->focusController().focusedOrMainFrame();
686
687     if (PluginView* pluginView = focusedPluginViewForFrame(frame)) {
688         String selection = pluginView->getSelectionString();
689         if (!selection.isNull()) {
690             stringValue = selection;
691             return;
692         }
693     }
694
695     if (frame.selection().isNone())
696         return;
697
698     stringValue = frame.editor().stringSelectionForPasteboard();
699 }
700
701 void WebPage::getDataSelectionForPasteboard(const String pasteboardType, SharedMemory::Handle& handle, uint64_t& size)
702 {
703     Frame& frame = m_page->focusController().focusedOrMainFrame();
704     if (frame.selection().isNone())
705         return;
706
707     RefPtr<SharedBuffer> buffer = frame.editor().dataSelectionForPasteboard(pasteboardType);
708     if (!buffer) {
709         size = 0;
710         return;
711     }
712     size = buffer->size();
713     RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::create(size);
714     memcpy(sharedMemoryBuffer->data(), buffer->data(), size);
715     sharedMemoryBuffer->createHandle(handle, SharedMemory::ReadOnly);
716 }
717
718 WKAccessibilityWebPageObject* WebPage::accessibilityRemoteObject()
719 {
720     return m_mockAccessibilityElement.get();
721 }
722          
723 bool WebPage::platformHasLocalDataForURL(const WebCore::URL& url)
724 {
725     NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
726     [request setValue:(NSString*)userAgent(url) forHTTPHeaderField:@"User-Agent"];
727     NSCachedURLResponse *cachedResponse;
728     if (CFURLStorageSessionRef storageSession = corePage()->mainFrame().loader().networkingContext()->storageSession().platformSession())
729         cachedResponse = WKCachedResponseForRequest(storageSession, request);
730     else
731         cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
732     [request release];
733     
734     return cachedResponse;
735 }
736
737 static NSCachedURLResponse *cachedResponseForURL(WebPage* webPage, const URL& url)
738 {
739     RetainPtr<NSMutableURLRequest> request = adoptNS([[NSMutableURLRequest alloc] initWithURL:url]);
740     [request setValue:(NSString *)webPage->userAgent(url) forHTTPHeaderField:@"User-Agent"];
741
742     if (CFURLStorageSessionRef storageSession = webPage->corePage()->mainFrame().loader().networkingContext()->storageSession().platformSession())
743         return WKCachedResponseForRequest(storageSession, request.get());
744
745     return [[NSURLCache sharedURLCache] cachedResponseForRequest:request.get()];
746 }
747
748 String WebPage::cachedSuggestedFilenameForURL(const URL& url)
749 {
750     return [[cachedResponseForURL(this, url) response] suggestedFilename];
751 }
752
753 String WebPage::cachedResponseMIMETypeForURL(const URL& url)
754 {
755     return [[cachedResponseForURL(this, url) response] MIMEType];
756 }
757
758 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const URL& url)
759 {
760     return SharedBuffer::wrapNSData([cachedResponseForURL(this, url) data]);
761 }
762
763 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest& request)
764 {
765     if ([NSURLConnection canHandleRequest:request.nsURLRequest(DoNotUpdateHTTPBody)])
766         return true;
767
768     // FIXME: Return true if this scheme is any one WebKit2 knows how to handle.
769     return request.url().protocolIs("applewebdata");
770 }
771
772 void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent& event, bool& result)
773 {
774     Frame& frame = m_page->focusController().focusedOrMainFrame();
775
776 #if ENABLE(DRAG_SUPPORT)
777     HitTestResult hitResult = frame.eventHandler().hitTestResultAtPoint(frame.view()->windowToContents(event.position()), HitTestRequest::ReadOnly | HitTestRequest::Active);
778     if (hitResult.isSelected())
779         result = frame.eventHandler().eventMayStartDrag(platform(event));
780     else
781 #endif
782         result = false;
783 }
784
785 void WebPage::acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent& event, bool& result)
786 {
787     result = false;
788     Frame& frame = m_page->focusController().focusedOrMainFrame();
789
790     HitTestResult hitResult = frame.eventHandler().hitTestResultAtPoint(frame.view()->windowToContents(event.position()), HitTestRequest::ReadOnly | HitTestRequest::Active);
791     frame.eventHandler().setActivationEventNumber(eventNumber);
792 #if ENABLE(DRAG_SUPPORT)
793     if (hitResult.isSelected())
794         result = frame.eventHandler().eventMayStartDrag(platform(event));
795     else
796 #endif
797         result = !!hitResult.scrollbar();
798 }
799
800 void WebPage::setTopOverhangImage(PassRefPtr<WebImage> image)
801 {
802     FrameView* frameView = m_mainFrame->coreFrame()->view();
803     if (!frameView)
804         return;
805
806     GraphicsLayer* layer = frameView->setWantsLayerForTopOverHangArea(image.get());
807     if (!layer)
808         return;
809
810     layer->setSize(image->size());
811     layer->setPosition(FloatPoint(0, -image->size().height()));
812
813     RetainPtr<CGImageRef> cgImage = image->bitmap()->makeCGImageCopy();
814     layer->platformLayer().contents = (id)cgImage.get();
815 }
816
817 void WebPage::setBottomOverhangImage(PassRefPtr<WebImage> image)
818 {
819     FrameView* frameView = m_mainFrame->coreFrame()->view();
820     if (!frameView)
821         return;
822
823     GraphicsLayer* layer = frameView->setWantsLayerForBottomOverHangArea(image.get());
824     if (!layer)
825         return;
826
827     layer->setSize(image->size());
828     
829     RetainPtr<CGImageRef> cgImage = image->bitmap()->makeCGImageCopy();
830     layer->platformLayer().contents = (id)cgImage.get();
831 }
832
833 void WebPage::updateHeaderAndFooterLayersForDeviceScaleChange(float scaleFactor)
834 {    
835     if (m_headerBanner)
836         m_headerBanner->didChangeDeviceScaleFactor(scaleFactor);
837     if (m_footerBanner)
838         m_footerBanner->didChangeDeviceScaleFactor(scaleFactor);
839 }
840
841 void WebPage::computePagesForPrintingPDFDocument(uint64_t frameID, const PrintInfo& printInfo, Vector<IntRect>& resultPageRects)
842 {
843     ASSERT(resultPageRects.isEmpty());
844     WebFrame* frame = WebProcess::singleton().webFrame(frameID);
845     Frame* coreFrame = frame ? frame->coreFrame() : 0;
846     RetainPtr<PDFDocument> pdfDocument = coreFrame ? pdfDocumentForPrintingFrame(coreFrame) : 0;
847     if ([pdfDocument allowsPrinting]) {
848         NSUInteger pageCount = [pdfDocument pageCount];
849         IntRect pageRect(0, 0, ceilf(printInfo.availablePaperWidth), ceilf(printInfo.availablePaperHeight));
850         for (NSUInteger i = 1; i <= pageCount; ++i) {
851             resultPageRects.append(pageRect);
852             pageRect.move(0, pageRect.height());
853         }
854     }
855 }
856
857 static inline CGFloat roundCGFloat(CGFloat f)
858 {
859     if (sizeof(CGFloat) == sizeof(float))
860         return roundf(static_cast<float>(f));
861     return static_cast<CGFloat>(round(f));
862 }
863
864 static void drawPDFPage(PDFDocument *pdfDocument, CFIndex pageIndex, CGContextRef context, CGFloat pageSetupScaleFactor, CGSize paperSize)
865 {
866     CGContextSaveGState(context);
867
868     CGContextScaleCTM(context, pageSetupScaleFactor, pageSetupScaleFactor);
869
870     PDFPage *pdfPage = [pdfDocument pageAtIndex:pageIndex];
871     NSRect cropBox = [pdfPage boundsForBox:kPDFDisplayBoxCropBox];
872     if (NSIsEmptyRect(cropBox))
873         cropBox = [pdfPage boundsForBox:kPDFDisplayBoxMediaBox];
874     else
875         cropBox = NSIntersectionRect(cropBox, [pdfPage boundsForBox:kPDFDisplayBoxMediaBox]);
876
877     // Always auto-rotate PDF content regardless of the paper orientation.
878     NSInteger rotation = [pdfPage rotation];
879     if (rotation == 90 || rotation == 270)
880         std::swap(cropBox.size.width, cropBox.size.height);
881
882     bool shouldRotate = (paperSize.width < paperSize.height) != (cropBox.size.width < cropBox.size.height);
883     if (shouldRotate)
884         std::swap(cropBox.size.width, cropBox.size.height);
885
886     // Center.
887     CGFloat widthDifference = paperSize.width / pageSetupScaleFactor - cropBox.size.width;
888     CGFloat heightDifference = paperSize.height / pageSetupScaleFactor - cropBox.size.height;
889     if (widthDifference || heightDifference)
890         CGContextTranslateCTM(context, roundCGFloat(widthDifference / 2), roundCGFloat(heightDifference / 2));
891
892     if (shouldRotate) {
893         CGContextRotateCTM(context, static_cast<CGFloat>(piOverTwoDouble));
894         CGContextTranslateCTM(context, 0, -cropBox.size.width);
895     }
896
897     [NSGraphicsContext saveGraphicsState];
898     [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]];
899     [pdfPage drawWithBox:kPDFDisplayBoxCropBox];
900     [NSGraphicsContext restoreGraphicsState];
901
902     CGAffineTransform transform = CGContextGetCTM(context);
903
904     for (PDFAnnotation *annotation in [pdfPage annotations]) {
905         if (![annotation isKindOfClass:pdfAnnotationLinkClass()])
906             continue;
907
908         PDFAnnotationLink *linkAnnotation = (PDFAnnotationLink *)annotation;
909         NSURL *url = [linkAnnotation URL];
910         if (!url)
911             continue;
912
913         CGRect urlRect = NSRectToCGRect([linkAnnotation bounds]);
914         CGRect transformedRect = CGRectApplyAffineTransform(urlRect, transform);
915         CGPDFContextSetURLForRect(context, (CFURLRef)url, transformedRect);
916     }
917
918     CGContextRestoreGState(context);
919 }
920
921 void WebPage::drawPDFDocument(CGContextRef context, PDFDocument *pdfDocument, const PrintInfo& printInfo, const WebCore::IntRect& rect)
922 {
923     NSUInteger pageCount = [pdfDocument pageCount];
924     IntSize paperSize(ceilf(printInfo.availablePaperWidth), ceilf(printInfo.availablePaperHeight));
925     IntRect pageRect(IntPoint(), paperSize);
926     for (NSUInteger i = 0; i < pageCount; ++i) {
927         if (pageRect.intersects(rect)) {
928             CGContextSaveGState(context);
929
930             CGContextTranslateCTM(context, pageRect.x() - rect.x(), pageRect.y() - rect.y());
931             drawPDFPage(pdfDocument, i, context, printInfo.pageSetupScaleFactor, paperSize);
932
933             CGContextRestoreGState(context);
934         }
935         pageRect.move(0, pageRect.height());
936     }
937 }
938
939 void WebPage::drawPagesToPDFFromPDFDocument(CGContextRef context, PDFDocument *pdfDocument, const PrintInfo& printInfo, uint32_t first, uint32_t count)
940 {
941     NSUInteger pageCount = [pdfDocument pageCount];
942     for (uint32_t page = first; page < first + count; ++page) {
943         if (page >= pageCount)
944             break;
945
946         RetainPtr<CFDictionaryRef> pageInfo = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
947
948         CGPDFContextBeginPage(context, pageInfo.get());
949         drawPDFPage(pdfDocument, page, context, printInfo.pageSetupScaleFactor, CGSizeMake(printInfo.availablePaperWidth, printInfo.availablePaperHeight));
950         CGPDFContextEndPage(context);
951     }
952 }
953
954 #if ENABLE(WEBGL)
955 WebCore::WebGLLoadPolicy WebPage::webGLPolicyForURL(WebFrame* frame, const String& url)
956 {
957     uint32_t policyResult = 0;
958
959     if (sendSync(Messages::WebPageProxy::WebGLPolicyForURL(url), Messages::WebPageProxy::WebGLPolicyForURL::Reply(policyResult)))
960         return static_cast<WebGLLoadPolicy>(policyResult);
961
962     return WebGLAllowCreation;
963 }
964
965 WebCore::WebGLLoadPolicy WebPage::resolveWebGLPolicyForURL(WebFrame* frame, const String& url)
966 {
967     uint32_t policyResult = 0;
968
969     if (sendSync(Messages::WebPageProxy::ResolveWebGLPolicyForURL(url), Messages::WebPageProxy::ResolveWebGLPolicyForURL::Reply(policyResult)))
970         return static_cast<WebGLLoadPolicy>(policyResult);
971
972     return WebGLAllowCreation;
973 }
974 #endif // ENABLE(WEBGL)
975
976 #if ENABLE(TELEPHONE_NUMBER_DETECTION)
977 void WebPage::handleTelephoneNumberClick(const String& number, const IntPoint& point)
978 {
979     send(Messages::WebPageProxy::ShowTelephoneNumberMenu(number, point));
980 }
981 #endif
982
983 #if ENABLE(SERVICE_CONTROLS)
984 void WebPage::handleSelectionServiceClick(FrameSelection& selection, const Vector<String>& phoneNumbers, const IntPoint& point)
985 {
986     RefPtr<Range> range = selection.selection().firstRange();
987     if (!range)
988         return;
989
990     NSAttributedString *attributedSelection = attributedStringFromRange(*range);
991     if (!attributedSelection)
992         return;
993
994     NSData *selectionData = [attributedSelection RTFDFromRange:NSMakeRange(0, [attributedSelection length]) documentAttributes:nil];
995     IPC::DataReference data = IPC::DataReference(reinterpret_cast<const uint8_t*>([selectionData bytes]), [selectionData length]);
996     bool isEditable = selection.selection().isContentEditable();
997
998     send(Messages::WebPageProxy::ShowSelectionServiceMenu(data, phoneNumbers, isEditable, point));
999 }
1000 #endif
1001
1002 String WebPage::platformUserAgent(const URL&) const
1003 {
1004     return String();
1005 }
1006
1007 static TextIndicatorPresentationTransition textIndicatorTransitionForActionMenu(Range* selectionRange, Range& indicatorRange, bool forImmediateAction, bool forDataDetectors)
1008 {
1009     if (areRangesEqual(&indicatorRange, selectionRange) || (forDataDetectors && !forImmediateAction))
1010         return forImmediateAction ? TextIndicatorPresentationTransition::Crossfade : TextIndicatorPresentationTransition::BounceAndCrossfade;
1011     return forImmediateAction ? TextIndicatorPresentationTransition::FadeIn : TextIndicatorPresentationTransition::Bounce;
1012 }
1013
1014 void WebPage::performActionMenuHitTestAtLocation(WebCore::FloatPoint locationInViewCooordinates, bool forImmediateAction)
1015 {
1016     layoutIfNeeded();
1017
1018     MainFrame& mainFrame = corePage()->mainFrame();
1019     if (!mainFrame.view() || !mainFrame.view()->renderView()) {
1020         send(Messages::WebPageProxy::DidPerformActionMenuHitTest(WebHitTestResult::Data(), forImmediateAction, false, UserData()));
1021         return;
1022     }
1023
1024     IntPoint locationInContentCoordinates = mainFrame.view()->rootViewToContents(roundedIntPoint(locationInViewCooordinates));
1025     HitTestResult hitTestResult = mainFrame.eventHandler().hitTestResultAtPoint(locationInContentCoordinates);
1026
1027     m_lastActionMenuHitTestPreventsDefault = false;
1028     Element* element = hitTestResult.innerElement();
1029
1030     if (forImmediateAction) {
1031         mainFrame.eventHandler().setImmediateActionStage(ImmediateActionStage::PerformedHitTest);
1032         if (element)
1033             m_lastActionMenuHitTestPreventsDefault = element->dispatchMouseForceWillBegin();
1034     }
1035
1036     WebHitTestResult::Data actionMenuResult(hitTestResult);
1037     actionMenuResult.hitTestLocationInViewCooordinates = locationInViewCooordinates;
1038
1039     RefPtr<Range> selectionRange = corePage()->focusController().focusedOrMainFrame().selection().selection().firstRange();
1040
1041     URL absoluteLinkURL = hitTestResult.absoluteLinkURL();
1042     Element *URLElement = hitTestResult.URLElement();
1043     if (!absoluteLinkURL.isEmpty() && URLElement) {
1044         RefPtr<Range> linkRange = rangeOfContents(*URLElement);
1045         actionMenuResult.linkTextIndicator = TextIndicator::createWithRange(*linkRange, textIndicatorTransitionForActionMenu(selectionRange.get(), *linkRange, forImmediateAction, false));
1046     }
1047
1048     NSDictionary *options = nil;
1049     RefPtr<Range> lookupRange = lookupTextAtLocation(locationInViewCooordinates, &options);
1050     actionMenuResult.lookupText = lookupRange ? lookupRange->text() : String();
1051
1052     if (lookupRange) {
1053         if (Node* node = hitTestResult.innerNode()) {
1054             if (Frame* hitTestResultFrame = node->document().frame())
1055                 actionMenuResult.dictionaryPopupInfo = dictionaryPopupInfoForRange(hitTestResultFrame, *lookupRange.get(), &options, textIndicatorTransitionForActionMenu(selectionRange.get(), *lookupRange, forImmediateAction, false));
1056         }
1057     }
1058
1059     m_lastActionMenuRangeForSelection = lookupRange;
1060     m_lastActionMenuHitTestResult = hitTestResult;
1061
1062     if (!forImmediateAction) {
1063         if (Image* image = hitTestResult.image()) {
1064             RefPtr<SharedBuffer> buffer = image->data();
1065             String imageExtension = image->filenameExtension();
1066             if (!imageExtension.isEmpty() && buffer) {
1067                 actionMenuResult.imageSharedMemory = SharedMemory::create(buffer->size());
1068                 memcpy(actionMenuResult.imageSharedMemory->data(), buffer->data(), buffer->size());
1069                 actionMenuResult.imageExtension = imageExtension;
1070                 actionMenuResult.imageSize = buffer->size();
1071             }
1072         }
1073     }
1074
1075     bool pageOverlayDidOverrideDataDetectors = false;
1076     for (const auto& overlay : mainFrame.pageOverlayController().pageOverlays()) {
1077         WebPageOverlay* webOverlay = WebPageOverlay::fromCoreOverlay(*overlay);
1078         if (!webOverlay)
1079             continue;
1080
1081         RefPtr<Range> mainResultRange;
1082         DDActionContext *actionContext = webOverlay->actionContextForResultAtPoint(locationInContentCoordinates, mainResultRange);
1083         if (!actionContext || !mainResultRange)
1084             continue;
1085
1086         pageOverlayDidOverrideDataDetectors = true;
1087         actionMenuResult.detectedDataActionContext = actionContext;
1088
1089         Vector<FloatQuad> quads;
1090         mainResultRange->textQuads(quads);
1091         FloatRect detectedDataBoundingBox;
1092         FrameView* frameView = mainResultRange->ownerDocument().view();
1093         for (const auto& quad : quads)
1094             detectedDataBoundingBox.unite(frameView->contentsToWindow(quad.enclosingBoundingBox()));
1095
1096         actionMenuResult.detectedDataBoundingBox = detectedDataBoundingBox;
1097         actionMenuResult.detectedDataTextIndicator = TextIndicator::createWithRange(*mainResultRange, textIndicatorTransitionForActionMenu(selectionRange.get(), *mainResultRange, forImmediateAction, true));
1098         actionMenuResult.detectedDataOriginatingPageOverlay = overlay->pageOverlayID();
1099         m_lastActionMenuRangeForSelection = mainResultRange;
1100
1101         break;
1102     }
1103
1104     // FIXME: Avoid scanning if we will just throw away the result (e.g. we're over a link).
1105     if (!pageOverlayDidOverrideDataDetectors && hitTestResult.innerNode() && hitTestResult.innerNode()->isTextNode()) {
1106         FloatRect detectedDataBoundingBox;
1107         RefPtr<Range> detectedDataRange;
1108         actionMenuResult.detectedDataActionContext = DataDetection::detectItemAroundHitTestResult(hitTestResult, detectedDataBoundingBox, detectedDataRange);
1109         if (actionMenuResult.detectedDataActionContext && detectedDataRange) {
1110             actionMenuResult.detectedDataBoundingBox = detectedDataBoundingBox;
1111             actionMenuResult.detectedDataTextIndicator = TextIndicator::createWithRange(*detectedDataRange, textIndicatorTransitionForActionMenu(selectionRange.get(), *detectedDataRange, forImmediateAction, true));
1112             m_lastActionMenuRangeForSelection = detectedDataRange;
1113         }
1114     }
1115
1116     RefPtr<API::Object> userData;
1117     injectedBundleContextMenuClient().prepareForActionMenu(*this, hitTestResult, userData);
1118
1119     send(Messages::WebPageProxy::DidPerformActionMenuHitTest(actionMenuResult, forImmediateAction, m_lastActionMenuHitTestPreventsDefault, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
1120 }
1121
1122 PassRefPtr<WebCore::Range> WebPage::lookupTextAtLocation(FloatPoint locationInViewCooordinates, NSDictionary **options)
1123 {
1124     MainFrame& mainFrame = corePage()->mainFrame();
1125     if (!mainFrame.view() || !mainFrame.view()->renderView())
1126         return nullptr;
1127
1128     IntPoint point = roundedIntPoint(locationInViewCooordinates);
1129     HitTestResult result = mainFrame.eventHandler().hitTestResultAtPoint(m_page->mainFrame().view()->windowToContents(point));
1130     return rangeForDictionaryLookupAtHitTestResult(result, options);
1131 }
1132
1133 void WebPage::selectLastActionMenuRange()
1134 {
1135     if (m_lastActionMenuRangeForSelection)
1136         corePage()->mainFrame().selection().setSelectedRange(m_lastActionMenuRangeForSelection.get(), DOWNSTREAM, true);
1137 }
1138
1139 void WebPage::focusAndSelectLastActionMenuHitTestResult()
1140 {
1141     if (!m_lastActionMenuHitTestResult.isContentEditable())
1142         return;
1143
1144     Element* element = m_lastActionMenuHitTestResult.innerElement();
1145     if (!element)
1146         return;
1147
1148     Frame* frame = element->document().frame();
1149     if (!frame)
1150         return;
1151
1152     m_page->focusController().setFocusedElement(element, frame);
1153     VisiblePosition position = frame->visiblePositionForPoint(m_lastActionMenuHitTestResult.roundedPointInInnerNodeFrame());
1154     frame->selection().setSelection(position);
1155 }
1156
1157 void WebPage::inputDeviceForceDidChange(float force, int stage)
1158 {
1159     Element* element = m_lastActionMenuHitTestResult.innerElement();
1160     if (!element)
1161         return;
1162
1163     if (!m_lastActionMenuHitTestPreventsDefault)
1164         return;
1165
1166     float overallForce = stage < 1 ? force : force + stage - 1;
1167     element->dispatchMouseForceChanged(overallForce, m_page->mainFrame().eventHandler().lastMouseDownEvent());
1168
1169     if (m_lastForceStage == 1 && stage == 2)
1170         element->dispatchMouseForceDown(m_page->mainFrame().eventHandler().lastMouseDownEvent());
1171     else if (m_lastForceStage == 2 && stage == 1) {
1172         element->dispatchMouseForceUp(m_page->mainFrame().eventHandler().lastMouseDownEvent());
1173         element->dispatchMouseForceClick(m_page->mainFrame().eventHandler().lastMouseDownEvent());
1174     }
1175
1176     m_lastForceStage = stage;
1177 }
1178
1179 void WebPage::immediateActionDidUpdate()
1180 {
1181     m_page->mainFrame().eventHandler().setImmediateActionStage(ImmediateActionStage::ActionUpdated);
1182 }
1183
1184 void WebPage::immediateActionDidCancel()
1185 {
1186     m_page->mainFrame().eventHandler().setImmediateActionStage(ImmediateActionStage::ActionCancelled);
1187
1188     Element* element = m_lastActionMenuHitTestResult.innerElement();
1189     if (!element)
1190         return;
1191
1192     if (!m_lastActionMenuHitTestPreventsDefault)
1193         return;
1194
1195     element->dispatchMouseForceCancelled(m_page->mainFrame().eventHandler().lastMouseDownEvent());
1196 }
1197
1198 void WebPage::immediateActionDidComplete()
1199 {
1200     m_page->mainFrame().eventHandler().setImmediateActionStage(ImmediateActionStage::ActionCompleted);
1201 }
1202
1203 void WebPage::dataDetectorsDidPresentUI(PageOverlay::PageOverlayID overlayID)
1204 {
1205     MainFrame& mainFrame = corePage()->mainFrame();
1206     for (const auto& overlay : mainFrame.pageOverlayController().pageOverlays()) {
1207         if (overlay->pageOverlayID() == overlayID) {
1208             if (WebPageOverlay* webOverlay = WebPageOverlay::fromCoreOverlay(*overlay))
1209                 webOverlay->dataDetectorsDidPresentUI();
1210             return;
1211         }
1212     }
1213 }
1214
1215 void WebPage::dataDetectorsDidChangeUI(PageOverlay::PageOverlayID overlayID)
1216 {
1217     MainFrame& mainFrame = corePage()->mainFrame();
1218     for (const auto& overlay : mainFrame.pageOverlayController().pageOverlays()) {
1219         if (overlay->pageOverlayID() == overlayID) {
1220             if (WebPageOverlay* webOverlay = WebPageOverlay::fromCoreOverlay(*overlay))
1221                 webOverlay->dataDetectorsDidChangeUI();
1222             return;
1223         }
1224     }
1225 }
1226
1227 void WebPage::dataDetectorsDidHideUI(PageOverlay::PageOverlayID overlayID)
1228 {
1229     MainFrame& mainFrame = corePage()->mainFrame();
1230
1231     // Dispatching a fake mouse event will allow clients to display any UI that is normally displayed on hover.
1232     mainFrame.eventHandler().dispatchFakeMouseMoveEventSoon();
1233
1234     for (const auto& overlay : mainFrame.pageOverlayController().pageOverlays()) {
1235         if (overlay->pageOverlayID() == overlayID) {
1236             if (WebPageOverlay* webOverlay = WebPageOverlay::fromCoreOverlay(*overlay))
1237                 webOverlay->dataDetectorsDidHideUI();
1238             return;
1239         }
1240     }
1241 }
1242
1243 void WebPage::setFont(const String& fontFamily, double fontSize, uint64_t fontTraits)
1244 {
1245     Frame& frame = m_page->focusController().focusedOrMainFrame();
1246     frame.editor().applyFontStyles(fontFamily, fontSize, fontTraits);
1247 }
1248
1249 #if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS)
1250 void WebPage::playbackTargetSelected(const WebCore::MediaPlaybackTarget& playbackTarget) const
1251 {
1252     m_page->didChoosePlaybackTarget(playbackTarget);
1253 }
1254
1255 void WebPage::playbackTargetAvailabilityDidChange(bool changed)
1256 {
1257     m_page->playbackTargetAvailabilityDidChange(changed);
1258 }
1259 #endif
1260
1261
1262 } // namespace WebKit
1263
1264 #endif // PLATFORM(MAC)