upload tizen1.0 source
[profile/ivi/webkit-efl.git] / Source / WebKit2 / WebProcess / WebPage / efl / WebPageEfl.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4  * Copyright (C) 2011 Igalia S.L.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25  * THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "WebPage.h"
30
31 #include "NotImplemented.h"
32 #include "WebEvent.h"
33 #include "WindowsKeyboardCodes.h"
34 #include <WebCore/FocusController.h>
35 #include <WebCore/Frame.h>
36 #include <WebCore/KeyboardEvent.h>
37 #include <WebCore/Page.h>
38 #include <WebCore/PlatformKeyboardEvent.h>
39 #include <WebCore/Settings.h>
40
41 #if OS(TIZEN)
42 #include "Arguments.h"
43 #include "WebCoreArgumentCoders.h"
44 #include "WebFrame.h"
45 #include "WebImage.h"
46 #include "WebPageProxyMessages.h"
47 #include <WebCore/FrameView.h>
48
49 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
50 #include <WebCore/HTMLInputElement.h>
51 #include <WebCore/HTMLNames.h>
52 #endif
53
54 #if ENABLE(TIZEN_SUPPORT_RSS_LINK_PARSING)
55 #include "HTMLLinkElement.h"
56 #include <WebCore/html/HTMLAllCollection.h>
57 #include <efl/RssItemEfl.h>
58 #endif
59
60 #endif // #if OS(TIZEN)
61
62 using namespace WebCore;
63
64 namespace WebKit {
65
66 void WebPage::platformInitialize()
67 {
68 #if OS(TIZEN)
69     Settings* settings = m_page->settings();
70     // If accelerated compositing is enabled, we want to be in force-compositing mode, so that we don't switch between composited/non-composited state.
71     settings->setForceCompositingMode(true);
72 #else
73     notImplemented();
74 #endif
75 }
76
77 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
78 {
79     notImplemented();
80 }
81
82 static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
83 {
84     page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
85 }
86
87 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
88 {
89     notImplemented();
90     return false;
91 }
92
93 bool WebPage::platformHasLocalDataForURL(const KURL&)
94 {
95     notImplemented();
96     return false;
97 }
98
99 String WebPage::cachedResponseMIMETypeForURL(const KURL&)
100 {
101     notImplemented();
102     return String();
103 }
104
105 bool WebPage::platformCanHandleRequest(const ResourceRequest&)
106 {
107     notImplemented();
108     return true;
109 }
110
111 String WebPage::cachedSuggestedFilenameForURL(const KURL&)
112 {
113     notImplemented();
114     return String();
115 }
116
117 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const KURL&)
118 {
119     notImplemented();
120     return 0;
121 }
122
123 #if !OS(TIZEN)
124 const char* WebPage::interpretKeyEvent(const KeyboardEvent* evt)
125 {
126     notImplemented();
127     return 0;
128 }
129 #else
130 // XXX: not contributed
131 static const unsigned CtrlKey = 1 << 0;
132 static const unsigned AltKey = 1 << 1;
133 static const unsigned ShiftKey = 1 << 2;
134
135 struct KeyDownEntry {
136     unsigned virtualKey;
137     unsigned modifiers;
138     const char* name;
139 };
140
141 struct KeyPressEntry {
142     unsigned charCode;
143     unsigned modifiers;
144     const char* name;
145 };
146
147 static const KeyDownEntry keyDownEntries[] = {
148     { VK_LEFT,   0,                  "MoveLeft"                                    },
149     { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
150     { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
151     { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
152     { VK_RIGHT,  0,                  "MoveRight"                                   },
153     { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
154     { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
155     { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
156     { VK_UP,     0,                  "MoveUp"                                      },
157     { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
158     { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
159     { VK_DOWN,   0,                  "MoveDown"                                    },
160     { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
161     { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
162     { VK_PRIOR,  0,                  "MovePageUp"                                  },
163     { VK_NEXT,   0,                  "MovePageDown"                                },
164     { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
165     { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
166     { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
167     { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
168
169     { VK_END,    0,                  "MoveToEndOfLine"                             },
170     { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
171     { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
172     { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
173
174     { VK_BACK,   0,                  "DeleteBackward"                              },
175     { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
176     { VK_DELETE, 0,                  "DeleteForward"                               },
177     { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
178     { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
179
180     { 'B',       CtrlKey,            "ToggleBold"                                  },
181     { 'I',       CtrlKey,            "ToggleItalic"                                },
182
183     { VK_ESCAPE, 0,                  "Cancel"                                      },
184     { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
185     { VK_TAB,    0,                  "InsertTab"                                   },
186     { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
187     { VK_RETURN, 0,                  "InsertNewline"                               },
188     { VK_RETURN, CtrlKey,            "InsertNewline"                               },
189     { VK_RETURN, AltKey,             "InsertNewline"                               },
190     { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
191 };
192
193 static const KeyPressEntry keyPressEntries[] = {
194     { '\t',   0,                  "InsertTab"                                   },
195     { '\t',   ShiftKey,           "InsertBacktab"                               },
196     { '\r',   0,                  "InsertNewline"                               },
197     { '\r',   CtrlKey,            "InsertNewline"                               },
198     { '\r',   AltKey,             "InsertNewline"                               },
199     { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
200 };
201
202 const char* WebPage::interpretKeyEvent(const KeyboardEvent* event)
203 {
204     ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
205
206     static HashMap<int, const char*>* keyDownCommandsMap = 0;
207     static HashMap<int, const char*>* keyPressCommandsMap = 0;
208
209     if (!keyDownCommandsMap) {
210         keyDownCommandsMap = new HashMap<int, const char*>;
211         keyPressCommandsMap = new HashMap<int, const char*>;
212
213         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
214             keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
215
216         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
217             keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
218     }
219
220     unsigned modifiers = 0;
221     if (event->shiftKey())
222         modifiers |= ShiftKey;
223     if (event->altKey())
224         modifiers |= AltKey;
225     if (event->ctrlKey())
226         modifiers |= CtrlKey;
227
228     if (event->type() == eventNames().keydownEvent) {
229         int mapKey = modifiers << 16 | event->keyCode();
230         return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
231     }
232
233     int mapKey = modifiers << 16 | event->charCode();
234     return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
235 }
236
237 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
238 IntSize WebPage::contentsSize() const
239 {
240     FrameView* frameView = m_page->mainFrame()->view();
241     if (!frameView)
242         return IntSize(0, 0);
243
244     return frameView->contentsSize();
245 }
246 #endif
247
248 void WebPage::scrollMainFrameBy(const IntSize& scrollOffset)
249 {
250     m_page->mainFrame()->view()->scrollBy(scrollOffset);
251 }
252
253 void WebPage::scrollMainFrameTo(const IntPoint& scrollPosition)
254 {
255     m_page->mainFrame()->view()->setScrollPosition(scrollPosition);
256 }
257
258 void WebPage::createSnapshot(const IntRect rect, float scaleFactor, ShareableBitmap::Handle& snapshotHandle)
259 {
260     FrameView* frameView = m_mainFrame->coreFrame()->view();
261     if (!frameView)
262         return;
263
264     RefPtr<WebImage> snapshotImage = scaledSnapshotInViewCoordinates(rect, scaleFactor, ImageOptionsShareable);
265     if (!snapshotImage || !snapshotImage->bitmap())
266         return;
267
268     snapshotImage->bitmap()->createHandle(snapshotHandle);
269 }
270
271 void WebPage::requestUpdateFormNavigation()
272 {
273     Frame* frame = m_page->focusController()->focusedOrMainFrame();
274     if (!frame)
275         return;
276
277     Document* document = frame->document();
278     if (!document)
279         return;
280
281     Node* focusedNode = document->focusedNode();
282
283     Vector<RefPtr<Node> > focusableNodes;
284     document->getFocusableNodes(focusableNodes);
285
286     int formElementCount = 0;
287     int currentNodeIndex = -1;
288     const Vector<RefPtr<Node> >::iterator end = focusableNodes.end();
289     for (Vector<RefPtr<Node> >::iterator it = focusableNodes.begin(); it != end; ++it) {
290         AtomicString nodeName = (*it).get()->nodeName();
291         if ((equalIgnoringCase(nodeName, "INPUT") && !equalIgnoringCase((*it).get()->toInputElement()->type(), "CHECKBOX"))
292             || equalIgnoringCase(nodeName, "SELECT")) {
293             if ((*it).get() == focusedNode) {
294                 currentNodeIndex = formElementCount;
295             }
296             formElementCount++;
297         }
298     }
299
300     send(Messages::WebPageProxy::UpdateFormNavigation(formElementCount, currentNodeIndex));
301 }
302
303 void WebPage::moveFocus(int newIndex)
304 {
305     Frame* frame = m_page->focusController()->focusedOrMainFrame();
306     if (!frame)
307         return;
308
309     Document* document = frame->document();
310     if (!document)
311         return;
312
313     Vector<RefPtr<Node> > focusableNodes;
314     document->getFocusableNodes(focusableNodes);
315
316     int index = 0;
317     const Vector<RefPtr<Node> >::iterator end = focusableNodes.end();
318     for (Vector<RefPtr<Node> >::iterator it = focusableNodes.begin(); it != end; ++it) {
319         AtomicString nodeName = (*it).get()->nodeName();
320         if (equalIgnoringCase(nodeName, "SELECT")) {
321             if (index == newIndex) {
322                 (*it).get()->setFocus();
323                 LayoutPoint position = LayoutPoint(0, 0);
324                 PlatformMouseEvent event = PlatformMouseEvent(position, position, LeftButton, PlatformEvent::MouseMoved, 1, false, false, false, false, 0);
325                 (*it).get()->dispatchMouseEvent(event, "mousedown", 0, 0);
326             }
327             index++;
328         } else if (equalIgnoringCase(nodeName, "INPUT")
329             && !equalIgnoringCase((*it).get()->toInputElement()->type(), "CHECKBOX")) {
330             if (index == newIndex) {
331                 HTMLInputElement* elem = (*it).get()->toInputElement();
332                 elem->focus();
333             }
334             index++;
335         }
336     }
337 }
338
339 void WebPage::confirmComposition(const String& compositionString)
340 {
341     Frame* frame = m_page->focusController()->focusedOrMainFrame();
342     if (!frame || !frame->editor()->canEdit())
343         return;
344     frame->editor()->confirmComposition(compositionString);
345 }
346
347 void WebPage::setComposition(const String& compositionString, const Vector<WebCore::CompositionUnderline>& underlines, uint64_t cursorPosition)
348 {
349     Frame* frame = m_page->focusController()->focusedOrMainFrame();
350     if (!frame || !frame->editor()->canEdit())
351         return;
352     frame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
353 }
354
355 #if ENABLE(TIZEN_TEXT_CARET_HANDLING_WK2)
356 void WebPage::setCaretPosition(const WebCore::IntPoint& pos)
357 {
358     Frame* frame = m_page->focusController()->focusedOrMainFrame();
359     if (!frame)
360         return;
361
362     WebCore::FrameSelection* controller = frame->selection();
363     if (!controller)
364         return;
365
366     WebCore::IntPoint point = pos;
367
368     WebCore::HitTestResult result = frame->eventHandler()->hitTestResultAtPoint
369             (point, /*allowShadowContent*/ true, /*ignoreClipping*/ true);
370
371     if (result.scrollbar())
372         return;
373
374     WebCore::Node* innerNode = result.innerNode();
375
376     if (!innerNode || !innerNode->renderer())
377         return;
378
379     WebCore::VisiblePosition visiblePos;
380
381     const int boundariesWidth = 2;
382
383     // we check if content is richly editable - because those input field behave other than plain text ones
384     // sometimes they may consists a node structure and they need special approach
385     if (innerNode->rendererIsRichlyEditable()) {
386         // point gets inner node local coordinates
387         point = result.localPoint();
388         WebCore::IntRect rect = innerNode->renderer()->absoluteBoundingBoxRect(true);
389
390         // it is not the best way to do this, but it is not as slow and it works - so maybe in the future someone
391         // will have a better idea how to solve it
392         // here we are getting innerNode from HitTestResult - unfortunately this is a kind of high level node
393         // in the code below I am trying to obtain low level node - #text - to get its coordinates and size
394
395         // all those getting nodes rects are needed to bypass WebCore's methods of positioning caret when user
396         // is clicking outside a node - and cheat WebCore telling it that actually we clicked into input field
397         // node, not outside of it
398         WebCore::Node* deepInnerNode = innerNode->renderer()->positionForPoint(point).deepEquivalent().deprecatedNode();
399
400         if (!deepInnerNode || !deepInnerNode->renderer())
401             return;
402
403         // so we get a base node rectange
404         WebCore::IntRect deepNodeRect = deepInnerNode->renderer()->absoluteBoundingBoxRect(true);
405
406         // we modify our local point to adjust it to base node local coordinates
407         point.move(rect.x() - deepNodeRect.x(), rect.y() - deepNodeRect.y());
408
409         // if we are outside the rect we cheat, that we are just inside of it
410         if (point.y() < 0)
411             point.setY(0);
412         else if (point.y() >= deepNodeRect.height())
413             point.setY(deepNodeRect.height() - 1);
414
415         // visible position created - caret ready to set
416         visiblePos = deepInnerNode->renderer()->positionForPoint(point);
417         if (visiblePos.isNull())
418             return;
419     } else {
420         // for plain text input fields we can get only a caret bounding box
421         if (!controller->isCaret() || !controller->caretRenderer())
422             return;
423
424         const WebCore::Node* node = controller->start().deprecatedNode();
425         if (!node || !node->renderer())
426             return;
427
428         WebCore::IntRect rect = controller->caretRenderer()->absoluteBoundingBoxRect(true);
429
430         // here we also cheat input field that we actually are just inside of if
431         if (point.x() < rect.x())
432             point.setX(rect.x());
433         else if (point.x() > rect.maxX())
434             point.setX(rect.maxX());
435         if (point.y() < rect.y() + boundariesWidth)
436             point.setY(rect.y() + boundariesWidth);
437         else if (point.y() >= rect.maxY() - boundariesWidth)
438             point.setY(rect.maxY() - boundariesWidth - 1);
439
440         // hit test with fake (adjusted) coordinates
441         WebCore::HitTestResult newResult = frame->eventHandler()->hitTestResultAtPoint
442                 (point, /*allowShadowContent*/ true, /*ignoreClipping*/ true);
443
444         if (!newResult.isContentEditable())
445             return;
446
447         WebCore::Node* newInnerNode = newResult.innerNode();
448
449         if (!newInnerNode || !newInnerNode->renderer())
450             return;
451
452         // visible position created
453         visiblePos = newInnerNode->renderer()->positionForPoint(newResult.localPoint());
454         if (visiblePos.isNull())
455             return;
456     }
457
458     // create visible selection from visible position
459     WebCore::VisibleSelection newSelection = WebCore::VisibleSelection(visiblePos);
460     controller->setSelection(newSelection, WebCore::CharacterGranularity);
461     // after setting selection caret blinking is suspended by default so we are unsuspedning it
462     controller->setCaretBlinkingSuspended(false);
463 }
464
465 void WebPage::getCaretPosition(WebCore::IntRect& rect)
466 {
467     Frame* frame = m_page->focusController()->focusedOrMainFrame();
468     if (!frame)
469         return;
470
471     WebCore::FrameSelection* controller = frame->selection();
472     if (!controller)
473         return;
474
475     WebCore::Node* node = controller->start().deprecatedNode();
476     if (!node || !node->renderer() || !node->isContentEditable())
477         return;
478
479     if (controller->isCaret())
480         rect = controller->absoluteCaretBounds();
481 }
482 #endif
483
484 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
485 void WebPage::setFocusedInputElementValue(const String& inputValue)
486 {
487     Frame* frame = m_page->focusController()->focusedOrMainFrame();
488     if (frame
489         && frame->document()
490         && frame->document()->focusedNode()) {
491         Node* node = frame->document()->focusedNode();
492         if (node->nodeType() == Node::ELEMENT_NODE) {
493             if (node->hasTagName(HTMLNames::inputTag)) {
494                 static_cast<HTMLInputElement*>(node)->setValue(inputValue, true);
495             }
496         }
497     }
498 }
499 #endif
500
501 #if ENABLE(TIZEN_GESTURE)
502 void WebPage::setFocusToNodeAtPoint(const IntPoint& point)
503 {
504     Frame* frame = m_page->focusController()->focusedOrMainFrame();
505     FrameView* frameView = frame->view();
506     if (!frameView || (point.x() < 0 && point.y() < 0)) {
507         frame->document()->setFocusedNode(0);
508         return;
509     }
510
511     HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(frameView->windowToContents(point), false);
512     Node* node = result.innerNode();
513     while (node) {
514         if (node->isMouseFocusable()) {
515             frame->document()->setFocusedNode(node);
516             break;
517         }
518         node = node->parentOrHostNode();
519     }
520 }
521 #endif
522
523 void WebPage::hitTestResultAtPoint(const IntPoint& point, WebHitTestResult::Data& hitTestResultData)
524 {
525     Frame* frame = m_page->focusController()->focusedOrMainFrame();
526     FrameView* frameView = frame->view();
527     if (!frameView)
528         return;
529
530     HitTestResult hitTestResult = frame->eventHandler()->hitTestResultAtPoint(frameView->windowToContents(point), false);
531     hitTestResultData.absoluteImageURL = hitTestResult.absoluteImageURL().string();
532     hitTestResultData.absoluteLinkURL = hitTestResult.absoluteLinkURL().string();
533     hitTestResultData.absoluteMediaURL = hitTestResult.absoluteMediaURL().string();
534     hitTestResultData.linkLabel = hitTestResult.textContent();
535     hitTestResultData.linkTitle = hitTestResult.titleDisplayString();
536 }
537
538 #if ENABLE(TIZEN_SUPPORT_RSS_LINK_PARSING)
539 void WebPage::getRssItems(uint64_t callbackID)
540 {
541     if (!m_page->mainFrame())
542         return;
543     Document* document = m_page->mainFrame()->document();
544     if (!document)
545         return;
546     RefPtr<HTMLAllCollection>collection = document->all();
547
548     WTF::String Rss("application/rss+xml");
549     WTF::String Atom("application/atom+xml");
550     WTF::String Alternate("alternate");
551
552     Vector<RssItemEfl> rssItems;
553
554     for (Node* node = collection->firstItem(); node; node = collection->nextItem()) {
555         HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(node);
556         if (linkElement->rel() == Alternate) {
557             RssItemEfl::LinkTypeEfl type;
558             if (linkElement->type() == Rss)
559                 type = RssItemEfl::LINK_TYPE_EFL_RSS;
560             else if (linkElement->type() == Atom)
561                 type = RssItemEfl::LINK_TYPE_EFL_ATOM;
562             else
563                 continue;
564
565             RssItemEfl rssItem(linkElement->href(), linkElement->title(), type);
566             rssItems.append(rssItem);
567         }
568     }
569     send(Messages::WebPageProxy::GetRssItemsCallback(rssItems, callbackID));
570
571     return;
572 }
573 #endif // #if ENABLE(TIZEN_SUPPORT_RSS_LINK_PARSING)
574
575 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
576 void WebPage::recordingSurfaceSetEnableSet(bool enable)
577 {
578     m_recordingSurfaceSetEnable = enable;
579 }
580 #endif
581
582 #endif // #if !OS(TIZEN)
583
584 } // namespace WebKit