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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
31 #include "NotImplemented.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>
42 #include "Arguments.h"
43 #include "WebCoreArgumentCoders.h"
46 #include "WebPageProxyMessages.h"
47 #include <WebCore/FrameView.h>
49 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
50 #include <WebCore/HTMLInputElement.h>
51 #include <WebCore/HTMLNames.h>
54 #if ENABLE(TIZEN_SUPPORT_RSS_LINK_PARSING)
55 #include "HTMLLinkElement.h"
56 #include <WebCore/html/HTMLAllCollection.h>
57 #include <efl/RssItemEfl.h>
60 #endif // #if OS(TIZEN)
62 using namespace WebCore;
66 void WebPage::platformInitialize()
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);
77 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
82 static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
84 page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
87 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
93 bool WebPage::platformHasLocalDataForURL(const KURL&)
99 String WebPage::cachedResponseMIMETypeForURL(const KURL&)
105 bool WebPage::platformCanHandleRequest(const ResourceRequest&)
111 String WebPage::cachedSuggestedFilenameForURL(const KURL&)
117 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const KURL&)
124 const char* WebPage::interpretKeyEvent(const KeyboardEvent* evt)
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;
135 struct KeyDownEntry {
141 struct KeyPressEntry {
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" },
169 { VK_END, 0, "MoveToEndOfLine" },
170 { VK_END, ShiftKey, "MoveToEndOfLineAndModifySelection" },
171 { VK_END, CtrlKey, "MoveToEndOfDocument" },
172 { VK_END, CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection" },
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" },
180 { 'B', CtrlKey, "ToggleBold" },
181 { 'I', CtrlKey, "ToggleItalic" },
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" },
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" },
202 const char* WebPage::interpretKeyEvent(const KeyboardEvent* event)
204 ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
206 static HashMap<int, const char*>* keyDownCommandsMap = 0;
207 static HashMap<int, const char*>* keyPressCommandsMap = 0;
209 if (!keyDownCommandsMap) {
210 keyDownCommandsMap = new HashMap<int, const char*>;
211 keyPressCommandsMap = new HashMap<int, const char*>;
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);
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);
220 unsigned modifiers = 0;
221 if (event->shiftKey())
222 modifiers |= ShiftKey;
225 if (event->ctrlKey())
226 modifiers |= CtrlKey;
228 if (event->type() == eventNames().keydownEvent) {
229 int mapKey = modifiers << 16 | event->keyCode();
230 return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
233 int mapKey = modifiers << 16 | event->charCode();
234 return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
237 #if ENABLE(TIZEN_WEBKIT2_TILED_BACKING_STORE)
238 IntSize WebPage::contentsSize() const
240 FrameView* frameView = m_page->mainFrame()->view();
242 return IntSize(0, 0);
244 return frameView->contentsSize();
248 void WebPage::scrollMainFrameBy(const IntSize& scrollOffset)
250 m_page->mainFrame()->view()->scrollBy(scrollOffset);
253 void WebPage::scrollMainFrameTo(const IntPoint& scrollPosition)
255 m_page->mainFrame()->view()->setScrollPosition(scrollPosition);
258 void WebPage::createSnapshot(const IntRect rect, float scaleFactor, ShareableBitmap::Handle& snapshotHandle)
260 FrameView* frameView = m_mainFrame->coreFrame()->view();
264 RefPtr<WebImage> snapshotImage = scaledSnapshotInViewCoordinates(rect, scaleFactor, ImageOptionsShareable);
265 if (!snapshotImage || !snapshotImage->bitmap())
268 snapshotImage->bitmap()->createHandle(snapshotHandle);
271 void WebPage::requestUpdateFormNavigation()
273 Frame* frame = m_page->focusController()->focusedOrMainFrame();
277 Document* document = frame->document();
281 Node* focusedNode = document->focusedNode();
283 Vector<RefPtr<Node> > focusableNodes;
284 document->getFocusableNodes(focusableNodes);
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;
300 send(Messages::WebPageProxy::UpdateFormNavigation(formElementCount, currentNodeIndex));
303 void WebPage::moveFocus(int newIndex)
305 Frame* frame = m_page->focusController()->focusedOrMainFrame();
309 Document* document = frame->document();
313 Vector<RefPtr<Node> > focusableNodes;
314 document->getFocusableNodes(focusableNodes);
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);
328 } else if (equalIgnoringCase(nodeName, "INPUT")
329 && !equalIgnoringCase((*it).get()->toInputElement()->type(), "CHECKBOX")) {
330 if (index == newIndex) {
331 HTMLInputElement* elem = (*it).get()->toInputElement();
339 void WebPage::confirmComposition(const String& compositionString)
341 Frame* frame = m_page->focusController()->focusedOrMainFrame();
342 if (!frame || !frame->editor()->canEdit())
344 frame->editor()->confirmComposition(compositionString);
347 void WebPage::setComposition(const String& compositionString, const Vector<WebCore::CompositionUnderline>& underlines, uint64_t cursorPosition)
349 Frame* frame = m_page->focusController()->focusedOrMainFrame();
350 if (!frame || !frame->editor()->canEdit())
352 frame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
355 #if ENABLE(TIZEN_TEXT_CARET_HANDLING_WK2)
356 void WebPage::setCaretPosition(const WebCore::IntPoint& pos)
358 Frame* frame = m_page->focusController()->focusedOrMainFrame();
362 WebCore::FrameSelection* controller = frame->selection();
366 WebCore::IntPoint point = pos;
368 WebCore::HitTestResult result = frame->eventHandler()->hitTestResultAtPoint
369 (point, /*allowShadowContent*/ true, /*ignoreClipping*/ true);
371 if (result.scrollbar())
374 WebCore::Node* innerNode = result.innerNode();
376 if (!innerNode || !innerNode->renderer())
379 WebCore::VisiblePosition visiblePos;
381 const int boundariesWidth = 2;
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);
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
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();
400 if (!deepInnerNode || !deepInnerNode->renderer())
403 // so we get a base node rectange
404 WebCore::IntRect deepNodeRect = deepInnerNode->renderer()->absoluteBoundingBoxRect(true);
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());
409 // if we are outside the rect we cheat, that we are just inside of it
412 else if (point.y() >= deepNodeRect.height())
413 point.setY(deepNodeRect.height() - 1);
415 // visible position created - caret ready to set
416 visiblePos = deepInnerNode->renderer()->positionForPoint(point);
417 if (visiblePos.isNull())
420 // for plain text input fields we can get only a caret bounding box
421 if (!controller->isCaret() || !controller->caretRenderer())
424 const WebCore::Node* node = controller->start().deprecatedNode();
425 if (!node || !node->renderer())
428 WebCore::IntRect rect = controller->caretRenderer()->absoluteBoundingBoxRect(true);
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);
440 // hit test with fake (adjusted) coordinates
441 WebCore::HitTestResult newResult = frame->eventHandler()->hitTestResultAtPoint
442 (point, /*allowShadowContent*/ true, /*ignoreClipping*/ true);
444 if (!newResult.isContentEditable())
447 WebCore::Node* newInnerNode = newResult.innerNode();
449 if (!newInnerNode || !newInnerNode->renderer())
452 // visible position created
453 visiblePos = newInnerNode->renderer()->positionForPoint(newResult.localPoint());
454 if (visiblePos.isNull())
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);
465 void WebPage::getCaretPosition(WebCore::IntRect& rect)
467 Frame* frame = m_page->focusController()->focusedOrMainFrame();
471 WebCore::FrameSelection* controller = frame->selection();
475 WebCore::Node* node = controller->start().deprecatedNode();
476 if (!node || !node->renderer() || !node->isContentEditable())
479 if (controller->isCaret())
480 rect = controller->absoluteCaretBounds();
484 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
485 void WebPage::setFocusedInputElementValue(const String& inputValue)
487 Frame* frame = m_page->focusController()->focusedOrMainFrame();
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);
501 #if ENABLE(TIZEN_GESTURE)
502 void WebPage::setFocusToNodeAtPoint(const IntPoint& point)
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);
511 HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(frameView->windowToContents(point), false);
512 Node* node = result.innerNode();
514 if (node->isMouseFocusable()) {
515 frame->document()->setFocusedNode(node);
518 node = node->parentOrHostNode();
523 void WebPage::hitTestResultAtPoint(const IntPoint& point, WebHitTestResult::Data& hitTestResultData)
525 Frame* frame = m_page->focusController()->focusedOrMainFrame();
526 FrameView* frameView = frame->view();
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();
538 #if ENABLE(TIZEN_SUPPORT_RSS_LINK_PARSING)
539 void WebPage::getRssItems(uint64_t callbackID)
541 if (!m_page->mainFrame())
543 Document* document = m_page->mainFrame()->document();
546 RefPtr<HTMLAllCollection>collection = document->all();
548 WTF::String Rss("application/rss+xml");
549 WTF::String Atom("application/atom+xml");
550 WTF::String Alternate("alternate");
552 Vector<RssItemEfl> rssItems;
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;
565 RssItemEfl rssItem(linkElement->href(), linkElement->title(), type);
566 rssItems.append(rssItem);
569 send(Messages::WebPageProxy::GetRssItemsCallback(rssItems, callbackID));
573 #endif // #if ENABLE(TIZEN_SUPPORT_RSS_LINK_PARSING)
575 #if ENABLE(TIZEN_RECORDING_SURFACE_SET)
576 void WebPage::recordingSurfaceSetEnableSet(bool enable)
578 m_recordingSurfaceSetEnable = enable;
582 #endif // #if !OS(TIZEN)
584 } // namespace WebKit