2 Copyright (C) 2008, 2009 Nokia Corporation and/or its subsidiary(-ies)
3 Copyright (C) 2007 Staikos Computing Services Inc.
4 Copyright (C) 2007 Apple Inc.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
26 #include "qwebframe.h"
27 #include "qwebpage_p.h"
28 #include "qwebframe_p.h"
29 #include "qwebhistory.h"
30 #include "qwebhistory_p.h"
31 #include "qwebinspector.h"
32 #include "qwebinspector_p.h"
33 #include "qwebsettings.h"
34 #include "qwebkitplatformplugin.h"
35 #include "qwebkitversion.h"
37 #include "CSSComputedStyleDeclaration.h"
38 #include "CSSParser.h"
39 #include "ApplicationCacheStorage.h"
40 #include "BackForwardListImpl.h"
41 #include "MemoryCache.h"
43 #include "ChromeClientQt.h"
44 #include "ClientRect.h"
45 #include "ContextMenu.h"
46 #include "ContextMenuClientQt.h"
47 #include "ContextMenuController.h"
48 #if ENABLE(DEVICE_ORIENTATION)
49 #include "DeviceMotionClientQt.h"
50 #include "DeviceOrientationClientMock.h"
51 #include "DeviceOrientationClientQt.h"
53 #include "DocumentLoader.h"
54 #include "DragClientQt.h"
55 #include "DragController.h"
57 #include "DragSession.h"
59 #include "EditorClientQt.h"
60 #include "FocusController.h"
61 #include "FormState.h"
63 #include "FrameLoadRequest.h"
64 #include "FrameLoader.h"
65 #include "FrameLoader.h"
66 #include "FrameLoaderClientQt.h"
67 #include "FrameTree.h"
68 #include "FrameView.h"
69 #if ENABLE(GEOLOCATION)
70 #include "GeolocationClientMock.h"
71 #include "GeolocationClientQt.h"
72 #include "GeolocationController.h"
74 #include "GeolocationPermissionClientQt.h"
75 #include "HTMLFormElement.h"
76 #include "HTMLFrameOwnerElement.h"
77 #include "HTMLInputElement.h"
78 #include "HTMLNames.h"
79 #include "HitTestResult.h"
81 #include "InitWebCoreQt.h"
82 #include "InspectorClientQt.h"
83 #include "InspectorController.h"
84 #include "InspectorServerQt.h"
86 #include "LocalizedStrings.h"
87 #include "MIMETypeRegistry.h"
88 #include "NavigationAction.h"
89 #include "NetworkingContext.h"
91 #include "NotificationPresenterClientQt.h"
92 #include "NotImplemented.h"
94 #include "PageClientQt.h"
95 #include "PageGroup.h"
96 #include "Pasteboard.h"
97 #include "PlatformKeyboardEvent.h"
98 #include "PlatformTouchEvent.h"
99 #include "PlatformWheelEvent.h"
100 #include "PluginDatabase.h"
101 #include "PluginDatabase.h"
102 #include "PluginPackage.h"
103 #include "ProgressTracker.h"
104 #include "QtPlatformPlugin.h"
105 #include "RenderTextControl.h"
106 #include "RenderThemeQt.h"
107 #include "SchemeRegistry.h"
108 #include "Scrollbar.h"
109 #include "ScrollbarTheme.h"
110 #include "SecurityOrigin.h"
111 #include "Settings.h"
112 #if defined Q_OS_WIN32
113 #include "SystemInfo.h"
115 #include "TextIterator.h"
116 #include "WebEventConversion.h"
117 #include "WindowFeatures.h"
118 #include "WorkerThread.h"
121 #include <QApplication>
122 #include <QBasicTimer>
124 #include <QColorDialog>
126 #include <QDesktopWidget>
127 #include <QDragEnterEvent>
128 #include <QDragLeaveEvent>
129 #include <QDragMoveEvent>
130 #include <QDropEvent>
131 #include <QFileDialog>
132 #include <QInputDialog>
135 #include <QMessageBox>
136 #include <QNetworkProxy>
137 #include <QUndoStack>
140 #include <QClipboard>
141 #include <QSslSocket>
144 #include <QTextCharFormat>
145 #include <QTouchEvent>
146 #include <QNetworkAccessManager>
147 #include <QNetworkRequest>
148 #if defined(Q_WS_X11)
151 #if USE(QT_MOBILITY_SYSTEMINFO)
152 #include <qsysteminfo.h>
155 using namespace WebCore;
157 // from text/qfont.cpp
159 extern Q_GUI_EXPORT int qt_defaultDpi();
162 bool QWebPagePrivate::drtRun = false;
164 // Lookup table mapping QWebPage::WebActions to the associated Editor commands
165 static const char* editorCommandWebActions[] =
169 0, // OpenLinkInNewWindow,
170 0, // OpenFrameInNewWindow,
172 0, // DownloadLinkToDisk,
173 0, // CopyLinkToClipboard,
175 0, // OpenImageInNewWindow,
176 0, // DownloadImageToDisk,
177 0, // CopyImageToClipboard,
190 "MoveForward", // MoveToNextChar,
191 "MoveBackward", // MoveToPreviousChar,
192 "MoveWordForward", // MoveToNextWord,
193 "MoveWordBackward", // MoveToPreviousWord,
194 "MoveDown", // MoveToNextLine,
195 "MoveUp", // MoveToPreviousLine,
196 "MoveToBeginningOfLine", // MoveToStartOfLine,
197 "MoveToEndOfLine", // MoveToEndOfLine,
198 "MoveToBeginningOfParagraph", // MoveToStartOfBlock,
199 "MoveToEndOfParagraph", // MoveToEndOfBlock,
200 "MoveToBeginningOfDocument", // MoveToStartOfDocument,
201 "MoveToEndOfDocument", // MoveToEndOfDocument,
202 "MoveForwardAndModifySelection", // SelectNextChar,
203 "MoveBackwardAndModifySelection", // SelectPreviousChar,
204 "MoveWordForwardAndModifySelection", // SelectNextWord,
205 "MoveWordBackwardAndModifySelection", // SelectPreviousWord,
206 "MoveDownAndModifySelection", // SelectNextLine,
207 "MoveUpAndModifySelection", // SelectPreviousLine,
208 "MoveToBeginningOfLineAndModifySelection", // SelectStartOfLine,
209 "MoveToEndOfLineAndModifySelection", // SelectEndOfLine,
210 "MoveToBeginningOfParagraphAndModifySelection", // SelectStartOfBlock,
211 "MoveToEndOfParagraphAndModifySelection", // SelectEndOfBlock,
212 "MoveToBeginningOfDocumentAndModifySelection", //SelectStartOfDocument,
213 "MoveToEndOfDocumentAndModifySelection", // SelectEndOfDocument,
214 "DeleteWordBackward", // DeleteStartOfWord,
215 "DeleteWordForward", // DeleteEndOfWord,
217 0, // SetTextDirectionDefault,
218 0, // SetTextDirectionLeftToRight,
219 0, // SetTextDirectionRightToLeft,
221 "ToggleBold", // ToggleBold,
222 "ToggleItalic", // ToggleItalic,
223 "ToggleUnderline", // ToggleUnderline,
225 0, // InspectElement,
227 "InsertNewline", // InsertParagraphSeparator
228 "InsertLineBreak", // InsertLineSeparator
230 "SelectAll", // SelectAll
231 0, // ReloadAndBypassCache,
233 "PasteAndMatchStyle", // PasteAndMatchStyle
234 "RemoveFormat", // RemoveFormat
235 "Strikethrough", // ToggleStrikethrough,
236 "Subscript", // ToggleSubscript
237 "Superscript", // ToggleSuperscript
238 "InsertUnorderedList", // InsertUnorderedList
239 "InsertOrderedList", // InsertOrderedList
241 "Outdent", // Outdent,
243 "AlignCenter", // AlignCenter,
244 "AlignJustified", // AlignJustified,
245 "AlignLeft", // AlignLeft,
246 "AlignRight", // AlignRight,
248 0, // StopScheduledPageRefresh,
250 0, // CopyImageUrlToClipboard,
255 // Lookup the appropriate editor command to use for WebAction \a action
256 const char* QWebPagePrivate::editorCommandForWebActions(QWebPage::WebAction action)
258 if ((action > QWebPage::NoWebAction) && (action < int(sizeof(editorCommandWebActions) / sizeof(const char*))))
259 return editorCommandWebActions[action];
263 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
266 if (actions & Qt::CopyAction)
267 result |= DragOperationCopy;
268 // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
269 // hence it should be considered as "move"
270 if (actions & Qt::MoveAction)
271 result |= (DragOperationMove | DragOperationGeneric);
272 if (actions & Qt::LinkAction)
273 result |= DragOperationLink;
274 if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink))
275 result = DragOperationEvery;
276 return (DragOperation)result;
279 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
281 Qt::DropAction result = Qt::IgnoreAction;
282 if (actions & DragOperationCopy)
283 result = Qt::CopyAction;
284 else if (actions & DragOperationMove)
285 result = Qt::MoveAction;
286 // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
287 // hence it should be considered as "move"
288 else if (actions & DragOperationGeneric)
289 result = Qt::MoveAction;
290 else if (actions & DragOperationLink)
291 result = Qt::LinkAction;
295 QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
298 #ifndef QT_NO_UNDOSTACK
301 , insideOpenCall(false)
304 , clickCausedFocus(false)
306 , forwardUnsupportedContent(false)
307 , smartInsertDeleteEnabled(true)
308 , selectTrailingWhitespaceEnabled(false)
309 , linkPolicy(QWebPage::DontDelegateLinks)
310 , viewportSize(QSize(0, 0))
312 , useFixedLayout(false)
314 , inspectorFrontend(0)
316 , inspectorIsInternalOnly(false)
317 , m_lastDropAction(Qt::IgnoreAction)
319 #if ENABLE(GEOLOCATION) || ENABLE(DEVICE_ORIENTATION)
320 bool useMock = QWebPagePrivate::drtRun;
323 WebCore::initializeWebCoreQt();
325 Page::PageClients pageClients;
326 pageClients.chromeClient = new ChromeClientQt(q);
327 pageClients.contextMenuClient = new ContextMenuClientQt();
328 pageClients.editorClient = new EditorClientQt(q);
329 pageClients.dragClient = new DragClientQt(q);
330 pageClients.inspectorClient = new InspectorClientQt(q);
331 page = new Page(pageClients);
332 #if ENABLE(GEOLOCATION)
334 // In case running in DumpRenderTree mode set the controller to mock provider.
335 GeolocationClientMock* mock = new GeolocationClientMock;
336 WebCore::provideGeolocationTo(page, mock);
337 mock->setController(WebCore::GeolocationController::from(page));
339 WebCore::provideGeolocationTo(page, new GeolocationClientQt(q));
341 #if ENABLE(DEVICE_ORIENTATION)
343 WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientMock);
345 WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientQt);
346 WebCore::provideDeviceMotionTo(page, new DeviceMotionClientQt);
348 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
349 WebCore::provideNotification(page, NotificationPresenterClientQt::notificationPresenter());
352 // By default each page is put into their own unique page group, which affects popup windows
353 // and visited links. Page groups (per process only) is a feature making it possible to use
354 // separate settings for each group, so that for instance an integrated browser/email reader
355 // can use different settings for displaying HTML pages and HTML email. To make QtWebKit work
356 // as expected out of the box, we use a default group similar to what other ports are doing.
357 page->setGroupName("Default Group");
359 settings = new QWebSettings(page->settings());
361 history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList()));
362 memset(actions, 0, sizeof(actions));
364 PageGroup::setShouldTrackVisitedLinks(true);
366 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
367 NotificationPresenterClientQt::notificationPresenter()->addClient();
371 QWebPagePrivate::~QWebPagePrivate()
373 if (inspector && inspectorIsInternalOnly) {
374 // Since we have to delete an internal inspector,
375 // call setInspector(0) directly to prevent potential crashes
378 #ifndef QT_NO_CONTEXTMENU
379 delete currentContextMenu.data();
381 #ifndef QT_NO_UNDOSTACK
388 inspector->setPage(0);
390 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
391 NotificationPresenterClientQt::notificationPresenter()->removeClient();
395 WebCore::ViewportArguments QWebPagePrivate::viewportArguments()
397 return page ? page->viewportArguments() : WebCore::ViewportArguments();
400 WebCore::Page* QWebPagePrivate::core(const QWebPage* page)
402 return page->d->page;
405 QWebPagePrivate* QWebPagePrivate::priv(QWebPage* page)
410 bool QWebPagePrivate::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
413 && frame == mainFrame.data())
415 return q->acceptNavigationRequest(frame, request, type);
418 void QWebPagePrivate::createMainFrame()
421 QWebFrameData frameData(page);
422 mainFrame = new QWebFrame(q, &frameData);
424 emit q->frameCreated(mainFrame.data());
428 static QWebPage::WebAction webActionForContextMenuAction(WebCore::ContextMenuAction action)
431 case WebCore::ContextMenuItemTagOpenLink: return QWebPage::OpenLink;
432 case WebCore::ContextMenuItemTagOpenLinkInNewWindow: return QWebPage::OpenLinkInNewWindow;
433 case WebCore::ContextMenuItemTagDownloadLinkToDisk: return QWebPage::DownloadLinkToDisk;
434 case WebCore::ContextMenuItemTagCopyLinkToClipboard: return QWebPage::CopyLinkToClipboard;
435 case WebCore::ContextMenuItemTagOpenImageInNewWindow: return QWebPage::OpenImageInNewWindow;
436 case WebCore::ContextMenuItemTagDownloadImageToDisk: return QWebPage::DownloadImageToDisk;
437 case WebCore::ContextMenuItemTagCopyImageToClipboard: return QWebPage::CopyImageToClipboard;
438 case WebCore::ContextMenuItemTagCopyImageUrlToClipboard: return QWebPage::CopyImageUrlToClipboard;
439 case WebCore::ContextMenuItemTagOpenFrameInNewWindow: return QWebPage::OpenFrameInNewWindow;
440 case WebCore::ContextMenuItemTagCopy: return QWebPage::Copy;
441 case WebCore::ContextMenuItemTagGoBack: return QWebPage::Back;
442 case WebCore::ContextMenuItemTagGoForward: return QWebPage::Forward;
443 case WebCore::ContextMenuItemTagStop: return QWebPage::Stop;
444 case WebCore::ContextMenuItemTagReload: return QWebPage::Reload;
445 case WebCore::ContextMenuItemTagCut: return QWebPage::Cut;
446 case WebCore::ContextMenuItemTagPaste: return QWebPage::Paste;
447 case WebCore::ContextMenuItemTagDefaultDirection: return QWebPage::SetTextDirectionDefault;
448 case WebCore::ContextMenuItemTagLeftToRight: return QWebPage::SetTextDirectionLeftToRight;
449 case WebCore::ContextMenuItemTagRightToLeft: return QWebPage::SetTextDirectionRightToLeft;
450 case WebCore::ContextMenuItemTagBold: return QWebPage::ToggleBold;
451 case WebCore::ContextMenuItemTagItalic: return QWebPage::ToggleItalic;
452 case WebCore::ContextMenuItemTagUnderline: return QWebPage::ToggleUnderline;
453 case WebCore::ContextMenuItemTagSelectAll: return QWebPage::SelectAll;
454 #if ENABLE(INSPECTOR)
455 case WebCore::ContextMenuItemTagInspectElement: return QWebPage::InspectElement;
459 return QWebPage::NoWebAction;
462 #ifndef QT_NO_CONTEXTMENU
463 QMenu *QWebPagePrivate::createContextMenu(const WebCore::ContextMenu *webcoreMenu,
464 const QList<WebCore::ContextMenuItem> *items, QBitArray *visitedWebActions)
466 if (!client || !webcoreMenu)
469 QMenu* menu = new QMenu(client->ownerWidget());
470 for (int i = 0; i < items->count(); ++i) {
471 const ContextMenuItem &item = items->at(i);
472 switch (item.type()) {
473 case WebCore::CheckableActionType: /* fall through */
474 case WebCore::ActionType: {
475 QWebPage::WebAction action = webActionForContextMenuAction(item.action());
476 QAction *a = q->action(action);
478 ContextMenuItem it(item);
479 page->contextMenuController()->checkOrEnableIfNeeded(it);
480 PlatformMenuItemDescription desc = it.releasePlatformDescription();
481 a->setEnabled(desc.enabled);
482 a->setChecked(desc.checked);
483 a->setCheckable(item.type() == WebCore::CheckableActionType);
486 visitedWebActions->setBit(action);
490 case WebCore::SeparatorType:
491 menu->addSeparator();
493 case WebCore::SubmenuType: {
494 QMenu *subMenu = createContextMenu(webcoreMenu, item.platformSubMenu(), visitedWebActions);
496 bool anyEnabledAction = false;
498 QList<QAction *> actions = subMenu->actions();
499 for (int i = 0; i < actions.count(); ++i) {
500 if (actions.at(i)->isVisible())
501 anyEnabledAction |= actions.at(i)->isEnabled();
504 // don't show sub-menus with just disabled actions
505 if (anyEnabledAction) {
506 subMenu->setTitle(item.title());
507 menu->addAction(subMenu->menuAction());
516 #endif // QT_NO_CONTEXTMENU
519 void QWebPagePrivate::_q_webActionTriggered(bool checked)
521 QAction *a = qobject_cast<QAction *>(q->sender());
524 QWebPage::WebAction action = static_cast<QWebPage::WebAction>(a->data().toInt());
525 q->triggerAction(action, checked);
527 #endif // QT_NO_ACTION
529 void QWebPagePrivate::_q_cleanupLeakMessages()
532 // Need this to make leak messages accurate.
533 memoryCache()->setCapacities(0, 0, 0);
537 void QWebPagePrivate::updateAction(QWebPage::WebAction action)
542 QAction *a = actions[action];
543 if (!a || !mainFrame)
546 WebCore::FrameLoader *loader = mainFrame.data()->d->frame->loader();
547 WebCore::Editor *editor = page->focusController()->focusedOrMainFrame()->editor();
549 bool enabled = a->isEnabled();
550 bool checked = a->isChecked();
554 enabled = page->canGoBackOrForward(-1);
556 case QWebPage::Forward:
557 enabled = page->canGoBackOrForward(1);
560 enabled = loader->isLoading();
562 case QWebPage::Reload:
563 case QWebPage::ReloadAndBypassCache:
564 enabled = !loader->isLoading();
566 #ifndef QT_NO_UNDOSTACK
569 // those two are handled by QUndoStack
571 #endif // QT_NO_UNDOSTACK
572 case QWebPage::SelectAll: // editor command is always enabled
574 case QWebPage::SetTextDirectionDefault:
575 case QWebPage::SetTextDirectionLeftToRight:
576 case QWebPage::SetTextDirectionRightToLeft:
577 enabled = editor->canEdit();
581 // see if it's an editor command
582 const char* commandName = editorCommandForWebActions(action);
584 // if it's an editor command, let it's logic determine state
586 Editor::Command command = editor->command(commandName);
587 enabled = command.isEnabled();
589 checked = command.state() != FalseTriState;
597 a->setEnabled(enabled);
599 if (a->isCheckable())
600 a->setChecked(checked);
601 #endif // QT_NO_ACTION
604 void QWebPagePrivate::updateNavigationActions()
606 updateAction(QWebPage::Back);
607 updateAction(QWebPage::Forward);
608 updateAction(QWebPage::Stop);
609 updateAction(QWebPage::Reload);
610 updateAction(QWebPage::ReloadAndBypassCache);
613 void QWebPagePrivate::updateEditorActions()
615 updateAction(QWebPage::Cut);
616 updateAction(QWebPage::Copy);
617 updateAction(QWebPage::Paste);
618 updateAction(QWebPage::MoveToNextChar);
619 updateAction(QWebPage::MoveToPreviousChar);
620 updateAction(QWebPage::MoveToNextWord);
621 updateAction(QWebPage::MoveToPreviousWord);
622 updateAction(QWebPage::MoveToNextLine);
623 updateAction(QWebPage::MoveToPreviousLine);
624 updateAction(QWebPage::MoveToStartOfLine);
625 updateAction(QWebPage::MoveToEndOfLine);
626 updateAction(QWebPage::MoveToStartOfBlock);
627 updateAction(QWebPage::MoveToEndOfBlock);
628 updateAction(QWebPage::MoveToStartOfDocument);
629 updateAction(QWebPage::MoveToEndOfDocument);
630 updateAction(QWebPage::SelectNextChar);
631 updateAction(QWebPage::SelectPreviousChar);
632 updateAction(QWebPage::SelectNextWord);
633 updateAction(QWebPage::SelectPreviousWord);
634 updateAction(QWebPage::SelectNextLine);
635 updateAction(QWebPage::SelectPreviousLine);
636 updateAction(QWebPage::SelectStartOfLine);
637 updateAction(QWebPage::SelectEndOfLine);
638 updateAction(QWebPage::SelectStartOfBlock);
639 updateAction(QWebPage::SelectEndOfBlock);
640 updateAction(QWebPage::SelectStartOfDocument);
641 updateAction(QWebPage::SelectEndOfDocument);
642 updateAction(QWebPage::DeleteStartOfWord);
643 updateAction(QWebPage::DeleteEndOfWord);
644 updateAction(QWebPage::SetTextDirectionDefault);
645 updateAction(QWebPage::SetTextDirectionLeftToRight);
646 updateAction(QWebPage::SetTextDirectionRightToLeft);
647 updateAction(QWebPage::ToggleBold);
648 updateAction(QWebPage::ToggleItalic);
649 updateAction(QWebPage::ToggleUnderline);
650 updateAction(QWebPage::InsertParagraphSeparator);
651 updateAction(QWebPage::InsertLineSeparator);
652 updateAction(QWebPage::PasteAndMatchStyle);
653 updateAction(QWebPage::RemoveFormat);
654 updateAction(QWebPage::ToggleStrikethrough);
655 updateAction(QWebPage::ToggleSubscript);
656 updateAction(QWebPage::ToggleSuperscript);
657 updateAction(QWebPage::InsertUnorderedList);
658 updateAction(QWebPage::InsertOrderedList);
659 updateAction(QWebPage::Indent);
660 updateAction(QWebPage::Outdent);
661 updateAction(QWebPage::AlignCenter);
662 updateAction(QWebPage::AlignJustified);
663 updateAction(QWebPage::AlignLeft);
664 updateAction(QWebPage::AlignRight);
667 void QWebPagePrivate::timerEvent(QTimerEvent *ev)
669 int timerId = ev->timerId();
670 if (timerId == tripleClickTimer.timerId())
671 tripleClickTimer.stop();
677 void QWebPagePrivate::mouseMoveEvent(T* ev)
679 WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
683 bool accepted = frame->eventHandler()->mouseMoved(convertMouseEvent(ev, 0));
684 ev->setAccepted(accepted);
688 void QWebPagePrivate::mousePressEvent(T* ev)
690 WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
694 RefPtr<WebCore::Node> oldNode;
695 Frame* focusedFrame = page->focusController()->focusedFrame();
696 if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
697 oldNode = focusedDocument->focusedNode();
699 if (tripleClickTimer.isActive()
700 && (ev->pos() - tripleClick).manhattanLength()
701 < QApplication::startDragDistance()) {
702 mouseTripleClickEvent(ev);
706 bool accepted = false;
707 adjustPointForClicking(ev);
708 PlatformMouseEvent mev = convertMouseEvent(ev, 1);
709 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
710 if (mev.button() != NoButton)
711 accepted = frame->eventHandler()->handleMousePressEvent(mev);
712 ev->setAccepted(accepted);
714 RefPtr<WebCore::Node> newNode;
715 focusedFrame = page->focusController()->focusedFrame();
716 if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
717 newNode = focusedDocument->focusedNode();
719 if (newNode && oldNode != newNode)
720 clickCausedFocus = true;
724 void QWebPagePrivate::mouseDoubleClickEvent(T *ev)
726 WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
730 bool accepted = false;
731 PlatformMouseEvent mev = convertMouseEvent(ev, 2);
732 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
733 if (mev.button() != NoButton)
734 accepted = frame->eventHandler()->handleMousePressEvent(mev);
735 ev->setAccepted(accepted);
737 tripleClickTimer.start(QApplication::doubleClickInterval(), q);
738 tripleClick = QPointF(ev->pos()).toPoint();
742 void QWebPagePrivate::mouseTripleClickEvent(T *ev)
744 WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
748 bool accepted = false;
749 PlatformMouseEvent mev = convertMouseEvent(ev, 3);
750 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
751 if (mev.button() != NoButton)
752 accepted = frame->eventHandler()->handleMousePressEvent(mev);
753 ev->setAccepted(accepted);
756 void QWebPagePrivate::handleClipboard(QEvent* ev, Qt::MouseButton button)
758 #ifndef QT_NO_CLIPBOARD
759 if (QApplication::clipboard()->supportsSelection()) {
760 WebCore::Frame* focusFrame = page->focusController()->focusedOrMainFrame();
761 if (button == Qt::MidButton) {
763 focusFrame->editor()->command(AtomicString("PasteGlobalSelection")).execute();
764 ev->setAccepted(true);
772 void QWebPagePrivate::mouseReleaseEvent(T *ev)
774 WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
778 bool accepted = false;
779 adjustPointForClicking(ev);
780 PlatformMouseEvent mev = convertMouseEvent(ev, 0);
781 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
782 if (mev.button() != NoButton)
783 accepted = frame->eventHandler()->handleMouseReleaseEvent(mev);
784 ev->setAccepted(accepted);
786 if (!ev->isAccepted())
787 handleClipboard(ev, ev->button());
788 handleSoftwareInputPanel(ev->button(), QPointF(ev->pos()).toPoint());
791 void QWebPagePrivate::handleSoftwareInputPanel(Qt::MouseButton button, const QPoint& pos)
793 Frame* frame = page->focusController()->focusedFrame();
797 if (client && client->inputMethodEnabled()
798 && frame->document()->focusedNode()
799 && button == Qt::LeftButton && qApp->autoSipEnabled()) {
800 QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
801 client->ownerWidget()->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
802 if (!clickCausedFocus || behavior == QStyle::RSIP_OnMouseClick) {
803 HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(frame->view()->windowToContents(pos));
804 if (result.isContentEditable()) {
805 QEvent event(QEvent::RequestSoftwareInputPanel);
806 QApplication::sendEvent(client->ownerWidget(), &event);
811 clickCausedFocus = false;
814 #ifndef QT_NO_CONTEXTMENU
815 void QWebPagePrivate::contextMenuEvent(const QPoint& globalPos)
817 QMenu *menu = q->createStandardContextMenu();
819 menu->exec(globalPos);
823 #endif // QT_NO_CONTEXTMENU
827 This function creates the standard context menu which is shown when
828 the user clicks on the web page with the right mouse button. It is
829 called from the default contextMenuEvent() handler. The popup menu's
830 ownership is transferred to the caller.
832 QMenu *QWebPage::createStandardContextMenu()
834 #ifndef QT_NO_CONTEXTMENU
835 QMenu* menu = d->currentContextMenu.data();
836 d->currentContextMenu = 0;
843 #ifndef QT_NO_WHEELEVENT
845 void QWebPagePrivate::wheelEvent(T *ev)
847 WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
851 PlatformWheelEvent pev = convertWheelEvent(ev);
852 bool accepted = frame->eventHandler()->handleWheelEvent(pev);
853 ev->setAccepted(accepted);
855 #endif // QT_NO_WHEELEVENT
857 #ifndef QT_NO_SHORTCUT
858 QWebPage::WebAction QWebPagePrivate::editorActionForKeyEvent(QKeyEvent* event)
861 QKeySequence::StandardKey standardKey;
862 QWebPage::WebAction action;
863 } editorActions[] = {
864 { QKeySequence::Cut, QWebPage::Cut },
865 { QKeySequence::Copy, QWebPage::Copy },
866 { QKeySequence::Paste, QWebPage::Paste },
867 { QKeySequence::Undo, QWebPage::Undo },
868 { QKeySequence::Redo, QWebPage::Redo },
869 { QKeySequence::MoveToNextChar, QWebPage::MoveToNextChar },
870 { QKeySequence::MoveToPreviousChar, QWebPage::MoveToPreviousChar },
871 { QKeySequence::MoveToNextWord, QWebPage::MoveToNextWord },
872 { QKeySequence::MoveToPreviousWord, QWebPage::MoveToPreviousWord },
873 { QKeySequence::MoveToNextLine, QWebPage::MoveToNextLine },
874 { QKeySequence::MoveToPreviousLine, QWebPage::MoveToPreviousLine },
875 { QKeySequence::MoveToStartOfLine, QWebPage::MoveToStartOfLine },
876 { QKeySequence::MoveToEndOfLine, QWebPage::MoveToEndOfLine },
877 { QKeySequence::MoveToStartOfBlock, QWebPage::MoveToStartOfBlock },
878 { QKeySequence::MoveToEndOfBlock, QWebPage::MoveToEndOfBlock },
879 { QKeySequence::MoveToStartOfDocument, QWebPage::MoveToStartOfDocument },
880 { QKeySequence::MoveToEndOfDocument, QWebPage::MoveToEndOfDocument },
881 { QKeySequence::SelectNextChar, QWebPage::SelectNextChar },
882 { QKeySequence::SelectPreviousChar, QWebPage::SelectPreviousChar },
883 { QKeySequence::SelectNextWord, QWebPage::SelectNextWord },
884 { QKeySequence::SelectPreviousWord, QWebPage::SelectPreviousWord },
885 { QKeySequence::SelectNextLine, QWebPage::SelectNextLine },
886 { QKeySequence::SelectPreviousLine, QWebPage::SelectPreviousLine },
887 { QKeySequence::SelectStartOfLine, QWebPage::SelectStartOfLine },
888 { QKeySequence::SelectEndOfLine, QWebPage::SelectEndOfLine },
889 { QKeySequence::SelectStartOfBlock, QWebPage::SelectStartOfBlock },
890 { QKeySequence::SelectEndOfBlock, QWebPage::SelectEndOfBlock },
891 { QKeySequence::SelectStartOfDocument, QWebPage::SelectStartOfDocument },
892 { QKeySequence::SelectEndOfDocument, QWebPage::SelectEndOfDocument },
893 { QKeySequence::DeleteStartOfWord, QWebPage::DeleteStartOfWord },
894 { QKeySequence::DeleteEndOfWord, QWebPage::DeleteEndOfWord },
895 { QKeySequence::InsertParagraphSeparator, QWebPage::InsertParagraphSeparator },
896 { QKeySequence::InsertLineSeparator, QWebPage::InsertLineSeparator },
897 { QKeySequence::SelectAll, QWebPage::SelectAll },
898 { QKeySequence::UnknownKey, QWebPage::NoWebAction }
901 for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
902 if (event == editorActions[i].standardKey)
903 return editorActions[i].action;
905 return QWebPage::NoWebAction;
907 #endif // QT_NO_SHORTCUT
909 void QWebPagePrivate::keyPressEvent(QKeyEvent *ev)
911 bool handled = false;
912 WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
913 // we forward the key event to WebCore first to handle potential DOM
914 // defined event handlers and later on end up in EditorClientQt::handleKeyboardEvent
915 // to trigger editor commands via triggerAction().
917 handled = frame->eventHandler()->keyEvent(ev);
920 if (!handleScrolling(ev, frame)) {
923 q->triggerAction(QWebPage::Back);
925 case Qt::Key_Forward:
926 q->triggerAction(QWebPage::Forward);
929 q->triggerAction(QWebPage::Stop);
931 case Qt::Key_Refresh:
932 q->triggerAction(QWebPage::Reload);
934 case Qt::Key_Backspace:
935 if (ev->modifiers() == Qt::ShiftModifier)
936 q->triggerAction(QWebPage::Forward);
938 q->triggerAction(QWebPage::Back);
947 ev->setAccepted(handled);
950 void QWebPagePrivate::keyReleaseEvent(QKeyEvent *ev)
952 if (ev->isAutoRepeat()) {
953 ev->setAccepted(true);
957 WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
958 bool handled = frame->eventHandler()->keyEvent(ev);
959 ev->setAccepted(handled);
962 void QWebPagePrivate::focusInEvent(QFocusEvent*)
964 FocusController *focusController = page->focusController();
965 focusController->setActive(true);
966 focusController->setFocused(true);
967 if (!focusController->focusedFrame())
968 focusController->setFocusedFrame(QWebFramePrivate::core(mainFrame.data()));
971 void QWebPagePrivate::focusOutEvent(QFocusEvent*)
973 // only set the focused frame inactive so that we stop painting the caret
974 // and the focus frame. But don't tell the focus controller so that upon
975 // focusInEvent() we can re-activate the frame.
976 FocusController *focusController = page->focusController();
977 // Call setFocused first so that window.onblur doesn't get called twice
978 focusController->setFocused(false);
979 focusController->setActive(false);
983 void QWebPagePrivate::dragEnterEvent(T* ev)
985 #ifndef QT_NO_DRAGANDDROP
986 DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
987 QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
988 Qt::DropAction action = dragOpToDropAction(page->dragController()->dragEntered(&dragData).operation);
989 ev->setDropAction(action);
990 ev->acceptProposedAction();
995 void QWebPagePrivate::dragLeaveEvent(T *ev)
997 #ifndef QT_NO_DRAGANDDROP
998 DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
999 page->dragController()->dragExited(&dragData);
1005 void QWebPagePrivate::dragMoveEvent(T *ev)
1007 #ifndef QT_NO_DRAGANDDROP
1008 DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
1009 QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
1010 m_lastDropAction = dragOpToDropAction(page->dragController()->dragUpdated(&dragData).operation);
1011 ev->setDropAction(m_lastDropAction);
1012 if (m_lastDropAction != Qt::IgnoreAction)
1018 void QWebPagePrivate::dropEvent(T *ev)
1020 #ifndef QT_NO_DRAGANDDROP
1021 DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
1022 QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
1023 if (page->dragController()->performDrag(&dragData)) {
1024 ev->setDropAction(m_lastDropAction);
1030 void QWebPagePrivate::leaveEvent(QEvent*)
1032 // Fake a mouse move event just outside of the widget, since all
1033 // the interesting mouse-out behavior like invalidating scrollbars
1034 // is handled by the WebKit event handler's mouseMoved function.
1035 QMouseEvent fakeEvent(QEvent::MouseMove, QCursor::pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
1036 mouseMoveEvent(&fakeEvent);
1040 \property QWebPage::palette
1041 \brief the page's palette
1043 The base brush of the palette is used to draw the background of the main frame.
1045 By default, this property contains the application's default palette.
1047 void QWebPage::setPalette(const QPalette &pal)
1050 if (!d->mainFrame || !d->mainFrame.data()->d->frame->view())
1053 QBrush brush = pal.brush(QPalette::Base);
1054 QColor backgroundColor = brush.style() == Qt::SolidPattern ? brush.color() : QColor();
1055 QWebFramePrivate::core(d->mainFrame.data())->view()->updateBackgroundRecursively(backgroundColor, !backgroundColor.alpha());
1058 QPalette QWebPage::palette() const
1063 void QWebPagePrivate::inputMethodEvent(QInputMethodEvent *ev)
1065 WebCore::Frame *frame = page->focusController()->focusedOrMainFrame();
1066 WebCore::Editor *editor = frame->editor();
1068 if (!editor->canEdit()) {
1074 if (frame->selection()->rootEditableElement())
1075 node = frame->selection()->rootEditableElement()->shadowAncestorNode();
1077 Vector<CompositionUnderline> underlines;
1078 bool hasSelection = false;
1080 for (int i = 0; i < ev->attributes().size(); ++i) {
1081 const QInputMethodEvent::Attribute& a = ev->attributes().at(i);
1083 case QInputMethodEvent::TextFormat: {
1084 QTextCharFormat textCharFormat = a.value.value<QTextFormat>().toCharFormat();
1085 QColor qcolor = textCharFormat.underlineColor();
1086 underlines.append(CompositionUnderline(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)), Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())), false));
1089 case QInputMethodEvent::Cursor: {
1090 frame->selection()->setCaretVisible(a.length); //if length is 0 cursor is invisible
1092 RenderObject* caretRenderer = frame->selection()->caretRenderer();
1093 if (caretRenderer) {
1094 QColor qcolor = a.value.value<QColor>();
1095 caretRenderer->style()->setColor(Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())));
1100 case QInputMethodEvent::Selection: {
1101 hasSelection = true;
1102 // A selection in the inputMethodEvent is always reflected in the visible text
1104 if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
1105 textControl->setSelectionRange(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
1108 if (!ev->preeditString().isEmpty())
1109 editor->setComposition(ev->preeditString(), underlines, qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
1111 // If we are in the middle of a composition, an empty pre-edit string and a selection of zero
1112 // cancels the current composition
1113 if (editor->hasComposition() && (a.start + a.length == 0))
1114 editor->setComposition(QString(), underlines, 0, 0);
1123 if (node && ev->replacementLength() > 0) {
1124 int cursorPos = frame->selection()->extent().offsetInContainerNode();
1125 int start = cursorPos + ev->replacementStart();
1126 if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
1127 textControl->setSelectionRange(start, start + ev->replacementLength());
1128 // Commit regardless of whether commitString is empty, to get rid of selection.
1129 editor->confirmComposition(ev->commitString());
1130 } else if (!ev->commitString().isEmpty()) {
1131 if (editor->hasComposition())
1132 editor->confirmComposition(ev->commitString());
1134 editor->insertText(ev->commitString(), 0);
1135 } else if (!hasSelection && !ev->preeditString().isEmpty())
1136 editor->setComposition(ev->preeditString(), underlines, 0, 0);
1137 else if (ev->preeditString().isEmpty() && editor->hasComposition())
1138 editor->confirmComposition(String());
1143 #ifndef QT_NO_PROPERTIES
1146 double deferredRepaintDelay;
1147 double initialDeferredRepaintDelayDuringLoading;
1148 double maxDeferredRepaintDelayDuringLoading;
1149 double deferredRepaintDelayIncrementDuringLoading;
1150 } QRepaintThrottlingPreset;
1152 void QWebPagePrivate::dynamicPropertyChangeEvent(QDynamicPropertyChangeEvent* event)
1154 if (event->propertyName() == "_q_viewMode") {
1155 page->setViewMode(Page::stringToViewMode(q->property("_q_viewMode").toString()));
1156 } else if (event->propertyName() == "_q_HTMLTokenizerChunkSize") {
1157 int chunkSize = q->property("_q_HTMLTokenizerChunkSize").toInt();
1158 q->handle()->page->setCustomHTMLTokenizerChunkSize(chunkSize);
1159 } else if (event->propertyName() == "_q_HTMLTokenizerTimeDelay") {
1160 double timeDelay = q->property("_q_HTMLTokenizerTimeDelay").toDouble();
1161 q->handle()->page->setCustomHTMLTokenizerTimeDelay(timeDelay);
1162 } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelay") {
1163 double p = q->property("_q_RepaintThrottlingDeferredRepaintDelay").toDouble();
1164 FrameView::setRepaintThrottlingDeferredRepaintDelay(p);
1165 } else if (event->propertyName() == "_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading") {
1166 double p = q->property("_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading").toDouble();
1167 FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(p);
1168 } else if (event->propertyName() == "_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading") {
1169 double p = q->property("_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading").toDouble();
1170 FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(p);
1171 } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading") {
1172 double p = q->property("_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading").toDouble();
1173 FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(p);
1174 } else if (event->propertyName() == "_q_RepaintThrottlingPreset") {
1175 static const QRepaintThrottlingPreset presets[] = {
1176 { "NoThrottling", 0, 0, 0, 0 },
1177 { "Legacy", 0.025, 0, 2.5, 0.5 },
1178 { "Minimal", 0.01, 0, 1, 0.2 },
1179 { "Medium", 0.025, 1, 5, 0.5 },
1180 { "Heavy", 0.1, 2, 10, 1 }
1183 QString p = q->property("_q_RepaintThrottlingPreset").toString();
1184 for (size_t i = 0; i < sizeof(presets) / sizeof(presets[0]); i++) {
1185 if (p == QLatin1String(presets[i].name)) {
1186 FrameView::setRepaintThrottlingDeferredRepaintDelay(
1187 presets[i].deferredRepaintDelay);
1188 FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(
1189 presets[i].initialDeferredRepaintDelayDuringLoading);
1190 FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(
1191 presets[i].maxDeferredRepaintDelayDuringLoading);
1192 FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(
1193 presets[i].deferredRepaintDelayIncrementDuringLoading);
1198 else if (event->propertyName() == "_q_webInspectorServerPort") {
1199 InspectorServerQt* inspectorServer = InspectorServerQt::server();
1200 inspectorServer->listen(inspectorServerPort());
1201 } else if (event->propertyName() == "_q_deadDecodedDataDeletionInterval") {
1202 double interval = q->property("_q_deadDecodedDataDeletionInterval").toDouble();
1203 memoryCache()->setDeadDecodedDataDeletionInterval(interval);
1208 void QWebPagePrivate::shortcutOverrideEvent(QKeyEvent* event)
1210 WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
1211 WebCore::Editor* editor = frame->editor();
1212 if (editor->canEdit()) {
1213 if (event->modifiers() == Qt::NoModifier
1214 || event->modifiers() == Qt::ShiftModifier
1215 || event->modifiers() == Qt::KeypadModifier) {
1216 if (event->key() < Qt::Key_Escape) {
1219 switch (event->key()) {
1220 case Qt::Key_Return:
1222 case Qt::Key_Delete:
1225 case Qt::Key_Backspace:
1237 #ifndef QT_NO_SHORTCUT
1238 else if (editorActionForKeyEvent(event) != QWebPage::NoWebAction)
1244 bool QWebPagePrivate::handleScrolling(QKeyEvent *ev, Frame *frame)
1246 ScrollDirection direction;
1247 ScrollGranularity granularity;
1249 #ifndef QT_NO_SHORTCUT
1250 if (ev == QKeySequence::MoveToNextPage
1251 || (ev->key() == Qt::Key_Space && !(ev->modifiers() & Qt::ShiftModifier))) {
1252 granularity = ScrollByPage;
1253 direction = ScrollDown;
1254 } else if (ev == QKeySequence::MoveToPreviousPage
1255 || ((ev->key() == Qt::Key_Space) && (ev->modifiers() & Qt::ShiftModifier))) {
1256 granularity = ScrollByPage;
1257 direction = ScrollUp;
1259 #endif // QT_NO_SHORTCUT
1260 if ((ev->key() == Qt::Key_Up && ev->modifiers() & Qt::ControlModifier)
1261 || ev->key() == Qt::Key_Home) {
1262 granularity = ScrollByDocument;
1263 direction = ScrollUp;
1264 } else if ((ev->key() == Qt::Key_Down && ev->modifiers() & Qt::ControlModifier)
1265 || ev->key() == Qt::Key_End) {
1266 granularity = ScrollByDocument;
1267 direction = ScrollDown;
1269 switch (ev->key()) {
1271 granularity = ScrollByLine;
1272 direction = ScrollUp;
1275 granularity = ScrollByLine;
1276 direction = ScrollDown;
1279 granularity = ScrollByLine;
1280 direction = ScrollLeft;
1283 granularity = ScrollByLine;
1284 direction = ScrollRight;
1291 return frame->eventHandler()->scrollRecursively(direction, granularity);
1294 void QWebPagePrivate::adjustPointForClicking(QMouseEvent*)
1299 #if !defined(QT_NO_GRAPHICSVIEW)
1300 void QWebPagePrivate::adjustPointForClicking(QGraphicsSceneMouseEvent* ev)
1302 QtPlatformPlugin platformPlugin;
1303 OwnPtr<QWebTouchModifier> touchModifier = platformPlugin.createTouchModifier();
1307 unsigned topPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Up);
1308 unsigned rightPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Right);
1309 unsigned bottomPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Down);
1310 unsigned leftPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Left);
1312 touchModifier = nullptr;
1314 if (!topPadding && !rightPadding && !bottomPadding && !leftPadding)
1317 Document* startingDocument = page->mainFrame()->document();
1318 if (!startingDocument)
1321 IntPoint originalPoint(QPointF(ev->pos()).toPoint());
1322 TouchAdjuster touchAdjuster(topPadding, rightPadding, bottomPadding, leftPadding);
1323 IntPoint adjustedPoint = touchAdjuster.findCandidatePointForTouch(originalPoint, startingDocument);
1324 if (adjustedPoint == IntPoint::zero())
1327 ev->setPos(QPointF(adjustedPoint));
1331 bool QWebPagePrivate::touchEvent(QTouchEvent* event)
1333 #if ENABLE(TOUCH_EVENTS)
1334 WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
1338 // Always accept the QTouchEvent so that we'll receive also TouchUpdate and TouchEnd events
1339 event->setAccepted(true);
1341 // Return whether the default action was cancelled in the JS event handler
1342 return frame->eventHandler()->handleTouchEvent(convertTouchEvent(event));
1350 This method is used by the input method to query a set of properties of the page
1351 to be able to support complex input method operations as support for surrounding
1352 text and reconversions.
1354 \a property specifies which property is queried.
1356 \sa QWidget::inputMethodEvent(), QInputMethodEvent, QInputContext
1358 QVariant QWebPage::inputMethodQuery(Qt::InputMethodQuery property) const
1360 Frame* frame = d->page->focusController()->focusedFrame();
1364 WebCore::Editor* editor = frame->editor();
1366 RenderObject* renderer = 0;
1367 RenderTextControl* renderTextControl = 0;
1369 if (frame->selection()->rootEditableElement())
1370 renderer = frame->selection()->rootEditableElement()->shadowAncestorNode()->renderer();
1372 if (renderer && renderer->isTextControl())
1373 renderTextControl = toRenderTextControl(renderer);
1376 case Qt::ImMicroFocus: {
1377 WebCore::FrameView* view = frame->view();
1378 if (view && view->needsLayout()) {
1379 // We can't access absoluteCaretBounds() while the view needs to layout.
1382 return QVariant(view->contentsToWindow(frame->selection()->absoluteCaretBounds()));
1385 if (renderTextControl) {
1386 RenderStyle* renderStyle = renderTextControl->style();
1387 return QVariant(QFont(renderStyle->font().syntheticFont()));
1389 return QVariant(QFont());
1391 case Qt::ImCursorPosition: {
1392 if (editor->hasComposition())
1393 return QVariant(frame->selection()->end().offsetInContainerNode());
1394 return QVariant(frame->selection()->extent().offsetInContainerNode());
1396 case Qt::ImSurroundingText: {
1397 if (renderTextControl && renderTextControl->textFormControlElement()) {
1398 QString text = renderTextControl->textFormControlElement()->value();
1399 RefPtr<Range> range = editor->compositionRange();
1401 text.remove(range->startPosition().offsetInContainerNode(), TextIterator::rangeLength(range.get()));
1402 return QVariant(text);
1406 case Qt::ImCurrentSelection: {
1407 if (!editor->hasComposition() && renderTextControl && renderTextControl->textFormControlElement()) {
1408 int start = frame->selection()->start().offsetInContainerNode();
1409 int end = frame->selection()->end().offsetInContainerNode();
1411 return QVariant(QString(renderTextControl->textFormControlElement()->value()).mid(start, end - start));
1416 case Qt::ImAnchorPosition: {
1417 if (editor->hasComposition())
1418 return QVariant(frame->selection()->start().offsetInContainerNode());
1419 return QVariant(frame->selection()->base().offsetInContainerNode());
1421 case Qt::ImMaximumTextLength: {
1422 if (frame->selection()->isContentEditable()) {
1423 if (frame->document() && frame->document()->focusedNode()) {
1424 if (frame->document()->focusedNode()->hasTagName(HTMLNames::inputTag)) {
1425 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(frame->document()->focusedNode());
1426 return QVariant(inputElement->maxLength());
1429 return QVariant(HTMLInputElement::maximumLength);
1441 void QWebPagePrivate::setInspector(QWebInspector* insp)
1444 inspector->d->setFrontend(0);
1446 if (inspectorIsInternalOnly) {
1447 QWebInspector* inspToDelete = inspector;
1449 inspectorIsInternalOnly = false;
1450 delete inspToDelete; // Delete after to prevent infinite recursion
1455 // Give inspector frontend web view if previously created
1456 if (inspector && inspectorFrontend)
1457 inspector->d->setFrontend(inspectorFrontend);
1462 Returns the inspector and creates it if it wasn't created yet.
1463 The instance created here will not be available through QWebPage's API.
1465 QWebInspector* QWebPagePrivate::getOrCreateInspector()
1467 #if ENABLE(INSPECTOR)
1469 QWebInspector* insp = new QWebInspector;
1471 inspectorIsInternalOnly = true;
1473 Q_ASSERT(inspector); // Associated through QWebInspector::setPage(q)
1480 InspectorController* QWebPagePrivate::inspectorController()
1482 #if ENABLE(INSPECTOR)
1483 return page->inspectorController();
1489 quint16 QWebPagePrivate::inspectorServerPort()
1491 #if ENABLE(INSPECTOR) && !defined(QT_NO_PROPERTIES)
1492 if (q && q->property("_q_webInspectorServerPort").isValid())
1493 return q->property("_q_webInspectorServerPort").toInt();
1498 static bool hasMouseListener(Element* element)
1501 return element->hasEventListeners(eventNames().clickEvent)
1502 || element->hasEventListeners(eventNames().mousedownEvent)
1503 || element->hasEventListeners(eventNames().mouseupEvent);
1506 static bool isClickableElement(Element* element, RefPtr<NodeList> list)
1509 bool isClickable = hasMouseListener(element);
1510 if (!isClickable && list) {
1511 Element* parent = element->parentElement();
1512 unsigned count = list->length();
1513 for (unsigned i = 0; i < count && parent; i++) {
1514 if (list->item(i) != parent)
1517 isClickable = hasMouseListener(parent);
1521 parent = parent->parentElement();
1525 ExceptionCode ec = 0;
1527 || element->webkitMatchesSelector("a,*:link,*:visited,*[role=button],button,input,select,label", ec)
1528 || CSSComputedStyleDeclaration::create(element)->getPropertyValue(cssPropertyID("cursor")) == "pointer";
1531 static bool isValidFrameOwner(Element* element)
1534 return element->isFrameOwnerElement() && static_cast<HTMLFrameOwnerElement*>(element)->contentFrame();
1537 static Element* nodeToElement(Node* node)
1539 if (node && node->isElementNode())
1540 return static_cast<Element*>(node);
1544 QWebPagePrivate::TouchAdjuster::TouchAdjuster(unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
1545 : m_topPadding(topPadding)
1546 , m_rightPadding(rightPadding)
1547 , m_bottomPadding(bottomPadding)
1548 , m_leftPadding(leftPadding)
1552 IntPoint QWebPagePrivate::TouchAdjuster::findCandidatePointForTouch(const IntPoint& touchPoint, Document* document) const
1557 int x = touchPoint.x();
1558 int y = touchPoint.y();
1560 RefPtr<NodeList> intersectedNodes = document->nodesFromRect(x, y, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding);
1561 if (!intersectedNodes)
1564 Element* closestClickableElement = 0;
1565 IntRect largestIntersectionRect;
1566 FrameView* view = document->frame()->view();
1568 // Touch rect in contents coordinates.
1569 IntRect touchRect(HitTestResult::rectForPoint(view->windowToContents(IntPoint(x, y)), m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding));
1571 // Iterate over the list of nodes hit looking for the one whose bounding area
1572 // has largest intersection with the touch area (point + padding).
1573 for (unsigned i = 0; i < intersectedNodes->length(); i++) {
1574 Node* currentNode = intersectedNodes->item(i);
1576 Element* currentElement = nodeToElement(currentNode);
1577 if (!currentElement || (!isClickableElement(currentElement, 0) && !isValidFrameOwner(currentElement)))
1580 IntRect currentElementBoundingRect = currentElement->getPixelSnappedRect();
1581 currentElementBoundingRect.intersect(touchRect);
1583 if (currentElementBoundingRect.isEmpty())
1586 int currentIntersectionRectArea = currentElementBoundingRect.width() * currentElementBoundingRect.height();
1587 int largestIntersectionRectArea = largestIntersectionRect.width() * largestIntersectionRect.height();
1588 if (currentIntersectionRectArea > largestIntersectionRectArea) {
1589 closestClickableElement = currentElement;
1590 largestIntersectionRect = currentElementBoundingRect;
1594 if (largestIntersectionRect.isEmpty())
1597 // Handle the case when user taps a inner frame. It is done in three steps:
1598 // 1) Transform the original touch point to the inner document coordinates;
1599 // 1) Call nodesFromRect for the inner document in case;
1600 // 3) Re-add the inner frame offset (location) before passing the new clicking
1601 // position to WebCore.
1602 if (closestClickableElement->isFrameOwnerElement()) {
1603 // Adjust client coordinates' origin to be top left of inner frame viewport.
1604 PassRefPtr<ClientRect> rect = closestClickableElement->getBoundingClientRect();
1605 IntPoint newTouchPoint = touchPoint;
1606 IntSize offset = IntSize(rect->left(), rect->top());
1607 newTouchPoint -= offset;
1609 HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(closestClickableElement);
1610 Document* childDocument = owner->contentFrame()->document();
1611 return findCandidatePointForTouch(newTouchPoint, childDocument);
1613 return view->contentsToWindow(largestIntersectionRect).center();
1617 \enum QWebPage::FindFlag
1619 This enum describes the options available to the findText() function. The options
1620 can be OR-ed together from the following list:
1622 \value FindBackward Searches backwards instead of forwards.
1623 \value FindCaseSensitively By default findText() works case insensitive. Specifying this option
1624 changes the behaviour to a case sensitive find operation.
1625 \value FindWrapsAroundDocument Makes findText() restart from the beginning of the document if the end
1626 was reached and the text was not found.
1627 \value HighlightAllOccurrences Highlights all existing occurrences of a specific string.
1628 (This value was introduced in 4.6.)
1632 \enum QWebPage::LinkDelegationPolicy
1634 This enum defines the delegation policies a webpage can have when activating links and emitting
1635 the linkClicked() signal.
1637 \value DontDelegateLinks No links are delegated. Instead, QWebPage tries to handle them all.
1638 \value DelegateExternalLinks When activating links that point to documents not stored on the
1639 local filesystem or an equivalent - such as the Qt resource system - then linkClicked() is emitted.
1640 \value DelegateAllLinks Whenever a link is activated the linkClicked() signal is emitted.
1642 \sa QWebPage::linkDelegationPolicy
1646 \enum QWebPage::NavigationType
1648 This enum describes the types of navigation available when browsing through hyperlinked
1651 \value NavigationTypeLinkClicked The user clicked on a link or pressed return on a focused link.
1652 \value NavigationTypeFormSubmitted The user activated a submit button for an HTML form.
1653 \value NavigationTypeBackOrForward Navigation to a previously shown document in the back or forward history is requested.
1654 \value NavigationTypeReload The user activated the reload action.
1655 \value NavigationTypeFormResubmitted An HTML form was submitted a second time.
1656 \value NavigationTypeOther A navigation to another document using a method not listed above.
1658 \sa acceptNavigationRequest()
1662 \enum QWebPage::WebAction
1664 This enum describes the types of action which can be performed on the web page.
1666 Actions only have an effect when they are applicable. The availability of
1667 actions can be be determined by checking \l{QAction::}{isEnabled()} on the
1668 action returned by action().
1670 One method of enabling the text editing, cursor movement, and text selection actions
1671 is by setting \l contentEditable to true.
1673 \value NoWebAction No action is triggered.
1674 \value OpenLink Open the current link.
1675 \value OpenLinkInNewWindow Open the current link in a new window.
1676 \value OpenFrameInNewWindow Replicate the current frame in a new window.
1677 \value DownloadLinkToDisk Download the current link to the disk.
1678 \value CopyLinkToClipboard Copy the current link to the clipboard.
1679 \value OpenImageInNewWindow Open the highlighted image in a new window.
1680 \value DownloadImageToDisk Download the highlighted image to the disk.
1681 \value CopyImageToClipboard Copy the highlighted image to the clipboard. (Added in Qt 4.8)
1682 \value CopyImageUrlToClipboard Copy the highlighted image's URL to the clipboard.
1683 \value Back Navigate back in the history of navigated links.
1684 \value Forward Navigate forward in the history of navigated links.
1685 \value Stop Stop loading the current page.
1686 \value StopScheduledPageRefresh Stop all pending page refresh/redirect requests. (Added in Qt 4.7)
1687 \value Reload Reload the current page.
1688 \value ReloadAndBypassCache Reload the current page, but do not use any local cache. (Added in Qt 4.6)
1689 \value Cut Cut the content currently selected into the clipboard.
1690 \value Copy Copy the content currently selected into the clipboard.
1691 \value Paste Paste content from the clipboard.
1692 \value Undo Undo the last editing action.
1693 \value Redo Redo the last editing action.
1694 \value MoveToNextChar Move the cursor to the next character.
1695 \value MoveToPreviousChar Move the cursor to the previous character.
1696 \value MoveToNextWord Move the cursor to the next word.
1697 \value MoveToPreviousWord Move the cursor to the previous word.
1698 \value MoveToNextLine Move the cursor to the next line.
1699 \value MoveToPreviousLine Move the cursor to the previous line.
1700 \value MoveToStartOfLine Move the cursor to the start of the line.
1701 \value MoveToEndOfLine Move the cursor to the end of the line.
1702 \value MoveToStartOfBlock Move the cursor to the start of the block.
1703 \value MoveToEndOfBlock Move the cursor to the end of the block.
1704 \value MoveToStartOfDocument Move the cursor to the start of the document.
1705 \value MoveToEndOfDocument Move the cursor to the end of the document.
1706 \value SelectNextChar Select to the next character.
1707 \value SelectPreviousChar Select to the previous character.
1708 \value SelectNextWord Select to the next word.
1709 \value SelectPreviousWord Select to the previous word.
1710 \value SelectNextLine Select to the next line.
1711 \value SelectPreviousLine Select to the previous line.
1712 \value SelectStartOfLine Select to the start of the line.
1713 \value SelectEndOfLine Select to the end of the line.
1714 \value SelectStartOfBlock Select to the start of the block.
1715 \value SelectEndOfBlock Select to the end of the block.
1716 \value SelectStartOfDocument Select to the start of the document.
1717 \value SelectEndOfDocument Select to the end of the document.
1718 \value DeleteStartOfWord Delete to the start of the word.
1719 \value DeleteEndOfWord Delete to the end of the word.
1720 \value SetTextDirectionDefault Set the text direction to the default direction.
1721 \value SetTextDirectionLeftToRight Set the text direction to left-to-right.
1722 \value SetTextDirectionRightToLeft Set the text direction to right-to-left.
1723 \value ToggleBold Toggle the formatting between bold and normal weight.
1724 \value ToggleItalic Toggle the formatting between italic and normal style.
1725 \value ToggleUnderline Toggle underlining.
1726 \value InspectElement Show the Web Inspector with the currently highlighted HTML element.
1727 \value InsertParagraphSeparator Insert a new paragraph.
1728 \value InsertLineSeparator Insert a new line.
1729 \value SelectAll Selects all content.
1730 \value PasteAndMatchStyle Paste content from the clipboard with current style. (Added in Qt 4.6)
1731 \value RemoveFormat Removes formatting and style. (Added in Qt 4.6)
1732 \value ToggleStrikethrough Toggle the formatting between strikethrough and normal style. (Added in Qt 4.6)
1733 \value ToggleSubscript Toggle the formatting between subscript and baseline. (Added in Qt 4.6)
1734 \value ToggleSuperscript Toggle the formatting between supercript and baseline. (Added in Qt 4.6)
1735 \value InsertUnorderedList Toggles the selection between an ordered list and a normal block. (Added in Qt 4.6)
1736 \value InsertOrderedList Toggles the selection between an ordered list and a normal block. (Added in Qt 4.6)
1737 \value Indent Increases the indentation of the currently selected format block by one increment. (Added in Qt 4.6)
1738 \value Outdent Decreases the indentation of the currently selected format block by one increment. (Added in Qt 4.6)
1739 \value AlignCenter Applies center alignment to content. (Added in Qt 4.6)
1740 \value AlignJustified Applies full justification to content. (Added in Qt 4.6)
1741 \value AlignLeft Applies left justification to content. (Added in Qt 4.6)
1742 \value AlignRight Applies right justification to content. (Added in Qt 4.6)
1745 \omitvalue WebActionCount
1750 \enum QWebPage::WebWindowType
1752 This enum describes the types of window that can be created by the createWindow() function.
1754 \value WebBrowserWindow The window is a regular web browser window.
1755 \value WebModalDialog The window acts as modal dialog.
1760 \class QWebPage::ViewportAttributes
1762 \brief The QWebPage::ViewportAttributes class describes hints that can be applied to a viewport.
1764 QWebPage::ViewportAttributes provides a description of a viewport, such as viewport geometry,
1765 initial scale factor with limits, plus information about whether a user should be able
1766 to scale the contents in the viewport or not, ie. by zooming.
1768 ViewportAttributes can be set by a web author using the viewport meta tag extension, documented
1769 at \l{http://developer.apple.com/safari/library/documentation/appleapplications/reference/safariwebcontent/usingtheviewport/usingtheviewport.html}{Safari Reference Library: Using the Viewport Meta Tag}.
1771 All values might not be set, as such when dealing with the hints, the developer needs to
1772 check whether the values are valid. Negative values denote an invalid qreal value.
1778 Constructs an empty QWebPage::ViewportAttributes.
1780 QWebPage::ViewportAttributes::ViewportAttributes()
1782 , m_initialScaleFactor(-1.0)
1783 , m_minimumScaleFactor(-1.0)
1784 , m_maximumScaleFactor(-1.0)
1785 , m_devicePixelRatio(-1.0)
1786 , m_isUserScalable(true)
1793 Constructs a QWebPage::ViewportAttributes which is a copy from \a other .
1795 QWebPage::ViewportAttributes::ViewportAttributes(const QWebPage::ViewportAttributes& other)
1797 , m_initialScaleFactor(other.m_initialScaleFactor)
1798 , m_minimumScaleFactor(other.m_minimumScaleFactor)
1799 , m_maximumScaleFactor(other.m_maximumScaleFactor)
1800 , m_devicePixelRatio(other.m_devicePixelRatio)
1801 , m_isUserScalable(other.m_isUserScalable)
1802 , m_isValid(other.m_isValid)
1803 , m_size(other.m_size)
1809 Destroys the QWebPage::ViewportAttributes.
1811 QWebPage::ViewportAttributes::~ViewportAttributes()
1817 Assigns the given QWebPage::ViewportAttributes to this viewport hints and returns a
1820 QWebPage::ViewportAttributes& QWebPage::ViewportAttributes::operator=(const QWebPage::ViewportAttributes& other)
1822 if (this != &other) {
1824 m_initialScaleFactor = other.m_initialScaleFactor;
1825 m_minimumScaleFactor = other.m_minimumScaleFactor;
1826 m_maximumScaleFactor = other.m_maximumScaleFactor;
1827 m_isUserScalable = other.m_isUserScalable;
1828 m_isValid = other.m_isValid;
1829 m_size = other.m_size;
1835 /*! \fn inline bool QWebPage::ViewportAttributes::isValid() const
1836 Returns whether this is a valid ViewportAttributes or not.
1838 An invalid ViewportAttributes will have an empty QSize, negative values for scale factors and
1839 true for the boolean isUserScalable.
1842 /*! \fn inline QSize QWebPage::ViewportAttributes::size() const
1843 Returns the size of the viewport.
1846 /*! \fn inline qreal QWebPage::ViewportAttributes::initialScaleFactor() const
1847 Returns the initial scale of the viewport as a multiplier.
1850 /*! \fn inline qreal QWebPage::ViewportAttributes::minimumScaleFactor() const
1851 Returns the minimum scale value of the viewport as a multiplier.
1854 /*! \fn inline qreal QWebPage::ViewportAttributes::maximumScaleFactor() const
1855 Returns the maximum scale value of the viewport as a multiplier.
1858 /*! \fn inline bool QWebPage::ViewportAttributes::isUserScalable() const
1859 Determines whether or not the scale can be modified by the user.
1866 \brief The QWebPage class provides an object to view and edit web documents.
1870 QWebPage holds a main frame responsible for web content, settings, the history
1871 of navigated links and actions. This class can be used, together with QWebFrame,
1872 to provide functionality like QWebView in a widget-less environment.
1874 QWebPage's API is very similar to QWebView, as you are still provided with
1875 common functions like action() (known as
1876 \l{QWebView::pageAction()}{pageAction}() in QWebView), triggerAction(),
1877 findText() and settings(). More QWebView-like functions can be found in the
1878 main frame of QWebPage, obtained via the mainFrame() function. For example,
1879 the \l{QWebFrame::load()}{load}(), \l{QWebFrame::setUrl()}{setUrl}() and
1880 \l{QWebFrame::setHtml()}{setHtml}() functions for QWebPage can be accessed
1883 The loadStarted() signal is emitted when the page begins to load.The
1884 loadProgress() signal, on the other hand, is emitted whenever an element
1885 of the web page completes loading, such as an embedded image, a script,
1886 etc. Finally, the loadFinished() signal is emitted when the page contents
1887 are loaded completely, independent of script execution or page rendering.
1888 Its argument, either true or false, indicates whether or not the load
1889 operation succeeded.
1891 \section1 Using QWebPage in a Widget-less Environment
1893 Before you begin painting a QWebPage object, you need to set the size of
1894 the viewport by calling setViewportSize(). Then, you invoke the main
1895 frame's render function (QWebFrame::render()). An example of this
1896 is shown in the code snippet below.
1898 Suppose we have a \c Thumbnail class as follows:
1900 \snippet webkitsnippets/webpage/main.cpp 0
1902 The \c Thumbnail's constructor takes in a \a url. We connect our QWebPage
1903 object's \l{QWebPage::}{loadFinished()} signal to our private slot,
1906 \snippet webkitsnippets/webpage/main.cpp 1
1908 The \c render() function shows how we can paint a thumbnail using a
1911 \snippet webkitsnippets/webpage/main.cpp 2
1913 We begin by setting the \l{QWebPage::viewportSize()}{viewportSize} and
1914 then we instantiate a QImage object, \c image, with the same size as our
1915 \l{QWebPage::viewportSize()}{viewportSize}. This image is then sent
1916 as a parameter to \c painter. Next, we render the contents of the main
1917 frame and its subframes into \c painter. Finally, we save the scaled image.
1923 Constructs an empty QWebPage with parent \a parent.
1925 QWebPage::QWebPage(QObject *parent)
1927 , d(new QWebPagePrivate(this))
1929 setView(qobject_cast<QWidget*>(parent));
1931 connect(this, SIGNAL(loadProgress(int)), this, SLOT(_q_onLoadProgressChanged(int)));
1933 connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(_q_cleanupLeakMessages()));
1938 Destroys the web page.
1940 QWebPage::~QWebPage()
1942 d->createMainFrame();
1943 FrameLoader* loader = d->mainFrame.data()->d->frame->loader();
1945 loader->detachFromParent();
1950 Returns the main frame of the page.
1952 The main frame provides access to the hierarchy of sub-frames and is also needed if you
1953 want to explicitly render a web page into a given painter.
1957 QWebFrame *QWebPage::mainFrame() const
1959 d->createMainFrame();
1960 return d->mainFrame.data();
1964 Returns the frame currently active.
1966 \sa mainFrame(), frameCreated()
1968 QWebFrame *QWebPage::currentFrame() const
1970 d->createMainFrame();
1971 WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
1972 return qobject_cast<QWebFrame*>(frame->loader()->networkingContext()->originatingObject());
1979 Returns the frame at the given point \a pos, or 0 if there is no frame at
1982 \sa mainFrame(), currentFrame()
1984 QWebFrame* QWebPage::frameAt(const QPoint& pos) const
1986 QWebFrame* webFrame = mainFrame();
1987 if (!webFrame->geometry().contains(pos))
1989 QWebHitTestResult hitTestResult = webFrame->hitTestContent(pos);
1990 return hitTestResult.frame();
1994 Returns a pointer to the view's history of navigated web pages.
1996 QWebHistory *QWebPage::history() const
1998 d->createMainFrame();
2003 Sets the \a view that is associated with the web page.
2007 void QWebPage::setView(QWidget* view)
2009 if (this->view() == view)
2013 setViewportSize(view ? view->size() : QSize(0, 0));
2015 // If we have no client, we install a special client delegating
2016 // the responsibility to the QWidget. This is the code path
2017 // handling a.o. the "legacy" QWebView.
2019 // If such a special delegate already exist, we substitute the view.
2022 if (d->client->isQWidgetClient())
2023 static_cast<PageClientQWidget*>(d->client.get())->view = view;
2028 d->client = adoptPtr(new PageClientQWidget(view, this));
2032 Returns the view widget that is associated with the web page.
2036 QWidget *QWebPage::view() const
2038 return d->view.data();
2042 This function is called whenever a JavaScript program tries to print a \a message to the web browser's console.
2044 For example in case of evaluation errors the source URL may be provided in \a sourceID as well as the \a lineNumber.
2046 The default implementation prints nothing.
2048 void QWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID)
2052 // Catch plugin logDestroy message for LayoutTests/plugins/open-and-close-window-with-plugin.html
2053 // At this point DRT's WebPage has already been destroyed
2054 if (QWebPagePrivate::drtRun) {
2055 if (message == QLatin1String("PLUGIN: NPP_Destroy")) {
2056 fprintf(stdout, "CONSOLE MESSAGE: ");
2058 fprintf(stdout, "line %d: ", lineNumber);
2059 fprintf(stdout, "%s\n", message.toUtf8().constData());
2065 This function is called whenever a JavaScript program running inside \a frame calls the alert() function with
2068 The default implementation shows the message, \a msg, with QMessageBox::information.
2070 void QWebPage::javaScriptAlert(QWebFrame *frame, const QString& msg)
2073 #ifndef QT_NO_MESSAGEBOX
2074 QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2075 QMessageBox box(parent);
2076 box.setWindowTitle(tr("JavaScript Alert - %1").arg(mainFrame()->url().host()));
2077 box.setTextFormat(Qt::PlainText);
2079 box.setStandardButtons(QMessageBox::Ok);
2085 This function is called whenever a JavaScript program running inside \a frame calls the confirm() function
2086 with the message, \a msg. Returns true if the user confirms the message; otherwise returns false.
2088 The default implementation executes the query using QMessageBox::information with QMessageBox::Ok and QMessageBox::Cancel buttons.
2090 bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg)
2093 #ifdef QT_NO_MESSAGEBOX
2096 QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2097 QMessageBox box(parent);
2098 box.setWindowTitle(tr("JavaScript Confirm - %1").arg(mainFrame()->url().host()));
2099 box.setTextFormat(Qt::PlainText);
2101 box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
2102 return QMessageBox::Ok == box.exec();
2107 This function is called whenever a JavaScript program running inside \a frame tries to prompt the user for input.
2108 The program may provide an optional message, \a msg, as well as a default value for the input in \a defaultValue.
2110 If the prompt was cancelled by the user the implementation should return false; otherwise the
2111 result should be written to \a result and true should be returned. If the prompt was not cancelled by the
2112 user, the implementation should return true and the result string must not be null.
2114 The default implementation uses QInputDialog::getText().
2116 bool QWebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result)
2120 #ifndef QT_NO_INPUTDIALOG
2122 QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2123 QInputDialog dlg(parent);
2124 dlg.setWindowTitle(tr("JavaScript Prompt - %1").arg(mainFrame()->url().host()));
2126 // Hack to force the dialog's QLabel into plain text mode
2127 // prevents https://bugs.webkit.org/show_bug.cgi?id=34429
2128 QLabel* label = dlg.findChild<QLabel*>();
2130 label->setTextFormat(Qt::PlainText);
2132 // double the &'s because single & will underline the following character
2133 // (Accelerator mnemonics)
2134 QString escMsg(msg);
2135 escMsg.replace(QChar::fromLatin1('&'), QLatin1String("&&"));
2136 dlg.setLabelText(escMsg);
2138 dlg.setTextEchoMode(QLineEdit::Normal);
2139 dlg.setTextValue(defaultValue);
2144 *result = dlg.textValue();
2150 \fn bool QWebPage::shouldInterruptJavaScript()
2152 This function is called when a JavaScript program is running for a long period of time.
2154 If the user wanted to stop the JavaScript the implementation should return true; otherwise false.
2156 The default implementation executes the query using QMessageBox::information with QMessageBox::Yes and QMessageBox::No buttons.
2158 \warning Because of binary compatibility constraints, this function is not virtual. If you want to
2159 provide your own implementation in a QWebPage subclass, reimplement the shouldInterruptJavaScript()
2160 slot in your subclass instead. QtWebKit will dynamically detect the slot and call it.
2162 bool QWebPage::shouldInterruptJavaScript()
2164 #ifdef QT_NO_MESSAGEBOX
2167 QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2168 return QMessageBox::Yes == QMessageBox::information(parent, tr("JavaScript Problem - %1").arg(mainFrame()->url().host()), tr("The script on this page appears to have a problem. Do you want to stop the script?"), QMessageBox::Yes, QMessageBox::No);
2172 void QWebPage::setFeaturePermission(QWebFrame* frame, Feature feature, PermissionPolicy policy)
2176 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
2177 if (policy == PermissionGrantedByUser)
2178 NotificationPresenterClientQt::notificationPresenter()->allowNotificationForFrame(frame->d->frame);
2182 #if ENABLE(GEOLOCATION)
2183 GeolocationPermissionClientQt::geolocationPermissionClient()->setPermission(frame, policy);
2193 This function is called whenever WebKit wants to create a new window of the given \a type, for
2194 example when a JavaScript program requests to open a document in a new window.
2196 If the new window can be created, the new window's QWebPage is returned; otherwise a null pointer is returned.
2198 If the view associated with the web page is a QWebView object, then the default implementation forwards
2199 the request to QWebView's createWindow() function; otherwise it returns a null pointer.
2201 If \a type is WebModalDialog, the application must call setWindowModality(Qt::ApplicationModal) on the new window.
2203 \note In the cases when the window creation is being triggered by JavaScript, apart from
2204 reimplementing this method application must also set the JavaScriptCanOpenWindows attribute
2205 of QWebSettings to true in order for it to get called.
2207 \sa acceptNavigationRequest(), QWebView::createWindow()
2209 QWebPage *QWebPage::createWindow(WebWindowType type)
2211 QWebView *webView = qobject_cast<QWebView*>(view());
2213 QWebView *newView = webView->createWindow(type);
2215 return newView->page();
2221 This function is called whenever WebKit encounters a HTML object element with type "application/x-qt-plugin". It is
2222 called regardless of the value of QWebSettings::PluginsEnabled. The \a classid, \a url, \a paramNames and \a paramValues
2223 correspond to the HTML object element attributes and child elements to configure the embeddable object.
2225 QObject *QWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues)
2229 Q_UNUSED(paramNames)
2230 Q_UNUSED(paramValues)
2234 static void extractContentTypeFromHash(const HashSet<String>& types, QStringList* list)
2239 HashSet<String>::const_iterator endIt = types.end();
2240 for (HashSet<String>::const_iterator it = types.begin(); it != endIt; ++it)
2244 static void extractContentTypeFromPluginVector(const Vector<PluginPackage*>& plugins, QStringList* list)
2249 for (unsigned int i = 0; i < plugins.size(); ++i) {
2250 MIMEToDescriptionsMap::const_iterator map_it = plugins[i]->mimeToDescriptions().begin();
2251 MIMEToDescriptionsMap::const_iterator map_end = plugins[i]->mimeToDescriptions().end();
2252 for (; map_it != map_end; ++map_it)
2253 *list << map_it->first;
2258 * Returns the list of all content types supported by QWebPage.
2260 QStringList QWebPage::supportedContentTypes() const
2262 QStringList mimeTypes;
2264 extractContentTypeFromHash(MIMETypeRegistry::getSupportedImageMIMETypes(), &mimeTypes);
2265 extractContentTypeFromHash(MIMETypeRegistry::getSupportedNonImageMIMETypes(), &mimeTypes);
2266 if (d->page->settings() && d->page->settings()->arePluginsEnabled())
2267 extractContentTypeFromPluginVector(PluginDatabase::installedPlugins()->plugins(), &mimeTypes);
2273 * Returns true if QWebPage can handle the given \a mimeType; otherwise, returns false.
2275 bool QWebPage::supportsContentType(const QString& mimeType) const
2277 const String type = mimeType.toLower();
2278 if (MIMETypeRegistry::isSupportedImageMIMEType(type))
2281 if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
2284 if (d->page->settings() && d->page->settings()->arePluginsEnabled()
2285 && PluginDatabase::installedPlugins()->isMIMETypeRegistered(type))
2291 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
2293 return WebCore::FrameLoadRequest(frame->document()->securityOrigin(),
2294 WebCore::ResourceRequest(url, frame->loader()->outgoingReferrer()));
2297 static void openNewWindow(const QUrl& url, WebCore::Frame* frame)
2299 if (Page* oldPage = frame->page()) {
2300 WindowFeatures features;
2301 NavigationAction action;
2302 FrameLoadRequest request = frameLoadRequest(url, frame);
2303 if (Page* newPage = oldPage->chrome()->createWindow(frame, request, features, action)) {
2304 newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, MaybeSendReferrer);
2305 newPage->chrome()->show();
2310 static void collectChildFrames(QWebFrame* frame, QList<QWebFrame*>& list)
2312 list << frame->childFrames();
2313 QListIterator<QWebFrame*> it(frame->childFrames());
2314 while (it.hasNext()) {
2315 collectChildFrames(it.next(), list);
2320 This function can be called to trigger the specified \a action.
2321 It is also called by QtWebKit if the user triggers the action, for example
2322 through a context menu item.
2324 If \a action is a checkable action then \a checked specified whether the action
2329 void QWebPage::triggerAction(WebAction action, bool)
2331 WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
2334 WebCore::Editor *editor = frame->editor();
2335 const char *command = 0;
2339 if (QWebFrame *targetFrame = d->hitTestResult.linkTargetFrame()) {
2340 WTF::RefPtr<WebCore::Frame> wcFrame = targetFrame->d->frame;
2341 targetFrame->d->frame->loader()->loadFrameRequest(frameLoadRequest(d->hitTestResult.linkUrl(), wcFrame.get()),
2342 /*lockHistory*/ false, /*lockBackForwardList*/ false, /*event*/ 0,
2343 /*FormState*/ 0, MaybeSendReferrer);
2347 case OpenLinkInNewWindow:
2348 openNewWindow(d->hitTestResult.linkUrl(), frame);
2350 case OpenFrameInNewWindow: {
2351 KURL url = frame->loader()->documentLoader()->unreachableURL();
2353 url = frame->loader()->documentLoader()->url();
2354 openNewWindow(url, frame);
2357 case CopyLinkToClipboard: {
2358 #if defined(Q_WS_X11)
2359 bool oldSelectionMode = Pasteboard::generalPasteboard()->isSelectionMode();
2360 Pasteboard::generalPasteboard()->setSelectionMode(true);
2361 editor->copyURL(d->hitTestResult.linkUrl(), d->hitTestResult.linkText());
2362 Pasteboard::generalPasteboard()->setSelectionMode(oldSelectionMode);
2364 editor->copyURL(d->hitTestResult.linkUrl(), d->hitTestResult.linkText());
2367 case OpenImageInNewWindow:
2368 openNewWindow(d->hitTestResult.imageUrl(), frame);
2370 case DownloadImageToDisk:
2371 frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.imageUrl(), frame->loader()->outgoingReferrer()));
2373 case DownloadLinkToDisk:
2374 frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.linkUrl(), frame->loader()->outgoingReferrer()));
2376 #ifndef QT_NO_CLIPBOARD
2377 case CopyImageToClipboard:
2378 QApplication::clipboard()->setPixmap(d->hitTestResult.pixmap());
2380 case CopyImageUrlToClipboard:
2381 QApplication::clipboard()->setText(d->hitTestResult.imageUrl().toString());
2388 d->page->goForward();
2391 mainFrame()->d->frame->loader()->stopForUserCancel();
2392 d->updateNavigationActions();
2395 mainFrame()->d->frame->loader()->reload(/*endtoendreload*/false);
2397 case ReloadAndBypassCache:
2398 mainFrame()->d->frame->loader()->reload(/*endtoendreload*/true);
2400 case SetTextDirectionDefault:
2401 editor->setBaseWritingDirection(NaturalWritingDirection);
2403 case SetTextDirectionLeftToRight:
2404 editor->setBaseWritingDirection(LeftToRightWritingDirection);
2406 case SetTextDirectionRightToLeft:
2407 editor->setBaseWritingDirection(RightToLeftWritingDirection);
2409 case InspectElement: {
2410 #if ENABLE(INSPECTOR)
2411 if (!d->hitTestResult.isNull()) {
2412 d->getOrCreateInspector(); // Make sure the inspector is created
2413 d->inspector->show(); // The inspector is expected to be shown on inspection
2414 d->page->inspectorController()->inspect(d->hitTestResult.d->innerNonSharedNode.get());
2419 case StopScheduledPageRefresh: {
2420 QWebFrame* topFrame = mainFrame();
2421 topFrame->d->frame->navigationScheduler()->cancel();
2422 QList<QWebFrame*> childFrames;
2423 collectChildFrames(topFrame, childFrames);
2424 QListIterator<QWebFrame*> it(childFrames);
2425 while (it.hasNext())
2426 it.next()->d->frame->navigationScheduler()->cancel();
2430 command = QWebPagePrivate::editorCommandForWebActions(action);
2435 editor->command(command).execute();
2439 QColor QWebPagePrivate::colorSelectionRequested(const QColor &selectedColor)
2441 QColor ret = selectedColor;
2442 #ifndef QT_NO_COLORDIALOG
2443 QWidget* parent = (client) ? client->ownerWidget() : 0;
2444 ret = QColorDialog::getColor(selectedColor, parent);
2446 ret = selectedColor;
2451 QSize QWebPage::viewportSize() const
2453 if (d->mainFrame && d->mainFrame.data()->d->frame->view())
2454 return d->mainFrame.data()->d->frame->view()->frameRect().size();
2456 return d->viewportSize;
2460 \property QWebPage::viewportSize
2461 \brief the size of the viewport
2463 The size affects for example the visibility of scrollbars
2464 if the document is larger than the viewport.
2466 By default, for a newly-created Web page, this property contains a size with
2467 zero width and height.
2469 \sa QWebFrame::render(), preferredContentsSize
2471 void QWebPage::setViewportSize(const QSize &size) const
2473 d->viewportSize = size;
2475 QWebFrame *frame = mainFrame();
2476 if (frame->d->frame && frame->d->frame->view()) {
2477 WebCore::FrameView* view = frame->d->frame->view();
2479 view->adjustViewSize();
2483 static int getintenv(const char* variable)
2486 int value = qgetenv(variable).toInt(&ok);
2487 return (ok) ? value : -1;
2490 static QSize queryDeviceSizeForScreenContainingWidget(const QWidget* widget)
2492 QDesktopWidget* desktop = QApplication::desktop();
2499 // Returns the available geometry of the screen which contains widget.
2500 // NOTE: this must be the the full screen size including any fixed status areas etc.
2501 size = desktop->availableGeometry(widget).size();
2503 size = desktop->availableGeometry().size();
2505 // This must be in portrait mode, adjust if not.
2506 if (size.width() > size.height()) {
2507 int width = size.width();
2508 size.setWidth(size.height());
2509 size.setHeight(width);
2516 Computes the optimal viewport configuration given the \a availableSize, when
2517 user interface components are disregarded.
2519 The configuration is also dependent on the device screen size which is obtained
2520 automatically. For testing purposes the size can be overridden by setting two
2521 environment variables QTWEBKIT_DEVICE_WIDTH and QTWEBKIT_DEVICE_HEIGHT, which
2522 both needs to be set.
2524 The ViewportAttributes includes a pixel density ratio, which will also be exposed to
2525 the web author though the -webkit-pixel-ratio media feature. This is the ratio
2526 between 1 density-independent pixel (DPI) and physical pixels.
2528 A density-independent pixel is equivalent to one physical pixel on a 160 DPI screen,
2529 so on our platform assumes that as the baseline density.
2531 The conversion of DIP units to screen pixels is quite simple:
2533 pixels = DIPs * (density / 160).
2535 Thus, on a 240 DPI screen, 1 DIPs would equal 1.5 physical pixels.
2537 An invalid instance will be returned in the case an empty size is passed to the
2540 \note The density is automatically obtained from the DPI of the screen where the page
2541 is being shown, but as many X11 servers are reporting wrong DPI, it is possible to
2542 override it using QX11Info::setAppDpiY().
2545 QWebPage::ViewportAttributes QWebPage::viewportAttributesForSize(const QSize& availableSize) const
2547 static int desktopWidth = 980;
2549 ViewportAttributes result;
2551 if (availableSize.isEmpty())
2552 return result; // Returns an invalid instance.
2554 int deviceWidth = getintenv("QTWEBKIT_DEVICE_WIDTH");
2555 int deviceHeight = getintenv("QTWEBKIT_DEVICE_HEIGHT");
2557 // Both environment variables need to be set - or they will be ignored.
2558 if (deviceWidth < 0 && deviceHeight < 0) {
2559 QSize size = queryDeviceSizeForScreenContainingWidget((d->client) ? d->client->ownerWidget() : 0);
2560 deviceWidth = size.width();
2561 deviceHeight = size.height();
2564 WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(d->viewportArguments(), desktopWidth, deviceWidth, deviceHeight, qt_defaultDpi() / WebCore::ViewportArguments::deprecatedTargetDPI, availableSize);
2565 WebCore::restrictMinimumScaleFactorToViewportSize(conf, availableSize);
2566 WebCore::restrictScaleFactorToInitialScaleIfNotUserScalable(conf);
2568 result.m_isValid = true;
2569 result.m_size = QSizeF(conf.layoutSize.width(), conf.layoutSize.height());
2570 result.m_initialScaleFactor = conf.initialScale;
2571 result.m_minimumScaleFactor = conf.minimumScale;
2572 result.m_maximumScaleFactor = conf.maximumScale;
2573 result.m_devicePixelRatio = conf.devicePixelRatio;
2574 result.m_isUserScalable = static_cast<bool>(conf.userScalable);
2576 d->page->setDeviceScaleFactor(conf.devicePixelRatio);
2581 QSize QWebPage::preferredContentsSize() const
2583 QWebFrame* frame = d->mainFrame.data();
2585 WebCore::FrameView* view = frame->d->frame->view();
2586 if (view && view->useFixedLayout())
2587 return d->mainFrame.data()->d->frame->view()->fixedLayoutSize();
2590 return d->fixedLayoutSize;
2594 \property QWebPage::preferredContentsSize
2596 \brief a custom size used for laying out the page contents.
2598 By default all pages are laid out using the viewport of the page as the base.
2600 As pages mostly are designed for desktop usage, they often do not layout properly
2601 on small devices as the contents require a certain view width. For this reason
2602 it is common to use a different layout size and then scale the contents to fit
2603 within the actual view.
2605 If this property is set to a valid size, this size is used for all layout needs
2606 instead of the size of the viewport.
2608 Setting an invalid size, makes the page fall back to using the viewport size for layout.
2612 void QWebPage::setPreferredContentsSize(const QSize& size) const
2614 // FIXME: Rename this method to setCustomLayoutSize
2616 d->fixedLayoutSize = size;
2618 QWebFrame* frame = mainFrame();
2619 if (!frame->d->frame || !frame->d->frame->view())
2622 WebCore::FrameView* view = frame->d->frame->view();
2624 if (size.isValid()) {
2625 view->setUseFixedLayout(true);
2626 view->setFixedLayoutSize(size);
2627 } else if (view->useFixedLayout())
2628 view->setUseFixedLayout(false);
2634 This function is to be called after any (animated) scroll/pan has ended, in the case the application handles the
2635 scrolling/panning of the web contents. This is commonly used in combination with tiling where is it common for
2636 the application to pan the actual view, which then resizes itself to the size of the contents.
2638 \note Calling this function makes WebKit stop trying to calculate the visibleContentRect. To turn that on
2639 again, call this method with an empty rect.
2641 \sa QGraphicsWebView::resizesToContents, QWebSettings::TiledBackingStoreEnabled
2643 void QWebPage::setActualVisibleContentRect(const QRect& rect) const
2645 QWebFrame* frame = mainFrame();
2646 if (!frame->d->frame || !frame->d->frame->view())
2649 WebCore::FrameView* view = frame->d->frame->view();
2650 view->setFixedVisibleContentRect(rect);
2654 \fn bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2656 This function is called whenever WebKit requests to navigate \a frame to the resource specified by \a request by means of
2657 the specified navigation type \a type.
2659 If \a frame is a null pointer then navigation to a new window is requested. If the request is
2660 accepted createWindow() will be called.
2662 The default implementation interprets the page's linkDelegationPolicy and emits linkClicked accordingly or returns true
2663 to let QWebPage handle the navigation itself.
2667 bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2670 if (type == NavigationTypeLinkClicked) {
2671 switch (d->linkPolicy) {
2672 case DontDelegateLinks:
2675 case DelegateExternalLinks:
2676 if (WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal(request.url().scheme()))
2678 emit linkClicked(request.url());
2681 case DelegateAllLinks:
2682 emit linkClicked(request.url());
2690 \property QWebPage::hasSelection
2691 \brief whether this page contains selected content or not.
2693 \sa selectionChanged()
2695 bool QWebPage::hasSelection() const
2697 d->createMainFrame();
2698 WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2700 return (frame->selection()->selection().selectionType() != VisibleSelection::NoSelection);
2705 \property QWebPage::selectedText
2706 \brief the text currently selected
2708 By default, this property contains an empty string.
2710 \sa selectionChanged(), selectedHtml()
2712 QString QWebPage::selectedText() const
2714 d->createMainFrame();
2715 WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2716 if (frame->selection()->selection().selectionType() == VisibleSelection::NoSelection)
2718 return frame->editor()->selectedText();
2723 \property QWebPage::selectedHtml
2724 \brief the HTML currently selected
2726 By default, this property contains an empty string.
2728 \sa selectionChanged(), selectedText()
2730 QString QWebPage::selectedHtml() const
2732 d->createMainFrame();
2733 return d->page->focusController()->focusedOrMainFrame()->editor()->selectedRange()->toHTML();
2736 #ifndef QT_NO_ACTION
2738 Returns a QAction for the specified WebAction \a action.
2740 The action is owned by the QWebPage but you can customize the look by
2741 changing its properties.
2743 QWebPage also takes care of implementing the action, so that upon
2744 triggering the corresponding action is performed on the page.
2748 QAction *QWebPage::action(WebAction action) const
2750 if (action == QWebPage::NoWebAction) return 0;
2751 if (d->actions[action])
2752 return d->actions[action];
2756 QStyle *style = d->client ? d->client->style() : qApp->style();
2757 bool checkable = false;
2761 text = contextMenuItemTagOpenLink();
2763 case OpenLinkInNewWindow:
2764 text = contextMenuItemTagOpenLinkInNewWindow();
2766 case OpenFrameInNewWindow:
2767 text = contextMenuItemTagOpenFrameInNewWindow();
2770 case DownloadLinkToDisk:
2771 text = contextMenuItemTagDownloadLinkToDisk();
2773 case CopyLinkToClipboard:
2774 text = contextMenuItemTagCopyLinkToClipboard();
2777 case OpenImageInNewWindow:
2778 text = contextMenuItemTagOpenImageInNewWindow();
2780 case DownloadImageToDisk:
2781 text = contextMenuItemTagDownloadImageToDisk();
2783 case CopyImageToClipboard:
2784 text = contextMenuItemTagCopyImageToClipboard();
2786 case CopyImageUrlToClipboard:
2787 text = contextMenuItemTagCopyImageUrlToClipboard();
2791 text = contextMenuItemTagGoBack();
2792 icon = style->standardIcon(QStyle::SP_ArrowBack);
2795 text = contextMenuItemTagGoForward();
2796 icon = style->standardIcon(QStyle::SP_ArrowForward);
2799 text = contextMenuItemTagStop();
2800 icon = style->standardIcon(QStyle::SP_BrowserStop);
2803 text = contextMenuItemTagReload();
2804 icon = style->standardIcon(QStyle::SP_BrowserReload);
2808 text = contextMenuItemTagCut();
2811 text = contextMenuItemTagCopy();
2814 text = contextMenuItemTagPaste();
2817 text = contextMenuItemTagSelectAll();
2819 #ifndef QT_NO_UNDOSTACK
2821 QAction *a = undoStack()->createUndoAction(d->q);
2822 d->actions[action] = a;
2826 QAction *a = undoStack()->createRedoAction(d->q);
2827 d->actions[action] = a;
2830 #endif // QT_NO_UNDOSTACK
2831 case MoveToNextChar:
2832 text = tr("Move the cursor to the next character");
2834 case MoveToPreviousChar:
2835 text = tr("Move the cursor to the previous character");
2837 case MoveToNextWord:
2838 text = tr("Move the cursor to the next word");
2840 case MoveToPreviousWord:
2841 text = tr("Move the cursor to the previous word");
2843 case MoveToNextLine:
2844 text = tr("Move the cursor to the next line");
2846 case MoveToPreviousLine:
2847 text = tr("Move the cursor to the previous line");
2849 case MoveToStartOfLine:
2850 text = tr("Move the cursor to the start of the line");
2852 case MoveToEndOfLine:
2853 text = tr("Move the cursor to the end of the line");
2855 case MoveToStartOfBlock:
2856 text = tr("Move the cursor to the start of the block");
2858 case MoveToEndOfBlock:
2859 text = tr("Move the cursor to the end of the block");
2861 case MoveToStartOfDocument:
2862 text = tr("Move the cursor to the start of the document");
2864 case MoveToEndOfDocument:
2865 text = tr("Move the cursor to the end of the document");
2867 case SelectNextChar:
2868 text = tr("Select to the next character");
2870 case SelectPreviousChar:
2871 text = tr("Select to the previous character");
2873 case SelectNextWord:
2874 text = tr("Select to the next word");
2876 case SelectPreviousWord:
2877 text = tr("Select to the previous word");
2879 case SelectNextLine:
2880 text = tr("Select to the next line");
2882 case SelectPreviousLine:
2883 text = tr("Select to the previous line");
2885 case SelectStartOfLine:
2886 text = tr("Select to the start of the line");
2888 case SelectEndOfLine:
2889 text = tr("Select to the end of the line");
2891 case SelectStartOfBlock:
2892 text = tr("Select to the start of the block");
2894 case SelectEndOfBlock:
2895 text = tr("Select to the end of the block");
2897 case SelectStartOfDocument:
2898 text = tr("Select to the start of the document");
2900 case SelectEndOfDocument:
2901 text = tr("Select to the end of the document");
2903 case DeleteStartOfWord:
2904 text = tr("Delete to the start of the word");
2906 case DeleteEndOfWord:
2907 text = tr("Delete to the end of the word");
2910 case SetTextDirectionDefault:
2911 text = contextMenuItemTagDefaultDirection();
2913 case SetTextDirectionLeftToRight:
2914 text = contextMenuItemTagLeftToRight();
2917 case SetTextDirectionRightToLeft:
2918 text = contextMenuItemTagRightToLeft();
2923 text = contextMenuItemTagBold();
2927 text = contextMenuItemTagItalic();
2930 case ToggleUnderline:
2931 text = contextMenuItemTagUnderline();
2935 case InspectElement:
2936 text = contextMenuItemTagInspectElement();
2939 case InsertParagraphSeparator:
2940 text = tr("Insert a new paragraph");
2942 case InsertLineSeparator:
2943 text = tr("Insert a new line");
2946 case PasteAndMatchStyle:
2947 text = tr("Paste and Match Style");
2950 text = tr("Remove formatting");
2953 case ToggleStrikethrough:
2954 text = tr("Strikethrough");
2957 case ToggleSubscript:
2958 text = tr("Subscript");
2961 case ToggleSuperscript:
2962 text = tr("Superscript");
2965 case InsertUnorderedList:
2966 text = tr("Insert Bulleted List");
2969 case InsertOrderedList:
2970 text = tr("Insert Numbered List");
2974 text = tr("Indent");
2977 text = tr("Outdent");
2980 text = tr("Center");
2982 case AlignJustified:
2983 text = tr("Justify");
2986 text = tr("Align Left");
2989 text = tr("Align Right");
3000 QAction *a = new QAction(d->q);
3003 a->setCheckable(checkable);
3006 connect(a, SIGNAL(triggered(bool)),
3007 this, SLOT(_q_webActionTriggered(bool)));
3009 d->actions[action] = a;
3010 d->updateAction(action);
3013 #endif // QT_NO_ACTION
3016 \property QWebPage::modified
3017 \brief whether the page contains unsubmitted form data, or the contents have been changed.
3019 By default, this property is false.
3021 \sa contentsChanged(), contentEditable, undoStack()
3023 bool QWebPage::isModified() const
3025 #ifdef QT_NO_UNDOSTACK
3030 return d->undoStack->canUndo();
3031 #endif // QT_NO_UNDOSTACK
3034 #ifndef QT_NO_UNDOSTACK
3036 Returns a pointer to the undo stack used for editable content.
3040 QUndoStack *QWebPage::undoStack() const
3043 d->undoStack = new QUndoStack(const_cast<QWebPage *>(this));
3045 return d->undoStack;
3047 #endif // QT_NO_UNDOSTACK
3051 bool QWebPage::event(QEvent *ev)
3053 switch (ev->type()) {
3055 d->timerEvent(static_cast<QTimerEvent*>(ev));
3057 case QEvent::MouseMove:
3058 d->mouseMoveEvent(static_cast<QMouseEvent*>(ev));
3060 case QEvent::MouseButtonPress:
3061 d->mousePressEvent(static_cast<QMouseEvent*>(ev));
3063 case QEvent::MouseButtonDblClick:
3064 d->mouseDoubleClickEvent(static_cast<QMouseEvent*>(ev));
3066 case QEvent::MouseButtonRelease:
3067 d->mouseReleaseEvent(static_cast<QMouseEvent*>(ev));
3069 #if !defined(QT_NO_GRAPHICSVIEW)
3070 case QEvent::GraphicsSceneMouseMove:
3071 d->mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3073 case QEvent::GraphicsSceneMousePress:
3074 d->mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3076 case QEvent::GraphicsSceneMouseDoubleClick:
3077 d->mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3079 case QEvent::GraphicsSceneMouseRelease:
3080 d->mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3083 #ifndef QT_NO_CONTEXTMENU
3084 case QEvent::ContextMenu:
3085 d->contextMenuEvent(static_cast<QContextMenuEvent*>(ev)->globalPos());
3087 #if !defined(QT_NO_GRAPHICSVIEW)
3088 case QEvent::GraphicsSceneContextMenu:
3089 d->contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(ev)->screenPos());
3093 #ifndef QT_NO_WHEELEVENT
3095 d->wheelEvent(static_cast<QWheelEvent*>(ev));
3097 #if !defined(QT_NO_GRAPHICSVIEW)
3098 case QEvent::GraphicsSceneWheel:
3099 d->wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(ev));
3103 case QEvent::KeyPress:
3104 d->keyPressEvent(static_cast<QKeyEvent*>(ev));
3106 case QEvent::KeyRelease:
3107 d->keyReleaseEvent(static_cast<QKeyEvent*>(ev));
3109 case QEvent::FocusIn:
3110 d->focusInEvent(static_cast<QFocusEvent*>(ev));
3112 case QEvent::FocusOut:
3113 d->focusOutEvent(static_cast<QFocusEvent*>(ev));
3115 #ifndef QT_NO_DRAGANDDROP
3116 case QEvent::DragEnter:
3117 d->dragEnterEvent(static_cast<QDragEnterEvent*>(ev));
3119 case QEvent::DragLeave:
3120 d->dragLeaveEvent(static_cast<QDragLeaveEvent*>(ev));
3122 case QEvent::DragMove:
3123 d->dragMoveEvent(static_cast<QDragMoveEvent*>(ev));
3126 d->dropEvent(static_cast<QDropEvent*>(ev));
3128 #if !defined(QT_NO_GRAPHICSVIEW)
3129 case QEvent::GraphicsSceneDragEnter:
3130 d->dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3132 case QEvent::GraphicsSceneDragMove:
3133 d->dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3135 case QEvent::GraphicsSceneDragLeave:
3136 d->dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3138 case QEvent::GraphicsSceneDrop:
3139 d->dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3144 case QEvent::InputMethod:
3145 d->inputMethodEvent(static_cast<QInputMethodEvent*>(ev));
3147 case QEvent::ShortcutOverride:
3148 d->shortcutOverrideEvent(static_cast<QKeyEvent*>(ev));
3153 case QEvent::TouchBegin:
3154 case QEvent::TouchUpdate:
3155 case QEvent::TouchEnd:
3156 case QEvent::TouchCancel:
3157 // Return whether the default action was cancelled in the JS event handler
3158 return d->touchEvent(static_cast<QTouchEvent*>(ev));
3159 #ifndef QT_NO_PROPERTIES
3160 case QEvent::DynamicPropertyChange:
3161 d->dynamicPropertyChangeEvent(static_cast<QDynamicPropertyChangeEvent*>(ev));
3165 return QObject::event(ev);
3172 Similar to QWidget::focusNextPrevChild() it focuses the next focusable web element
3173 if \a next is true; otherwise the previous element is focused.
3175 Returns true if it can find a new focusable element, or false if it can't.
3177 bool QWebPage::focusNextPrevChild(bool next)
3179 QKeyEvent ev(QEvent::KeyPress, Qt::Key_Tab, Qt::KeyboardModifiers(next ? Qt::NoModifier : Qt::ShiftModifier));
3180 d->keyPressEvent(&ev);
3181 bool hasFocusedNode = false;
3182 Frame *frame = d->page->focusController()->focusedFrame();
3184 Document *document = frame->document();
3185 hasFocusedNode = document && document->focusedNode();
3187 //qDebug() << "focusNextPrevChild(" << next << ") =" << ev.isAccepted() << "focusedNode?" << hasFocusedNode;
3188 return hasFocusedNode;
3192 \property QWebPage::contentEditable
3193 \brief whether the content in this QWebPage is editable or not
3196 If this property is enabled the contents of the page can be edited by the user through a visible
3197 cursor. If disabled (the default) only HTML elements in the web page with their
3198 \c{contenteditable} attribute set are editable.
3200 \sa modified, contentsChanged(), WebAction
3202 void QWebPage::setContentEditable(bool editable)
3204 if (isContentEditable() != editable) {
3205 d->page->setEditable(editable);
3206 d->page->setTabKeyCyclesThroughElements(!editable);
3208 WebCore::Frame* frame = d->mainFrame.data()->d->frame;
3210 frame->editor()->applyEditingStyleToBodyElement();
3211 // FIXME: mac port calls this if there is no selectedDOMRange
3212 //frame->setSelectionFromNone();
3216 d->updateEditorActions();
3220 bool QWebPage::isContentEditable() const
3222 return d->page->isEditable();
3226 \property QWebPage::forwardUnsupportedContent
3227 \brief whether QWebPage should forward unsupported content
3229 If enabled, the unsupportedContent() signal is emitted with a network reply that
3230 can be used to read the content.
3232 If disabled, the download of such content is aborted immediately.
3234 By default unsupported content is not forwarded.
3237 void QWebPage::setForwardUnsupportedContent(bool forward)
3239 d->forwardUnsupportedContent = forward;
3242 bool QWebPage::forwardUnsupportedContent() const
3244 return d->forwardUnsupportedContent;
3248 \property QWebPage::linkDelegationPolicy
3249 \brief how QWebPage should delegate the handling of links through the
3250 linkClicked() signal
3252 The default is to delegate no links.
3255 void QWebPage::setLinkDelegationPolicy(LinkDelegationPolicy policy)
3257 d->linkPolicy = policy;
3260 QWebPage::LinkDelegationPolicy QWebPage::linkDelegationPolicy() const
3262 return d->linkPolicy;
3265 #ifndef QT_NO_CONTEXTMENU
3267 static bool handleScrollbarContextMenuEvent(Scrollbar* scrollBar, QContextMenuEvent* event)
3269 if (!QApplication::style()->styleHint(QStyle::SH_ScrollBar_ContextMenu))
3272 bool horizontal = (scrollBar->orientation() == HorizontalScrollbar);
3275 QAction* actScrollHere = menu.addAction(QCoreApplication::translate("QWebPage", "Scroll here"));
3276 menu.addSeparator();
3278 QAction* actScrollTop = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Left edge") : QCoreApplication::translate("QWebPage", "Top"));
3279 QAction* actScrollBottom = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Right edge") : QCoreApplication::translate("QWebPage", "Bottom"));
3280 menu.addSeparator();
3282 QAction* actPageUp = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Page left") : QCoreApplication::translate("QWebPage", "Page up"));
3283 QAction* actPageDown = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Page right") : QCoreApplication::translate("QWebPage", "Page down"));
3284 menu.addSeparator();
3286 QAction* actScrollUp = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Scroll left") : QCoreApplication::translate("QWebPage", "Scroll up"));
3287 QAction* actScrollDown = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Scroll right") : QCoreApplication::translate("QWebPage", "Scroll down"));
3289 QAction* actionSelected = menu.exec(event->globalPos());
3291 if (actionSelected == actScrollHere) {
3292 ScrollbarTheme* theme = scrollBar->theme();
3293 // Set the pressed position to the middle of the thumb so that when we
3294 // do move, the delta will be from the current pixel position of the
3295 // thumb to the new position
3296 int position = theme->trackPosition(scrollBar) + theme->thumbPosition(scrollBar) + theme->thumbLength(scrollBar) / 2;
3297 scrollBar->setPressedPos(position);
3298 const QPoint pos = scrollBar->convertFromContainingWindow(event->pos());
3299 scrollBar->moveThumb(horizontal ? pos.x() : pos.y());
3300 } else if (actionSelected == actScrollTop)
3301 scrollBar->scrollableArea()->scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByDocument);
3302 else if (actionSelected == actScrollBottom)
3303 scrollBar->scrollableArea()->scroll(horizontal ? ScrollRight : ScrollDown, ScrollByDocument);
3304 else if (actionSelected == actPageUp)
3305 scrollBar->scrollableArea()->scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByPage);
3306 else if (actionSelected == actPageDown)
3307 scrollBar->scrollableArea()->scroll(horizontal ? ScrollRight : ScrollDown, ScrollByPage);
3308 else if (actionSelected == actScrollUp)
3309 scrollBar->scrollableArea()->scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByLine);
3310 else if (actionSelected == actScrollDown)
3311 scrollBar->scrollableArea()->scroll(horizontal ? ScrollRight : ScrollDown, ScrollByLine);
3316 Filters the context menu event, \a event, through handlers for scrollbars and
3317 custom event handlers in the web page. Returns true if the event was handled;
3320 A web page may swallow a context menu event through a custom event handler, allowing for context
3321 menus to be implemented in HTML/JavaScript. This is used by \l{http://maps.google.com/}{Google
3324 bool QWebPage::swallowContextMenuEvent(QContextMenuEvent *event)
3326 d->page->contextMenuController()->clearContextMenu();
3328 if (QWebFrame* webFrame = frameAt(event->pos())) {
3329 Frame* frame = QWebFramePrivate::core(webFrame);
3330 if (Scrollbar* scrollbar = frame->view()->scrollbarAtPoint(convertMouseEvent(event, 1).position()))
3331 return handleScrollbarContextMenuEvent(scrollbar, event);
3334 WebCore::Frame* focusedFrame = d->page->focusController()->focusedOrMainFrame();
3335 focusedFrame->eventHandler()->sendContextMenuEvent(convertMouseEvent(event, 1));
3336 ContextMenu *menu = d->page->contextMenuController()->contextMenu();
3337 // If the website defines its own handler then sendContextMenuEvent takes care of
3338 // calling/showing it and the context menu pointer will be zero. This is the case
3339 // on maps.google.com for example.
3343 #endif // QT_NO_CONTEXTMENU
3346 Updates the page's actions depending on the position \a pos. For example if \a pos is over an image
3347 element the CopyImageToClipboard action is enabled.
3349 void QWebPage::updatePositionDependentActions(const QPoint &pos)
3351 #ifndef QT_NO_ACTION
3352 // First we disable all actions, but keep track of which ones were originally enabled.
3353 QBitArray originallyEnabledWebActions(QWebPage::WebActionCount);
3354 for (int i = ContextMenuItemTagNoAction; i < ContextMenuItemBaseApplicationTag; ++i) {
3355 QWebPage::WebAction action = webActionForContextMenuAction(WebCore::ContextMenuAction(i));
3356 if (QAction *a = this->action(action)) {
3357 originallyEnabledWebActions.setBit(action, a->isEnabled());
3358 a->setEnabled(false);
3361 #endif // QT_NO_ACTION
3363 d->createMainFrame();
3364 WebCore::Frame* focusedFrame = d->page->focusController()->focusedOrMainFrame();
3366 HitTestResult result = focusedFrame->eventHandler()->hitTestResultAtPoint(focusedFrame->view()->windowToContents(pos));
3367 if (result.scrollbar())
3368 d->hitTestResult = QWebHitTestResult();
3370 d->hitTestResult = QWebHitTestResult(new QWebHitTestResultPrivate(result));
3371 d->page->contextMenuController()->setHitTestResult(result);
3373 #if ENABLE(INSPECTOR)
3374 if (d->page->inspectorController()->enabled())
3375 d->page->contextMenuController()->addInspectElementItem();
3378 QBitArray visitedWebActions(QWebPage::WebActionCount);
3380 #ifndef QT_NO_CONTEXTMENU
3381 delete d->currentContextMenu.data();
3383 // Then we let createContextMenu() enable the actions that are put into the menu
3384 d->currentContextMenu = d->createContextMenu(d->page->contextMenuController()->contextMenu(), d->page->contextMenuController()->contextMenu()->platformDescription(), &visitedWebActions);
3385 #endif // QT_NO_CONTEXTMENU
3387 #ifndef QT_NO_ACTION
3388 // Finally, we restore the original enablement for the actions that were not put into the menu.
3389 originallyEnabledWebActions &= ~visitedWebActions; // Mask out visited actions (they're part of the menu)
3390 for (int i = 0; i < QWebPage::WebActionCount; ++i) {
3391 if (originallyEnabledWebActions.at(i)) {
3392 if (QAction *a = this->action(QWebPage::WebAction(i)))
3393 a->setEnabled(true);
3396 #endif // QT_NO_ACTION
3398 // This whole process ensures that any actions put into to the context menu has the right
3399 // enablement, while also keeping the correct enablement for actions that were left out of
3407 \enum QWebPage::Extension
3409 This enum describes the types of extensions that the page can support. Before using these extensions, you
3410 should verify that the extension is supported by calling supportsExtension().
3412 \value ChooseMultipleFilesExtension Whether the web page supports multiple file selection.
3413 This extension is invoked when the web content requests one or more file names, for example
3414 as a result of the user clicking on a "file upload" button in a HTML form where multiple
3415 file selection is allowed.
3417 \value ErrorPageExtension Whether the web page can provide an error page when loading fails.
3418 (introduced in Qt 4.6)
3420 \sa ChooseMultipleFilesExtensionOption, ChooseMultipleFilesExtensionReturn, ErrorPageExtensionOption, ErrorPageExtensionReturn
3424 \enum QWebPage::ErrorDomain
3427 This enum describes the domain of an ErrorPageExtensionOption object (i.e. the layer in which the error occurred).
3429 \value QtNetwork The error occurred in the QtNetwork layer; the error code is of type QNetworkReply::NetworkError.
3430 \value Http The error occurred in the HTTP layer; the error code is a HTTP status code (see QNetworkRequest::HttpStatusCodeAttribute).
3431 \value WebKit The error is an internal WebKit error.
3435 \class QWebPage::ExtensionOption
3437 \brief The ExtensionOption class provides an extended input argument to QWebPage's extension support.
3441 \sa QWebPage::extension(), QWebPage::ExtensionReturn
3446 \class QWebPage::ExtensionReturn
3448 \brief The ExtensionReturn class provides an output result from a QWebPage's extension.
3452 \sa QWebPage::extension(), QWebPage::ExtensionOption
3456 \class QWebPage::ErrorPageExtensionOption
3458 \brief The ErrorPageExtensionOption class describes the option
3459 for the error page extension.
3463 The ErrorPageExtensionOption class holds the \a url for which an error occurred as well as
3464 the associated \a frame.
3466 The error itself is reported by an error \a domain, the \a error code as well as \a errorString.
3468 \sa QWebPage::extension(), QWebPage::ErrorPageExtensionReturn
3472 \variable QWebPage::ErrorPageExtensionOption::url
3473 \brief the url for which an error occurred
3477 \variable QWebPage::ErrorPageExtensionOption::frame
3478 \brief the frame associated with the error
3482 \variable QWebPage::ErrorPageExtensionOption::domain
3483 \brief the domain that reported the error
3487 \variable QWebPage::ErrorPageExtensionOption::error
3488 \brief the error code. Interpretation of the value depends on the \a domain
3489 \sa QWebPage::ErrorDomain
3493 \variable QWebPage::ErrorPageExtensionOption::errorString
3494 \brief a string that describes the error
3498 \class QWebPage::ErrorPageExtensionReturn
3500 \brief The ErrorPageExtensionReturn describes the error page, which will be shown for the
3501 frame for which the error occured.
3505 The ErrorPageExtensionReturn class holds the data needed for creating an error page. Some are
3506 optional such as \a contentType, which defaults to "text/html", as well as the \a encoding, which
3507 is assumed to be UTF-8 if not indicated otherwise.
3509 The error page is stored in the \a content byte array, as HTML content. In order to convert a
3510 QString to a byte array, the QString::toUtf8() method can be used.
3512 External objects such as stylesheets or images&nb