Simplify hitTestResultAtPoint and nodesFromRect APIs
[WebKit-https.git] / Source / WebKit / qt / Api / qwebpage.cpp
1 /*
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.
5
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.
10
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.
15
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.
20 */
21
22 #include "config.h"
23 #include "qwebpage.h"
24
25 #include "qwebview.h"
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"
36
37 #include "CSSComputedStyleDeclaration.h"
38 #include "CSSParser.h"
39 #include "ApplicationCacheStorage.h"
40 #include "BackForwardListImpl.h"
41 #include "MemoryCache.h"
42 #include "Chrome.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"
52 #endif
53 #include "DocumentLoader.h"
54 #include "DragClientQt.h"
55 #include "DragController.h"
56 #include "DragData.h"
57 #include "DragSession.h"
58 #include "Editor.h"
59 #include "EditorClientQt.h"
60 #include "FocusController.h"
61 #include "FormState.h"
62 #include "Frame.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"
73 #endif
74 #include "GeolocationPermissionClientQt.h"
75 #include "HTMLFormElement.h"
76 #include "HTMLFrameOwnerElement.h"
77 #include "HTMLInputElement.h"
78 #include "HTMLNames.h"
79 #include "HitTestResult.h"
80 #include "Image.h"
81 #include "InitWebCoreQt.h"
82 #include "InspectorClientQt.h"
83 #include "InspectorController.h"
84 #include "InspectorServerQt.h"
85 #include "KURL.h"
86 #include "LocalizedStrings.h"
87 #include "MIMETypeRegistry.h"
88 #include "NavigationAction.h"
89 #include "NetworkingContext.h"
90 #include "NodeList.h"
91 #include "NotificationPresenterClientQt.h"
92 #include "NotImplemented.h"
93 #include "Page.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"
114 #endif // Q_OS_WIN32
115 #include "TextIterator.h"
116 #include "WebEventConversion.h"
117 #include "WindowFeatures.h"
118 #include "WorkerThread.h"
119
120 #include <QAction>
121 #include <QApplication>
122 #include <QBasicTimer>
123 #include <QBitArray>
124 #include <QColorDialog>
125 #include <QDebug>
126 #include <QDesktopWidget>
127 #include <QDragEnterEvent>
128 #include <QDragLeaveEvent>
129 #include <QDragMoveEvent>
130 #include <QDropEvent>
131 #include <QFileDialog>
132 #include <QInputDialog>
133 #include <QLabel>
134 #include <QMenu>
135 #include <QMessageBox>
136 #include <QNetworkProxy>
137 #include <QUndoStack>
138 #include <QUrl>
139 #include <QPainter>
140 #include <QClipboard>
141 #include <QSslSocket>
142 #include <QStyle>
143 #include <QSysInfo>
144 #include <QTextCharFormat>
145 #include <QTouchEvent>
146 #include <QNetworkAccessManager>
147 #include <QNetworkRequest>
148 #if defined(Q_WS_X11)
149 #include <QX11Info>
150 #endif
151 #if USE(QT_MOBILITY_SYSTEMINFO)
152 #include <qsysteminfo.h>
153 #endif
154
155 using namespace WebCore;
156
157 // from text/qfont.cpp
158 QT_BEGIN_NAMESPACE
159 extern Q_GUI_EXPORT int qt_defaultDpi();
160 QT_END_NAMESPACE
161
162 bool QWebPagePrivate::drtRun = false;
163
164 // Lookup table mapping QWebPage::WebActions to the associated Editor commands
165 static const char* editorCommandWebActions[] =
166 {
167     0, // OpenLink,
168
169     0, // OpenLinkInNewWindow,
170     0, // OpenFrameInNewWindow,
171
172     0, // DownloadLinkToDisk,
173     0, // CopyLinkToClipboard,
174
175     0, // OpenImageInNewWindow,
176     0, // DownloadImageToDisk,
177     0, // CopyImageToClipboard,
178
179     0, // Back,
180     0, // Forward,
181     0, // Stop,
182     0, // Reload,
183
184     "Cut", // Cut,
185     "Copy", // Copy,
186     "Paste", // Paste,
187
188     "Undo", // Undo,
189     "Redo", // Redo,
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,
216
217     0, // SetTextDirectionDefault,
218     0, // SetTextDirectionLeftToRight,
219     0, // SetTextDirectionRightToLeft,
220
221     "ToggleBold", // ToggleBold,
222     "ToggleItalic", // ToggleItalic,
223     "ToggleUnderline", // ToggleUnderline,
224
225     0, // InspectElement,
226
227     "InsertNewline", // InsertParagraphSeparator
228     "InsertLineBreak", // InsertLineSeparator
229
230     "SelectAll", // SelectAll
231     0, // ReloadAndBypassCache,
232
233     "PasteAndMatchStyle", // PasteAndMatchStyle
234     "RemoveFormat", // RemoveFormat
235     "Strikethrough", // ToggleStrikethrough,
236     "Subscript", // ToggleSubscript
237     "Superscript", // ToggleSuperscript
238     "InsertUnorderedList", // InsertUnorderedList
239     "InsertOrderedList", // InsertOrderedList
240     "Indent", // Indent
241     "Outdent", // Outdent,
242
243     "AlignCenter", // AlignCenter,
244     "AlignJustified", // AlignJustified,
245     "AlignLeft", // AlignLeft,
246     "AlignRight", // AlignRight,
247
248     0, // StopScheduledPageRefresh,
249
250     0, // CopyImageUrlToClipboard,
251
252     0 // WebActionCount
253 };
254
255 // Lookup the appropriate editor command to use for WebAction \a action
256 const char* QWebPagePrivate::editorCommandForWebActions(QWebPage::WebAction action)
257 {
258     if ((action > QWebPage::NoWebAction) && (action < int(sizeof(editorCommandWebActions) / sizeof(const char*))))
259         return editorCommandWebActions[action];
260     return 0;
261 }
262
263 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
264 {
265     unsigned result = 0;
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;
277 }
278
279 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
280 {
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;
292     return result;
293 }
294
295 QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
296     : q(qq)
297     , page(0)
298 #ifndef QT_NO_UNDOSTACK
299     , undoStack(0)
300 #endif
301     , insideOpenCall(false)
302     , m_totalBytes(0)
303     , m_bytesReceived()
304     , clickCausedFocus(false)
305     , networkManager(0)
306     , forwardUnsupportedContent(false)
307     , smartInsertDeleteEnabled(true)
308     , selectTrailingWhitespaceEnabled(false)
309     , linkPolicy(QWebPage::DontDelegateLinks)
310     , viewportSize(QSize(0, 0))
311     , settings(0)
312     , useFixedLayout(false)
313     , pluginFactory(0)
314     , inspectorFrontend(0)
315     , inspector(0)
316     , inspectorIsInternalOnly(false)
317     , m_lastDropAction(Qt::IgnoreAction)
318 {
319 #if ENABLE(GEOLOCATION) || ENABLE(DEVICE_ORIENTATION)
320     bool useMock = QWebPagePrivate::drtRun;
321 #endif
322
323     WebCore::initializeWebCoreQt();
324
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)
333     if (useMock) {
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));
338     } else
339         WebCore::provideGeolocationTo(page, new GeolocationClientQt(q));
340 #endif
341 #if ENABLE(DEVICE_ORIENTATION)
342     if (useMock)
343         WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientMock);
344     else
345         WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientQt);
346     WebCore::provideDeviceMotionTo(page, new DeviceMotionClientQt);
347 #endif
348 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
349     WebCore::provideNotification(page, NotificationPresenterClientQt::notificationPresenter());
350 #endif
351
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");
358
359     settings = new QWebSettings(page->settings());
360
361     history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList()));
362     memset(actions, 0, sizeof(actions));
363
364     PageGroup::setShouldTrackVisitedLinks(true);
365     
366 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
367     NotificationPresenterClientQt::notificationPresenter()->addClient();
368 #endif
369 }
370
371 QWebPagePrivate::~QWebPagePrivate()
372 {
373     if (inspector && inspectorIsInternalOnly) {
374         // Since we have to delete an internal inspector,
375         // call setInspector(0) directly to prevent potential crashes
376         setInspector(0);
377     }
378 #ifndef QT_NO_CONTEXTMENU
379     delete currentContextMenu.data();
380 #endif
381 #ifndef QT_NO_UNDOSTACK
382     delete undoStack;
383 #endif
384     delete settings;
385     delete page;
386     
387     if (inspector)
388         inspector->setPage(0);
389
390 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
391     NotificationPresenterClientQt::notificationPresenter()->removeClient();
392 #endif
393 }
394
395 WebCore::ViewportArguments QWebPagePrivate::viewportArguments()
396 {
397     return page ? page->viewportArguments() : WebCore::ViewportArguments();
398 }
399
400 WebCore::Page* QWebPagePrivate::core(const QWebPage* page)
401 {
402     return page->d->page;
403 }
404
405 QWebPagePrivate* QWebPagePrivate::priv(QWebPage* page)
406 {
407     return page->d;
408 }
409
410 bool QWebPagePrivate::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
411 {
412     if (insideOpenCall
413         && frame == mainFrame.data())
414         return true;
415     return q->acceptNavigationRequest(frame, request, type);
416 }
417
418 void QWebPagePrivate::createMainFrame()
419 {
420     if (!mainFrame) {
421         QWebFrameData frameData(page);
422         mainFrame = new QWebFrame(q, &frameData);
423
424         emit q->frameCreated(mainFrame.data());
425     }
426 }
427
428 static QWebPage::WebAction webActionForContextMenuAction(WebCore::ContextMenuAction action)
429 {
430     switch (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;
456 #endif
457         default: break;
458     }
459     return QWebPage::NoWebAction;
460 }
461
462 #ifndef QT_NO_CONTEXTMENU
463 QMenu *QWebPagePrivate::createContextMenu(const WebCore::ContextMenu *webcoreMenu,
464         const QList<WebCore::ContextMenuItem> *items, QBitArray *visitedWebActions)
465 {
466     if (!client || !webcoreMenu)
467         return 0;
468
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);
477                 if (a) {
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);
484
485                     menu->addAction(a);
486                     visitedWebActions->setBit(action);
487                 }
488                 break;
489             }
490             case WebCore::SeparatorType:
491                 menu->addSeparator();
492                 break;
493             case WebCore::SubmenuType: {
494                 QMenu *subMenu = createContextMenu(webcoreMenu, item.platformSubMenu(), visitedWebActions);
495
496                 bool anyEnabledAction = false;
497
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();
502                 }
503
504                 // don't show sub-menus with just disabled actions
505                 if (anyEnabledAction) {
506                     subMenu->setTitle(item.title());
507                     menu->addAction(subMenu->menuAction());
508                 } else
509                     delete subMenu;
510                 break;
511             }
512         }
513     }
514     return menu;
515 }
516 #endif // QT_NO_CONTEXTMENU
517
518 #ifndef QT_NO_ACTION
519 void QWebPagePrivate::_q_webActionTriggered(bool checked)
520 {
521     QAction *a = qobject_cast<QAction *>(q->sender());
522     if (!a)
523         return;
524     QWebPage::WebAction action = static_cast<QWebPage::WebAction>(a->data().toInt());
525     q->triggerAction(action, checked);
526 }
527 #endif // QT_NO_ACTION
528
529 void QWebPagePrivate::_q_cleanupLeakMessages()
530 {
531 #ifndef NDEBUG
532     // Need this to make leak messages accurate.
533     memoryCache()->setCapacities(0, 0, 0);
534 #endif
535 }
536
537 void QWebPagePrivate::updateAction(QWebPage::WebAction action)
538 {
539 #ifdef QT_NO_ACTION
540     Q_UNUSED(action)
541 #else
542     QAction *a = actions[action];
543     if (!a || !mainFrame)
544         return;
545
546     WebCore::FrameLoader *loader = mainFrame.data()->d->frame->loader();
547     WebCore::Editor *editor = page->focusController()->focusedOrMainFrame()->editor();
548
549     bool enabled = a->isEnabled();
550     bool checked = a->isChecked();
551
552     switch (action) {
553         case QWebPage::Back:
554             enabled = page->canGoBackOrForward(-1);
555             break;
556         case QWebPage::Forward:
557             enabled = page->canGoBackOrForward(1);
558             break;
559         case QWebPage::Stop:
560             enabled = loader->isLoading();
561             break;
562         case QWebPage::Reload:
563         case QWebPage::ReloadAndBypassCache:
564             enabled = !loader->isLoading();
565             break;
566 #ifndef QT_NO_UNDOSTACK
567         case QWebPage::Undo:
568         case QWebPage::Redo:
569             // those two are handled by QUndoStack
570             break;
571 #endif // QT_NO_UNDOSTACK
572         case QWebPage::SelectAll: // editor command is always enabled
573             break;
574         case QWebPage::SetTextDirectionDefault:
575         case QWebPage::SetTextDirectionLeftToRight:
576         case QWebPage::SetTextDirectionRightToLeft:
577             enabled = editor->canEdit();
578             checked = false;
579             break;
580         default: {
581             // see if it's an editor command
582             const char* commandName = editorCommandForWebActions(action);
583
584             // if it's an editor command, let it's logic determine state
585             if (commandName) {
586                 Editor::Command command = editor->command(commandName);
587                 enabled = command.isEnabled();
588                 if (enabled)
589                     checked = command.state() != FalseTriState;
590                 else
591                     checked = false;
592             }
593             break;
594         }
595     }
596
597     a->setEnabled(enabled);
598
599     if (a->isCheckable())
600         a->setChecked(checked);
601 #endif // QT_NO_ACTION
602 }
603
604 void QWebPagePrivate::updateNavigationActions()
605 {
606     updateAction(QWebPage::Back);
607     updateAction(QWebPage::Forward);
608     updateAction(QWebPage::Stop);
609     updateAction(QWebPage::Reload);
610     updateAction(QWebPage::ReloadAndBypassCache);
611 }
612
613 void QWebPagePrivate::updateEditorActions()
614 {
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);
665 }
666
667 void QWebPagePrivate::timerEvent(QTimerEvent *ev)
668 {
669     int timerId = ev->timerId();
670     if (timerId == tripleClickTimer.timerId())
671         tripleClickTimer.stop();
672     else
673         q->timerEvent(ev);
674 }
675
676 template<class T>
677 void QWebPagePrivate::mouseMoveEvent(T* ev)
678 {
679     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
680     if (!frame->view())
681         return;
682
683     bool accepted = frame->eventHandler()->mouseMoved(convertMouseEvent(ev, 0));
684     ev->setAccepted(accepted);
685 }
686
687 template<class T>
688 void QWebPagePrivate::mousePressEvent(T* ev)
689 {
690     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
691     if (!frame->view())
692         return;
693
694     RefPtr<WebCore::Node> oldNode;
695     Frame* focusedFrame = page->focusController()->focusedFrame();
696     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
697         oldNode = focusedDocument->focusedNode();
698
699     if (tripleClickTimer.isActive()
700             && (ev->pos() - tripleClick).manhattanLength()
701                 < QApplication::startDragDistance()) {
702         mouseTripleClickEvent(ev);
703         return;
704     }
705
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);
713
714     RefPtr<WebCore::Node> newNode;
715     focusedFrame = page->focusController()->focusedFrame();
716     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
717         newNode = focusedDocument->focusedNode();
718
719     if (newNode && oldNode != newNode)
720         clickCausedFocus = true;
721 }
722
723 template<class T>
724 void QWebPagePrivate::mouseDoubleClickEvent(T *ev)
725 {
726     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
727     if (!frame->view())
728         return;
729
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);
736
737     tripleClickTimer.start(QApplication::doubleClickInterval(), q);
738     tripleClick = QPointF(ev->pos()).toPoint();
739 }
740
741 template<class T>
742 void QWebPagePrivate::mouseTripleClickEvent(T *ev)
743 {
744     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
745     if (!frame->view())
746         return;
747
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);
754 }
755
756 void QWebPagePrivate::handleClipboard(QEvent* ev, Qt::MouseButton button)
757 {
758 #ifndef QT_NO_CLIPBOARD
759     if (QApplication::clipboard()->supportsSelection()) {
760         WebCore::Frame* focusFrame = page->focusController()->focusedOrMainFrame();
761         if (button == Qt::MidButton) {
762             if (focusFrame) {
763                 focusFrame->editor()->command(AtomicString("PasteGlobalSelection")).execute();
764                 ev->setAccepted(true);
765             }
766         }
767     }
768 #endif
769 }
770
771 template<class T>
772 void QWebPagePrivate::mouseReleaseEvent(T *ev)
773 {
774     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
775     if (!frame->view())
776         return;
777
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);
785
786     if (!ev->isAccepted())
787         handleClipboard(ev, ev->button());
788     handleSoftwareInputPanel(ev->button(), QPointF(ev->pos()).toPoint());
789 }
790
791 void QWebPagePrivate::handleSoftwareInputPanel(Qt::MouseButton button, const QPoint& pos)
792 {
793     Frame* frame = page->focusController()->focusedFrame();
794     if (!frame)
795         return;
796
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);
807             }
808         }
809     }
810
811     clickCausedFocus = false;
812 }
813
814 #ifndef QT_NO_CONTEXTMENU
815 void QWebPagePrivate::contextMenuEvent(const QPoint& globalPos)
816 {
817     QMenu *menu = q->createStandardContextMenu();
818     if (menu) {
819         menu->exec(globalPos);
820         delete menu;
821     }
822 }
823 #endif // QT_NO_CONTEXTMENU
824
825 /*!
826     \since 4.5
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.
831  */
832 QMenu *QWebPage::createStandardContextMenu()
833 {
834 #ifndef QT_NO_CONTEXTMENU
835     QMenu* menu = d->currentContextMenu.data();
836     d->currentContextMenu = 0;
837     return menu;
838 #else
839     return 0;
840 #endif
841 }
842
843 #ifndef QT_NO_WHEELEVENT
844 template<class T>
845 void QWebPagePrivate::wheelEvent(T *ev)
846 {
847     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
848     if (!frame->view())
849         return;
850
851     PlatformWheelEvent pev = convertWheelEvent(ev);
852     bool accepted = frame->eventHandler()->handleWheelEvent(pev);
853     ev->setAccepted(accepted);
854 }
855 #endif // QT_NO_WHEELEVENT
856
857 #ifndef QT_NO_SHORTCUT
858 QWebPage::WebAction QWebPagePrivate::editorActionForKeyEvent(QKeyEvent* event)
859 {
860     static struct {
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 }
899     };
900
901     for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
902         if (event == editorActions[i].standardKey)
903             return editorActions[i].action;
904
905     return QWebPage::NoWebAction;
906 }
907 #endif // QT_NO_SHORTCUT
908
909 void QWebPagePrivate::keyPressEvent(QKeyEvent *ev)
910 {
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().
916     if (!handled)
917         handled = frame->eventHandler()->keyEvent(ev);
918     if (!handled) {
919         handled = true;
920         if (!handleScrolling(ev, frame)) {
921             switch (ev->key()) {
922             case Qt::Key_Back:
923                 q->triggerAction(QWebPage::Back);
924                 break;
925             case Qt::Key_Forward:
926                 q->triggerAction(QWebPage::Forward);
927                 break;
928             case Qt::Key_Stop:
929                 q->triggerAction(QWebPage::Stop);
930                 break;
931             case Qt::Key_Refresh:
932                 q->triggerAction(QWebPage::Reload);
933                 break;
934             case Qt::Key_Backspace:
935                 if (ev->modifiers() == Qt::ShiftModifier)
936                     q->triggerAction(QWebPage::Forward);
937                 else
938                     q->triggerAction(QWebPage::Back);
939                 break;
940             default:
941                 handled = false;
942                 break;
943             }
944         }
945     }
946
947     ev->setAccepted(handled);
948 }
949
950 void QWebPagePrivate::keyReleaseEvent(QKeyEvent *ev)
951 {
952     if (ev->isAutoRepeat()) {
953         ev->setAccepted(true);
954         return;
955     }
956
957     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
958     bool handled = frame->eventHandler()->keyEvent(ev);
959     ev->setAccepted(handled);
960 }
961
962 void QWebPagePrivate::focusInEvent(QFocusEvent*)
963 {
964     FocusController *focusController = page->focusController();
965     focusController->setActive(true);
966     focusController->setFocused(true);
967     if (!focusController->focusedFrame())
968         focusController->setFocusedFrame(QWebFramePrivate::core(mainFrame.data()));
969 }
970
971 void QWebPagePrivate::focusOutEvent(QFocusEvent*)
972 {
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);
980 }
981
982 template<class T>
983 void QWebPagePrivate::dragEnterEvent(T* ev)
984 {
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();
991 #endif
992 }
993
994 template<class T>
995 void QWebPagePrivate::dragLeaveEvent(T *ev)
996 {
997 #ifndef QT_NO_DRAGANDDROP
998     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
999     page->dragController()->dragExited(&dragData);
1000     ev->accept();
1001 #endif
1002 }
1003
1004 template<class T>
1005 void QWebPagePrivate::dragMoveEvent(T *ev)
1006 {
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)
1013         ev->accept();
1014 #endif
1015 }
1016
1017 template<class T>
1018 void QWebPagePrivate::dropEvent(T *ev)
1019 {
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);
1025         ev->accept();
1026     }
1027 #endif
1028 }
1029
1030 void QWebPagePrivate::leaveEvent(QEvent*)
1031 {
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);
1037 }
1038
1039 /*!
1040     \property QWebPage::palette
1041     \brief the page's palette
1042
1043     The base brush of the palette is used to draw the background of the main frame.
1044
1045     By default, this property contains the application's default palette.
1046 */
1047 void QWebPage::setPalette(const QPalette &pal)
1048 {
1049     d->palette = pal;
1050     if (!d->mainFrame || !d->mainFrame.data()->d->frame->view())
1051         return;
1052
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());
1056 }
1057
1058 QPalette QWebPage::palette() const
1059 {
1060     return d->palette;
1061 }
1062
1063 void QWebPagePrivate::inputMethodEvent(QInputMethodEvent *ev)
1064 {
1065     WebCore::Frame *frame = page->focusController()->focusedOrMainFrame();
1066     WebCore::Editor *editor = frame->editor();
1067
1068     if (!editor->canEdit()) {
1069         ev->ignore();
1070         return;
1071     }
1072
1073     Node* node = 0;
1074     if (frame->selection()->rootEditableElement())
1075         node = frame->selection()->rootEditableElement()->shadowAncestorNode();
1076
1077     Vector<CompositionUnderline> underlines;
1078     bool hasSelection = false;
1079
1080     for (int i = 0; i < ev->attributes().size(); ++i) {
1081         const QInputMethodEvent::Attribute& a = ev->attributes().at(i);
1082         switch (a.type) {
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));
1087             break;
1088         }
1089         case QInputMethodEvent::Cursor: {
1090             frame->selection()->setCaretVisible(a.length); //if length is 0 cursor is invisible
1091             if (a.length > 0) {
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())));
1096                 }
1097             }
1098             break;
1099         }
1100         case QInputMethodEvent::Selection: {
1101             hasSelection = true;
1102             // A selection in the inputMethodEvent is always reflected in the visible text
1103             if (node) {
1104                 if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
1105                     textControl->setSelectionRange(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
1106             }
1107
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)));
1110             else {
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);
1115             }
1116             break;
1117         }
1118         default:
1119             break;
1120         }
1121     }
1122
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());
1133         else
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());
1139
1140     ev->accept();
1141 }
1142
1143 #ifndef QT_NO_PROPERTIES
1144 typedef struct {
1145     const char* name;
1146     double deferredRepaintDelay;
1147     double initialDeferredRepaintDelayDuringLoading;
1148     double maxDeferredRepaintDelayDuringLoading;
1149     double deferredRepaintDelayIncrementDuringLoading;
1150 } QRepaintThrottlingPreset;
1151
1152 void QWebPagePrivate::dynamicPropertyChangeEvent(QDynamicPropertyChangeEvent* event)
1153 {
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 }
1181         };
1182
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);
1194                 break;
1195             }
1196         }
1197     }
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);
1204     }
1205 }
1206 #endif
1207
1208 void QWebPagePrivate::shortcutOverrideEvent(QKeyEvent* event)
1209 {
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) {
1217                     event->accept();
1218                 } else {
1219                     switch (event->key()) {
1220                     case Qt::Key_Return:
1221                     case Qt::Key_Enter:
1222                     case Qt::Key_Delete:
1223                     case Qt::Key_Home:
1224                     case Qt::Key_End:
1225                     case Qt::Key_Backspace:
1226                     case Qt::Key_Left:
1227                     case Qt::Key_Right:
1228                     case Qt::Key_Up:
1229                     case Qt::Key_Down:
1230                     case Qt::Key_Tab:
1231                         event->accept();
1232                     default:
1233                         break;
1234                     }
1235                 }
1236         }
1237 #ifndef QT_NO_SHORTCUT
1238         else if (editorActionForKeyEvent(event) != QWebPage::NoWebAction)
1239             event->accept();
1240 #endif
1241     }
1242 }
1243
1244 bool QWebPagePrivate::handleScrolling(QKeyEvent *ev, Frame *frame)
1245 {
1246     ScrollDirection direction;
1247     ScrollGranularity granularity;
1248
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;
1258     } else
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;
1268     } else {
1269         switch (ev->key()) {
1270             case Qt::Key_Up:
1271                 granularity = ScrollByLine;
1272                 direction = ScrollUp;
1273                 break;
1274             case Qt::Key_Down:
1275                 granularity = ScrollByLine;
1276                 direction = ScrollDown;
1277                 break;
1278             case Qt::Key_Left:
1279                 granularity = ScrollByLine;
1280                 direction = ScrollLeft;
1281                 break;
1282             case Qt::Key_Right:
1283                 granularity = ScrollByLine;
1284                 direction = ScrollRight;
1285                 break;
1286             default:
1287                 return false;
1288         }
1289     }
1290
1291     return frame->eventHandler()->scrollRecursively(direction, granularity);
1292 }
1293
1294 void QWebPagePrivate::adjustPointForClicking(QMouseEvent*)
1295 {
1296     notImplemented();
1297 }
1298
1299 #if !defined(QT_NO_GRAPHICSVIEW)
1300 void QWebPagePrivate::adjustPointForClicking(QGraphicsSceneMouseEvent* ev)
1301 {
1302     QtPlatformPlugin platformPlugin;
1303     OwnPtr<QWebTouchModifier> touchModifier = platformPlugin.createTouchModifier();
1304     if (!touchModifier)
1305         return;
1306
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);
1311
1312     touchModifier = nullptr;
1313
1314     if (!topPadding && !rightPadding && !bottomPadding && !leftPadding)
1315         return;
1316
1317     Document* startingDocument = page->mainFrame()->document();
1318     if (!startingDocument)
1319         return;
1320
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())
1325         return;
1326
1327     ev->setPos(QPointF(adjustedPoint));
1328 }
1329 #endif
1330
1331 bool QWebPagePrivate::touchEvent(QTouchEvent* event)
1332 {
1333 #if ENABLE(TOUCH_EVENTS)
1334     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
1335     if (!frame->view())
1336         return false;
1337
1338     // Always accept the QTouchEvent so that we'll receive also TouchUpdate and TouchEnd events
1339     event->setAccepted(true);
1340
1341     // Return whether the default action was cancelled in the JS event handler
1342     return frame->eventHandler()->handleTouchEvent(convertTouchEvent(event));
1343 #else
1344     event->ignore();
1345     return false;
1346 #endif
1347 }
1348
1349 /*!
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.
1353
1354   \a property specifies which property is queried.
1355
1356   \sa QWidget::inputMethodEvent(), QInputMethodEvent, QInputContext
1357 */
1358 QVariant QWebPage::inputMethodQuery(Qt::InputMethodQuery property) const
1359 {
1360     Frame* frame = d->page->focusController()->focusedFrame();
1361     if (!frame)
1362         return QVariant();
1363
1364     WebCore::Editor* editor = frame->editor();
1365
1366     RenderObject* renderer = 0;
1367     RenderTextControl* renderTextControl = 0;
1368
1369     if (frame->selection()->rootEditableElement())
1370         renderer = frame->selection()->rootEditableElement()->shadowAncestorNode()->renderer();
1371
1372     if (renderer && renderer->isTextControl())
1373         renderTextControl = toRenderTextControl(renderer);
1374
1375     switch (property) {
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.
1380                 return QVariant();
1381             }
1382             return QVariant(view->contentsToWindow(frame->selection()->absoluteCaretBounds()));
1383         }
1384         case Qt::ImFont: {
1385             if (renderTextControl) {
1386                 RenderStyle* renderStyle = renderTextControl->style();
1387                 return QVariant(QFont(renderStyle->font().syntheticFont()));
1388             }
1389             return QVariant(QFont());
1390         }
1391         case Qt::ImCursorPosition: {
1392             if (editor->hasComposition())
1393                 return QVariant(frame->selection()->end().offsetInContainerNode());
1394             return QVariant(frame->selection()->extent().offsetInContainerNode());
1395         }
1396         case Qt::ImSurroundingText: {
1397             if (renderTextControl && renderTextControl->textFormControlElement()) {
1398                 QString text = renderTextControl->textFormControlElement()->value();
1399                 RefPtr<Range> range = editor->compositionRange();
1400                 if (range)
1401                     text.remove(range->startPosition().offsetInContainerNode(), TextIterator::rangeLength(range.get()));
1402                 return QVariant(text);
1403             }
1404             return QVariant();
1405         }
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();
1410                 if (end > start)
1411                     return QVariant(QString(renderTextControl->textFormControlElement()->value()).mid(start, end - start));
1412             }
1413             return QVariant();
1414
1415         }
1416         case Qt::ImAnchorPosition: {
1417             if (editor->hasComposition())
1418                 return QVariant(frame->selection()->start().offsetInContainerNode());
1419             return QVariant(frame->selection()->base().offsetInContainerNode());
1420         }
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());
1427                     }
1428                 }
1429                 return QVariant(HTMLInputElement::maximumLength);
1430             }
1431             return QVariant(0);
1432         }
1433         default:
1434             return QVariant();
1435     }
1436 }
1437
1438 /*!
1439     \internal
1440 */
1441 void QWebPagePrivate::setInspector(QWebInspector* insp)
1442 {
1443     if (inspector)
1444         inspector->d->setFrontend(0);
1445
1446     if (inspectorIsInternalOnly) {
1447         QWebInspector* inspToDelete = inspector;
1448         inspector = 0;
1449         inspectorIsInternalOnly = false;
1450         delete inspToDelete;    // Delete after to prevent infinite recursion
1451     }
1452
1453     inspector = insp;
1454
1455     // Give inspector frontend web view if previously created
1456     if (inspector && inspectorFrontend)
1457         inspector->d->setFrontend(inspectorFrontend);
1458 }
1459
1460 /*!
1461     \internal
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.
1464 */
1465 QWebInspector* QWebPagePrivate::getOrCreateInspector()
1466 {
1467 #if ENABLE(INSPECTOR)
1468     if (!inspector) {
1469         QWebInspector* insp = new QWebInspector;
1470         insp->setPage(q);
1471         inspectorIsInternalOnly = true;
1472
1473         Q_ASSERT(inspector); // Associated through QWebInspector::setPage(q)
1474     }
1475 #endif
1476     return inspector;
1477 }
1478
1479 /*! \internal */
1480 InspectorController* QWebPagePrivate::inspectorController()
1481 {
1482 #if ENABLE(INSPECTOR)
1483     return page->inspectorController();
1484 #else
1485     return 0;
1486 #endif
1487 }
1488
1489 quint16 QWebPagePrivate::inspectorServerPort()
1490 {
1491 #if ENABLE(INSPECTOR) && !defined(QT_NO_PROPERTIES)
1492     if (q && q->property("_q_webInspectorServerPort").isValid())
1493         return q->property("_q_webInspectorServerPort").toInt();
1494 #endif
1495     return 0;
1496 }
1497
1498 static bool hasMouseListener(Element* element)
1499 {
1500     ASSERT(element);
1501     return element->hasEventListeners(eventNames().clickEvent)
1502         || element->hasEventListeners(eventNames().mousedownEvent)
1503         || element->hasEventListeners(eventNames().mouseupEvent);
1504 }
1505
1506 static bool isClickableElement(Element* element, RefPtr<NodeList> list)
1507 {
1508     ASSERT(element);
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)
1515                 continue;
1516
1517             isClickable = hasMouseListener(parent);
1518             if (isClickable)
1519                 break;
1520
1521             parent = parent->parentElement();
1522         }
1523     }
1524
1525     ExceptionCode ec = 0;
1526     return isClickable
1527         || element->webkitMatchesSelector("a,*:link,*:visited,*[role=button],button,input,select,label", ec)
1528         || CSSComputedStyleDeclaration::create(element)->getPropertyValue(cssPropertyID("cursor")) == "pointer";
1529 }
1530
1531 static bool isValidFrameOwner(Element* element)
1532 {
1533     ASSERT(element);
1534     return element->isFrameOwnerElement() && static_cast<HTMLFrameOwnerElement*>(element)->contentFrame();
1535 }
1536
1537 static Element* nodeToElement(Node* node)
1538 {
1539     if (node && node->isElementNode())
1540         return static_cast<Element*>(node);
1541     return 0;
1542 }
1543
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)
1549 {
1550 }
1551
1552 IntPoint QWebPagePrivate::TouchAdjuster::findCandidatePointForTouch(const IntPoint& touchPoint, Document* document) const
1553 {
1554     if (!document)
1555         return IntPoint();
1556
1557     int x = touchPoint.x();
1558     int y = touchPoint.y();
1559
1560     RefPtr<NodeList> intersectedNodes = document->nodesFromRect(x, y, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding);
1561     if (!intersectedNodes)
1562         return IntPoint();
1563
1564     Element* closestClickableElement = 0;
1565     IntRect largestIntersectionRect;
1566     FrameView* view = document->frame()->view();
1567
1568     // Touch rect in contents coordinates.
1569     IntRect touchRect(HitTestResult::rectForPoint(view->windowToContents(IntPoint(x, y)), m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding));
1570
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);
1575
1576         Element* currentElement = nodeToElement(currentNode);
1577         if (!currentElement || (!isClickableElement(currentElement, 0) && !isValidFrameOwner(currentElement)))
1578             continue;
1579
1580         IntRect currentElementBoundingRect = currentElement->getPixelSnappedRect();
1581         currentElementBoundingRect.intersect(touchRect);
1582
1583         if (currentElementBoundingRect.isEmpty())
1584             continue;
1585
1586         int currentIntersectionRectArea = currentElementBoundingRect.width() * currentElementBoundingRect.height();
1587         int largestIntersectionRectArea = largestIntersectionRect.width() * largestIntersectionRect.height();
1588         if (currentIntersectionRectArea > largestIntersectionRectArea) {
1589             closestClickableElement = currentElement;
1590             largestIntersectionRect = currentElementBoundingRect;
1591         }
1592     }
1593
1594     if (largestIntersectionRect.isEmpty())
1595         return IntPoint();
1596
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;
1608
1609         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(closestClickableElement);
1610         Document* childDocument = owner->contentFrame()->document();
1611         return findCandidatePointForTouch(newTouchPoint, childDocument);
1612     }
1613     return view->contentsToWindow(largestIntersectionRect).center();
1614 }
1615
1616 /*!
1617    \enum QWebPage::FindFlag
1618
1619    This enum describes the options available to the findText() function. The options
1620    can be OR-ed together from the following list:
1621
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.)
1629 */
1630
1631 /*!
1632     \enum QWebPage::LinkDelegationPolicy
1633
1634     This enum defines the delegation policies a webpage can have when activating links and emitting
1635     the linkClicked() signal.
1636
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.
1641
1642     \sa QWebPage::linkDelegationPolicy
1643 */
1644
1645 /*!
1646     \enum QWebPage::NavigationType
1647
1648     This enum describes the types of navigation available when browsing through hyperlinked
1649     documents.
1650
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.
1657
1658     \sa acceptNavigationRequest()
1659 */
1660
1661 /*!
1662     \enum QWebPage::WebAction
1663
1664     This enum describes the types of action which can be performed on the web page.
1665
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().
1669
1670     One method of enabling the text editing, cursor movement, and text selection actions
1671     is by setting \l contentEditable to true.
1672
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)
1743
1744
1745     \omitvalue WebActionCount
1746
1747 */
1748
1749 /*!
1750     \enum QWebPage::WebWindowType
1751
1752     This enum describes the types of window that can be created by the createWindow() function.
1753
1754     \value WebBrowserWindow The window is a regular web browser window.
1755     \value WebModalDialog The window acts as modal dialog.
1756 */
1757
1758
1759 /*!
1760     \class QWebPage::ViewportAttributes
1761     \since 4.7
1762     \brief The QWebPage::ViewportAttributes class describes hints that can be applied to a viewport.
1763
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.
1767
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}.
1770
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.
1773
1774     \inmodule QtWebKit
1775 */
1776
1777 /*!
1778     Constructs an empty QWebPage::ViewportAttributes.
1779 */
1780 QWebPage::ViewportAttributes::ViewportAttributes()
1781     : d(0)
1782     , m_initialScaleFactor(-1.0)
1783     , m_minimumScaleFactor(-1.0)
1784     , m_maximumScaleFactor(-1.0)
1785     , m_devicePixelRatio(-1.0)
1786     , m_isUserScalable(true)
1787     , m_isValid(false)
1788 {
1789
1790 }
1791
1792 /*!
1793     Constructs a QWebPage::ViewportAttributes which is a copy from \a other .
1794 */
1795 QWebPage::ViewportAttributes::ViewportAttributes(const QWebPage::ViewportAttributes& other)
1796     : d(other.d)
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)
1804 {
1805
1806 }
1807
1808 /*!
1809     Destroys the QWebPage::ViewportAttributes.
1810 */
1811 QWebPage::ViewportAttributes::~ViewportAttributes()
1812 {
1813
1814 }
1815
1816 /*!
1817     Assigns the given QWebPage::ViewportAttributes to this viewport hints and returns a
1818     reference to this.
1819 */
1820 QWebPage::ViewportAttributes& QWebPage::ViewportAttributes::operator=(const QWebPage::ViewportAttributes& other)
1821 {
1822     if (this != &other) {
1823         d = other.d;
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;
1830     }
1831
1832     return *this;
1833 }
1834
1835 /*! \fn inline bool QWebPage::ViewportAttributes::isValid() const
1836     Returns whether this is a valid ViewportAttributes or not.
1837
1838     An invalid ViewportAttributes will have an empty QSize, negative values for scale factors and
1839     true for the boolean isUserScalable.
1840 */
1841
1842 /*! \fn inline QSize QWebPage::ViewportAttributes::size() const
1843     Returns the size of the viewport.
1844 */
1845
1846 /*! \fn inline qreal QWebPage::ViewportAttributes::initialScaleFactor() const
1847     Returns the initial scale of the viewport as a multiplier.
1848 */
1849
1850 /*! \fn inline qreal QWebPage::ViewportAttributes::minimumScaleFactor() const
1851     Returns the minimum scale value of the viewport as a multiplier.
1852 */
1853
1854 /*! \fn inline qreal QWebPage::ViewportAttributes::maximumScaleFactor() const
1855     Returns the maximum scale value of the viewport as a multiplier.
1856 */
1857
1858 /*! \fn inline bool QWebPage::ViewportAttributes::isUserScalable() const
1859     Determines whether or not the scale can be modified by the user.
1860 */
1861
1862
1863 /*!
1864     \class QWebPage
1865     \since 4.4
1866     \brief The QWebPage class provides an object to view and edit web documents.
1867
1868     \inmodule QtWebKit
1869
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.
1873
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
1881     using QWebFrame.
1882
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.
1890
1891     \section1 Using QWebPage in a Widget-less Environment
1892
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.
1897
1898     Suppose we have a \c Thumbnail class as follows:
1899
1900     \snippet webkitsnippets/webpage/main.cpp 0
1901
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,
1904     \c render().
1905
1906     \snippet webkitsnippets/webpage/main.cpp 1
1907
1908     The \c render() function shows how we can paint a thumbnail using a
1909     QWebPage object.
1910
1911     \snippet webkitsnippets/webpage/main.cpp 2
1912
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.
1918
1919     \sa QWebFrame
1920 */
1921
1922 /*!
1923     Constructs an empty QWebPage with parent \a parent.
1924 */
1925 QWebPage::QWebPage(QObject *parent)
1926     : QObject(parent)
1927     , d(new QWebPagePrivate(this))
1928 {
1929     setView(qobject_cast<QWidget*>(parent));
1930
1931     connect(this, SIGNAL(loadProgress(int)), this, SLOT(_q_onLoadProgressChanged(int)));
1932 #ifndef NDEBUG
1933     connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(_q_cleanupLeakMessages()));
1934 #endif
1935 }
1936
1937 /*!
1938     Destroys the web page.
1939 */
1940 QWebPage::~QWebPage()
1941 {
1942     d->createMainFrame();
1943     FrameLoader* loader = d->mainFrame.data()->d->frame->loader();
1944     if (loader)
1945         loader->detachFromParent();
1946     delete d;
1947 }
1948
1949 /*!
1950     Returns the main frame of the page.
1951
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.
1954
1955     \sa currentFrame()
1956 */
1957 QWebFrame *QWebPage::mainFrame() const
1958 {
1959     d->createMainFrame();
1960     return d->mainFrame.data();
1961 }
1962
1963 /*!
1964     Returns the frame currently active.
1965
1966     \sa mainFrame(), frameCreated()
1967 */
1968 QWebFrame *QWebPage::currentFrame() const
1969 {
1970     d->createMainFrame();
1971     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
1972     return qobject_cast<QWebFrame*>(frame->loader()->networkingContext()->originatingObject());
1973 }
1974
1975
1976 /*!
1977     \since 4.6
1978
1979     Returns the frame at the given point \a pos, or 0 if there is no frame at
1980     that position.
1981
1982     \sa mainFrame(), currentFrame()
1983 */
1984 QWebFrame* QWebPage::frameAt(const QPoint& pos) const
1985 {
1986     QWebFrame* webFrame = mainFrame();
1987     if (!webFrame->geometry().contains(pos))
1988         return 0;
1989     QWebHitTestResult hitTestResult = webFrame->hitTestContent(pos);
1990     return hitTestResult.frame();
1991 }
1992
1993 /*!
1994     Returns a pointer to the view's history of navigated web pages.
1995 */
1996 QWebHistory *QWebPage::history() const
1997 {
1998     d->createMainFrame();
1999     return &d->history;
2000 }
2001
2002 /*!
2003     Sets the \a view that is associated with the web page.
2004
2005     \sa view()
2006 */
2007 void QWebPage::setView(QWidget* view)
2008 {
2009     if (this->view() == view)
2010         return;
2011
2012     d->view = view;
2013     setViewportSize(view ? view->size() : QSize(0, 0));
2014
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.
2018     //
2019     // If such a special delegate already exist, we substitute the view.
2020
2021     if (d->client) {
2022         if (d->client->isQWidgetClient())
2023             static_cast<PageClientQWidget*>(d->client.get())->view = view;
2024         return;
2025     }
2026
2027     if (view)
2028         d->client = adoptPtr(new PageClientQWidget(view, this));
2029 }
2030
2031 /*!
2032     Returns the view widget that is associated with the web page.
2033
2034     \sa setView()
2035 */
2036 QWidget *QWebPage::view() const
2037 {
2038     return d->view.data();
2039 }
2040
2041 /*!
2042     This function is called whenever a JavaScript program tries to print a \a message to the web browser's console.
2043
2044     For example in case of evaluation errors the source URL may be provided in \a sourceID as well as the \a lineNumber.
2045
2046     The default implementation prints nothing.
2047 */
2048 void QWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID)
2049 {
2050     Q_UNUSED(sourceID)
2051
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: ");
2057             if (lineNumber)
2058                 fprintf(stdout, "line %d: ", lineNumber);
2059             fprintf(stdout, "%s\n", message.toUtf8().constData());
2060         }
2061     }
2062 }
2063
2064 /*!
2065     This function is called whenever a JavaScript program running inside \a frame calls the alert() function with
2066     the message \a msg.
2067
2068     The default implementation shows the message, \a msg, with QMessageBox::information.
2069 */
2070 void QWebPage::javaScriptAlert(QWebFrame *frame, const QString& msg)
2071 {
2072     Q_UNUSED(frame)
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);
2078     box.setText(msg);
2079     box.setStandardButtons(QMessageBox::Ok);
2080     box.exec();
2081 #endif
2082 }
2083
2084 /*!
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.
2087
2088     The default implementation executes the query using QMessageBox::information with QMessageBox::Ok and QMessageBox::Cancel buttons.
2089 */
2090 bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg)
2091 {
2092     Q_UNUSED(frame)
2093 #ifdef QT_NO_MESSAGEBOX
2094     return true;
2095 #else
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);
2100     box.setText(msg);
2101     box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
2102     return QMessageBox::Ok == box.exec();
2103 #endif
2104 }
2105
2106 /*!
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.
2109
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.
2113
2114     The default implementation uses QInputDialog::getText().
2115 */
2116 bool QWebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result)
2117 {
2118     Q_UNUSED(frame)
2119     bool ok = false;
2120 #ifndef QT_NO_INPUTDIALOG
2121
2122     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2123     QInputDialog dlg(parent);
2124     dlg.setWindowTitle(tr("JavaScript Prompt - %1").arg(mainFrame()->url().host()));
2125
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*>();
2129     if (label)
2130         label->setTextFormat(Qt::PlainText);
2131
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);
2137
2138     dlg.setTextEchoMode(QLineEdit::Normal);
2139     dlg.setTextValue(defaultValue);
2140
2141     ok = !!dlg.exec();
2142
2143     if (ok && result)
2144         *result = dlg.textValue();
2145 #endif
2146     return ok;
2147 }
2148
2149 /*!
2150     \fn bool QWebPage::shouldInterruptJavaScript()
2151     \since 4.6
2152     This function is called when a JavaScript program is running for a long period of time.
2153
2154     If the user wanted to stop the JavaScript the implementation should return true; otherwise false.
2155
2156     The default implementation executes the query using QMessageBox::information with QMessageBox::Yes and QMessageBox::No buttons.
2157
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.
2161 */
2162 bool QWebPage::shouldInterruptJavaScript()
2163 {
2164 #ifdef QT_NO_MESSAGEBOX
2165     return false;
2166 #else
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);
2169 #endif
2170 }
2171
2172 void QWebPage::setFeaturePermission(QWebFrame* frame, Feature feature, PermissionPolicy policy)
2173 {
2174     switch (feature) {
2175     case Notifications:
2176 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
2177         if (policy == PermissionGrantedByUser)
2178             NotificationPresenterClientQt::notificationPresenter()->allowNotificationForFrame(frame->d->frame);
2179 #endif
2180         break;
2181     case Geolocation:
2182 #if ENABLE(GEOLOCATION)
2183         GeolocationPermissionClientQt::geolocationPermissionClient()->setPermission(frame, policy);
2184 #endif
2185         break;
2186
2187     default:
2188         break;
2189     }
2190 }
2191
2192 /*!
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.
2195
2196     If the new window can be created, the new window's QWebPage is returned; otherwise a null pointer is returned.
2197
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.
2200
2201     If \a type is WebModalDialog, the application must call setWindowModality(Qt::ApplicationModal) on the new window.
2202
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.
2206
2207     \sa acceptNavigationRequest(), QWebView::createWindow()
2208 */
2209 QWebPage *QWebPage::createWindow(WebWindowType type)
2210 {
2211     QWebView *webView = qobject_cast<QWebView*>(view());
2212     if (webView) {
2213         QWebView *newView = webView->createWindow(type);
2214         if (newView)
2215             return newView->page();
2216     }
2217     return 0;
2218 }
2219
2220 /*!
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.
2224 */
2225 QObject *QWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
2226 {
2227     Q_UNUSED(classid)
2228     Q_UNUSED(url)
2229     Q_UNUSED(paramNames)
2230     Q_UNUSED(paramValues)
2231     return 0;
2232 }
2233
2234 static void extractContentTypeFromHash(const HashSet<String>& types, QStringList* list)
2235 {
2236     if (!list)
2237         return;
2238
2239     HashSet<String>::const_iterator endIt = types.end();
2240     for (HashSet<String>::const_iterator it = types.begin(); it != endIt; ++it)
2241         *list << *it;
2242 }
2243
2244 static void extractContentTypeFromPluginVector(const Vector<PluginPackage*>& plugins, QStringList* list)
2245 {
2246     if (!list)
2247         return;
2248
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;
2254     }
2255 }
2256
2257 /*!
2258  *  Returns the list of all content types supported by QWebPage.
2259  */
2260 QStringList QWebPage::supportedContentTypes() const
2261 {
2262     QStringList mimeTypes;
2263
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);
2268
2269     return mimeTypes;
2270 }
2271
2272 /*!
2273  *  Returns true if QWebPage can handle the given \a mimeType; otherwise, returns false.
2274  */
2275 bool QWebPage::supportsContentType(const QString& mimeType) const
2276 {
2277     const String type = mimeType.toLower();
2278     if (MIMETypeRegistry::isSupportedImageMIMEType(type))
2279         return true;
2280
2281     if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
2282         return true;
2283
2284     if (d->page->settings() && d->page->settings()->arePluginsEnabled()
2285         && PluginDatabase::installedPlugins()->isMIMETypeRegistered(type))
2286         return true;
2287
2288     return false;
2289 }
2290
2291 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
2292 {
2293     return WebCore::FrameLoadRequest(frame->document()->securityOrigin(),
2294         WebCore::ResourceRequest(url, frame->loader()->outgoingReferrer()));
2295 }
2296
2297 static void openNewWindow(const QUrl& url, WebCore::Frame* frame)
2298 {
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();
2306         }
2307     }
2308 }
2309
2310 static void collectChildFrames(QWebFrame* frame, QList<QWebFrame*>& list)
2311 {
2312     list << frame->childFrames();
2313     QListIterator<QWebFrame*> it(frame->childFrames());
2314     while (it.hasNext()) {
2315         collectChildFrames(it.next(), list);
2316     }
2317 }
2318
2319 /*!
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.
2323
2324     If \a action is a checkable action then \a checked specified whether the action
2325     is toggled or not.
2326
2327     \sa action()
2328 */
2329 void QWebPage::triggerAction(WebAction action, bool)
2330 {
2331     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
2332     if (!frame)
2333         return;
2334     WebCore::Editor *editor = frame->editor();
2335     const char *command = 0;
2336
2337     switch (action) {
2338         case OpenLink:
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);
2344                 break;
2345             }
2346             // fall through
2347         case OpenLinkInNewWindow:
2348             openNewWindow(d->hitTestResult.linkUrl(), frame);
2349             break;
2350         case OpenFrameInNewWindow: {
2351             KURL url = frame->loader()->documentLoader()->unreachableURL();
2352             if (url.isEmpty())
2353                 url = frame->loader()->documentLoader()->url();
2354             openNewWindow(url, frame);
2355             break;
2356         }
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);
2363 #endif
2364             editor->copyURL(d->hitTestResult.linkUrl(), d->hitTestResult.linkText());
2365             break;
2366         }
2367         case OpenImageInNewWindow:
2368             openNewWindow(d->hitTestResult.imageUrl(), frame);
2369             break;
2370         case DownloadImageToDisk:
2371             frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.imageUrl(), frame->loader()->outgoingReferrer()));
2372             break;
2373         case DownloadLinkToDisk:
2374             frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.linkUrl(), frame->loader()->outgoingReferrer()));
2375             break;
2376 #ifndef QT_NO_CLIPBOARD
2377         case CopyImageToClipboard:
2378             QApplication::clipboard()->setPixmap(d->hitTestResult.pixmap());
2379             break;
2380         case CopyImageUrlToClipboard:
2381             QApplication::clipboard()->setText(d->hitTestResult.imageUrl().toString());
2382             break;
2383 #endif
2384         case Back:
2385             d->page->goBack();
2386             break;
2387         case Forward:
2388             d->page->goForward();
2389             break;
2390         case Stop:
2391             mainFrame()->d->frame->loader()->stopForUserCancel();
2392             d->updateNavigationActions();
2393             break;
2394         case Reload:
2395             mainFrame()->d->frame->loader()->reload(/*endtoendreload*/false);
2396             break;
2397         case ReloadAndBypassCache:
2398             mainFrame()->d->frame->loader()->reload(/*endtoendreload*/true);
2399             break;
2400         case SetTextDirectionDefault:
2401             editor->setBaseWritingDirection(NaturalWritingDirection);
2402             break;
2403         case SetTextDirectionLeftToRight:
2404             editor->setBaseWritingDirection(LeftToRightWritingDirection);
2405             break;
2406         case SetTextDirectionRightToLeft:
2407             editor->setBaseWritingDirection(RightToLeftWritingDirection);
2408             break;
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());
2415             }
2416 #endif
2417             break;
2418         }
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();
2427             break;
2428         }
2429         default:
2430             command = QWebPagePrivate::editorCommandForWebActions(action);
2431             break;
2432     }
2433
2434     if (command)
2435         editor->command(command).execute();
2436 }
2437
2438
2439 QColor QWebPagePrivate::colorSelectionRequested(const QColor &selectedColor)
2440 {
2441     QColor ret = selectedColor;
2442 #ifndef QT_NO_COLORDIALOG
2443     QWidget* parent = (client) ? client->ownerWidget() : 0;
2444     ret = QColorDialog::getColor(selectedColor, parent);
2445     if (!ret.isValid())
2446         ret = selectedColor;
2447 #endif
2448     return ret;
2449 }
2450
2451 QSize QWebPage::viewportSize() const
2452 {
2453     if (d->mainFrame && d->mainFrame.data()->d->frame->view())
2454         return d->mainFrame.data()->d->frame->view()->frameRect().size();
2455
2456     return d->viewportSize;
2457 }
2458
2459 /*!
2460     \property QWebPage::viewportSize
2461     \brief the size of the viewport
2462
2463     The size affects for example the visibility of scrollbars
2464     if the document is larger than the viewport.
2465
2466     By default, for a newly-created Web page, this property contains a size with
2467     zero width and height.
2468
2469     \sa QWebFrame::render(), preferredContentsSize
2470 */
2471 void QWebPage::setViewportSize(const QSize &size) const
2472 {
2473     d->viewportSize = size;
2474
2475     QWebFrame *frame = mainFrame();
2476     if (frame->d->frame && frame->d->frame->view()) {
2477         WebCore::FrameView* view = frame->d->frame->view();
2478         view->resize(size);
2479         view->adjustViewSize();
2480     }
2481 }
2482
2483 static int getintenv(const char* variable)
2484 {
2485     bool ok;
2486     int value = qgetenv(variable).toInt(&ok);
2487     return (ok) ? value : -1;
2488 }
2489
2490 static QSize queryDeviceSizeForScreenContainingWidget(const QWidget* widget)
2491 {
2492     QDesktopWidget* desktop = QApplication::desktop();
2493     if (!desktop)
2494         return QSize();
2495
2496     QSize size;
2497
2498     if (widget) {
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();
2502     } else
2503         size = desktop->availableGeometry().size();
2504
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);
2510     }
2511
2512     return size;
2513 }
2514
2515 /*!
2516     Computes the optimal viewport configuration given the \a availableSize, when
2517     user interface components are disregarded.
2518
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.
2523
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.
2527
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.
2530
2531     The conversion of DIP units to screen pixels is quite simple:
2532
2533     pixels = DIPs * (density / 160).
2534
2535     Thus, on a 240 DPI screen, 1 DIPs would equal 1.5 physical pixels.
2536
2537     An invalid instance will be returned in the case an empty size is passed to the
2538     method.
2539
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().
2543 */
2544
2545 QWebPage::ViewportAttributes QWebPage::viewportAttributesForSize(const QSize& availableSize) const
2546 {
2547     static int desktopWidth = 980;
2548
2549     ViewportAttributes result;
2550
2551      if (availableSize.isEmpty())
2552          return result; // Returns an invalid instance.
2553
2554     int deviceWidth = getintenv("QTWEBKIT_DEVICE_WIDTH");
2555     int deviceHeight = getintenv("QTWEBKIT_DEVICE_HEIGHT");
2556
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();
2562     }
2563
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);
2567
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);
2575
2576     d->page->setDeviceScaleFactor(conf.devicePixelRatio);
2577
2578     return result;
2579 }
2580
2581 QSize QWebPage::preferredContentsSize() const
2582 {
2583     QWebFrame* frame = d->mainFrame.data();
2584     if (frame) {
2585         WebCore::FrameView* view = frame->d->frame->view();
2586         if (view && view->useFixedLayout())
2587             return d->mainFrame.data()->d->frame->view()->fixedLayoutSize();
2588     }
2589
2590     return d->fixedLayoutSize;
2591 }
2592
2593 /*!
2594     \property QWebPage::preferredContentsSize
2595     \since 4.6
2596     \brief a custom size used for laying out the page contents.
2597
2598     By default all pages are laid out using the viewport of the page as the base.
2599
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.
2604
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.
2607
2608     Setting an invalid size, makes the page fall back to using the viewport size for layout.
2609
2610     \sa viewportSize
2611 */
2612 void QWebPage::setPreferredContentsSize(const QSize& size) const
2613 {
2614     // FIXME: Rename this method to setCustomLayoutSize
2615
2616     d->fixedLayoutSize = size;
2617
2618     QWebFrame* frame = mainFrame();
2619     if (!frame->d->frame || !frame->d->frame->view())
2620         return;
2621
2622     WebCore::FrameView* view = frame->d->frame->view();
2623
2624     if (size.isValid()) {
2625         view->setUseFixedLayout(true);
2626         view->setFixedLayoutSize(size);
2627     } else if (view->useFixedLayout())
2628         view->setUseFixedLayout(false);
2629
2630     view->layout();
2631 }
2632
2633 /*
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.
2637
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.
2640
2641     \sa QGraphicsWebView::resizesToContents, QWebSettings::TiledBackingStoreEnabled
2642 */
2643 void QWebPage::setActualVisibleContentRect(const QRect& rect) const
2644 {
2645     QWebFrame* frame = mainFrame();
2646     if (!frame->d->frame || !frame->d->frame->view())
2647         return;
2648
2649     WebCore::FrameView* view = frame->d->frame->view();
2650     view->setFixedVisibleContentRect(rect);
2651 }
2652
2653 /*!
2654     \fn bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2655
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.
2658
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.
2661
2662     The default implementation interprets the page's linkDelegationPolicy and emits linkClicked accordingly or returns true
2663     to let QWebPage handle the navigation itself.
2664
2665     \sa createWindow()
2666 */
2667 bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2668 {
2669     Q_UNUSED(frame)
2670     if (type == NavigationTypeLinkClicked) {
2671         switch (d->linkPolicy) {
2672             case DontDelegateLinks:
2673                 return true;
2674
2675             case DelegateExternalLinks:
2676                 if (WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal(request.url().scheme()))
2677                     return true;
2678                 emit linkClicked(request.url());
2679                 return false;
2680
2681             case DelegateAllLinks:
2682                 emit linkClicked(request.url());
2683                 return false;
2684         }
2685     }
2686     return true;
2687 }
2688
2689 /*!
2690     \property QWebPage::hasSelection
2691     \brief whether this page contains selected content or not.
2692
2693     \sa selectionChanged()
2694 */
2695 bool QWebPage::hasSelection() const
2696 {
2697     d->createMainFrame();
2698     WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2699     if (frame)
2700         return (frame->selection()->selection().selectionType() != VisibleSelection::NoSelection);
2701     return false;
2702 }
2703
2704 /*!
2705     \property QWebPage::selectedText
2706     \brief the text currently selected
2707
2708     By default, this property contains an empty string.
2709
2710     \sa selectionChanged(), selectedHtml()
2711 */
2712 QString QWebPage::selectedText() const
2713 {
2714     d->createMainFrame();
2715     WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2716     if (frame->selection()->selection().selectionType() == VisibleSelection::NoSelection)
2717         return QString();
2718     return frame->editor()->selectedText();
2719 }
2720
2721 /*!
2722     \since 4.8
2723     \property QWebPage::selectedHtml
2724     \brief the HTML currently selected
2725
2726     By default, this property contains an empty string.
2727
2728     \sa selectionChanged(), selectedText()
2729 */
2730 QString QWebPage::selectedHtml() const
2731 {
2732     d->createMainFrame();
2733     return d->page->focusController()->focusedOrMainFrame()->editor()->selectedRange()->toHTML();
2734 }
2735
2736 #ifndef QT_NO_ACTION
2737 /*!
2738    Returns a QAction for the specified WebAction \a action.
2739
2740    The action is owned by the QWebPage but you can customize the look by
2741    changing its properties.
2742
2743    QWebPage also takes care of implementing the action, so that upon
2744    triggering the corresponding action is performed on the page.
2745
2746    \sa triggerAction()
2747 */
2748 QAction *QWebPage::action(WebAction action) const
2749 {
2750     if (action == QWebPage::NoWebAction) return 0;
2751     if (d->actions[action])
2752         return d->actions[action];
2753
2754     QString text;
2755     QIcon icon;
2756     QStyle *style = d->client ? d->client->style() : qApp->style();
2757     bool checkable = false;
2758
2759     switch (action) {
2760         case OpenLink:
2761             text = contextMenuItemTagOpenLink();
2762             break;
2763         case OpenLinkInNewWindow:
2764             text = contextMenuItemTagOpenLinkInNewWindow();
2765             break;
2766         case OpenFrameInNewWindow:
2767             text = contextMenuItemTagOpenFrameInNewWindow();
2768             break;
2769
2770         case DownloadLinkToDisk:
2771             text = contextMenuItemTagDownloadLinkToDisk();
2772             break;
2773         case CopyLinkToClipboard:
2774             text = contextMenuItemTagCopyLinkToClipboard();
2775             break;
2776
2777         case OpenImageInNewWindow:
2778             text = contextMenuItemTagOpenImageInNewWindow();
2779             break;
2780         case DownloadImageToDisk:
2781             text = contextMenuItemTagDownloadImageToDisk();
2782             break;
2783         case CopyImageToClipboard:
2784             text = contextMenuItemTagCopyImageToClipboard();
2785             break;
2786         case CopyImageUrlToClipboard:
2787             text = contextMenuItemTagCopyImageUrlToClipboard();
2788             break;
2789
2790         case Back:
2791             text = contextMenuItemTagGoBack();
2792             icon = style->standardIcon(QStyle::SP_ArrowBack);
2793             break;
2794         case Forward:
2795             text = contextMenuItemTagGoForward();
2796             icon = style->standardIcon(QStyle::SP_ArrowForward);
2797             break;
2798         case Stop:
2799             text = contextMenuItemTagStop();
2800             icon = style->standardIcon(QStyle::SP_BrowserStop);
2801             break;
2802         case Reload:
2803             text = contextMenuItemTagReload();
2804             icon = style->standardIcon(QStyle::SP_BrowserReload);
2805             break;
2806
2807         case Cut:
2808             text = contextMenuItemTagCut();
2809             break;
2810         case Copy:
2811             text = contextMenuItemTagCopy();
2812             break;
2813         case Paste:
2814             text = contextMenuItemTagPaste();
2815             break;
2816         case SelectAll:
2817             text = contextMenuItemTagSelectAll();
2818             break;
2819 #ifndef QT_NO_UNDOSTACK
2820         case Undo: {
2821             QAction *a = undoStack()->createUndoAction(d->q);
2822             d->actions[action] = a;
2823             return a;
2824         }
2825         case Redo: {
2826             QAction *a = undoStack()->createRedoAction(d->q);
2827             d->actions[action] = a;
2828             return a;
2829         }
2830 #endif // QT_NO_UNDOSTACK
2831         case MoveToNextChar:
2832             text = tr("Move the cursor to the next character");
2833             break;
2834         case MoveToPreviousChar:
2835             text = tr("Move the cursor to the previous character");
2836             break;
2837         case MoveToNextWord:
2838             text = tr("Move the cursor to the next word");
2839             break;
2840         case MoveToPreviousWord:
2841             text = tr("Move the cursor to the previous word");
2842             break;
2843         case MoveToNextLine:
2844             text = tr("Move the cursor to the next line");
2845             break;
2846         case MoveToPreviousLine:
2847             text = tr("Move the cursor to the previous line");
2848             break;
2849         case MoveToStartOfLine:
2850             text = tr("Move the cursor to the start of the line");
2851             break;
2852         case MoveToEndOfLine:
2853             text = tr("Move the cursor to the end of the line");
2854             break;
2855         case MoveToStartOfBlock:
2856             text = tr("Move the cursor to the start of the block");
2857             break;
2858         case MoveToEndOfBlock:
2859             text = tr("Move the cursor to the end of the block");
2860             break;
2861         case MoveToStartOfDocument:
2862             text = tr("Move the cursor to the start of the document");
2863             break;
2864         case MoveToEndOfDocument:
2865             text = tr("Move the cursor to the end of the document");
2866             break;
2867         case SelectNextChar:
2868             text = tr("Select to the next character");
2869             break;
2870         case SelectPreviousChar:
2871             text = tr("Select to the previous character");
2872             break;
2873         case SelectNextWord:
2874             text = tr("Select to the next word");
2875             break;
2876         case SelectPreviousWord:
2877             text = tr("Select to the previous word");
2878             break;
2879         case SelectNextLine:
2880             text = tr("Select to the next line");
2881             break;
2882         case SelectPreviousLine:
2883             text = tr("Select to the previous line");
2884             break;
2885         case SelectStartOfLine:
2886             text = tr("Select to the start of the line");
2887             break;
2888         case SelectEndOfLine:
2889             text = tr("Select to the end of the line");
2890             break;
2891         case SelectStartOfBlock:
2892             text = tr("Select to the start of the block");
2893             break;
2894         case SelectEndOfBlock:
2895             text = tr("Select to the end of the block");
2896             break;
2897         case SelectStartOfDocument:
2898             text = tr("Select to the start of the document");
2899             break;
2900         case SelectEndOfDocument:
2901             text = tr("Select to the end of the document");
2902             break;
2903         case DeleteStartOfWord:
2904             text = tr("Delete to the start of the word");
2905             break;
2906         case DeleteEndOfWord:
2907             text = tr("Delete to the end of the word");
2908             break;
2909
2910         case SetTextDirectionDefault:
2911             text = contextMenuItemTagDefaultDirection();
2912             break;
2913         case SetTextDirectionLeftToRight:
2914             text = contextMenuItemTagLeftToRight();
2915             checkable = true;
2916             break;
2917         case SetTextDirectionRightToLeft:
2918             text = contextMenuItemTagRightToLeft();
2919             checkable = true;
2920             break;
2921
2922         case ToggleBold:
2923             text = contextMenuItemTagBold();
2924             checkable = true;
2925             break;
2926         case ToggleItalic:
2927             text = contextMenuItemTagItalic();
2928             checkable = true;
2929             break;
2930         case ToggleUnderline:
2931             text = contextMenuItemTagUnderline();
2932             checkable = true;
2933             break;
2934
2935         case InspectElement:
2936             text = contextMenuItemTagInspectElement();
2937             break;
2938
2939         case InsertParagraphSeparator:
2940             text = tr("Insert a new paragraph");
2941             break;
2942         case InsertLineSeparator:
2943             text = tr("Insert a new line");
2944             break;
2945
2946         case PasteAndMatchStyle:
2947             text = tr("Paste and Match Style");
2948             break;
2949         case RemoveFormat:
2950             text = tr("Remove formatting");
2951             break;
2952
2953         case ToggleStrikethrough:
2954             text = tr("Strikethrough");
2955             checkable = true;
2956             break;
2957         case ToggleSubscript:
2958             text = tr("Subscript");
2959             checkable = true;
2960             break;
2961         case ToggleSuperscript:
2962             text = tr("Superscript");
2963             checkable = true;
2964             break;
2965         case InsertUnorderedList:
2966             text = tr("Insert Bulleted List");
2967             checkable = true;
2968             break;
2969         case InsertOrderedList:
2970             text = tr("Insert Numbered List");
2971             checkable = true;
2972             break;
2973         case Indent:
2974             text = tr("Indent");
2975             break;
2976         case Outdent:
2977             text = tr("Outdent");
2978             break;
2979         case AlignCenter:
2980             text = tr("Center");
2981             break;
2982         case AlignJustified:
2983             text = tr("Justify");
2984             break;
2985         case AlignLeft:
2986             text = tr("Align Left");
2987             break;
2988         case AlignRight:
2989             text = tr("Align Right");
2990             break;
2991         case NoWebAction:
2992             return 0;
2993         default:
2994             break;
2995     }
2996
2997     if (text.isEmpty())
2998         return 0;
2999
3000     QAction *a = new QAction(d->q);
3001     a->setText(text);
3002     a->setData(action);
3003     a->setCheckable(checkable);
3004     a->setIcon(icon);
3005
3006     connect(a, SIGNAL(triggered(bool)),
3007             this, SLOT(_q_webActionTriggered(bool)));
3008
3009     d->actions[action] = a;
3010     d->updateAction(action);
3011     return a;
3012 }
3013 #endif // QT_NO_ACTION
3014
3015 /*!
3016     \property QWebPage::modified
3017     \brief whether the page contains unsubmitted form data, or the contents have been changed.
3018
3019     By default, this property is false.
3020
3021     \sa contentsChanged(), contentEditable, undoStack()
3022 */
3023 bool QWebPage::isModified() const
3024 {
3025 #ifdef QT_NO_UNDOSTACK
3026     return false;
3027 #else
3028     if (!d->undoStack)
3029         return false;
3030     return d->undoStack->canUndo();
3031 #endif // QT_NO_UNDOSTACK
3032 }
3033
3034 #ifndef QT_NO_UNDOSTACK
3035 /*!
3036     Returns a pointer to the undo stack used for editable content.
3037
3038     \sa modified
3039 */
3040 QUndoStack *QWebPage::undoStack() const
3041 {
3042     if (!d->undoStack)
3043         d->undoStack = new QUndoStack(const_cast<QWebPage *>(this));
3044
3045     return d->undoStack;
3046 }
3047 #endif // QT_NO_UNDOSTACK
3048
3049 /*! \reimp
3050 */
3051 bool QWebPage::event(QEvent *ev)
3052 {
3053     switch (ev->type()) {
3054     case QEvent::Timer:
3055         d->timerEvent(static_cast<QTimerEvent*>(ev));
3056         break;
3057     case QEvent::MouseMove:
3058         d->mouseMoveEvent(static_cast<QMouseEvent*>(ev));
3059         break;
3060     case QEvent::MouseButtonPress:
3061         d->mousePressEvent(static_cast<QMouseEvent*>(ev));
3062         break;
3063     case QEvent::MouseButtonDblClick:
3064         d->mouseDoubleClickEvent(static_cast<QMouseEvent*>(ev));
3065         break;
3066     case QEvent::MouseButtonRelease:
3067         d->mouseReleaseEvent(static_cast<QMouseEvent*>(ev));
3068         break;
3069 #if !defined(QT_NO_GRAPHICSVIEW)
3070     case QEvent::GraphicsSceneMouseMove:
3071         d->mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3072         break;
3073     case QEvent::GraphicsSceneMousePress:
3074         d->mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3075         break;
3076     case QEvent::GraphicsSceneMouseDoubleClick:
3077         d->mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3078         break;
3079     case QEvent::GraphicsSceneMouseRelease:
3080         d->mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3081         break;
3082 #endif
3083 #ifndef QT_NO_CONTEXTMENU
3084     case QEvent::ContextMenu:
3085         d->contextMenuEvent(static_cast<QContextMenuEvent*>(ev)->globalPos());
3086         break;
3087 #if !defined(QT_NO_GRAPHICSVIEW)
3088     case QEvent::GraphicsSceneContextMenu:
3089         d->contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(ev)->screenPos());
3090         break;
3091 #endif
3092 #endif
3093 #ifndef QT_NO_WHEELEVENT
3094     case QEvent::Wheel:
3095         d->wheelEvent(static_cast<QWheelEvent*>(ev));
3096         break;
3097 #if !defined(QT_NO_GRAPHICSVIEW)
3098     case QEvent::GraphicsSceneWheel:
3099         d->wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(ev));
3100         break;
3101 #endif
3102 #endif
3103     case QEvent::KeyPress:
3104         d->keyPressEvent(static_cast<QKeyEvent*>(ev));
3105         break;
3106     case QEvent::KeyRelease:
3107         d->keyReleaseEvent(static_cast<QKeyEvent*>(ev));
3108         break;
3109     case QEvent::FocusIn:
3110         d->focusInEvent(static_cast<QFocusEvent*>(ev));
3111         break;
3112     case QEvent::FocusOut:
3113         d->focusOutEvent(static_cast<QFocusEvent*>(ev));
3114         break;
3115 #ifndef QT_NO_DRAGANDDROP
3116     case QEvent::DragEnter:
3117         d->dragEnterEvent(static_cast<QDragEnterEvent*>(ev));
3118         break;
3119     case QEvent::DragLeave:
3120         d->dragLeaveEvent(static_cast<QDragLeaveEvent*>(ev));
3121         break;
3122     case QEvent::DragMove:
3123         d->dragMoveEvent(static_cast<QDragMoveEvent*>(ev));
3124         break;
3125     case QEvent::Drop:
3126         d->dropEvent(static_cast<QDropEvent*>(ev));
3127         break;
3128 #if !defined(QT_NO_GRAPHICSVIEW)
3129     case QEvent::GraphicsSceneDragEnter:
3130         d->dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3131         break;
3132     case QEvent::GraphicsSceneDragMove:
3133         d->dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3134         break;
3135     case QEvent::GraphicsSceneDragLeave:
3136         d->dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3137         break;
3138     case QEvent::GraphicsSceneDrop:
3139         d->dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3140         break;
3141 #endif
3142
3143 #endif
3144     case QEvent::InputMethod:
3145         d->inputMethodEvent(static_cast<QInputMethodEvent*>(ev));
3146         break;
3147     case QEvent::ShortcutOverride:
3148         d->shortcutOverrideEvent(static_cast<QKeyEvent*>(ev));
3149         break;
3150     case QEvent::Leave:
3151         d->leaveEvent(ev);
3152         break;
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));
3162         break;
3163 #endif
3164     default:
3165         return QObject::event(ev);
3166     }
3167
3168     return true;
3169 }
3170
3171 /*!
3172     Similar to QWidget::focusNextPrevChild() it focuses the next focusable web element
3173     if \a next is true; otherwise the previous element is focused.
3174
3175     Returns true if it can find a new focusable element, or false if it can't.
3176 */
3177 bool QWebPage::focusNextPrevChild(bool next)
3178 {
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();
3183     if (frame) {
3184         Document *document = frame->document();
3185         hasFocusedNode = document && document->focusedNode();
3186     }
3187     //qDebug() << "focusNextPrevChild(" << next << ") =" << ev.isAccepted() << "focusedNode?" << hasFocusedNode;
3188     return hasFocusedNode;
3189 }
3190
3191 /*!
3192     \property QWebPage::contentEditable
3193     \brief whether the content in this QWebPage is editable or not
3194     \since 4.5
3195
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.
3199
3200     \sa modified, contentsChanged(), WebAction
3201 */
3202 void QWebPage::setContentEditable(bool editable)
3203 {
3204     if (isContentEditable() != editable) {
3205         d->page->setEditable(editable);
3206         d->page->setTabKeyCyclesThroughElements(!editable);
3207         if (d->mainFrame) {
3208             WebCore::Frame* frame = d->mainFrame.data()->d->frame;
3209             if (editable) {
3210                 frame->editor()->applyEditingStyleToBodyElement();
3211                 // FIXME: mac port calls this if there is no selectedDOMRange
3212                 //frame->setSelectionFromNone();
3213             }
3214         }
3215
3216         d->updateEditorActions();
3217     }
3218 }
3219
3220 bool QWebPage::isContentEditable() const
3221 {
3222     return d->page->isEditable();
3223 }
3224
3225 /*!
3226     \property QWebPage::forwardUnsupportedContent
3227     \brief whether QWebPage should forward unsupported content
3228
3229     If enabled, the unsupportedContent() signal is emitted with a network reply that
3230     can be used to read the content.
3231
3232     If disabled, the download of such content is aborted immediately.
3233
3234     By default unsupported content is not forwarded.
3235 */
3236
3237 void QWebPage::setForwardUnsupportedContent(bool forward)
3238 {
3239     d->forwardUnsupportedContent = forward;
3240 }
3241
3242 bool QWebPage::forwardUnsupportedContent() const
3243 {
3244     return d->forwardUnsupportedContent;
3245 }
3246
3247 /*!
3248     \property QWebPage::linkDelegationPolicy
3249     \brief how QWebPage should delegate the handling of links through the
3250     linkClicked() signal
3251
3252     The default is to delegate no links.
3253 */
3254
3255 void QWebPage::setLinkDelegationPolicy(LinkDelegationPolicy policy)
3256 {
3257     d->linkPolicy = policy;
3258 }
3259
3260 QWebPage::LinkDelegationPolicy QWebPage::linkDelegationPolicy() const
3261 {
3262     return d->linkPolicy;
3263 }
3264
3265 #ifndef QT_NO_CONTEXTMENU
3266
3267 static bool handleScrollbarContextMenuEvent(Scrollbar* scrollBar, QContextMenuEvent* event)
3268 {
3269     if (!QApplication::style()->styleHint(QStyle::SH_ScrollBar_ContextMenu))
3270         return true;
3271
3272     bool horizontal = (scrollBar->orientation() == HorizontalScrollbar);
3273
3274     QMenu menu;
3275     QAction* actScrollHere = menu.addAction(QCoreApplication::translate("QWebPage", "Scroll here"));
3276     menu.addSeparator();
3277
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();
3281
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();
3285
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"));
3288
3289     QAction* actionSelected = menu.exec(event->globalPos());
3290
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);
3312     return true;
3313 }
3314
3315 /*!
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;
3318     otherwise false.
3319
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
3322     Maps}, for example.
3323 */
3324 bool QWebPage::swallowContextMenuEvent(QContextMenuEvent *event)
3325 {
3326     d->page->contextMenuController()->clearContextMenu();
3327
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);
3332     }
3333
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.
3340
3341     return !menu;
3342 }
3343 #endif // QT_NO_CONTEXTMENU
3344
3345 /*!
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.
3348 */
3349 void QWebPage::updatePositionDependentActions(const QPoint &pos)
3350 {
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);
3359         }
3360     }
3361 #endif // QT_NO_ACTION
3362
3363     d->createMainFrame();
3364     WebCore::Frame* focusedFrame = d->page->focusController()->focusedOrMainFrame();
3365
3366     HitTestResult result = focusedFrame->eventHandler()->hitTestResultAtPoint(focusedFrame->view()->windowToContents(pos));
3367     if (result.scrollbar())
3368         d->hitTestResult = QWebHitTestResult();
3369     else
3370         d->hitTestResult = QWebHitTestResult(new QWebHitTestResultPrivate(result));
3371     d->page->contextMenuController()->setHitTestResult(result);
3372
3373 #if ENABLE(INSPECTOR)
3374     if (d->page->inspectorController()->enabled())
3375         d->page->contextMenuController()->addInspectElementItem();
3376 #endif
3377
3378     QBitArray visitedWebActions(QWebPage::WebActionCount);
3379
3380 #ifndef QT_NO_CONTEXTMENU
3381     delete d->currentContextMenu.data();
3382
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
3386
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);
3394         }
3395     }
3396 #endif // QT_NO_ACTION
3397
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
3400     // the menu.
3401
3402 }
3403
3404
3405
3406 /*!
3407     \enum QWebPage::Extension
3408
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().
3411
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.
3416
3417     \value ErrorPageExtension Whether the web page can provide an error page when loading fails.
3418     (introduced in Qt 4.6)
3419
3420     \sa ChooseMultipleFilesExtensionOption, ChooseMultipleFilesExtensionReturn, ErrorPageExtensionOption, ErrorPageExtensionReturn
3421 */
3422
3423 /*!
3424     \enum QWebPage::ErrorDomain
3425     \since 4.6
3426
3427     This enum describes the domain of an ErrorPageExtensionOption object (i.e. the layer in which the error occurred).
3428
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.
3432 */
3433
3434 /*!
3435     \class QWebPage::ExtensionOption
3436     \since 4.4
3437     \brief The ExtensionOption class provides an extended input argument to QWebPage's extension support.
3438
3439     \inmodule QtWebKit
3440
3441     \sa QWebPage::extension(), QWebPage::ExtensionReturn
3442 */
3443
3444
3445 /*!
3446     \class QWebPage::ExtensionReturn
3447     \since 4.4
3448     \brief The ExtensionReturn class provides an output result from a QWebPage's extension.
3449
3450     \inmodule QtWebKit
3451
3452     \sa QWebPage::extension(), QWebPage::ExtensionOption
3453 */
3454
3455 /*!
3456     \class QWebPage::ErrorPageExtensionOption
3457     \since 4.6
3458     \brief The ErrorPageExtensionOption class describes the option
3459     for the error page extension.
3460
3461     \inmodule QtWebKit
3462
3463     The ErrorPageExtensionOption class holds the \a url for which an error occurred as well as
3464     the associated \a frame.
3465
3466     The error itself is reported by an error \a domain, the \a error code as well as \a errorString.
3467
3468     \sa QWebPage::extension(), QWebPage::ErrorPageExtensionReturn
3469 */
3470
3471 /*!
3472     \variable QWebPage::ErrorPageExtensionOption::url
3473     \brief the url for which an error occurred
3474 */
3475
3476 /*!
3477     \variable QWebPage::ErrorPageExtensionOption::frame
3478     \brief the frame associated with the error
3479 */
3480
3481 /*!
3482     \variable QWebPage::ErrorPageExtensionOption::domain
3483     \brief the domain that reported the error
3484 */
3485
3486 /*!
3487     \variable QWebPage::ErrorPageExtensionOption::error
3488     \brief the error code. Interpretation of the value depends on the \a domain
3489     \sa QWebPage::ErrorDomain
3490 */
3491
3492 /*!
3493     \variable QWebPage::ErrorPageExtensionOption::errorString
3494     \brief a string that describes the error
3495 */
3496
3497 /*!
3498     \class QWebPage::ErrorPageExtensionReturn
3499     \since 4.6
3500     \brief The ErrorPageExtensionReturn describes the error page, which will be shown for the
3501     frame for which the error occured.
3502
3503     \inmodule QtWebKit
3504
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.
3508
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.
3511
3512     External objects such as stylesheets or images&nb