1cac1d202bd7b36fd7b7aa1795666420ca81d324
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / ios / WebPageIOS.mm
1 /*
2  * Copyright (C) 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 #import "EditorState.h"
30 #import "InteractionInformationAtPosition.h"
31 #import "WebChromeClient.h"
32 #import "WebCoreArgumentCoders.h"
33 #import "WebFrame.h"
34 #import "WebPageProxyMessages.h"
35 #import "WebProcess.h"
36 #import "WKGestureTypes.h"
37 #import <CoreText/CTFont.h>
38 #import <WebCore/Chrome.h>
39 #import <WebCore/Element.h>
40 #import <WebCore/EventHandler.h>
41 #import <WebCore/FocusController.h>
42 #import <WebCore/FloatQuad.h>
43 #import <WebCore/Frame.h>
44 #import <WebCore/FrameView.h>
45 #import <WebCore/HitTestResult.h>
46 #import <WebCore/HTMLElementTypeHelpers.h>
47 #import <WebCore/MainFrame.h>
48 #import <WebCore/Node.h>
49 #import <WebCore/NotImplemented.h>
50 #import <WebCore/Page.h>
51 #import <WebCore/PlatformKeyboardEvent.h>
52 #import <WebCore/PlatformMouseEvent.h>
53 #import <WebCore/RenderImage.h>
54 #import <WebCore/SharedBuffer.h>
55 #import <WebCore/TextIterator.h>
56 #import <WebCore/VisibleUnits.h>
57 #import <WebCore/WebEvent.h>
58
59 using namespace WebCore;
60
61 namespace WebKit {
62
63 void WebPage::platformInitialize()
64 {
65     notImplemented();
66 }
67
68 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
69 {
70     notImplemented();
71 }
72
73 bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>&, KeyboardEvent*)
74 {
75     notImplemented();
76     return false;
77 }
78
79 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event, bool)
80 {
81     bool eventWasHandled = false;
82     bool sendResult = WebProcess::shared().parentProcessConnection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(editorState(), event->keyEvent()->type() == PlatformKeyboardEvent::Char),
83                                                                                Messages::WebPageProxy::InterpretKeyEvent::Reply(eventWasHandled), m_pageID);
84     if (!sendResult)
85         return false;
86
87     return eventWasHandled;
88 }
89
90 void WebPage::sendComplexTextInputToPlugin(uint64_t, const String&)
91 {
92     notImplemented();
93 }
94
95 void WebPage::setComposition(const String& text, Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd)
96 {
97     Frame& frame = m_page->focusController().focusedOrMainFrame();
98
99     if (frame.selection().isContentEditable())
100         frame.editor().setComposition(text, underlines, selectionStart, selectionEnd);
101 }
102
103 void WebPage::confirmComposition()
104 {
105     Frame& frame = m_page->focusController().focusedOrMainFrame();
106     frame.editor().confirmComposition();
107 }
108
109 void WebPage::cancelComposition(EditorState&)
110 {
111     notImplemented();
112 }
113
114 static PassRefPtr<Range> convertToRange(Frame* frame, NSRange nsrange)
115 {
116     if (nsrange.location > INT_MAX)
117         return 0;
118     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
119         nsrange.length = INT_MAX - nsrange.location;
120     
121     // our critical assumption is that we are only called by input methods that
122     // concentrate on a given area containing the selection
123     // We have to do this because of text fields and textareas. The DOM for those is not
124     // directly in the document DOM, so serialization is problematic. Our solution is
125     // to use the root editable element of the selection start as the positional base.
126     // That fits with AppKit's idea of an input context.
127     return TextIterator::rangeFromLocationAndLength(frame->selection().rootEditableElementOrDocumentElement(), nsrange.location, nsrange.length);
128 }
129
130 void WebPage::insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd)
131 {
132     Frame& frame = m_page->focusController().focusedOrMainFrame();
133     
134     if (replacementRangeStart != NSNotFound) {
135         RefPtr<Range> replacementRange = convertToRange(&frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart));
136         if (replacementRange)
137             frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
138     }
139     
140     if (!frame.editor().hasComposition()) {
141         // An insertText: might be handled by other responders in the chain if we don't handle it.
142         // One example is space bar that results in scrolling down the page.
143         frame.editor().insertText(text, 0);
144     } else
145         frame.editor().confirmComposition(text);
146 }
147
148 void WebPage::insertDictatedText(const String&, uint64_t, uint64_t, const Vector<WebCore::DictationAlternative>&, bool&, EditorState&)
149 {
150     notImplemented();
151 }
152
153 void WebPage::getMarkedRange(uint64_t&, uint64_t&)
154 {
155     notImplemented();
156 }
157
158 void WebPage::getSelectedRange(uint64_t&, uint64_t&)
159 {
160     notImplemented();
161 }
162
163 void WebPage::getAttributedSubstringFromRange(uint64_t, uint64_t, AttributedString&)
164 {
165     notImplemented();
166 }
167
168 void WebPage::characterIndexForPoint(IntPoint, uint64_t&)
169 {
170     notImplemented();
171 }
172
173 void WebPage::firstRectForCharacterRange(uint64_t, uint64_t, WebCore::IntRect&)
174 {
175     notImplemented();
176 }
177
178 void WebPage::executeKeypressCommands(const Vector<WebCore::KeypressCommand>&, bool&, EditorState&)
179 {
180     notImplemented();
181 }
182
183 void WebPage::performDictionaryLookupAtLocation(const FloatPoint&)
184 {
185     notImplemented();
186 }
187
188 void WebPage::performDictionaryLookupForSelection(Frame*, const VisibleSelection&)
189 {
190     notImplemented();
191 }
192
193 void WebPage::performDictionaryLookupForRange(Frame*, Range*, NSDictionary *)
194 {
195     notImplemented();
196 }
197
198 bool WebPage::performNonEditingBehaviorForSelector(const String&, WebCore::KeyboardEvent*)
199 {
200     notImplemented();
201     return false;
202 }
203
204 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&)
205 {
206     notImplemented();
207     return false;
208 }
209
210 void WebPage::registerUIProcessAccessibilityTokens(const IPC::DataReference&, const IPC::DataReference&)
211 {
212     notImplemented();
213 }
214
215 void WebPage::readSelectionFromPasteboard(const String&, bool&)
216 {
217     notImplemented();
218 }
219
220 void WebPage::getStringSelectionForPasteboard(String&)
221 {
222     notImplemented();
223 }
224
225 void WebPage::getDataSelectionForPasteboard(const String, SharedMemory::Handle&, uint64_t&)
226 {
227     notImplemented();
228 }
229
230 WKAccessibilityWebPageObject* WebPage::accessibilityRemoteObject()
231 {
232     notImplemented();
233     return 0;
234 }
235
236 bool WebPage::platformHasLocalDataForURL(const WebCore::URL&)
237 {
238     notImplemented();
239     return false;
240 }
241
242 String WebPage::cachedSuggestedFilenameForURL(const URL&)
243 {
244     notImplemented();
245     return String();
246 }
247
248 String WebPage::cachedResponseMIMETypeForURL(const URL&)
249 {
250     notImplemented();
251     return String();
252 }
253
254 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const URL&)
255 {
256     notImplemented();
257     return 0;
258 }
259
260 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest&)
261 {
262     notImplemented();
263     return false;
264 }
265
266 void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent&, bool&)
267 {
268     notImplemented();
269 }
270
271 void WebPage::acceptsFirstMouse(int, const WebKit::WebMouseEvent&, bool&)
272 {
273     notImplemented();
274 }
275
276 void WebPage::computePagesForPrintingPDFDocument(uint64_t, const PrintInfo&, Vector<IntRect>&)
277 {
278     notImplemented();
279 }
280
281 void WebPage::drawPagesToPDFFromPDFDocument(CGContextRef, PDFDocument *, const PrintInfo&, uint32_t, uint32_t)
282 {
283     notImplemented();
284 }
285
286 void WebPage::advanceToNextMisspelling(bool)
287 {
288     notImplemented();
289 }
290
291 void WebPage::handleTap(const IntPoint& point)
292 {
293     Frame& mainframe = m_page->mainFrame();
294     FloatPoint adjustedPoint;
295     mainframe.nodeRespondingToClickEvents(point, adjustedPoint);
296     IntPoint roundedAdjustedPoint = roundedIntPoint(adjustedPoint);
297
298     mainframe.eventHandler().mouseMoved(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, false, false, false, false, 0));
299     mainframe.eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, false, false, false, false, 0));
300     mainframe.eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MouseReleased, 1, false, false, false, false, 0));
301 }
302
303 void WebPage::tapHighlightAtPosition(uint64_t requestID, const FloatPoint& position)
304 {
305     Frame& mainframe = m_page->mainFrame();
306     FloatPoint adjustedPoint;
307     Node* node = mainframe.nodeRespondingToClickEvents(position, adjustedPoint);
308
309     if (!node)
310         return;
311
312     RenderObject *renderer = node->renderer();
313
314     Vector<FloatQuad> quads;
315     if (renderer) {
316         renderer->absoluteQuads(quads);
317         Color highlightColor = node->computedStyle()->tapHighlightColor();
318
319         RoundedRect::Radii borderRadii;
320         if (renderer->isBox()) {
321             RenderBox* box = toRenderBox(renderer);
322             borderRadii = box->borderRadii();
323         }
324
325         send(Messages::WebPageProxy::DidGetTapHighlightGeometries(requestID, highlightColor, quads, borderRadii.topLeft(), borderRadii.topRight(), borderRadii.bottomLeft(), borderRadii.bottomRight()));
326     }
327 }
328
329 void WebPage::blurAssistedNode()
330 {
331     if (m_assistedNode && m_assistedNode->isElementNode())
332         toElement(m_assistedNode.get())->blur();
333 }
334
335 static FloatQuad innerFrameQuad(Frame* frame, Node* assistedNode)
336 {
337     frame->document()->updateLayoutIgnorePendingStylesheets();
338     RenderObject* renderer;
339     if (assistedNode->hasTagName(HTMLNames::textareaTag) || assistedNode->hasTagName(HTMLNames::inputTag))
340         renderer = assistedNode->renderer();
341     else
342         renderer = assistedNode->rootEditableElement()->renderer();
343     
344     if (!renderer)
345         return FloatQuad();
346
347     RenderStyle& style = renderer->style();
348     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true /* use transforms*/);
349
350     boundingBox.move(style.borderLeftWidth(), style.borderTopWidth());
351     boundingBox.setWidth(boundingBox.width() - style.borderLeftWidth() - style.borderRightWidth());
352     boundingBox.setHeight(boundingBox.height() - style.borderBottomWidth() - style.borderTopWidth());
353
354     return FloatQuad(boundingBox);
355 }
356
357 static IntPoint constrainPoint(const IntPoint& point, Frame* frame, Node* assistedNode)
358 {
359     const int DEFAULT_CONSTRAIN_INSET = 2;
360     IntRect innerFrame = innerFrameQuad(frame, assistedNode).enclosingBoundingBox();
361     IntPoint constrainedPoint = point;
362
363     int minX = innerFrame.x() + DEFAULT_CONSTRAIN_INSET;
364     int maxX = innerFrame.maxX() - DEFAULT_CONSTRAIN_INSET;
365     int minY = innerFrame.y() + DEFAULT_CONSTRAIN_INSET;
366     int maxY = innerFrame.maxY() - DEFAULT_CONSTRAIN_INSET;
367
368     if (point.x() < minX)
369         constrainedPoint.setX(minX);
370     else if (point.x() > maxX)
371         constrainedPoint.setX(maxX);
372
373     if (point.y() < minY)
374         constrainedPoint.setY(minY);
375     else if (point.y() >= maxY)
376         constrainedPoint.setY(maxY);
377                     
378     return constrainedPoint;
379 }
380
381 void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
382 {
383     Frame& frame = m_page->focusController().focusedOrMainFrame();
384     FloatPoint adjustedPoint(point);
385
386     IntPoint constrainedPoint = m_assistedNode ? constrainPoint(point, &frame, m_assistedNode.get()) : point;
387     VisiblePosition position = frame.visiblePositionForPoint(constrainedPoint);
388     if (position.isNull()) {
389         send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, 0, callbackID));
390         return;
391     }
392     RefPtr<Range> range;
393     switch (static_cast<WKGestureType>(gestureType)) {
394     case WKGestureOneFingerTap:
395     {
396         VisiblePosition result;
397         // move the the position at the end of the word
398         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
399             // Don't cross line boundaries.
400             result = position;
401         } else if (withinTextUnitOfGranularity(position, WordGranularity, DirectionForward)) {
402             // The position lies within a word.
403             RefPtr<Range> wordRange = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionForward);
404
405             result = wordRange->startPosition();
406             if (distanceBetweenPositions(position, result) > 1)
407                 result = wordRange->endPosition();
408         } else if (atBoundaryOfGranularity(position, WordGranularity, DirectionBackward)) {
409             // The position is at the end of a word.
410             result = position;
411         } else {
412             // The position is not within a word.
413             // Go to the next boundary.
414             result = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionForward);
415
416             // If there is no such boundary we go to the end of the element.
417             if (result.isNull())
418                 result = endOfEditableContent(position);
419         }
420         if (result.isNotNull())
421             range = Range::create(*frame.document(), result, result);
422         if (range)
423             m_shouldReturnWordAtSelection = true;
424     }
425         break;
426
427     case WKGestureLoupe:
428         range = Range::create(*frame.document(), position, position);
429         break;
430
431     case WKGestureTapAndAHalf:
432         switch (static_cast<WKGestureRecognizerState>(gestureState)) {
433         case WKGestureRecognizerStateBegan:
434             range = wordRangeFromPosition(position);
435             m_currentWordRange = Range::create(*frame.document(), range->startPosition(), range->endPosition());
436             break;
437         case WKGestureRecognizerStateChanged:
438         {
439             range = Range::create(*frame.document(), m_currentWordRange->startPosition(), m_currentWordRange->endPosition());
440             ExceptionCode ec;
441             if (position < range->startPosition())
442                 range->setStart(position.deepEquivalent(), ec);
443             if (position > range->endPosition())
444                 range->setEnd(position.deepEquivalent(), ec);
445         }
446             break;
447         case WKGestureRecognizerStateEnded:
448         case WKGestureRecognizerStateCancelled:
449             m_currentWordRange = nullptr;
450             break;
451         case WKGestureRecognizerStateFailed:
452         case WKGestureRecognizerStatePossible:
453             ASSERT_NOT_REACHED();
454         }
455         break;
456
457     case WKGestureOneFingerDoubleTap:
458         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
459             // Double-tap at end of line only places insertion point there.
460             // This helps to get the callout for pasting at ends of lines,
461             // paragraphs, and documents.
462             range = Range::create(*frame.document(), position, position);
463          } else
464             range = wordRangeFromPosition(position);
465         break;
466
467     case WKGestureTwoFingerSingleTap:
468         // Single tap with two fingers selects the entire paragraph.
469         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
470         break;
471
472     case WKGestureOneFingerTripleTap:
473         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
474             // Triple-tap at end of line only places insertion point there.
475             // This helps to get the callout for pasting at ends of lines,
476             // paragraphs, and documents.
477             range = Range::create(*frame.document(), position, position);
478         } else
479             range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
480         break;
481
482     case WKGestureMakeWebSelection:
483         // FIXME: Here we should implement the logic for block selections.
484         range = wordRangeFromPosition(position);
485         break;
486
487     default:
488         break;
489     }
490     if (range)
491         frame.selection().setSelectedRange(range.get(), position.affinity(), true);
492
493     send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, 0, callbackID));
494     m_shouldReturnWordAtSelection = false;
495 }
496
497 static PassRefPtr<Range> rangeForPosition(Frame* frame, const VisiblePosition& position, bool baseIsStart)
498 {
499     RefPtr<Range> range;
500     VisiblePosition result = position;
501
502     if (baseIsStart) {
503         VisiblePosition selectionStart = frame->selection().selection().visibleStart();
504         bool wouldFlip = position <= selectionStart;
505
506         if (wouldFlip)
507             result = selectionStart.next();
508
509         if (result.isNotNull())
510             range = Range::create(*frame->document(), selectionStart, result);
511     } else {
512         VisiblePosition selectionEnd = frame->selection().selection().visibleEnd();
513         bool wouldFlip = position >= selectionEnd;
514
515         if (wouldFlip)
516             result = selectionEnd.previous();
517
518         if (result.isNotNull())
519             range = Range::create(*frame->document(), result, selectionEnd);
520     }
521
522     return range.release();
523 }
524
525 static PassRefPtr<Range> rangeAtWordBoundaryForPosition(Frame* frame, const VisiblePosition& position, bool baseIsStart, SelectionDirection direction)
526 {
527     SelectionDirection sameDirection = baseIsStart ? DirectionForward : DirectionBackward;
528     SelectionDirection oppositeDirection = baseIsStart ? DirectionBackward : DirectionForward;
529     VisiblePosition base = baseIsStart ? frame->selection().selection().visibleStart() : frame->selection().selection().visibleEnd();
530     VisiblePosition extent = baseIsStart ? frame->selection().selection().visibleEnd() : frame->selection().selection().visibleStart();
531     VisiblePosition initialExtent = position;
532
533     if (atBoundaryOfGranularity(extent, WordGranularity, sameDirection)) {
534         // This is a word boundary. Leave selection where it is.
535         return 0;
536     }
537
538     if (atBoundaryOfGranularity(extent, WordGranularity, oppositeDirection)) {
539         // This is a word boundary in the wrong direction. Nudge the selection to a character before proceeding.
540         extent = baseIsStart ? extent.previous() : extent.next();
541     }
542
543     // Extend to the boundary of the word.
544
545     VisiblePosition wordBoundary = positionOfNextBoundaryOfGranularity(extent, WordGranularity, sameDirection);
546     if (wordBoundary.isNotNull()
547         && atBoundaryOfGranularity(wordBoundary, WordGranularity, sameDirection)
548         && initialExtent != wordBoundary) {
549         extent = wordBoundary;
550         return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
551     }
552     // Conversely, if the initial extent equals the current word boundary, then
553     // run the rest of this function to see if the selection should extend
554     // the other direction to the other word.
555
556     // If this is where the extent was initially, then iterate in the other direction in the document until we hit the next word.
557     while (extent.isNotNull()
558            && !atBoundaryOfGranularity(extent, WordGranularity, sameDirection)
559            && extent != base
560            && !atBoundaryOfGranularity(extent, LineBoundary, sameDirection)
561            && !atBoundaryOfGranularity(extent, LineBoundary, oppositeDirection)) {
562         extent = baseIsStart ? extent.next() : extent.previous();
563     }
564
565     // Don't let the smart extension make the extent equal the base.
566     // Expand out to word boundary.
567     if (extent.isNull() || extent == base)
568         extent = wordBoundary;
569     if (extent.isNull())
570         return 0;
571
572     return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
573 }
574
575 void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches, bool baseIsStart, uint64_t callbackID)
576 {
577     Frame& frame = m_page->focusController().focusedOrMainFrame();
578     VisiblePosition position = frame.visiblePositionForPoint(point);
579     if (position.isNull()) {
580         send(Messages::WebPageProxy::TouchesCallback(point, touches, callbackID));
581         return;
582     }
583
584     RefPtr<Range> range;
585     VisiblePosition result;
586     
587     switch (static_cast<WKSelectionTouch>(touches)) {
588         case WKSelectionTouchStarted:
589         case WKSelectionTouchEndedNotMoving:
590             break;
591         
592         case WKSelectionTouchEnded:
593             if (frame.selection().isContentEditable()) {
594                 result = closestWordBoundaryForPosition(position);
595                 if (result.isNotNull())
596                     range = Range::create(*frame.document(), result, result);
597             } else
598                 range = rangeForPosition(&frame, position, baseIsStart);
599             break;
600
601         case WKSelectionTouchEndedMovingForward:
602             range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionForward);
603             break;
604             
605         case WKSelectionTouchEndedMovingBackward:
606             range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionBackward);
607             break;
608
609         case WKSelectionTouchMoved:
610             range = rangeForPosition(&frame, position, baseIsStart);
611             break;
612     }
613     if (range)
614         frame.selection().setSelectedRange(range.get(), position.affinity(), true);
615
616     send(Messages::WebPageProxy::TouchesCallback(point, touches, callbackID));
617 }
618
619 void WebPage::selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore::IntPoint& to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
620 {
621     Frame& frame = m_page->focusController().focusedOrMainFrame();
622     VisiblePosition fromPosition = frame.visiblePositionForPoint(from);
623     VisiblePosition toPosition = frame.visiblePositionForPoint(to);
624     RefPtr<Range> range;
625     if (fromPosition.isNotNull() && toPosition.isNotNull()) {
626         if (fromPosition < toPosition)
627             range = Range::create(*frame.document(), fromPosition, toPosition);
628         else
629             range = Range::create(*frame.document(), toPosition, fromPosition);
630         frame.selection().setSelectedRange(range.get(), fromPosition.affinity(), true);
631     }
632
633     // We can use the same callback for the gestures with one point.
634     send(Messages::WebPageProxy::GestureCallback(from, gestureType, gestureState, 0, callbackID));
635 }
636
637 void WebPage::extendSelection(uint32_t granularity)
638 {
639     // For the moment we handle only WordGranularity.
640     if (granularity != WordGranularity)
641         return;
642
643     Frame& frame = m_page->focusController().focusedOrMainFrame();
644     ASSERT(frame.selection().isCaret());
645     VisiblePosition position = frame.selection().selection().start();
646     frame.selection().setSelectedRange(wordRangeFromPosition(position).get(), position.affinity(), true);
647 }
648
649 void WebPage::requestAutocorrectionData(const String& textForAutocorrection, uint64_t callbackID)
650 {
651     RefPtr<Range> range;
652     Frame& frame = m_page->focusController().focusedOrMainFrame();
653     ASSERT(frame.selection().isCaret());
654     VisiblePosition position = frame.selection().selection().start();
655     Vector<SelectionRect> selectionRects;
656
657     range = wordRangeFromPosition(position);
658     String textForRange = plainText(range.get());
659     const unsigned maxSearchAttempts = 5;
660     for (size_t i = 0;  i < maxSearchAttempts && textForRange != textForAutocorrection; ++i)
661     {
662         position = range->startPosition().previous();
663         if (position.isNull() || position == range->startPosition())
664             break;
665         range = Range::create(*frame.document(), wordRangeFromPosition(position)->startPosition(), range->endPosition());
666         textForRange = plainText(range.get());
667     }
668     if (textForRange == textForAutocorrection)
669         range->collectSelectionRects(selectionRects);
670
671     Vector<FloatRect> rectsForText;
672     rectsForText.resize(selectionRects.size());
673
674     for (size_t i = 0; i < selectionRects.size(); i++)
675         rectsForText[i] = selectionRects[i].rect();
676
677     bool multipleFonts = false;
678     CTFontRef font = nil;
679     if (const SimpleFontData* fontData = frame.editor().fontForSelection(multipleFonts))
680         font = fontData->getCTFont();
681
682     CGFloat fontSize = CTFontGetSize(font);
683     uint64_t fontTraits = CTFontGetSymbolicTraits(font);
684     RetainPtr<NSString> fontName = adoptNS((NSString *)CTFontCopyFamilyName(font));
685     send(Messages::WebPageProxy::AutocorrectionDataCallback(rectsForText, fontName.get(), fontSize, fontTraits, callbackID));
686 }
687
688 void WebPage::applyAutocorrection(const String& correction, const String& originalText, uint64_t callbackID)
689 {
690     RefPtr<Range> range;
691     Frame& frame = m_page->focusController().focusedOrMainFrame();
692     ASSERT(frame.selection().isCaret());
693     VisiblePosition position = frame.selection().selection().start();
694
695     range = wordRangeFromPosition(position);
696     String textForRange = plainText(range.get());
697     if (textForRange != originalText) {
698         for (size_t i = 0; i < originalText.length(); ++i)
699             position = position.previous();
700         if (position.isNull())
701             position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
702         range = Range::create(*frame.document(), position, frame.selection().selection().start());
703         if (range)
704             textForRange = (range) ? plainText(range.get()) : emptyString();
705         unsigned loopCount = 0;
706         const unsigned maxPositionsAttempts = 10;
707         while (textForRange.length() && textForRange.length() > originalText.length() && loopCount < maxPositionsAttempts) {
708             position = position.next();
709             if (position.isNotNull() && position >= frame.selection().selection().start())
710                 range = NULL;
711             else
712                 range = Range::create(*frame.document(), position, frame.selection().selection().start());
713             textForRange = (range) ? plainText(range.get()) : emptyString();
714             loopCount++;
715         }
716     }
717     if (textForRange != originalText) {
718         send(Messages::WebPageProxy::StringCallback(String(), callbackID));
719         return;
720     }
721
722     frame.selection().setSelectedRange(range.get(), UPSTREAM, true);
723     if (correction.length())
724         frame.editor().insertText(correction, 0);
725     else
726         frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
727
728     send(Messages::WebPageProxy::StringCallback(correction, callbackID));
729 }
730
731 static void computeAutocorrectionContext(Frame& frame, String& contextBefore, String& markedText, String& selectedText, String& contextAfter, uint64_t& location, uint64_t& length)
732 {
733     RefPtr<Range> range;
734     VisiblePosition startPosition = frame.selection().selection().start();
735     VisiblePosition endPosition = frame.selection().selection().end();
736     location = NSNotFound;
737     length = 0;
738     const unsigned minContextWordCount = 3;
739     const unsigned minContextLenght = 12;
740     const unsigned maxContextLength = 30;
741
742     if (frame.selection().isRange())
743         selectedText = plainText(frame.selection().selection().toNormalizedRange().get());
744
745     if (frame.editor().hasComposition()) {
746         range = Range::create(*frame.document(), frame.editor().compositionRange()->startPosition(), startPosition);
747         String markedTextBefore;
748         if (range)
749             markedTextBefore = plainText(range.get());
750         range = Range::create(*frame.document(), endPosition, frame.editor().compositionRange()->endPosition());
751         String markedTextAfter;
752         if (range)
753             markedTextAfter = plainText(range.get());
754         markedText = markedTextBefore + selectedText + markedTextAfter;
755         if (!markedText.isEmpty()) {
756             location = markedTextBefore.length();
757             length = selectedText.length();
758         }
759     } else {
760         if (startPosition != startOfEditableContent(startPosition)) {
761             VisiblePosition currentPosition = startPosition;
762             VisiblePosition previousPosition;
763             unsigned totalContextLength = 0;
764             for (unsigned i = 0; i < minContextWordCount; ++i) {
765                 if (contextBefore.length() >= minContextLenght)
766                     break;
767                 previousPosition = startOfWord(positionOfNextBoundaryOfGranularity(currentPosition, WordGranularity, DirectionBackward));
768                 if (previousPosition.isNull())
769                     break;
770                 String currentWord = plainText(Range::create(*frame.document(), previousPosition, currentPosition).get());
771                 totalContextLength += currentWord.length();
772                 if (totalContextLength >= maxContextLength)
773                     break;
774                 currentPosition = previousPosition;
775             }
776             if (currentPosition.isNotNull() && currentPosition != startPosition) {
777                 contextBefore = plainText(Range::create(*frame.document(), currentPosition, startPosition).get());
778                 if (atBoundaryOfGranularity(currentPosition, ParagraphGranularity, DirectionBackward))
779                     contextBefore = ASCIILiteral("\n ") + contextBefore;
780             }
781         }
782
783         if (endPosition != endOfEditableContent(endPosition)) {
784             VisiblePosition nextPosition;
785             if (!atBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward) && withinTextUnitOfGranularity(endPosition, WordGranularity, DirectionForward))
786                 nextPosition = positionOfNextBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward);
787             if (nextPosition.isNotNull())
788                 contextAfter = plainText(Range::create(*frame.document(), endPosition, nextPosition).get());
789         }
790     }
791 }
792
793 void WebPage::requestAutocorrectionContext(uint64_t callbackID)
794 {
795     String contextBefore;
796     String contextAfter;
797     String selectedText;
798     String markedText;
799     uint64_t location;
800     uint64_t length;
801
802     computeAutocorrectionContext(m_page->focusController().focusedOrMainFrame(), contextBefore, markedText, selectedText, contextAfter, location, length);
803
804     send(Messages::WebPageProxy::AutocorrectionContextCallback(contextBefore, markedText, selectedText, contextAfter, location, length, callbackID));
805 }
806
807 void WebPage::getAutocorrectionContext(String& contextBefore, String& markedText, String& selectedText, String& contextAfter, uint64_t& location, uint64_t& length)
808 {
809     computeAutocorrectionContext(m_page->focusController().focusedOrMainFrame(), contextBefore, markedText, selectedText, contextAfter, location, length);
810 }
811
812 void WebPage::getPositionInformation(const IntPoint& point, InteractionInformationAtPosition& info)
813 {
814     FloatPoint adjustedPoint;
815     Node* hitNode = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
816
817     info.point = point;
818     info.nodeAtPositionIsAssistedNode = (hitNode == m_assistedNode);
819     if (hitNode) {
820         info.clickableElementName = hitNode->nodeName();
821
822         const HTMLElement* element = toHTMLElement(hitNode);
823         if (!element)
824             return;
825
826         if (element->renderer() && element->renderer()->isImage()) {
827             URL url = toRenderImage(element->renderer())->cachedImage()->url();
828             if (!url.string().isNull())
829                 info.url = url.string();
830         } else if (element->isLink())
831             info.url = element->getAttribute(HTMLNames::hrefAttr).string();
832     } else {
833         Frame& frame = m_page->mainFrame();
834         hitNode = frame.eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent).innerNode();
835         if (hitNode->isTextNode()) {
836             VisiblePosition position = frame.visiblePositionForPoint(point);
837             RefPtr<Range> range = wordRangeFromPosition(position);
838             if (range)
839                 range->collectSelectionRects(info.selectionRects);
840         } else {
841             // FIXME: implement the logic for the block selection.
842         }
843
844     }
845 }
846
847 void WebPage::requestPositionInformation(const IntPoint& point)
848 {
849     InteractionInformationAtPosition info;
850
851     getPositionInformation(point, info);
852     send(Messages::WebPageProxy::DidReceivePositionInformation(info));
853 }
854
855 void WebPage::elementDidFocus(WebCore::Node* node)
856 {
857     m_assistedNode = node;
858     if (node->hasTagName(WebCore::HTMLNames::inputTag) || node->hasTagName(WebCore::HTMLNames::textareaTag) || node->hasEditableStyle())
859         send(Messages::WebPageProxy::StartAssistingNode(WebCore::IntRect(), true, true));    
860 }
861
862 void WebPage::elementDidBlur(WebCore::Node* node)
863 {
864     if (m_assistedNode == node) {
865         send(Messages::WebPageProxy::StopAssistingNode());
866         m_assistedNode = 0;
867     }
868 }
869
870 void WebPage::didFinishScrolling(const WebCore::FloatPoint& contentOffset)
871 {
872     m_page->mainFrame().view()->setScrollOffset(WebCore::IntPoint(contentOffset));
873 }
874
875 void WebPage::didFinishZooming(float newScale)
876 {
877     m_page->setPageScaleFactor(newScale, m_page->mainFrame().view()->scrollPosition());
878 }
879
880 } // namespace WebKit