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