Reviewed by Adele Peterson.
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / mac / WebPageMac.mm
1 /*
2  * Copyright (C) 2010, 2011 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 #import "AccessibilityWebPageObject.h"
30 #import "AttributedString.h"
31 #import "DataReference.h"
32 #import "EditorState.h"
33 #import "PluginView.h"
34 #import "WebCoreArgumentCoders.h"
35 #import "WebEvent.h"
36 #import "WebEventConversion.h"
37 #import "WebFrame.h"
38 #import "WebPageProxyMessages.h"
39 #import "WebProcess.h"
40 #import <WebCore/AXObjectCache.h>
41 #import <WebCore/FocusController.h>
42 #import <WebCore/Frame.h>
43 #import <WebCore/FrameView.h>
44 #import <WebCore/HitTestResult.h>
45 #import <WebCore/HTMLConverter.h>
46 #import <WebCore/KeyboardEvent.h>
47 #import <WebCore/Page.h>
48 #import <WebCore/PlatformKeyboardEvent.h>
49 #import <WebCore/ResourceHandle.h>
50 #import <WebCore/ScrollView.h>
51 #import <WebCore/TextIterator.h>
52 #import <WebCore/WindowsKeyboardCodes.h>
53 #import <WebCore/visible_units.h>
54 #import <WebKitSystemInterface.h>
55
56 using namespace WebCore;
57
58 namespace WebKit {
59
60 static PassRefPtr<Range> convertToRange(Frame*, NSRange);
61
62 void WebPage::platformInitialize()
63 {
64     m_page->addSchedulePair(SchedulePair::create([NSRunLoop currentRunLoop], kCFRunLoopCommonModes));
65
66 #if !defined(BUILDING_ON_SNOW_LEOPARD)
67     AccessibilityWebPageObject* mockAccessibilityElement = [[[AccessibilityWebPageObject alloc] init] autorelease];
68
69     // Get the pid for the starting process.
70     pid_t pid = WebProcess::shared().presenterApplicationPid();    
71     WKAXInitializeElementWithPresenterPid(mockAccessibilityElement, pid);
72     [mockAccessibilityElement setWebPage:this];
73     
74     // send data back over
75     NSData* remoteToken = (NSData *)WKAXRemoteTokenForElement(mockAccessibilityElement); 
76     CoreIPC::DataReference dataToken = CoreIPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]);
77     send(Messages::WebPageProxy::RegisterWebProcessAccessibilityToken(dataToken));
78     m_mockAccessibilityElement = mockAccessibilityElement;
79 #endif
80 }
81
82 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
83 {
84 }
85
86 typedef HashMap<String, String> SelectorNameMap;
87
88 // Map selectors into Editor command names.
89 // This is not needed for any selectors that have the same name as the Editor command.
90 static const SelectorNameMap* createSelectorExceptionMap()
91 {
92     SelectorNameMap* map = new HashMap<String, String>;
93
94     map->add("insertNewlineIgnoringFieldEditor:", "InsertNewline");
95     map->add("insertParagraphSeparator:", "InsertNewline");
96     map->add("insertTabIgnoringFieldEditor:", "InsertTab");
97     map->add("pageDown:", "MovePageDown");
98     map->add("pageDownAndModifySelection:", "MovePageDownAndModifySelection");
99     map->add("pageUp:", "MovePageUp");
100     map->add("pageUpAndModifySelection:", "MovePageUpAndModifySelection");
101
102     return map;
103 }
104
105 static String commandNameForSelectorName(const String& selectorName)
106 {
107     // Check the exception map first.
108     static const SelectorNameMap* exceptionMap = createSelectorExceptionMap();
109     SelectorNameMap::const_iterator it = exceptionMap->find(selectorName);
110     if (it != exceptionMap->end())
111         return it->second;
112
113     // Remove the trailing colon.
114     // No need to capitalize the command name since Editor command names are not case sensitive.
115     size_t selectorNameLength = selectorName.length();
116     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
117         return String();
118     return selectorName.left(selectorNameLength - 1);
119 }
120
121 static Frame* frameForEvent(KeyboardEvent* event)
122 {
123     Node* node = event->target()->toNode();
124     ASSERT(node);
125     Frame* frame = node->document()->frame();
126     ASSERT(frame);
127     return frame;
128 }
129
130 bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>& commands, KeyboardEvent* event)
131 {
132     Frame* frame = frameForEvent(event);
133     ASSERT(frame->page() == corePage());
134
135     bool eventWasHandled = false;
136     for (size_t i = 0; i < commands.size(); ++i) {
137         if (commands[i].commandName == "insertText:") {
138             ASSERT(!frame->editor()->hasComposition());
139
140             if (!frame->editor()->canEdit())
141                 continue;
142
143             // An insertText: might be handled by other responders in the chain if we don't handle it.
144             // One example is space bar that results in scrolling down the page.
145             eventWasHandled |= frame->editor()->insertText(commands[i].text, event);
146         } else {
147             Editor::Command command = frame->editor()->command(commandNameForSelectorName(commands[i].commandName));
148             if (command.isSupported()) {
149                 bool commandExecutedByEditor = command.execute(event);
150                 eventWasHandled |= commandExecutedByEditor;
151                 if (!commandExecutedByEditor) {
152                     bool performedNonEditingBehavior = event->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown && performNonEditingBehaviorForSelector(commands[i].commandName);
153                     eventWasHandled |= performedNonEditingBehavior;
154                 }
155             } else {
156                 bool commandWasHandledByUIProcess = false;
157                 WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::ExecuteSavedCommandBySelector(commands[i].commandName), 
158                     Messages::WebPageProxy::ExecuteSavedCommandBySelector::Reply(commandWasHandledByUIProcess), m_pageID);
159                 eventWasHandled |= commandWasHandledByUIProcess;
160             }
161         }
162     }
163     return eventWasHandled;
164 }
165
166 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event, bool saveCommands)
167 {
168     ASSERT(!saveCommands || event->keypressCommands().isEmpty()); // Save commands once for each event.
169
170     Frame* frame = frameForEvent(event);
171     
172     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
173     if (!platformEvent)
174         return false;
175     Vector<KeypressCommand>& commands = event->keypressCommands();
176
177     if ([platformEvent->macEvent() type] == NSFlagsChanged)
178         return false;
179
180     bool eventWasHandled = false;
181     
182     if (saveCommands) {
183         KeyboardEvent* oldEvent = m_keyboardEventBeingInterpreted;
184         m_keyboardEventBeingInterpreted = event;
185         bool sendResult = WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretQueuedKeyEvent(editorState()), 
186             Messages::WebPageProxy::InterpretQueuedKeyEvent::Reply(eventWasHandled, commands), m_pageID);
187         m_keyboardEventBeingInterpreted = oldEvent;
188         if (!sendResult)
189             return false;
190
191         // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline.
192         // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that
193         // should be handled like normal text input after DOM event dispatch.
194         if (!event->keypressCommands().isEmpty())
195             return false;
196     } else {
197         // Are there commands that could just cause text insertion if executed via Editor?
198         // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
199         // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
200         // (e.g. Tab that inserts a Tab character, or Enter).
201         bool haveTextInsertionCommands = false;
202         for (size_t i = 0; i < commands.size(); ++i) {
203             if (frame->editor()->command(commandNameForSelectorName(commands[i].commandName)).isTextInsertion())
204                 haveTextInsertionCommands = true;
205         }
206         // If there are no text insertion commands, default keydown handler is the right time to execute the commands.
207         // Keypress (Char event) handler is the latest opportunity to execute.
208         if (!haveTextInsertionCommands || platformEvent->type() == PlatformKeyboardEvent::Char) {
209             eventWasHandled = executeKeypressCommandsInternal(event->keypressCommands(), event);
210             event->keypressCommands().clear();
211         }
212     }
213     return eventWasHandled;
214 }
215
216 void WebPage::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
217 {
218     for (HashSet<PluginView*>::const_iterator it = m_pluginViews.begin(), end = m_pluginViews.end(); it != end; ++it) {
219         if ((*it)->sendComplexTextInput(pluginComplexTextInputIdentifier, textInput))
220             break;
221     }
222 }
223
224 void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, EditorState& newState)
225 {
226     Frame* frame = m_page->focusController()->focusedOrMainFrame();
227
228     if (frame->selection()->isContentEditable()) {
229         RefPtr<Range> replacementRange;
230         if (replacementRangeStart != NSNotFound) {
231             replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart));
232             frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
233         }
234
235         frame->editor()->setComposition(text, underlines, selectionStart, selectionEnd);
236     }
237
238     newState = editorState();
239 }
240
241 void WebPage::confirmComposition(EditorState& newState)
242 {
243     Frame* frame = m_page->focusController()->focusedOrMainFrame();
244
245     frame->editor()->confirmComposition();
246
247     newState = editorState();
248 }
249
250 void WebPage::insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, bool& handled, EditorState& newState)
251 {
252     Frame* frame = m_page->focusController()->focusedOrMainFrame();
253
254     RefPtr<Range> replacementRange;
255     if (replacementRangeStart != NSNotFound) {
256         replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart));
257         frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
258     }
259
260     if (!frame->editor()->hasComposition()) {
261         // An insertText: might be handled by other responders in the chain if we don't handle it.
262         // One example is space bar that results in scrolling down the page.
263         handled = frame->editor()->insertText(text, m_keyboardEventBeingInterpreted);
264     } else {
265         handled = true;
266         frame->editor()->confirmComposition(text);
267     }
268
269     newState = editorState();
270 }
271
272 void WebPage::getMarkedRange(uint64_t& location, uint64_t& length)
273 {
274     location = NSNotFound;
275     length = 0;
276     Frame* frame = m_page->focusController()->focusedOrMainFrame();
277     if (!frame)
278         return;
279
280     RefPtr<Range> range = frame->editor()->compositionRange();
281     size_t locationSize;
282     size_t lengthSize;
283     if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) {
284         location = static_cast<uint64_t>(locationSize);
285         length = static_cast<uint64_t>(lengthSize);
286     }
287 }
288
289 void WebPage::getSelectedRange(uint64_t& location, uint64_t& length)
290 {
291     location = NSNotFound;
292     length = 0;
293     Frame* frame = m_page->focusController()->focusedOrMainFrame();
294     if (!frame)
295         return;
296
297     size_t locationSize;
298     size_t lengthSize;
299     RefPtr<Range> range = frame->selection()->toNormalizedRange();
300     if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) {
301         location = static_cast<uint64_t>(locationSize);
302         length = static_cast<uint64_t>(lengthSize);
303     }
304 }
305
306 void WebPage::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result)
307 {
308     NSRange nsRange = NSMakeRange(location, length - location);
309
310     Frame* frame = m_page->focusController()->focusedOrMainFrame();
311     if (!frame)
312         return;
313
314     if (frame->selection()->isNone() || !frame->selection()->isContentEditable() || frame->selection()->isInPasswordField())
315         return;
316
317     RefPtr<Range> range = convertToRange(frame, nsRange);
318     if (!range)
319         return;
320
321     result.string = [WebHTMLConverter editingAttributedStringFromRange:range.get()];
322     NSAttributedString* attributedString = result.string.get();
323     
324     // [WebHTMLConverter editingAttributedStringFromRange:] insists on inserting a trailing 
325     // whitespace at the end of the string which breaks the ATOK input method.  <rdar://problem/5400551>
326     // To work around this we truncate the resultant string to the correct length.
327     if ([attributedString length] > nsRange.length) {
328         ASSERT([attributedString length] == nsRange.length + 1);
329         ASSERT([[attributedString string] characterAtIndex:nsRange.length] == '\n' || [[attributedString string] characterAtIndex:nsRange.length] == ' ');
330         result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, nsRange.length)];
331     }
332 }
333
334 void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index)
335 {
336     index = NSNotFound;
337     Frame* frame = m_page->mainFrame();
338     if (!frame)
339         return;
340
341     HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(point, false);
342     frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame();
343     
344     RefPtr<Range> range = frame->rangeForPoint(result.point());
345     if (!range)
346         return;
347
348     size_t location;
349     size_t length;
350     if (TextIterator::locationAndLengthFromRange(range.get(), location, length))
351         index = static_cast<uint64_t>(location);
352 }
353
354 PassRefPtr<Range> convertToRange(Frame* frame, NSRange nsrange)
355 {
356     if (nsrange.location > INT_MAX)
357         return 0;
358     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
359         nsrange.length = INT_MAX - nsrange.location;
360         
361     // our critical assumption is that we are only called by input methods that
362     // concentrate on a given area containing the selection
363     // We have to do this because of text fields and textareas. The DOM for those is not
364     // directly in the document DOM, so serialization is problematic. Our solution is
365     // to use the root editable element of the selection start as the positional base.
366     // That fits with AppKit's idea of an input context.
367     Element* selectionRoot = frame->selection()->rootEditableElement();
368     Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
369     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
370 }
371     
372 void WebPage::firstRectForCharacterRange(uint64_t location, uint64_t length, WebCore::IntRect& resultRect)
373 {
374     Frame* frame = m_page->focusController()->focusedOrMainFrame();
375     resultRect.setLocation(IntPoint(0, 0));
376     resultRect.setSize(IntSize(0, 0));
377     
378     RefPtr<Range> range = convertToRange(frame, NSMakeRange(location, length));
379     if (!range)
380         return;
381     
382     ASSERT(range->startContainer());
383     ASSERT(range->endContainer());
384      
385     IntRect rect = frame->editor()->firstRectForRange(range.get());
386     resultRect = frame->view()->contentsToWindow(rect);
387 }
388
389 void WebPage::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands, bool& handled, EditorState& newState)
390 {
391     handled = executeKeypressCommandsInternal(commands, m_keyboardEventBeingInterpreted);
392     newState = editorState();
393 }
394
395 static bool isPositionInRange(const VisiblePosition& position, Range* range)
396 {
397     RefPtr<Range> positionRange = makeRange(position, position);
398
399     ExceptionCode ec = 0;
400     range->compareBoundaryPoints(Range::START_TO_START, positionRange.get(), ec);
401     if (ec)
402         return false;
403
404     if (!range->isPointInRange(positionRange->startContainer(), positionRange->startOffset(), ec))
405         return false;
406     if (ec)
407         return false;
408
409     return true;
410 }
411
412 static bool shouldUseSelection(const VisiblePosition& position, const VisibleSelection& selection)
413 {
414     RefPtr<Range> selectedRange = selection.toNormalizedRange();
415     if (!selectedRange)
416         return false;
417
418     return isPositionInRange(position, selectedRange.get());
419 }
420
421 void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint)
422 {
423     Frame* frame = m_page->mainFrame();
424     if (!frame)
425         return;
426
427     // Find the frame the point is over.
428     IntPoint point = roundedIntPoint(floatPoint);
429     HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(point, false);
430     frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame();
431
432     IntPoint translatedPoint = frame->view()->windowToContents(point);
433
434     // Don't do anything if there is no character at the point.
435     if (!frame->rangeForPoint(translatedPoint))
436         return;
437
438     VisiblePosition position = frame->visiblePositionForPoint(translatedPoint);
439     VisibleSelection selection = m_page->focusController()->focusedOrMainFrame()->selection()->selection();
440     if (shouldUseSelection(position, selection)) {
441         performDictionaryLookupForSelection(DictionaryPopupInfo::HotKey, frame, selection);
442         return;
443     }
444
445     NSDictionary *options = nil;
446
447 #if !defined(BUILDING_ON_SNOW_LEOPARD)
448     // As context, we are going to use the surrounding paragraph of text.
449     VisiblePosition paragraphStart = startOfParagraph(position);
450     VisiblePosition paragraphEnd = endOfParagraph(position);
451
452     NSRange rangeToPass = NSMakeRange(TextIterator::rangeLength(makeRange(paragraphStart, position).get()), 0);
453
454     RefPtr<Range> fullCharacterRange = makeRange(paragraphStart, paragraphEnd);
455     String fullPlainTextString = plainText(fullCharacterRange.get());
456
457     NSRange extractedRange = WKExtractWordDefinitionTokenRangeFromContextualString(fullPlainTextString, rangeToPass, &options);
458
459     RefPtr<Range> finalRange = TextIterator::subrange(fullCharacterRange.get(), extractedRange.location, extractedRange.length);
460     if (!finalRange)
461         return;
462 #else
463     RefPtr<Range> finalRange = makeRange(startOfWord(position), endOfWord(position));
464     if (!finalRange)
465         return;
466 #endif
467
468     performDictionaryLookupForRange(DictionaryPopupInfo::HotKey, frame, finalRange.get(), options);
469 }
470
471 void WebPage::performDictionaryLookupForSelection(DictionaryPopupInfo::Type type, Frame* frame, const VisibleSelection& selection)
472 {
473     RefPtr<Range> selectedRange = selection.toNormalizedRange();
474     if (!selectedRange)
475         return;
476
477     NSDictionary *options = nil;
478
479 #if !defined(BUILDING_ON_SNOW_LEOPARD)
480     VisiblePosition selectionStart = selection.visibleStart();
481     VisiblePosition selectionEnd = selection.visibleEnd();
482
483     // As context, we are going to use the surrounding paragraphs of text.
484     VisiblePosition paragraphStart = startOfParagraph(selectionStart);
485     VisiblePosition paragraphEnd = endOfParagraph(selectionEnd);
486
487     int lengthToSelectionStart = TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get());
488     int lengthToSelectionEnd = TextIterator::rangeLength(makeRange(paragraphStart, selectionEnd).get());
489     NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, lengthToSelectionEnd - lengthToSelectionStart);
490
491     String fullPlainTextString = plainText(makeRange(paragraphStart, paragraphEnd).get());
492
493     // Since we already have the range we want, we just need to grab the returned options.
494     WKExtractWordDefinitionTokenRangeFromContextualString(fullPlainTextString, rangeToPass, &options);
495 #endif
496
497     performDictionaryLookupForRange(type, frame, selectedRange.get(), options);
498 }
499
500 void WebPage::performDictionaryLookupForRange(DictionaryPopupInfo::Type type, Frame* frame, Range* range, NSDictionary *options)
501 {
502     String rangeText = range->text();
503     if (rangeText.stripWhiteSpace().isEmpty())
504         return;
505     
506     RenderObject* renderer = range->startContainer()->renderer();
507     RenderStyle* style = renderer->style();
508     NSFont *font = style->font().primaryFont()->getNSFont();
509     if (!font)
510         return;
511     
512     CFDictionaryRef fontDescriptorAttributes = (CFDictionaryRef)[[font fontDescriptor] fontAttributes];
513     if (!fontDescriptorAttributes)
514         return;
515
516     Vector<FloatQuad> quads;
517     range->textQuads(quads);
518     if (quads.isEmpty())
519         return;
520     
521     IntRect rangeRect = frame->view()->contentsToWindow(quads[0].enclosingBoundingBox());
522     
523     DictionaryPopupInfo dictionaryPopupInfo;
524     dictionaryPopupInfo.type = type;
525     dictionaryPopupInfo.origin = FloatPoint(rangeRect.x(), rangeRect.y());
526     dictionaryPopupInfo.fontInfo.fontAttributeDictionary = fontDescriptorAttributes;
527 #if !defined(BUILDING_ON_SNOW_LEOPARD)
528     dictionaryPopupInfo.options = (CFDictionaryRef)options;
529 #endif
530
531     send(Messages::WebPageProxy::DidPerformDictionaryLookup(rangeText, dictionaryPopupInfo));
532 }
533
534 bool WebPage::performNonEditingBehaviorForSelector(const String& selector)
535 {
536     // FIXME: All these selectors have corresponding Editor commands, but the commands only work in editable content.
537     // Should such non-editing behaviors be implemented in Editor or EventHandler::defaultArrowEventHandler() perhaps?
538     if (selector == "moveUp:")
539         scroll(m_page.get(), ScrollUp, ScrollByLine);
540     else if (selector == "moveToBeginningOfParagraph:")
541         scroll(m_page.get(), ScrollUp, ScrollByPage);
542     else if (selector == "moveToBeginningOfDocument:") {
543         scroll(m_page.get(), ScrollUp, ScrollByDocument);
544         scroll(m_page.get(), ScrollLeft, ScrollByDocument);
545     } else if (selector == "moveDown:")
546         scroll(m_page.get(), ScrollDown, ScrollByLine);
547     else if (selector == "moveToEndOfParagraph:")
548         scroll(m_page.get(), ScrollDown, ScrollByPage);
549     else if (selector == "moveToEndOfDocument:") {
550         scroll(m_page.get(), ScrollDown, ScrollByDocument);
551         scroll(m_page.get(), ScrollLeft, ScrollByDocument);
552     } else if (selector == "moveLeft:")
553         scroll(m_page.get(), ScrollLeft, ScrollByLine);
554     else if (selector == "moveWordLeft:")
555         scroll(m_page.get(), ScrollLeft, ScrollByPage);
556     else if (selector == "moveToLeftEndOfLine:")
557         m_page->goBack();
558     else if (selector == "moveRight:")
559         scroll(m_page.get(), ScrollRight, ScrollByLine);
560     else if (selector == "moveWordRight:")
561         scroll(m_page.get(), ScrollRight, ScrollByPage);
562     else if (selector == "moveToRightEndOfLine:")
563         m_page->goForward();
564     else
565         return false;
566
567     return true;
568 }
569
570 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&)
571 {
572     return false;
573 }
574
575 void WebPage::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& elementToken, const CoreIPC::DataReference& windowToken)
576 {
577 #if !defined(BUILDING_ON_SNOW_LEOPARD)
578     NSData* elementTokenData = [NSData dataWithBytes:elementToken.data() length:elementToken.size()];
579     NSData* windowTokenData = [NSData dataWithBytes:windowToken.data() length:windowToken.size()];
580     id remoteElement = WKAXRemoteElementForToken(elementTokenData);
581     id remoteWindow = WKAXRemoteElementForToken(windowTokenData);
582     WKAXSetWindowForRemoteElement(remoteWindow, remoteElement);
583     
584     [accessibilityRemoteObject() setRemoteParent:remoteElement];
585 #endif
586 }
587
588 void WebPage::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes, bool& result)
589 {
590     Frame* frame = m_page->focusController()->focusedOrMainFrame();
591     if (!frame || frame->selection()->isNone()) {
592         result = false;
593         return;
594     }
595     frame->editor()->writeSelectionToPasteboard(pasteboardName, pasteboardTypes);
596     result = true;
597 }
598
599 void WebPage::readSelectionFromPasteboard(const String& pasteboardName, bool& result)
600 {
601     Frame* frame = m_page->focusController()->focusedOrMainFrame();
602     if (!frame || frame->selection()->isNone()) {
603         result = false;
604         return;
605     }
606     frame->editor()->readSelectionFromPasteboard(pasteboardName);
607     result = true;
608 }
609     
610 AccessibilityWebPageObject* WebPage::accessibilityRemoteObject()
611 {
612     return m_mockAccessibilityElement.get();
613 }
614          
615 bool WebPage::platformHasLocalDataForURL(const WebCore::KURL& url)
616 {
617     NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
618     [request setValue:(NSString*)userAgent() forHTTPHeaderField:@"User-Agent"];
619     NSCachedURLResponse *cachedResponse;
620 #if USE(CFURLSTORAGESESSIONS)
621     if (CFURLStorageSessionRef storageSession = ResourceHandle::privateBrowsingStorageSession())
622         cachedResponse = WKCachedResponseForRequest(storageSession, request);
623     else
624 #endif
625         cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
626     [request release];
627     
628     return cachedResponse;
629 }
630
631 String WebPage::cachedResponseMIMETypeForURL(const WebCore::KURL& url)
632 {
633     NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
634     [request setValue:(NSString*)userAgent() forHTTPHeaderField:@"User-Agent"];
635     NSCachedURLResponse *cachedResponse;
636 #if USE(CFURLSTORAGESESSIONS)
637     if (CFURLStorageSessionRef storageSession = ResourceHandle::privateBrowsingStorageSession())
638         cachedResponse = WKCachedResponseForRequest(storageSession, request);
639     else
640 #endif
641         cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
642     [request release];
643     
644     return [[cachedResponse response] MIMEType];
645 }
646
647 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest& request)
648 {
649     if ([NSURLConnection canHandleRequest:request.nsURLRequest()])
650         return true;
651
652     // FIXME: Return true if this scheme is any one WebKit2 knows how to handle.
653     return request.url().protocolIs("applewebdata");
654 }
655
656 void WebPage::setDragSource(NSObject *dragSource)
657 {
658     m_dragSource = dragSource;
659 }
660
661 void WebPage::platformDragEnded()
662 {
663     // The draggedImage method releases its responder; we retain here to balance that.
664     [m_dragSource.get() retain];
665     // The drag source we care about here is NSFilePromiseDragSource, which doesn't look at
666     // the arguments. It's OK to just pass arbitrary constant values, so we just pass all zeroes.
667     [m_dragSource.get() draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationNone];
668     m_dragSource = nullptr;
669 }
670
671 void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent& event, bool& result)
672 {
673     result = false;
674     Frame* frame = m_page->focusController()->focusedOrMainFrame();
675     if (!frame)
676         return;
677
678     HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true);
679     if (hitResult.isSelected())
680         result = frame->eventHandler()->eventMayStartDrag(platform(event));
681 }
682
683 void WebPage::acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent& event, bool& result)
684 {
685     result = false;
686     Frame* frame = m_page->focusController()->focusedOrMainFrame();
687     if (!frame)
688         return;
689     
690     HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true);
691     frame->eventHandler()->setActivationEventNumber(eventNumber);
692     if (hitResult.isSelected())
693         result = frame->eventHandler()->eventMayStartDrag(platform(event));
694     else 
695         result = !!hitResult.scrollbar();
696 }
697
698 } // namespace WebKit