[Qt][WK2] fast/forms/access-key-for-all-elements.html fails
[WebKit-https.git] / Source / WebKit / qt / Api / qwebpage.cpp
1 /*
2     Copyright (C) 2008, 2009, 2012 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 "UserAgentQt.h"
117 #include "WebEventConversion.h"
118 #include "WebKitVersion.h"
119 #include "WindowFeatures.h"
120 #include "WorkerThread.h"
121
122 #include <QAction>
123 #include <QApplication>
124 #include <QBasicTimer>
125 #include <QBitArray>
126 #include <QColorDialog>
127 #include <QDebug>
128 #include <QDesktopWidget>
129 #include <QDragEnterEvent>
130 #include <QDragLeaveEvent>
131 #include <QDragMoveEvent>
132 #include <QDropEvent>
133 #include <QFileDialog>
134 #include <QInputDialog>
135 #include <QLabel>
136 #include <QMenu>
137 #include <QMessageBox>
138 #include <QNetworkProxy>
139 #include <QUndoStack>
140 #include <QUrl>
141 #include <QPainter>
142 #include <QClipboard>
143 #include <QSslSocket>
144 #include <QStyle>
145 #include <QSysInfo>
146 #include <QTextCharFormat>
147 #include <QTouchEvent>
148 #include <QNetworkAccessManager>
149 #include <QNetworkRequest>
150 #if defined(Q_WS_X11)
151 #include <QX11Info>
152 #endif
153 #if USE(QT_MOBILITY_SYSTEMINFO)
154 #include <qsysteminfo.h>
155 #endif
156
157 using namespace WebCore;
158
159 // from text/qfont.cpp
160 QT_BEGIN_NAMESPACE
161 extern Q_GUI_EXPORT int qt_defaultDpi();
162 QT_END_NAMESPACE
163
164 bool QWebPagePrivate::drtRun = false;
165
166 // Lookup table mapping QWebPage::WebActions to the associated Editor commands
167 static const char* editorCommandWebActions[] =
168 {
169     0, // OpenLink,
170
171     0, // OpenLinkInNewWindow,
172     0, // OpenFrameInNewWindow,
173
174     0, // DownloadLinkToDisk,
175     0, // CopyLinkToClipboard,
176
177     0, // OpenImageInNewWindow,
178     0, // DownloadImageToDisk,
179     0, // CopyImageToClipboard,
180
181     0, // Back,
182     0, // Forward,
183     0, // Stop,
184     0, // Reload,
185
186     "Cut", // Cut,
187     "Copy", // Copy,
188     "Paste", // Paste,
189
190     "Undo", // Undo,
191     "Redo", // Redo,
192     "MoveForward", // MoveToNextChar,
193     "MoveBackward", // MoveToPreviousChar,
194     "MoveWordForward", // MoveToNextWord,
195     "MoveWordBackward", // MoveToPreviousWord,
196     "MoveDown", // MoveToNextLine,
197     "MoveUp", // MoveToPreviousLine,
198     "MoveToBeginningOfLine", // MoveToStartOfLine,
199     "MoveToEndOfLine", // MoveToEndOfLine,
200     "MoveToBeginningOfParagraph", // MoveToStartOfBlock,
201     "MoveToEndOfParagraph", // MoveToEndOfBlock,
202     "MoveToBeginningOfDocument", // MoveToStartOfDocument,
203     "MoveToEndOfDocument", // MoveToEndOfDocument,
204     "MoveForwardAndModifySelection", // SelectNextChar,
205     "MoveBackwardAndModifySelection", // SelectPreviousChar,
206     "MoveWordForwardAndModifySelection", // SelectNextWord,
207     "MoveWordBackwardAndModifySelection", // SelectPreviousWord,
208     "MoveDownAndModifySelection", // SelectNextLine,
209     "MoveUpAndModifySelection", // SelectPreviousLine,
210     "MoveToBeginningOfLineAndModifySelection", // SelectStartOfLine,
211     "MoveToEndOfLineAndModifySelection", // SelectEndOfLine,
212     "MoveToBeginningOfParagraphAndModifySelection", // SelectStartOfBlock,
213     "MoveToEndOfParagraphAndModifySelection", // SelectEndOfBlock,
214     "MoveToBeginningOfDocumentAndModifySelection", //SelectStartOfDocument,
215     "MoveToEndOfDocumentAndModifySelection", // SelectEndOfDocument,
216     "DeleteWordBackward", // DeleteStartOfWord,
217     "DeleteWordForward", // DeleteEndOfWord,
218
219     0, // SetTextDirectionDefault,
220     0, // SetTextDirectionLeftToRight,
221     0, // SetTextDirectionRightToLeft,
222
223     "ToggleBold", // ToggleBold,
224     "ToggleItalic", // ToggleItalic,
225     "ToggleUnderline", // ToggleUnderline,
226
227     0, // InspectElement,
228
229     "InsertNewline", // InsertParagraphSeparator
230     "InsertLineBreak", // InsertLineSeparator
231
232     "SelectAll", // SelectAll
233     0, // ReloadAndBypassCache,
234
235     "PasteAndMatchStyle", // PasteAndMatchStyle
236     "RemoveFormat", // RemoveFormat
237     "Strikethrough", // ToggleStrikethrough,
238     "Subscript", // ToggleSubscript
239     "Superscript", // ToggleSuperscript
240     "InsertUnorderedList", // InsertUnorderedList
241     "InsertOrderedList", // InsertOrderedList
242     "Indent", // Indent
243     "Outdent", // Outdent,
244
245     "AlignCenter", // AlignCenter,
246     "AlignJustified", // AlignJustified,
247     "AlignLeft", // AlignLeft,
248     "AlignRight", // AlignRight,
249
250     0, // StopScheduledPageRefresh,
251
252     0, // CopyImageUrlToClipboard,
253
254     0 // WebActionCount
255 };
256
257 // Lookup the appropriate editor command to use for WebAction \a action
258 const char* QWebPagePrivate::editorCommandForWebActions(QWebPage::WebAction action)
259 {
260     if ((action > QWebPage::NoWebAction) && (action < int(sizeof(editorCommandWebActions) / sizeof(const char*))))
261         return editorCommandWebActions[action];
262     return 0;
263 }
264
265 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
266 {
267     unsigned result = 0;
268     if (actions & Qt::CopyAction)
269         result |= DragOperationCopy;
270     // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
271     // hence it should be considered as "move"
272     if (actions & Qt::MoveAction)
273         result |= (DragOperationMove | DragOperationGeneric);
274     if (actions & Qt::LinkAction)
275         result |= DragOperationLink;
276     if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink))
277         result = DragOperationEvery;
278     return (DragOperation)result;
279 }
280
281 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
282 {
283     Qt::DropAction result = Qt::IgnoreAction;
284     if (actions & DragOperationCopy)
285         result = Qt::CopyAction;
286     else if (actions & DragOperationMove)
287         result = Qt::MoveAction;
288     // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
289     // hence it should be considered as "move"
290     else if (actions & DragOperationGeneric)
291         result = Qt::MoveAction;
292     else if (actions & DragOperationLink)
293         result = Qt::LinkAction;
294     return result;
295 }
296
297 QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
298     : q(qq)
299     , page(0)
300 #ifndef QT_NO_UNDOSTACK
301     , undoStack(0)
302 #endif
303     , insideOpenCall(false)
304     , m_totalBytes(0)
305     , m_bytesReceived()
306     , clickCausedFocus(false)
307     , networkManager(0)
308     , forwardUnsupportedContent(false)
309     , smartInsertDeleteEnabled(true)
310     , selectTrailingWhitespaceEnabled(false)
311     , linkPolicy(QWebPage::DontDelegateLinks)
312     , viewportSize(QSize(0, 0))
313     , settings(0)
314     , useFixedLayout(false)
315     , pluginFactory(0)
316     , inspectorFrontend(0)
317     , inspector(0)
318     , inspectorIsInternalOnly(false)
319     , m_lastDropAction(Qt::IgnoreAction)
320 {
321 #if ENABLE(GEOLOCATION) || ENABLE(DEVICE_ORIENTATION)
322     bool useMock = QWebPagePrivate::drtRun;
323 #endif
324
325     WebCore::initializeWebCoreQt();
326
327     Page::PageClients pageClients;
328     pageClients.chromeClient = new ChromeClientQt(q);
329     pageClients.contextMenuClient = new ContextMenuClientQt();
330     pageClients.editorClient = new EditorClientQt(q);
331     pageClients.dragClient = new DragClientQt(q);
332     pageClients.inspectorClient = new InspectorClientQt(q);
333     page = new Page(pageClients);
334 #if ENABLE(GEOLOCATION)
335     if (useMock) {
336         // In case running in DumpRenderTree mode set the controller to mock provider.
337         GeolocationClientMock* mock = new GeolocationClientMock;
338         WebCore::provideGeolocationTo(page, mock);
339         mock->setController(WebCore::GeolocationController::from(page));
340     } else
341         WebCore::provideGeolocationTo(page, new GeolocationClientQt(q));
342 #endif
343 #if ENABLE(DEVICE_ORIENTATION)
344     if (useMock)
345         WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientMock);
346     else
347         WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientQt);
348     WebCore::provideDeviceMotionTo(page, new DeviceMotionClientQt);
349 #endif
350 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
351     WebCore::provideNotification(page, NotificationPresenterClientQt::notificationPresenter());
352 #endif
353
354     // By default each page is put into their own unique page group, which affects popup windows
355     // and visited links. Page groups (per process only) is a feature making it possible to use
356     // separate settings for each group, so that for instance an integrated browser/email reader
357     // can use different settings for displaying HTML pages and HTML email. To make QtWebKit work
358     // as expected out of the box, we use a default group similar to what other ports are doing.
359     page->setGroupName("Default Group");
360
361     settings = new QWebSettings(page->settings());
362
363     history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList()));
364     memset(actions, 0, sizeof(actions));
365
366     PageGroup::setShouldTrackVisitedLinks(true);
367     
368 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
369     NotificationPresenterClientQt::notificationPresenter()->addClient();
370 #endif
371 }
372
373 QWebPagePrivate::~QWebPagePrivate()
374 {
375     if (inspector && inspectorIsInternalOnly) {
376         // Since we have to delete an internal inspector,
377         // call setInspector(0) directly to prevent potential crashes
378         setInspector(0);
379     }
380 #ifndef QT_NO_CONTEXTMENU
381     delete currentContextMenu.data();
382 #endif
383 #ifndef QT_NO_UNDOSTACK
384     delete undoStack;
385 #endif
386     delete settings;
387     delete page;
388     
389     if (inspector)
390         inspector->setPage(0);
391
392 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
393     NotificationPresenterClientQt::notificationPresenter()->removeClient();
394 #endif
395 }
396
397 WebCore::ViewportArguments QWebPagePrivate::viewportArguments()
398 {
399     return page ? page->viewportArguments() : WebCore::ViewportArguments();
400 }
401
402 WebCore::Page* QWebPagePrivate::core(const QWebPage* page)
403 {
404     return page->d->page;
405 }
406
407 QWebPagePrivate* QWebPagePrivate::priv(QWebPage* page)
408 {
409     return page->d;
410 }
411
412 bool QWebPagePrivate::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
413 {
414     if (insideOpenCall
415         && frame == mainFrame.data())
416         return true;
417     return q->acceptNavigationRequest(frame, request, type);
418 }
419
420 void QWebPagePrivate::createMainFrame()
421 {
422     if (!mainFrame) {
423         QWebFrameData frameData(page);
424         mainFrame = new QWebFrame(q, &frameData);
425
426         emit q->frameCreated(mainFrame.data());
427     }
428 }
429
430 static QWebPage::WebAction webActionForContextMenuAction(WebCore::ContextMenuAction action)
431 {
432     switch (action) {
433         case WebCore::ContextMenuItemTagOpenLink: return QWebPage::OpenLink;
434         case WebCore::ContextMenuItemTagOpenLinkInNewWindow: return QWebPage::OpenLinkInNewWindow;
435         case WebCore::ContextMenuItemTagDownloadLinkToDisk: return QWebPage::DownloadLinkToDisk;
436         case WebCore::ContextMenuItemTagCopyLinkToClipboard: return QWebPage::CopyLinkToClipboard;
437         case WebCore::ContextMenuItemTagOpenImageInNewWindow: return QWebPage::OpenImageInNewWindow;
438         case WebCore::ContextMenuItemTagDownloadImageToDisk: return QWebPage::DownloadImageToDisk;
439         case WebCore::ContextMenuItemTagCopyImageToClipboard: return QWebPage::CopyImageToClipboard;
440         case WebCore::ContextMenuItemTagCopyImageUrlToClipboard: return QWebPage::CopyImageUrlToClipboard;
441         case WebCore::ContextMenuItemTagOpenFrameInNewWindow: return QWebPage::OpenFrameInNewWindow;
442         case WebCore::ContextMenuItemTagCopy: return QWebPage::Copy;
443         case WebCore::ContextMenuItemTagGoBack: return QWebPage::Back;
444         case WebCore::ContextMenuItemTagGoForward: return QWebPage::Forward;
445         case WebCore::ContextMenuItemTagStop: return QWebPage::Stop;
446         case WebCore::ContextMenuItemTagReload: return QWebPage::Reload;
447         case WebCore::ContextMenuItemTagCut: return QWebPage::Cut;
448         case WebCore::ContextMenuItemTagPaste: return QWebPage::Paste;
449         case WebCore::ContextMenuItemTagDefaultDirection: return QWebPage::SetTextDirectionDefault;
450         case WebCore::ContextMenuItemTagLeftToRight: return QWebPage::SetTextDirectionLeftToRight;
451         case WebCore::ContextMenuItemTagRightToLeft: return QWebPage::SetTextDirectionRightToLeft;
452         case WebCore::ContextMenuItemTagBold: return QWebPage::ToggleBold;
453         case WebCore::ContextMenuItemTagItalic: return QWebPage::ToggleItalic;
454         case WebCore::ContextMenuItemTagUnderline: return QWebPage::ToggleUnderline;
455         case WebCore::ContextMenuItemTagSelectAll: return QWebPage::SelectAll;
456 #if ENABLE(INSPECTOR)
457         case WebCore::ContextMenuItemTagInspectElement: return QWebPage::InspectElement;
458 #endif
459         default: break;
460     }
461     return QWebPage::NoWebAction;
462 }
463
464 #ifndef QT_NO_CONTEXTMENU
465 QMenu *QWebPagePrivate::createContextMenu(const WebCore::ContextMenu *webcoreMenu,
466         const QList<WebCore::ContextMenuItem> *items, QBitArray *visitedWebActions)
467 {
468     if (!client || !webcoreMenu)
469         return 0;
470
471     QMenu* menu = new QMenu(client->ownerWidget());
472     for (int i = 0; i < items->count(); ++i) {
473         const ContextMenuItem &item = items->at(i);
474         switch (item.type()) {
475             case WebCore::CheckableActionType: /* fall through */
476             case WebCore::ActionType: {
477                 QWebPage::WebAction action = webActionForContextMenuAction(item.action());
478                 QAction *a = q->action(action);
479                 if (a) {
480                     ContextMenuItem it(item);
481                     page->contextMenuController()->checkOrEnableIfNeeded(it);
482                     PlatformMenuItemDescription desc = it.releasePlatformDescription();
483                     a->setEnabled(desc.enabled);
484                     a->setChecked(desc.checked);
485                     a->setCheckable(item.type() == WebCore::CheckableActionType);
486
487                     menu->addAction(a);
488                     visitedWebActions->setBit(action);
489                 }
490                 break;
491             }
492             case WebCore::SeparatorType:
493                 menu->addSeparator();
494                 break;
495             case WebCore::SubmenuType: {
496                 QMenu *subMenu = createContextMenu(webcoreMenu, item.platformSubMenu(), visitedWebActions);
497
498                 bool anyEnabledAction = false;
499
500                 QList<QAction *> actions = subMenu->actions();
501                 for (int i = 0; i < actions.count(); ++i) {
502                     if (actions.at(i)->isVisible())
503                         anyEnabledAction |= actions.at(i)->isEnabled();
504                 }
505
506                 // don't show sub-menus with just disabled actions
507                 if (anyEnabledAction) {
508                     subMenu->setTitle(item.title());
509                     menu->addAction(subMenu->menuAction());
510                 } else
511                     delete subMenu;
512                 break;
513             }
514         }
515     }
516     return menu;
517 }
518 #endif // QT_NO_CONTEXTMENU
519
520 #ifndef QT_NO_ACTION
521 void QWebPagePrivate::_q_webActionTriggered(bool checked)
522 {
523     QAction *a = qobject_cast<QAction *>(q->sender());
524     if (!a)
525         return;
526     QWebPage::WebAction action = static_cast<QWebPage::WebAction>(a->data().toInt());
527     q->triggerAction(action, checked);
528 }
529 #endif // QT_NO_ACTION
530
531 void QWebPagePrivate::_q_cleanupLeakMessages()
532 {
533 #ifndef NDEBUG
534     // Need this to make leak messages accurate.
535     memoryCache()->setCapacities(0, 0, 0);
536 #endif
537 }
538
539 void QWebPagePrivate::updateAction(QWebPage::WebAction action)
540 {
541 #ifdef QT_NO_ACTION
542     Q_UNUSED(action)
543 #else
544     QAction *a = actions[action];
545     if (!a || !mainFrame)
546         return;
547
548     WebCore::FrameLoader *loader = mainFrame.data()->d->frame->loader();
549     WebCore::Editor *editor = page->focusController()->focusedOrMainFrame()->editor();
550
551     bool enabled = a->isEnabled();
552     bool checked = a->isChecked();
553
554     switch (action) {
555         case QWebPage::Back:
556             enabled = page->canGoBackOrForward(-1);
557             break;
558         case QWebPage::Forward:
559             enabled = page->canGoBackOrForward(1);
560             break;
561         case QWebPage::Stop:
562             enabled = loader->isLoading();
563             break;
564         case QWebPage::Reload:
565         case QWebPage::ReloadAndBypassCache:
566             enabled = !loader->isLoading();
567             break;
568 #ifndef QT_NO_UNDOSTACK
569         case QWebPage::Undo:
570         case QWebPage::Redo:
571             // those two are handled by QUndoStack
572             break;
573 #endif // QT_NO_UNDOSTACK
574         case QWebPage::SelectAll: // editor command is always enabled
575             break;
576         case QWebPage::SetTextDirectionDefault:
577         case QWebPage::SetTextDirectionLeftToRight:
578         case QWebPage::SetTextDirectionRightToLeft:
579             enabled = editor->canEdit();
580             checked = false;
581             break;
582         default: {
583             // see if it's an editor command
584             const char* commandName = editorCommandForWebActions(action);
585
586             // if it's an editor command, let it's logic determine state
587             if (commandName) {
588                 Editor::Command command = editor->command(commandName);
589                 enabled = command.isEnabled();
590                 if (enabled)
591                     checked = command.state() != FalseTriState;
592                 else
593                     checked = false;
594             }
595             break;
596         }
597     }
598
599     a->setEnabled(enabled);
600
601     if (a->isCheckable())
602         a->setChecked(checked);
603 #endif // QT_NO_ACTION
604 }
605
606 void QWebPagePrivate::updateNavigationActions()
607 {
608     updateAction(QWebPage::Back);
609     updateAction(QWebPage::Forward);
610     updateAction(QWebPage::Stop);
611     updateAction(QWebPage::Reload);
612     updateAction(QWebPage::ReloadAndBypassCache);
613 }
614
615 void QWebPagePrivate::updateEditorActions()
616 {
617     updateAction(QWebPage::Cut);
618     updateAction(QWebPage::Copy);
619     updateAction(QWebPage::Paste);
620     updateAction(QWebPage::MoveToNextChar);
621     updateAction(QWebPage::MoveToPreviousChar);
622     updateAction(QWebPage::MoveToNextWord);
623     updateAction(QWebPage::MoveToPreviousWord);
624     updateAction(QWebPage::MoveToNextLine);
625     updateAction(QWebPage::MoveToPreviousLine);
626     updateAction(QWebPage::MoveToStartOfLine);
627     updateAction(QWebPage::MoveToEndOfLine);
628     updateAction(QWebPage::MoveToStartOfBlock);
629     updateAction(QWebPage::MoveToEndOfBlock);
630     updateAction(QWebPage::MoveToStartOfDocument);
631     updateAction(QWebPage::MoveToEndOfDocument);
632     updateAction(QWebPage::SelectNextChar);
633     updateAction(QWebPage::SelectPreviousChar);
634     updateAction(QWebPage::SelectNextWord);
635     updateAction(QWebPage::SelectPreviousWord);
636     updateAction(QWebPage::SelectNextLine);
637     updateAction(QWebPage::SelectPreviousLine);
638     updateAction(QWebPage::SelectStartOfLine);
639     updateAction(QWebPage::SelectEndOfLine);
640     updateAction(QWebPage::SelectStartOfBlock);
641     updateAction(QWebPage::SelectEndOfBlock);
642     updateAction(QWebPage::SelectStartOfDocument);
643     updateAction(QWebPage::SelectEndOfDocument);
644     updateAction(QWebPage::DeleteStartOfWord);
645     updateAction(QWebPage::DeleteEndOfWord);
646     updateAction(QWebPage::SetTextDirectionDefault);
647     updateAction(QWebPage::SetTextDirectionLeftToRight);
648     updateAction(QWebPage::SetTextDirectionRightToLeft);
649     updateAction(QWebPage::ToggleBold);
650     updateAction(QWebPage::ToggleItalic);
651     updateAction(QWebPage::ToggleUnderline);
652     updateAction(QWebPage::InsertParagraphSeparator);
653     updateAction(QWebPage::InsertLineSeparator);
654     updateAction(QWebPage::PasteAndMatchStyle);
655     updateAction(QWebPage::RemoveFormat);
656     updateAction(QWebPage::ToggleStrikethrough);
657     updateAction(QWebPage::ToggleSubscript);
658     updateAction(QWebPage::ToggleSuperscript);
659     updateAction(QWebPage::InsertUnorderedList);
660     updateAction(QWebPage::InsertOrderedList);
661     updateAction(QWebPage::Indent);
662     updateAction(QWebPage::Outdent);
663     updateAction(QWebPage::AlignCenter);
664     updateAction(QWebPage::AlignJustified);
665     updateAction(QWebPage::AlignLeft);
666     updateAction(QWebPage::AlignRight);
667 }
668
669 void QWebPagePrivate::timerEvent(QTimerEvent *ev)
670 {
671     int timerId = ev->timerId();
672     if (timerId == tripleClickTimer.timerId())
673         tripleClickTimer.stop();
674     else
675         q->timerEvent(ev);
676 }
677
678 template<class T>
679 void QWebPagePrivate::mouseMoveEvent(T* ev)
680 {
681     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
682     if (!frame->view())
683         return;
684
685     bool accepted = frame->eventHandler()->mouseMoved(convertMouseEvent(ev, 0));
686     ev->setAccepted(accepted);
687 }
688
689 template<class T>
690 void QWebPagePrivate::mousePressEvent(T* ev)
691 {
692     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
693     if (!frame->view())
694         return;
695
696     RefPtr<WebCore::Node> oldNode;
697     Frame* focusedFrame = page->focusController()->focusedFrame();
698     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
699         oldNode = focusedDocument->focusedNode();
700
701     if (tripleClickTimer.isActive()
702             && (ev->pos() - tripleClick).manhattanLength()
703                 < QApplication::startDragDistance()) {
704         mouseTripleClickEvent(ev);
705         return;
706     }
707
708     bool accepted = false;
709     adjustPointForClicking(ev);
710     PlatformMouseEvent mev = convertMouseEvent(ev, 1);
711     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
712     if (mev.button() != NoButton)
713         accepted = frame->eventHandler()->handleMousePressEvent(mev);
714     ev->setAccepted(accepted);
715
716     RefPtr<WebCore::Node> newNode;
717     focusedFrame = page->focusController()->focusedFrame();
718     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
719         newNode = focusedDocument->focusedNode();
720
721     if (newNode && oldNode != newNode)
722         clickCausedFocus = true;
723 }
724
725 template<class T>
726 void QWebPagePrivate::mouseDoubleClickEvent(T *ev)
727 {
728     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
729     if (!frame->view())
730         return;
731
732     bool accepted = false;
733     PlatformMouseEvent mev = convertMouseEvent(ev, 2);
734     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
735     if (mev.button() != NoButton)
736         accepted = frame->eventHandler()->handleMousePressEvent(mev);
737     ev->setAccepted(accepted);
738
739     tripleClickTimer.start(QApplication::doubleClickInterval(), q);
740     tripleClick = QPointF(ev->pos()).toPoint();
741 }
742
743 template<class T>
744 void QWebPagePrivate::mouseTripleClickEvent(T *ev)
745 {
746     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
747     if (!frame->view())
748         return;
749
750     bool accepted = false;
751     PlatformMouseEvent mev = convertMouseEvent(ev, 3);
752     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
753     if (mev.button() != NoButton)
754         accepted = frame->eventHandler()->handleMousePressEvent(mev);
755     ev->setAccepted(accepted);
756 }
757
758 void QWebPagePrivate::handleClipboard(QEvent* ev, Qt::MouseButton button)
759 {
760 #ifndef QT_NO_CLIPBOARD
761     if (QApplication::clipboard()->supportsSelection()) {
762         WebCore::Frame* focusFrame = page->focusController()->focusedOrMainFrame();
763         if (button == Qt::MidButton) {
764             if (focusFrame) {
765                 focusFrame->editor()->command(AtomicString("PasteGlobalSelection")).execute();
766                 ev->setAccepted(true);
767             }
768         }
769     }
770 #endif
771 }
772
773 template<class T>
774 void QWebPagePrivate::mouseReleaseEvent(T *ev)
775 {
776     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
777     if (!frame->view())
778         return;
779
780     bool accepted = false;
781     adjustPointForClicking(ev);
782     PlatformMouseEvent mev = convertMouseEvent(ev, 0);
783     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
784     if (mev.button() != NoButton)
785         accepted = frame->eventHandler()->handleMouseReleaseEvent(mev);
786     ev->setAccepted(accepted);
787
788     if (!ev->isAccepted())
789         handleClipboard(ev, ev->button());
790     handleSoftwareInputPanel(ev->button(), QPointF(ev->pos()).toPoint());
791 }
792
793 void QWebPagePrivate::handleSoftwareInputPanel(Qt::MouseButton button, const QPoint& pos)
794 {
795     Frame* frame = page->focusController()->focusedFrame();
796     if (!frame)
797         return;
798
799     if (client && client->inputMethodEnabled()
800         && frame->document()->focusedNode()
801         && button == Qt::LeftButton && qApp->autoSipEnabled()) {
802         QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
803             client->ownerWidget()->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
804         if (!clickCausedFocus || behavior == QStyle::RSIP_OnMouseClick) {
805             HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(frame->view()->windowToContents(pos), false);
806             if (result.isContentEditable()) {
807                 QEvent event(QEvent::RequestSoftwareInputPanel);
808                 QApplication::sendEvent(client->ownerWidget(), &event);
809             }
810         }
811     }
812
813     clickCausedFocus = false;
814 }
815
816 #ifndef QT_NO_CONTEXTMENU
817 void QWebPagePrivate::contextMenuEvent(const QPoint& globalPos)
818 {
819     QMenu *menu = q->createStandardContextMenu();
820     if (menu) {
821         menu->exec(globalPos);
822         delete menu;
823     }
824 }
825 #endif // QT_NO_CONTEXTMENU
826
827 /*!
828     \since 4.5
829     This function creates the standard context menu which is shown when
830     the user clicks on the web page with the right mouse button. It is
831     called from the default contextMenuEvent() handler. The popup menu's
832     ownership is transferred to the caller.
833  */
834 QMenu *QWebPage::createStandardContextMenu()
835 {
836 #ifndef QT_NO_CONTEXTMENU
837     QMenu* menu = d->currentContextMenu.data();
838     d->currentContextMenu = 0;
839     return menu;
840 #else
841     return 0;
842 #endif
843 }
844
845 #ifndef QT_NO_WHEELEVENT
846 template<class T>
847 void QWebPagePrivate::wheelEvent(T *ev)
848 {
849     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
850     if (!frame->view())
851         return;
852
853     PlatformWheelEvent pev = convertWheelEvent(ev);
854     bool accepted = frame->eventHandler()->handleWheelEvent(pev);
855     ev->setAccepted(accepted);
856 }
857 #endif // QT_NO_WHEELEVENT
858
859 #ifndef QT_NO_SHORTCUT
860 QWebPage::WebAction QWebPagePrivate::editorActionForKeyEvent(QKeyEvent* event)
861 {
862     static struct {
863         QKeySequence::StandardKey standardKey;
864         QWebPage::WebAction action;
865     } editorActions[] = {
866         { QKeySequence::Cut, QWebPage::Cut },
867         { QKeySequence::Copy, QWebPage::Copy },
868         { QKeySequence::Paste, QWebPage::Paste },
869         { QKeySequence::Undo, QWebPage::Undo },
870         { QKeySequence::Redo, QWebPage::Redo },
871         { QKeySequence::MoveToNextChar, QWebPage::MoveToNextChar },
872         { QKeySequence::MoveToPreviousChar, QWebPage::MoveToPreviousChar },
873         { QKeySequence::MoveToNextWord, QWebPage::MoveToNextWord },
874         { QKeySequence::MoveToPreviousWord, QWebPage::MoveToPreviousWord },
875         { QKeySequence::MoveToNextLine, QWebPage::MoveToNextLine },
876         { QKeySequence::MoveToPreviousLine, QWebPage::MoveToPreviousLine },
877         { QKeySequence::MoveToStartOfLine, QWebPage::MoveToStartOfLine },
878         { QKeySequence::MoveToEndOfLine, QWebPage::MoveToEndOfLine },
879         { QKeySequence::MoveToStartOfBlock, QWebPage::MoveToStartOfBlock },
880         { QKeySequence::MoveToEndOfBlock, QWebPage::MoveToEndOfBlock },
881         { QKeySequence::MoveToStartOfDocument, QWebPage::MoveToStartOfDocument },
882         { QKeySequence::MoveToEndOfDocument, QWebPage::MoveToEndOfDocument },
883         { QKeySequence::SelectNextChar, QWebPage::SelectNextChar },
884         { QKeySequence::SelectPreviousChar, QWebPage::SelectPreviousChar },
885         { QKeySequence::SelectNextWord, QWebPage::SelectNextWord },
886         { QKeySequence::SelectPreviousWord, QWebPage::SelectPreviousWord },
887         { QKeySequence::SelectNextLine, QWebPage::SelectNextLine },
888         { QKeySequence::SelectPreviousLine, QWebPage::SelectPreviousLine },
889         { QKeySequence::SelectStartOfLine, QWebPage::SelectStartOfLine },
890         { QKeySequence::SelectEndOfLine, QWebPage::SelectEndOfLine },
891         { QKeySequence::SelectStartOfBlock, QWebPage::SelectStartOfBlock },
892         { QKeySequence::SelectEndOfBlock,  QWebPage::SelectEndOfBlock },
893         { QKeySequence::SelectStartOfDocument, QWebPage::SelectStartOfDocument },
894         { QKeySequence::SelectEndOfDocument, QWebPage::SelectEndOfDocument },
895         { QKeySequence::DeleteStartOfWord, QWebPage::DeleteStartOfWord },
896         { QKeySequence::DeleteEndOfWord, QWebPage::DeleteEndOfWord },
897         { QKeySequence::InsertParagraphSeparator, QWebPage::InsertParagraphSeparator },
898         { QKeySequence::InsertLineSeparator, QWebPage::InsertLineSeparator },
899         { QKeySequence::SelectAll, QWebPage::SelectAll },
900         { QKeySequence::UnknownKey, QWebPage::NoWebAction }
901     };
902
903     for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
904         if (event == editorActions[i].standardKey)
905             return editorActions[i].action;
906
907     return QWebPage::NoWebAction;
908 }
909 #endif // QT_NO_SHORTCUT
910
911 void QWebPagePrivate::keyPressEvent(QKeyEvent *ev)
912 {
913     bool handled = false;
914     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
915     // we forward the key event to WebCore first to handle potential DOM
916     // defined event handlers and later on end up in EditorClientQt::handleKeyboardEvent
917     // to trigger editor commands via triggerAction().
918     if (!handled)
919         handled = frame->eventHandler()->keyEvent(ev);
920     if (!handled) {
921         handled = true;
922         if (!handleScrolling(ev, frame)) {
923             switch (ev->key()) {
924             case Qt::Key_Back:
925                 q->triggerAction(QWebPage::Back);
926                 break;
927             case Qt::Key_Forward:
928                 q->triggerAction(QWebPage::Forward);
929                 break;
930             case Qt::Key_Stop:
931                 q->triggerAction(QWebPage::Stop);
932                 break;
933             case Qt::Key_Refresh:
934                 q->triggerAction(QWebPage::Reload);
935                 break;
936             case Qt::Key_Backspace:
937                 if (ev->modifiers() == Qt::ShiftModifier)
938                     q->triggerAction(QWebPage::Forward);
939                 else
940                     q->triggerAction(QWebPage::Back);
941                 break;
942             default:
943                 handled = false;
944                 break;
945             }
946         }
947     }
948
949     ev->setAccepted(handled);
950 }
951
952 void QWebPagePrivate::keyReleaseEvent(QKeyEvent *ev)
953 {
954     if (ev->isAutoRepeat()) {
955         ev->setAccepted(true);
956         return;
957     }
958
959     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
960     bool handled = frame->eventHandler()->keyEvent(ev);
961     ev->setAccepted(handled);
962 }
963
964 void QWebPagePrivate::focusInEvent(QFocusEvent*)
965 {
966     FocusController *focusController = page->focusController();
967     focusController->setActive(true);
968     focusController->setFocused(true);
969     if (!focusController->focusedFrame())
970         focusController->setFocusedFrame(QWebFramePrivate::core(mainFrame.data()));
971 }
972
973 void QWebPagePrivate::focusOutEvent(QFocusEvent*)
974 {
975     // only set the focused frame inactive so that we stop painting the caret
976     // and the focus frame. But don't tell the focus controller so that upon
977     // focusInEvent() we can re-activate the frame.
978     FocusController *focusController = page->focusController();
979     // Call setFocused first so that window.onblur doesn't get called twice
980     focusController->setFocused(false);
981     focusController->setActive(false);
982 }
983
984 template<class T>
985 void QWebPagePrivate::dragEnterEvent(T* ev)
986 {
987 #ifndef QT_NO_DRAGANDDROP
988     DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
989             QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
990     Qt::DropAction action = dragOpToDropAction(page->dragController()->dragEntered(&dragData).operation);
991     ev->setDropAction(action);
992     ev->acceptProposedAction();
993 #endif
994 }
995
996 template<class T>
997 void QWebPagePrivate::dragLeaveEvent(T *ev)
998 {
999 #ifndef QT_NO_DRAGANDDROP
1000     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
1001     page->dragController()->dragExited(&dragData);
1002     ev->accept();
1003 #endif
1004 }
1005
1006 template<class T>
1007 void QWebPagePrivate::dragMoveEvent(T *ev)
1008 {
1009 #ifndef QT_NO_DRAGANDDROP
1010     DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
1011             QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
1012     m_lastDropAction = dragOpToDropAction(page->dragController()->dragUpdated(&dragData).operation);
1013     ev->setDropAction(m_lastDropAction);
1014     if (m_lastDropAction != Qt::IgnoreAction)
1015         ev->accept();
1016 #endif
1017 }
1018
1019 template<class T>
1020 void QWebPagePrivate::dropEvent(T *ev)
1021 {
1022 #ifndef QT_NO_DRAGANDDROP
1023     DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
1024             QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
1025     if (page->dragController()->performDrag(&dragData)) {
1026         ev->setDropAction(m_lastDropAction);
1027         ev->accept();
1028     }
1029 #endif
1030 }
1031
1032 void QWebPagePrivate::leaveEvent(QEvent*)
1033 {
1034     // Fake a mouse move event just outside of the widget, since all
1035     // the interesting mouse-out behavior like invalidating scrollbars
1036     // is handled by the WebKit event handler's mouseMoved function.
1037     QMouseEvent fakeEvent(QEvent::MouseMove, QCursor::pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
1038     mouseMoveEvent(&fakeEvent);
1039 }
1040
1041 /*!
1042     \property QWebPage::palette
1043     \brief the page's palette
1044
1045     The base brush of the palette is used to draw the background of the main frame.
1046
1047     By default, this property contains the application's default palette.
1048 */
1049 void QWebPage::setPalette(const QPalette &pal)
1050 {
1051     d->palette = pal;
1052     if (!d->mainFrame || !d->mainFrame.data()->d->frame->view())
1053         return;
1054
1055     QBrush brush = pal.brush(QPalette::Base);
1056     QColor backgroundColor = brush.style() == Qt::SolidPattern ? brush.color() : QColor();
1057     QWebFramePrivate::core(d->mainFrame.data())->view()->updateBackgroundRecursively(backgroundColor, !backgroundColor.alpha());
1058 }
1059
1060 QPalette QWebPage::palette() const
1061 {
1062     return d->palette;
1063 }
1064
1065 void QWebPagePrivate::inputMethodEvent(QInputMethodEvent *ev)
1066 {
1067     WebCore::Frame *frame = page->focusController()->focusedOrMainFrame();
1068     WebCore::Editor *editor = frame->editor();
1069
1070     if (!editor->canEdit()) {
1071         ev->ignore();
1072         return;
1073     }
1074
1075     Node* node = 0;
1076     if (frame->selection()->rootEditableElement())
1077         node = frame->selection()->rootEditableElement()->shadowAncestorNode();
1078
1079     Vector<CompositionUnderline> underlines;
1080     bool hasSelection = false;
1081
1082     for (int i = 0; i < ev->attributes().size(); ++i) {
1083         const QInputMethodEvent::Attribute& a = ev->attributes().at(i);
1084         switch (a.type) {
1085         case QInputMethodEvent::TextFormat: {
1086             QTextCharFormat textCharFormat = a.value.value<QTextFormat>().toCharFormat();
1087             QColor qcolor = textCharFormat.underlineColor();
1088             underlines.append(CompositionUnderline(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)), Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())), false));
1089             break;
1090         }
1091         case QInputMethodEvent::Cursor: {
1092             frame->selection()->setCaretVisible(a.length); //if length is 0 cursor is invisible
1093             if (a.length > 0) {
1094                 RenderObject* caretRenderer = frame->selection()->caretRenderer();
1095                 if (caretRenderer) {
1096                     QColor qcolor = a.value.value<QColor>();
1097                     caretRenderer->style()->setColor(Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())));
1098                 }
1099             }
1100             break;
1101         }
1102         case QInputMethodEvent::Selection: {
1103             hasSelection = true;
1104             // A selection in the inputMethodEvent is always reflected in the visible text
1105             if (node) {
1106                 if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
1107                     textControl->setSelectionRange(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
1108             }
1109
1110             if (!ev->preeditString().isEmpty())
1111                 editor->setComposition(ev->preeditString(), underlines, qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
1112             else {
1113                 // If we are in the middle of a composition, an empty pre-edit string and a selection of zero
1114                 // cancels the current composition
1115                 if (editor->hasComposition() && (a.start + a.length == 0))
1116                     editor->setComposition(QString(), underlines, 0, 0);
1117             }
1118             break;
1119         }
1120         default:
1121             break;
1122         }
1123     }
1124
1125     if (node && ev->replacementLength() > 0) {
1126         int cursorPos = frame->selection()->extent().offsetInContainerNode();
1127         int start = cursorPos + ev->replacementStart();
1128         if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
1129             textControl->setSelectionRange(start, start + ev->replacementLength());
1130         // Commit regardless of whether commitString is empty, to get rid of selection.
1131         editor->confirmComposition(ev->commitString());
1132     } else if (!ev->commitString().isEmpty()) {
1133         if (editor->hasComposition())
1134             editor->confirmComposition(ev->commitString());
1135         else
1136             editor->insertText(ev->commitString(), 0);
1137     } else if (!hasSelection && !ev->preeditString().isEmpty())
1138         editor->setComposition(ev->preeditString(), underlines, 0, 0);
1139     else if (ev->preeditString().isEmpty() && editor->hasComposition())
1140         editor->confirmComposition(String());
1141
1142     ev->accept();
1143 }
1144
1145 #ifndef QT_NO_PROPERTIES
1146 typedef struct {
1147     const char* name;
1148     double deferredRepaintDelay;
1149     double initialDeferredRepaintDelayDuringLoading;
1150     double maxDeferredRepaintDelayDuringLoading;
1151     double deferredRepaintDelayIncrementDuringLoading;
1152 } QRepaintThrottlingPreset;
1153
1154 void QWebPagePrivate::dynamicPropertyChangeEvent(QDynamicPropertyChangeEvent* event)
1155 {
1156     if (event->propertyName() == "_q_viewMode") {
1157         page->setViewMode(Page::stringToViewMode(q->property("_q_viewMode").toString()));
1158     } else if (event->propertyName() == "_q_HTMLTokenizerChunkSize") {
1159         int chunkSize = q->property("_q_HTMLTokenizerChunkSize").toInt();
1160         q->handle()->page->setCustomHTMLTokenizerChunkSize(chunkSize);
1161     } else if (event->propertyName() == "_q_HTMLTokenizerTimeDelay") {
1162         double timeDelay = q->property("_q_HTMLTokenizerTimeDelay").toDouble();
1163         q->handle()->page->setCustomHTMLTokenizerTimeDelay(timeDelay);
1164     } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelay") {
1165         double p = q->property("_q_RepaintThrottlingDeferredRepaintDelay").toDouble();
1166         FrameView::setRepaintThrottlingDeferredRepaintDelay(p);
1167     } else if (event->propertyName() == "_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading") {
1168         double p = q->property("_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading").toDouble();
1169         FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(p);
1170     } else if (event->propertyName() == "_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading") {
1171         double p = q->property("_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading").toDouble();
1172         FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(p);
1173     } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading") {
1174         double p = q->property("_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading").toDouble();
1175         FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(p);
1176     } else if (event->propertyName() == "_q_RepaintThrottlingPreset") {
1177         static const QRepaintThrottlingPreset presets[] = {
1178             {   "NoThrottling",     0,      0,      0,      0 },
1179             {   "Legacy",       0.025,      0,    2.5,    0.5 },
1180             {   "Minimal",       0.01,      0,      1,    0.2 },
1181             {   "Medium",       0.025,      1,      5,    0.5 },
1182             {   "Heavy",          0.1,      2,     10,      1 }
1183         };
1184
1185         QString p = q->property("_q_RepaintThrottlingPreset").toString();
1186         for (size_t i = 0; i < sizeof(presets) / sizeof(presets[0]); i++) {
1187             if (p == QLatin1String(presets[i].name)) {
1188                 FrameView::setRepaintThrottlingDeferredRepaintDelay(
1189                         presets[i].deferredRepaintDelay);
1190                 FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(
1191                         presets[i].initialDeferredRepaintDelayDuringLoading);
1192                 FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(
1193                         presets[i].maxDeferredRepaintDelayDuringLoading);
1194                 FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(
1195                         presets[i].deferredRepaintDelayIncrementDuringLoading);
1196                 break;
1197             }
1198         }
1199     }
1200     else if (event->propertyName() == "_q_webInspectorServerPort") {
1201         InspectorServerQt* inspectorServer = InspectorServerQt::server();
1202         inspectorServer->listen(inspectorServerPort());
1203     } else if (event->propertyName() == "_q_deadDecodedDataDeletionInterval") {
1204         double interval = q->property("_q_deadDecodedDataDeletionInterval").toDouble();
1205         memoryCache()->setDeadDecodedDataDeletionInterval(interval);
1206     }
1207 }
1208 #endif
1209
1210 void QWebPagePrivate::shortcutOverrideEvent(QKeyEvent* event)
1211 {
1212     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
1213     WebCore::Editor* editor = frame->editor();
1214     if (editor->canEdit()) {
1215         if (event->modifiers() == Qt::NoModifier
1216             || event->modifiers() == Qt::ShiftModifier
1217             || event->modifiers() == Qt::KeypadModifier) {
1218                 if (event->key() < Qt::Key_Escape) {
1219                     event->accept();
1220                 } else {
1221                     switch (event->key()) {
1222                     case Qt::Key_Return:
1223                     case Qt::Key_Enter:
1224                     case Qt::Key_Delete:
1225                     case Qt::Key_Home:
1226                     case Qt::Key_End:
1227                     case Qt::Key_Backspace:
1228                     case Qt::Key_Left:
1229                     case Qt::Key_Right:
1230                     case Qt::Key_Up:
1231                     case Qt::Key_Down:
1232                     case Qt::Key_Tab:
1233                         event->accept();
1234                     default:
1235                         break;
1236                     }
1237                 }
1238         }
1239 #ifndef QT_NO_SHORTCUT
1240         else if (editorActionForKeyEvent(event) != QWebPage::NoWebAction)
1241             event->accept();
1242 #endif
1243     }
1244 }
1245
1246 bool QWebPagePrivate::handleScrolling(QKeyEvent *ev, Frame *frame)
1247 {
1248     ScrollDirection direction;
1249     ScrollGranularity granularity;
1250
1251 #ifndef QT_NO_SHORTCUT
1252     if (ev == QKeySequence::MoveToNextPage
1253         || (ev->key() == Qt::Key_Space && !(ev->modifiers() & Qt::ShiftModifier))) {
1254         granularity = ScrollByPage;
1255         direction = ScrollDown;
1256     } else if (ev == QKeySequence::MoveToPreviousPage
1257                || ((ev->key() == Qt::Key_Space) && (ev->modifiers() & Qt::ShiftModifier))) {
1258         granularity = ScrollByPage;
1259         direction = ScrollUp;
1260     } else
1261 #endif // QT_NO_SHORTCUT
1262     if ((ev->key() == Qt::Key_Up && ev->modifiers() & Qt::ControlModifier)
1263                || ev->key() == Qt::Key_Home) {
1264         granularity = ScrollByDocument;
1265         direction = ScrollUp;
1266     } else if ((ev->key() == Qt::Key_Down && ev->modifiers() & Qt::ControlModifier)
1267                || ev->key() == Qt::Key_End) {
1268         granularity = ScrollByDocument;
1269         direction = ScrollDown;
1270     } else {
1271         switch (ev->key()) {
1272             case Qt::Key_Up:
1273                 granularity = ScrollByLine;
1274                 direction = ScrollUp;
1275                 break;
1276             case Qt::Key_Down:
1277                 granularity = ScrollByLine;
1278                 direction = ScrollDown;
1279                 break;
1280             case Qt::Key_Left:
1281                 granularity = ScrollByLine;
1282                 direction = ScrollLeft;
1283                 break;
1284             case Qt::Key_Right:
1285                 granularity = ScrollByLine;
1286                 direction = ScrollRight;
1287                 break;
1288             default:
1289                 return false;
1290         }
1291     }
1292
1293     return frame->eventHandler()->scrollRecursively(direction, granularity);
1294 }
1295
1296 void QWebPagePrivate::adjustPointForClicking(QMouseEvent*)
1297 {
1298     notImplemented();
1299 }
1300
1301 #if !defined(QT_NO_GRAPHICSVIEW)
1302 void QWebPagePrivate::adjustPointForClicking(QGraphicsSceneMouseEvent* ev)
1303 {
1304     QtPlatformPlugin platformPlugin;
1305     OwnPtr<QWebTouchModifier> touchModifier = platformPlugin.createTouchModifier();
1306     if (!touchModifier)
1307         return;
1308
1309     unsigned topPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Up);
1310     unsigned rightPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Right);
1311     unsigned bottomPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Down);
1312     unsigned leftPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Left);
1313
1314     touchModifier = nullptr;
1315
1316     if (!topPadding && !rightPadding && !bottomPadding && !leftPadding)
1317         return;
1318
1319     Document* startingDocument = page->mainFrame()->document();
1320     if (!startingDocument)
1321         return;
1322
1323     IntPoint originalPoint(QPointF(ev->pos()).toPoint());
1324     TouchAdjuster touchAdjuster(topPadding, rightPadding, bottomPadding, leftPadding);
1325     IntPoint adjustedPoint = touchAdjuster.findCandidatePointForTouch(originalPoint, startingDocument);
1326     if (adjustedPoint == IntPoint::zero())
1327         return;
1328
1329     ev->setPos(QPointF(adjustedPoint));
1330 }
1331 #endif
1332
1333 bool QWebPagePrivate::touchEvent(QTouchEvent* event)
1334 {
1335 #if ENABLE(TOUCH_EVENTS)
1336     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
1337     if (!frame->view())
1338         return false;
1339
1340     // Always accept the QTouchEvent so that we'll receive also TouchUpdate and TouchEnd events
1341     event->setAccepted(true);
1342
1343     // Return whether the default action was cancelled in the JS event handler
1344     return frame->eventHandler()->handleTouchEvent(convertTouchEvent(event));
1345 #else
1346     event->ignore();
1347     return false;
1348 #endif
1349 }
1350
1351 /*!
1352   This method is used by the input method to query a set of properties of the page
1353   to be able to support complex input method operations as support for surrounding
1354   text and reconversions.
1355
1356   \a property specifies which property is queried.
1357
1358   \sa QWidget::inputMethodEvent(), QInputMethodEvent, QInputContext
1359 */
1360 QVariant QWebPage::inputMethodQuery(Qt::InputMethodQuery property) const
1361 {
1362     Frame* frame = d->page->focusController()->focusedFrame();
1363     if (!frame)
1364         return QVariant();
1365
1366     WebCore::Editor* editor = frame->editor();
1367
1368     RenderObject* renderer = 0;
1369     RenderTextControl* renderTextControl = 0;
1370
1371     if (frame->selection()->rootEditableElement())
1372         renderer = frame->selection()->rootEditableElement()->shadowAncestorNode()->renderer();
1373
1374     if (renderer && renderer->isTextControl())
1375         renderTextControl = toRenderTextControl(renderer);
1376
1377     switch (property) {
1378         case Qt::ImMicroFocus: {
1379             WebCore::FrameView* view = frame->view();
1380             if (view && view->needsLayout()) {
1381                 // We can't access absoluteCaretBounds() while the view needs to layout.
1382                 return QVariant();
1383             }
1384             return QVariant(view->contentsToWindow(frame->selection()->absoluteCaretBounds()));
1385         }
1386         case Qt::ImFont: {
1387             if (renderTextControl) {
1388                 RenderStyle* renderStyle = renderTextControl->style();
1389                 return QVariant(QFont(renderStyle->font().syntheticFont()));
1390             }
1391             return QVariant(QFont());
1392         }
1393         case Qt::ImCursorPosition: {
1394             if (editor->hasComposition())
1395                 return QVariant(frame->selection()->end().offsetInContainerNode());
1396             return QVariant(frame->selection()->extent().offsetInContainerNode());
1397         }
1398         case Qt::ImSurroundingText: {
1399             if (renderTextControl && renderTextControl->textFormControlElement()) {
1400                 QString text = renderTextControl->textFormControlElement()->value();
1401                 RefPtr<Range> range = editor->compositionRange();
1402                 if (range)
1403                     text.remove(range->startPosition().offsetInContainerNode(), TextIterator::rangeLength(range.get()));
1404                 return QVariant(text);
1405             }
1406             return QVariant();
1407         }
1408         case Qt::ImCurrentSelection: {
1409             if (!editor->hasComposition() && renderTextControl && renderTextControl->textFormControlElement()) {
1410                 int start = frame->selection()->start().offsetInContainerNode();
1411                 int end = frame->selection()->end().offsetInContainerNode();
1412                 if (end > start)
1413                     return QVariant(QString(renderTextControl->textFormControlElement()->value()).mid(start, end - start));
1414             }
1415             return QVariant();
1416
1417         }
1418         case Qt::ImAnchorPosition: {
1419             if (editor->hasComposition())
1420                 return QVariant(frame->selection()->start().offsetInContainerNode());
1421             return QVariant(frame->selection()->base().offsetInContainerNode());
1422         }
1423         case Qt::ImMaximumTextLength: {
1424             if (frame->selection()->isContentEditable()) {
1425                 if (frame->document() && frame->document()->focusedNode()) {
1426                     if (frame->document()->focusedNode()->hasTagName(HTMLNames::inputTag)) {
1427                         HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(frame->document()->focusedNode());
1428                         return QVariant(inputElement->maxLength());
1429                     }
1430                 }
1431                 return QVariant(HTMLInputElement::maximumLength);
1432             }
1433             return QVariant(0);
1434         }
1435         default:
1436             return QVariant();
1437     }
1438 }
1439
1440 /*!
1441     \internal
1442 */
1443 void QWebPagePrivate::setInspector(QWebInspector* insp)
1444 {
1445     if (inspector)
1446         inspector->d->setFrontend(0);
1447
1448     if (inspectorIsInternalOnly) {
1449         QWebInspector* inspToDelete = inspector;
1450         inspector = 0;
1451         inspectorIsInternalOnly = false;
1452         delete inspToDelete;    // Delete after to prevent infinite recursion
1453     }
1454
1455     inspector = insp;
1456
1457     // Give inspector frontend web view if previously created
1458     if (inspector && inspectorFrontend)
1459         inspector->d->setFrontend(inspectorFrontend);
1460 }
1461
1462 /*!
1463     \internal
1464     Returns the inspector and creates it if it wasn't created yet.
1465     The instance created here will not be available through QWebPage's API.
1466 */
1467 QWebInspector* QWebPagePrivate::getOrCreateInspector()
1468 {
1469 #if ENABLE(INSPECTOR)
1470     if (!inspector) {
1471         QWebInspector* insp = new QWebInspector;
1472         insp->setPage(q);
1473         inspectorIsInternalOnly = true;
1474
1475         Q_ASSERT(inspector); // Associated through QWebInspector::setPage(q)
1476     }
1477 #endif
1478     return inspector;
1479 }
1480
1481 /*! \internal */
1482 InspectorController* QWebPagePrivate::inspectorController()
1483 {
1484 #if ENABLE(INSPECTOR)
1485     return page->inspectorController();
1486 #else
1487     return 0;
1488 #endif
1489 }
1490
1491 quint16 QWebPagePrivate::inspectorServerPort()
1492 {
1493 #if ENABLE(INSPECTOR) && !defined(QT_NO_PROPERTIES)
1494     if (q && q->property("_q_webInspectorServerPort").isValid())
1495         return q->property("_q_webInspectorServerPort").toInt();
1496 #endif
1497     return 0;
1498 }
1499
1500 static bool hasMouseListener(Element* element)
1501 {
1502     ASSERT(element);
1503     return element->hasEventListeners(eventNames().clickEvent)
1504         || element->hasEventListeners(eventNames().mousedownEvent)
1505         || element->hasEventListeners(eventNames().mouseupEvent);
1506 }
1507
1508 static bool isClickableElement(Element* element, RefPtr<NodeList> list)
1509 {
1510     ASSERT(element);
1511     bool isClickable = hasMouseListener(element);
1512     if (!isClickable && list) {
1513         Element* parent = element->parentElement();
1514         unsigned count = list->length();
1515         for (unsigned i = 0; i < count && parent; i++) {
1516             if (list->item(i) != parent)
1517                 continue;
1518
1519             isClickable = hasMouseListener(parent);
1520             if (isClickable)
1521                 break;
1522
1523             parent = parent->parentElement();
1524         }
1525     }
1526
1527     ExceptionCode ec = 0;
1528     return isClickable
1529         || element->webkitMatchesSelector("a,*:link,*:visited,*[role=button],button,input,select,label", ec)
1530         || CSSComputedStyleDeclaration::create(element)->getPropertyValue(cssPropertyID("cursor")) == "pointer";
1531 }
1532
1533 static bool isValidFrameOwner(Element* element)
1534 {
1535     ASSERT(element);
1536     return element->isFrameOwnerElement() && static_cast<HTMLFrameOwnerElement*>(element)->contentFrame();
1537 }
1538
1539 static Element* nodeToElement(Node* node)
1540 {
1541     if (node && node->isElementNode())
1542         return static_cast<Element*>(node);
1543     return 0;
1544 }
1545
1546 QWebPagePrivate::TouchAdjuster::TouchAdjuster(unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
1547     : m_topPadding(topPadding)
1548     , m_rightPadding(rightPadding)
1549     , m_bottomPadding(bottomPadding)
1550     , m_leftPadding(leftPadding)
1551 {
1552 }
1553
1554 IntPoint QWebPagePrivate::TouchAdjuster::findCandidatePointForTouch(const IntPoint& touchPoint, Document* document) const
1555 {
1556     if (!document)
1557         return IntPoint();
1558
1559     int x = touchPoint.x();
1560     int y = touchPoint.y();
1561
1562     RefPtr<NodeList> intersectedNodes = document->nodesFromRect(x, y, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding, false /*ignoreClipping*/, false /*allowShadowContent*/);
1563     if (!intersectedNodes)
1564         return IntPoint();
1565
1566     Element* closestClickableElement = 0;
1567     IntRect largestIntersectionRect;
1568     FrameView* view = document->frame()->view();
1569
1570     // Touch rect in contents coordinates.
1571     IntRect touchRect(HitTestResult::rectForPoint(view->windowToContents(IntPoint(x, y)), m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding));
1572
1573     // Iterate over the list of nodes hit looking for the one whose bounding area
1574     // has largest intersection with the touch area (point + padding).
1575     for (unsigned i = 0; i < intersectedNodes->length(); i++) {
1576         Node* currentNode = intersectedNodes->item(i);
1577
1578         Element* currentElement = nodeToElement(currentNode);
1579         if (!currentElement || (!isClickableElement(currentElement, 0) && !isValidFrameOwner(currentElement)))
1580             continue;
1581
1582         IntRect currentElementBoundingRect = currentElement->pixelSnappedBoundingBox();
1583         currentElementBoundingRect.intersect(touchRect);
1584
1585         if (currentElementBoundingRect.isEmpty())
1586             continue;
1587
1588         int currentIntersectionRectArea = currentElementBoundingRect.width() * currentElementBoundingRect.height();
1589         int largestIntersectionRectArea = largestIntersectionRect.width() * largestIntersectionRect.height();
1590         if (currentIntersectionRectArea > largestIntersectionRectArea) {
1591             closestClickableElement = currentElement;
1592             largestIntersectionRect = currentElementBoundingRect;
1593         }
1594     }
1595
1596     if (largestIntersectionRect.isEmpty())
1597         return IntPoint();
1598
1599     // Handle the case when user taps a inner frame. It is done in three steps:
1600     // 1) Transform the original touch point to the inner document coordinates;
1601     // 1) Call nodesFromRect for the inner document in case;
1602     // 3) Re-add the inner frame offset (location) before passing the new clicking
1603     //    position to WebCore.
1604     if (closestClickableElement->isFrameOwnerElement()) {
1605         // Adjust client coordinates' origin to be top left of inner frame viewport.
1606         PassRefPtr<ClientRect> rect = closestClickableElement->getBoundingClientRect();
1607         IntPoint newTouchPoint = touchPoint;
1608         IntSize offset =  IntSize(rect->left(), rect->top());
1609         newTouchPoint -= offset;
1610
1611         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(closestClickableElement);
1612         Document* childDocument = owner->contentFrame()->document();
1613         return findCandidatePointForTouch(newTouchPoint, childDocument);
1614     }
1615     return view->contentsToWindow(largestIntersectionRect).center();
1616 }
1617
1618 /*!
1619    \enum QWebPage::FindFlag
1620
1621    This enum describes the options available to the findText() function. The options
1622    can be OR-ed together from the following list:
1623
1624    \value FindBackward Searches backwards instead of forwards.
1625    \value FindCaseSensitively By default findText() works case insensitive. Specifying this option
1626    changes the behaviour to a case sensitive find operation.
1627    \value FindWrapsAroundDocument Makes findText() restart from the beginning of the document if the end
1628    was reached and the text was not found.
1629    \value HighlightAllOccurrences Highlights all existing occurrences of a specific string.
1630        (This value was introduced in 4.6.)
1631 */
1632
1633 /*!
1634     \enum QWebPage::LinkDelegationPolicy
1635
1636     This enum defines the delegation policies a webpage can have when activating links and emitting
1637     the linkClicked() signal.
1638
1639     \value DontDelegateLinks No links are delegated. Instead, QWebPage tries to handle them all.
1640     \value DelegateExternalLinks When activating links that point to documents not stored on the
1641     local filesystem or an equivalent - such as the Qt resource system - then linkClicked() is emitted.
1642     \value DelegateAllLinks Whenever a link is activated the linkClicked() signal is emitted.
1643
1644     \sa QWebPage::linkDelegationPolicy
1645 */
1646
1647 /*!
1648     \enum QWebPage::NavigationType
1649
1650     This enum describes the types of navigation available when browsing through hyperlinked
1651     documents.
1652
1653     \value NavigationTypeLinkClicked The user clicked on a link or pressed return on a focused link.
1654     \value NavigationTypeFormSubmitted The user activated a submit button for an HTML form.
1655     \value NavigationTypeBackOrForward Navigation to a previously shown document in the back or forward history is requested.
1656     \value NavigationTypeReload The user activated the reload action.
1657     \value NavigationTypeFormResubmitted An HTML form was submitted a second time.
1658     \value NavigationTypeOther A navigation to another document using a method not listed above.
1659
1660     \sa acceptNavigationRequest()
1661 */
1662
1663 /*!
1664     \enum QWebPage::WebAction
1665
1666     This enum describes the types of action which can be performed on the web page.
1667
1668     Actions only have an effect when they are applicable. The availability of
1669     actions can be be determined by checking \l{QAction::}{isEnabled()} on the
1670     action returned by action().
1671
1672     One method of enabling the text editing, cursor movement, and text selection actions
1673     is by setting \l contentEditable to true.
1674
1675     \value NoWebAction No action is triggered.
1676     \value OpenLink Open the current link.
1677     \value OpenLinkInNewWindow Open the current link in a new window.
1678     \value OpenFrameInNewWindow Replicate the current frame in a new window.
1679     \value DownloadLinkToDisk Download the current link to the disk.
1680     \value CopyLinkToClipboard Copy the current link to the clipboard.
1681     \value OpenImageInNewWindow Open the highlighted image in a new window.
1682     \value DownloadImageToDisk Download the highlighted image to the disk.
1683     \value CopyImageToClipboard Copy the highlighted image to the clipboard.  (Added in Qt 4.8)
1684     \value CopyImageUrlToClipboard Copy the highlighted image's URL to the clipboard.
1685     \value Back Navigate back in the history of navigated links.
1686     \value Forward Navigate forward in the history of navigated links.
1687     \value Stop Stop loading the current page.
1688     \value StopScheduledPageRefresh Stop all pending page refresh/redirect requests.  (Added in Qt 4.7)
1689     \value Reload Reload the current page.
1690     \value ReloadAndBypassCache Reload the current page, but do not use any local cache. (Added in Qt 4.6)
1691     \value Cut Cut the content currently selected into the clipboard.
1692     \value Copy Copy the content currently selected into the clipboard.
1693     \value Paste Paste content from the clipboard.
1694     \value Undo Undo the last editing action.
1695     \value Redo Redo the last editing action.
1696     \value MoveToNextChar Move the cursor to the next character.
1697     \value MoveToPreviousChar Move the cursor to the previous character.
1698     \value MoveToNextWord Move the cursor to the next word.
1699     \value MoveToPreviousWord Move the cursor to the previous word.
1700     \value MoveToNextLine Move the cursor to the next line.
1701     \value MoveToPreviousLine Move the cursor to the previous line.
1702     \value MoveToStartOfLine Move the cursor to the start of the line.
1703     \value MoveToEndOfLine Move the cursor to the end of the line.
1704     \value MoveToStartOfBlock Move the cursor to the start of the block.
1705     \value MoveToEndOfBlock Move the cursor to the end of the block.
1706     \value MoveToStartOfDocument Move the cursor to the start of the document.
1707     \value MoveToEndOfDocument Move the cursor to the end of the document.
1708     \value SelectNextChar Select to the next character.
1709     \value SelectPreviousChar Select to the previous character.
1710     \value SelectNextWord Select to the next word.
1711     \value SelectPreviousWord Select to the previous word.
1712     \value SelectNextLine Select to the next line.
1713     \value SelectPreviousLine Select to the previous line.
1714     \value SelectStartOfLine Select to the start of the line.
1715     \value SelectEndOfLine Select to the end of the line.
1716     \value SelectStartOfBlock Select to the start of the block.
1717     \value SelectEndOfBlock Select to the end of the block.
1718     \value SelectStartOfDocument Select to the start of the document.
1719     \value SelectEndOfDocument Select to the end of the document.
1720     \value DeleteStartOfWord Delete to the start of the word.
1721     \value DeleteEndOfWord Delete to the end of the word.
1722     \value SetTextDirectionDefault Set the text direction to the default direction.
1723     \value SetTextDirectionLeftToRight Set the text direction to left-to-right.
1724     \value SetTextDirectionRightToLeft Set the text direction to right-to-left.
1725     \value ToggleBold Toggle the formatting between bold and normal weight.
1726     \value ToggleItalic Toggle the formatting between italic and normal style.
1727     \value ToggleUnderline Toggle underlining.
1728     \value InspectElement Show the Web Inspector with the currently highlighted HTML element.
1729     \value InsertParagraphSeparator Insert a new paragraph.
1730     \value InsertLineSeparator Insert a new line.
1731     \value SelectAll Selects all content.
1732     \value PasteAndMatchStyle Paste content from the clipboard with current style. (Added in Qt 4.6)
1733     \value RemoveFormat Removes formatting and style. (Added in Qt 4.6)
1734     \value ToggleStrikethrough Toggle the formatting between strikethrough and normal style. (Added in Qt 4.6)
1735     \value ToggleSubscript Toggle the formatting between subscript and baseline. (Added in Qt 4.6)
1736     \value ToggleSuperscript Toggle the formatting between supercript and baseline. (Added in Qt 4.6)
1737     \value InsertUnorderedList Toggles the selection between an ordered list and a normal block. (Added in Qt 4.6)
1738     \value InsertOrderedList Toggles the selection between an ordered list and a normal block. (Added in Qt 4.6)
1739     \value Indent Increases the indentation of the currently selected format block by one increment. (Added in Qt 4.6)
1740     \value Outdent Decreases the indentation of the currently selected format block by one increment. (Added in Qt 4.6)
1741     \value AlignCenter Applies center alignment to content. (Added in Qt 4.6)
1742     \value AlignJustified Applies full justification to content. (Added in Qt 4.6)
1743     \value AlignLeft Applies left justification to content. (Added in Qt 4.6)
1744     \value AlignRight Applies right justification to content. (Added in Qt 4.6)
1745
1746
1747     \omitvalue WebActionCount
1748
1749 */
1750
1751 /*!
1752     \enum QWebPage::WebWindowType
1753
1754     This enum describes the types of window that can be created by the createWindow() function.
1755
1756     \value WebBrowserWindow The window is a regular web browser window.
1757     \value WebModalDialog The window acts as modal dialog.
1758 */
1759
1760
1761 /*!
1762     \class QWebPage::ViewportAttributes
1763     \since 4.7
1764     \brief The QWebPage::ViewportAttributes class describes hints that can be applied to a viewport.
1765
1766     QWebPage::ViewportAttributes provides a description of a viewport, such as viewport geometry,
1767     initial scale factor with limits, plus information about whether a user should be able
1768     to scale the contents in the viewport or not, ie. by zooming.
1769
1770     ViewportAttributes can be set by a web author using the viewport meta tag extension, documented
1771     at \l{http://developer.apple.com/safari/library/documentation/appleapplications/reference/safariwebcontent/usingtheviewport/usingtheviewport.html}{Safari Reference Library: Using the Viewport Meta Tag}.
1772
1773     All values might not be set, as such when dealing with the hints, the developer needs to
1774     check whether the values are valid. Negative values denote an invalid qreal value.
1775
1776     \inmodule QtWebKit
1777 */
1778
1779 /*!
1780     Constructs an empty QWebPage::ViewportAttributes.
1781 */
1782 QWebPage::ViewportAttributes::ViewportAttributes()
1783     : d(0)
1784     , m_initialScaleFactor(-1.0)
1785     , m_minimumScaleFactor(-1.0)
1786     , m_maximumScaleFactor(-1.0)
1787     , m_devicePixelRatio(-1.0)
1788     , m_isUserScalable(true)
1789     , m_isValid(false)
1790 {
1791
1792 }
1793
1794 /*!
1795     Constructs a QWebPage::ViewportAttributes which is a copy from \a other .
1796 */
1797 QWebPage::ViewportAttributes::ViewportAttributes(const QWebPage::ViewportAttributes& other)
1798     : d(other.d)
1799     , m_initialScaleFactor(other.m_initialScaleFactor)
1800     , m_minimumScaleFactor(other.m_minimumScaleFactor)
1801     , m_maximumScaleFactor(other.m_maximumScaleFactor)
1802     , m_devicePixelRatio(other.m_devicePixelRatio)
1803     , m_isUserScalable(other.m_isUserScalable)
1804     , m_isValid(other.m_isValid)
1805     , m_size(other.m_size)
1806 {
1807
1808 }
1809
1810 /*!
1811     Destroys the QWebPage::ViewportAttributes.
1812 */
1813 QWebPage::ViewportAttributes::~ViewportAttributes()
1814 {
1815
1816 }
1817
1818 /*!
1819     Assigns the given QWebPage::ViewportAttributes to this viewport hints and returns a
1820     reference to this.
1821 */
1822 QWebPage::ViewportAttributes& QWebPage::ViewportAttributes::operator=(const QWebPage::ViewportAttributes& other)
1823 {
1824     if (this != &other) {
1825         d = other.d;
1826         m_initialScaleFactor = other.m_initialScaleFactor;
1827         m_minimumScaleFactor = other.m_minimumScaleFactor;
1828         m_maximumScaleFactor = other.m_maximumScaleFactor;
1829         m_isUserScalable = other.m_isUserScalable;
1830         m_isValid = other.m_isValid;
1831         m_size = other.m_size;
1832     }
1833
1834     return *this;
1835 }
1836
1837 /*! \fn inline bool QWebPage::ViewportAttributes::isValid() const
1838     Returns whether this is a valid ViewportAttributes or not.
1839
1840     An invalid ViewportAttributes will have an empty QSize, negative values for scale factors and
1841     true for the boolean isUserScalable.
1842 */
1843
1844 /*! \fn inline QSize QWebPage::ViewportAttributes::size() const
1845     Returns the size of the viewport.
1846 */
1847
1848 /*! \fn inline qreal QWebPage::ViewportAttributes::initialScaleFactor() const
1849     Returns the initial scale of the viewport as a multiplier.
1850 */
1851
1852 /*! \fn inline qreal QWebPage::ViewportAttributes::minimumScaleFactor() const
1853     Returns the minimum scale value of the viewport as a multiplier.
1854 */
1855
1856 /*! \fn inline qreal QWebPage::ViewportAttributes::maximumScaleFactor() const
1857     Returns the maximum scale value of the viewport as a multiplier.
1858 */
1859
1860 /*! \fn inline bool QWebPage::ViewportAttributes::isUserScalable() const
1861     Determines whether or not the scale can be modified by the user.
1862 */
1863
1864
1865 /*!
1866     \class QWebPage
1867     \since 4.4
1868     \brief The QWebPage class provides an object to view and edit web documents.
1869
1870     \inmodule QtWebKit
1871
1872     QWebPage holds a main frame responsible for web content, settings, the history
1873     of navigated links and actions. This class can be used, together with QWebFrame,
1874     to provide functionality like QWebView in a widget-less environment.
1875
1876     QWebPage's API is very similar to QWebView, as you are still provided with
1877     common functions like action() (known as
1878     \l{QWebView::pageAction()}{pageAction}() in QWebView), triggerAction(),
1879     findText() and settings(). More QWebView-like functions can be found in the
1880     main frame of QWebPage, obtained via the mainFrame() function. For example,
1881     the \l{QWebFrame::load()}{load}(), \l{QWebFrame::setUrl()}{setUrl}() and
1882     \l{QWebFrame::setHtml()}{setHtml}() functions for QWebPage can be accessed
1883     using QWebFrame.
1884
1885     The loadStarted() signal is emitted when the page begins to load.The
1886     loadProgress() signal, on the other hand, is emitted whenever an element
1887     of the web page completes loading, such as an embedded image, a script,
1888     etc. Finally, the loadFinished() signal is emitted when the page contents
1889     are loaded completely, independent of script execution or page rendering.
1890     Its argument, either true or false, indicates whether or not the load
1891     operation succeeded.
1892
1893     \section1 Using QWebPage in a Widget-less Environment
1894
1895     Before you begin painting a QWebPage object, you need to set the size of
1896     the viewport by calling setViewportSize(). Then, you invoke the main
1897     frame's render function (QWebFrame::render()). An example of this
1898     is shown in the code snippet below.
1899
1900     Suppose we have a \c Thumbnail class as follows:
1901
1902     \snippet webkitsnippets/webpage/main.cpp 0
1903
1904     The \c Thumbnail's constructor takes in a \a url. We connect our QWebPage
1905     object's \l{QWebPage::}{loadFinished()} signal to our private slot,
1906     \c render().
1907
1908     \snippet webkitsnippets/webpage/main.cpp 1
1909
1910     The \c render() function shows how we can paint a thumbnail using a
1911     QWebPage object.
1912
1913     \snippet webkitsnippets/webpage/main.cpp 2
1914
1915     We begin by setting the \l{QWebPage::viewportSize()}{viewportSize} and
1916     then we instantiate a QImage object, \c image, with the same size as our
1917     \l{QWebPage::viewportSize()}{viewportSize}. This image is then sent
1918     as a parameter to \c painter. Next, we render the contents of the main
1919     frame and its subframes into \c painter. Finally, we save the scaled image.
1920
1921     \sa QWebFrame
1922 */
1923
1924 /*!
1925     Constructs an empty QWebPage with parent \a parent.
1926 */
1927 QWebPage::QWebPage(QObject *parent)
1928     : QObject(parent)
1929     , d(new QWebPagePrivate(this))
1930 {
1931     setView(qobject_cast<QWidget*>(parent));
1932
1933     connect(this, SIGNAL(loadProgress(int)), this, SLOT(_q_onLoadProgressChanged(int)));
1934 #ifndef NDEBUG
1935     connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(_q_cleanupLeakMessages()));
1936 #endif
1937 }
1938
1939 /*!
1940     Destroys the web page.
1941 */
1942 QWebPage::~QWebPage()
1943 {
1944     d->createMainFrame();
1945     FrameLoader* loader = d->mainFrame.data()->d->frame->loader();
1946     if (loader)
1947         loader->detachFromParent();
1948     delete d;
1949 }
1950
1951 /*!
1952     Returns the main frame of the page.
1953
1954     The main frame provides access to the hierarchy of sub-frames and is also needed if you
1955     want to explicitly render a web page into a given painter.
1956
1957     \sa currentFrame()
1958 */
1959 QWebFrame *QWebPage::mainFrame() const
1960 {
1961     d->createMainFrame();
1962     return d->mainFrame.data();
1963 }
1964
1965 /*!
1966     Returns the frame currently active.
1967
1968     \sa mainFrame(), frameCreated()
1969 */
1970 QWebFrame *QWebPage::currentFrame() const
1971 {
1972     d->createMainFrame();
1973     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
1974     return qobject_cast<QWebFrame*>(frame->loader()->networkingContext()->originatingObject());
1975 }
1976
1977
1978 /*!
1979     \since 4.6
1980
1981     Returns the frame at the given point \a pos, or 0 if there is no frame at
1982     that position.
1983
1984     \sa mainFrame(), currentFrame()
1985 */
1986 QWebFrame* QWebPage::frameAt(const QPoint& pos) const
1987 {
1988     QWebFrame* webFrame = mainFrame();
1989     if (!webFrame->geometry().contains(pos))
1990         return 0;
1991     QWebHitTestResult hitTestResult = webFrame->hitTestContent(pos);
1992     return hitTestResult.frame();
1993 }
1994
1995 /*!
1996     Returns a pointer to the view's history of navigated web pages.
1997 */
1998 QWebHistory *QWebPage::history() const
1999 {
2000     d->createMainFrame();
2001     return &d->history;
2002 }
2003
2004 /*!
2005     Sets the \a view that is associated with the web page.
2006
2007     \sa view()
2008 */
2009 void QWebPage::setView(QWidget* view)
2010 {
2011     if (this->view() == view)
2012         return;
2013
2014     d->view = view;
2015     setViewportSize(view ? view->size() : QSize(0, 0));
2016
2017     // If we have no client, we install a special client delegating
2018     // the responsibility to the QWidget. This is the code path
2019     // handling a.o. the "legacy" QWebView.
2020     //
2021     // If such a special delegate already exist, we substitute the view.
2022
2023     if (d->client) {
2024         if (d->client->isQWidgetClient())
2025             static_cast<PageClientQWidget*>(d->client.get())->view = view;
2026         return;
2027     }
2028
2029     if (view)
2030         d->client = adoptPtr(new PageClientQWidget(view, this));
2031 }
2032
2033 /*!
2034     Returns the view widget that is associated with the web page.
2035
2036     \sa setView()
2037 */
2038 QWidget *QWebPage::view() const
2039 {
2040     return d->view.data();
2041 }
2042
2043 /*!
2044     This function is called whenever a JavaScript program tries to print a \a message to the web browser's console.
2045
2046     For example in case of evaluation errors the source URL may be provided in \a sourceID as well as the \a lineNumber.
2047
2048     The default implementation prints nothing.
2049 */
2050 void QWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID)
2051 {
2052     Q_UNUSED(sourceID)
2053
2054     // Catch plugin logDestroy message for LayoutTests/plugins/open-and-close-window-with-plugin.html
2055     // At this point DRT's WebPage has already been destroyed
2056     if (QWebPagePrivate::drtRun) {
2057         if (message == QLatin1String("PLUGIN: NPP_Destroy")) {
2058             fprintf(stdout, "CONSOLE MESSAGE: ");
2059             if (lineNumber)
2060                 fprintf(stdout, "line %d: ", lineNumber);
2061             fprintf(stdout, "%s\n", message.toUtf8().constData());
2062         }
2063     }
2064 }
2065
2066 /*!
2067     This function is called whenever a JavaScript program running inside \a frame calls the alert() function with
2068     the message \a msg.
2069
2070     The default implementation shows the message, \a msg, with QMessageBox::information.
2071 */
2072 void QWebPage::javaScriptAlert(QWebFrame *frame, const QString& msg)
2073 {
2074     Q_UNUSED(frame)
2075 #ifndef QT_NO_MESSAGEBOX
2076     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2077     QMessageBox box(parent);
2078     box.setWindowTitle(tr("JavaScript Alert - %1").arg(mainFrame()->url().host()));
2079     box.setTextFormat(Qt::PlainText);
2080     box.setText(msg);
2081     box.setStandardButtons(QMessageBox::Ok);
2082     box.exec();
2083 #endif
2084 }
2085
2086 /*!
2087     This function is called whenever a JavaScript program running inside \a frame calls the confirm() function
2088     with the message, \a msg. Returns true if the user confirms the message; otherwise returns false.
2089
2090     The default implementation executes the query using QMessageBox::information with QMessageBox::Ok and QMessageBox::Cancel buttons.
2091 */
2092 bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg)
2093 {
2094     Q_UNUSED(frame)
2095 #ifdef QT_NO_MESSAGEBOX
2096     return true;
2097 #else
2098     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2099     QMessageBox box(parent);
2100     box.setWindowTitle(tr("JavaScript Confirm - %1").arg(mainFrame()->url().host()));
2101     box.setTextFormat(Qt::PlainText);
2102     box.setText(msg);
2103     box.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
2104     return QMessageBox::Ok == box.exec();
2105 #endif
2106 }
2107
2108 /*!
2109     This function is called whenever a JavaScript program running inside \a frame tries to prompt the user for input.
2110     The program may provide an optional message, \a msg, as well as a default value for the input in \a defaultValue.
2111
2112     If the prompt was cancelled by the user the implementation should return false; otherwise the
2113     result should be written to \a result and true should be returned. If the prompt was not cancelled by the
2114     user, the implementation should return true and the result string must not be null.
2115
2116     The default implementation uses QInputDialog::getText().
2117 */
2118 bool QWebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result)
2119 {
2120     Q_UNUSED(frame)
2121     bool ok = false;
2122 #ifndef QT_NO_INPUTDIALOG
2123
2124     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2125     QInputDialog dlg(parent);
2126     dlg.setWindowTitle(tr("JavaScript Prompt - %1").arg(mainFrame()->url().host()));
2127
2128     // Hack to force the dialog's QLabel into plain text mode
2129     // prevents https://bugs.webkit.org/show_bug.cgi?id=34429
2130     QLabel* label = dlg.findChild<QLabel*>();
2131     if (label)
2132         label->setTextFormat(Qt::PlainText);
2133
2134     // double the &'s because single & will underline the following character
2135     // (Accelerator mnemonics)
2136     QString escMsg(msg);
2137     escMsg.replace(QChar::fromLatin1('&'), QLatin1String("&&"));
2138     dlg.setLabelText(escMsg);
2139
2140     dlg.setTextEchoMode(QLineEdit::Normal);
2141     dlg.setTextValue(defaultValue);
2142
2143     ok = !!dlg.exec();
2144
2145     if (ok && result)
2146         *result = dlg.textValue();
2147 #endif
2148     return ok;
2149 }
2150
2151 /*!
2152     \fn bool QWebPage::shouldInterruptJavaScript()
2153     \since 4.6
2154     This function is called when a JavaScript program is running for a long period of time.
2155
2156     If the user wanted to stop the JavaScript the implementation should return true; otherwise false.
2157
2158     The default implementation executes the query using QMessageBox::information with QMessageBox::Yes and QMessageBox::No buttons.
2159
2160     \warning Because of binary compatibility constraints, this function is not virtual. If you want to
2161     provide your own implementation in a QWebPage subclass, reimplement the shouldInterruptJavaScript()
2162     slot in your subclass instead. QtWebKit will dynamically detect the slot and call it.
2163 */
2164 bool QWebPage::shouldInterruptJavaScript()
2165 {
2166 #ifdef QT_NO_MESSAGEBOX
2167     return false;
2168 #else
2169     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2170     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);
2171 #endif
2172 }
2173
2174 void QWebPage::setFeaturePermission(QWebFrame* frame, Feature feature, PermissionPolicy policy)
2175 {
2176     switch (feature) {
2177     case Notifications:
2178 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
2179         if (policy == PermissionGrantedByUser)
2180             NotificationPresenterClientQt::notificationPresenter()->allowNotificationForFrame(frame->d->frame);
2181 #endif
2182         break;
2183     case Geolocation:
2184 #if ENABLE(GEOLOCATION)
2185         GeolocationPermissionClientQt::geolocationPermissionClient()->setPermission(frame, policy);
2186 #endif
2187         break;
2188
2189     default:
2190         break;
2191     }
2192 }
2193
2194 /*!
2195     This function is called whenever WebKit wants to create a new window of the given \a type, for
2196     example when a JavaScript program requests to open a document in a new window.
2197
2198     If the new window can be created, the new window's QWebPage is returned; otherwise a null pointer is returned.
2199
2200     If the view associated with the web page is a QWebView object, then the default implementation forwards
2201     the request to QWebView's createWindow() function; otherwise it returns a null pointer.
2202
2203     If \a type is WebModalDialog, the application must call setWindowModality(Qt::ApplicationModal) on the new window.
2204
2205     \note In the cases when the window creation is being triggered by JavaScript, apart from
2206     reimplementing this method application must also set the JavaScriptCanOpenWindows attribute
2207     of QWebSettings to true in order for it to get called.
2208
2209     \sa acceptNavigationRequest(), QWebView::createWindow()
2210 */
2211 QWebPage *QWebPage::createWindow(WebWindowType type)
2212 {
2213     QWebView *webView = qobject_cast<QWebView*>(view());
2214     if (webView) {
2215         QWebView *newView = webView->createWindow(type);
2216         if (newView)
2217             return newView->page();
2218     }
2219     return 0;
2220 }
2221
2222 /*!
2223     This function is called whenever WebKit encounters a HTML object element with type "application/x-qt-plugin". It is
2224     called regardless of the value of QWebSettings::PluginsEnabled. The \a classid, \a url, \a paramNames and \a paramValues
2225     correspond to the HTML object element attributes and child elements to configure the embeddable object.
2226 */
2227 QObject *QWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
2228 {
2229     Q_UNUSED(classid)
2230     Q_UNUSED(url)
2231     Q_UNUSED(paramNames)
2232     Q_UNUSED(paramValues)
2233     return 0;
2234 }
2235
2236 static void extractContentTypeFromHash(const HashSet<String>& types, QStringList* list)
2237 {
2238     if (!list)
2239         return;
2240
2241     HashSet<String>::const_iterator endIt = types.end();
2242     for (HashSet<String>::const_iterator it = types.begin(); it != endIt; ++it)
2243         *list << *it;
2244 }
2245
2246 static void extractContentTypeFromPluginVector(const Vector<PluginPackage*>& plugins, QStringList* list)
2247 {
2248     if (!list)
2249         return;
2250
2251     for (unsigned int i = 0; i < plugins.size(); ++i) {
2252         MIMEToDescriptionsMap::const_iterator map_it = plugins[i]->mimeToDescriptions().begin();
2253         MIMEToDescriptionsMap::const_iterator map_end = plugins[i]->mimeToDescriptions().end();
2254         for (; map_it != map_end; ++map_it)
2255             *list << map_it->first;
2256     }
2257 }
2258
2259 /*!
2260  *  Returns the list of all content types supported by QWebPage.
2261  */
2262 QStringList QWebPage::supportedContentTypes() const
2263 {
2264     QStringList mimeTypes;
2265
2266     extractContentTypeFromHash(MIMETypeRegistry::getSupportedImageMIMETypes(), &mimeTypes);
2267     extractContentTypeFromHash(MIMETypeRegistry::getSupportedNonImageMIMETypes(), &mimeTypes);
2268     if (d->page->settings() && d->page->settings()->arePluginsEnabled())
2269         extractContentTypeFromPluginVector(PluginDatabase::installedPlugins()->plugins(), &mimeTypes);
2270
2271     return mimeTypes;
2272 }
2273
2274 /*!
2275  *  Returns true if QWebPage can handle the given \a mimeType; otherwise, returns false.
2276  */
2277 bool QWebPage::supportsContentType(const QString& mimeType) const
2278 {
2279     const String type = mimeType.toLower();
2280     if (MIMETypeRegistry::isSupportedImageMIMEType(type))
2281         return true;
2282
2283     if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
2284         return true;
2285
2286     if (d->page->settings() && d->page->settings()->arePluginsEnabled()
2287         && PluginDatabase::installedPlugins()->isMIMETypeRegistered(type))
2288         return true;
2289
2290     return false;
2291 }
2292
2293 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
2294 {
2295     return WebCore::FrameLoadRequest(frame->document()->securityOrigin(),
2296         WebCore::ResourceRequest(url, frame->loader()->outgoingReferrer()));
2297 }
2298
2299 static void openNewWindow(const QUrl& url, WebCore::Frame* frame)
2300 {
2301     if (Page* oldPage = frame->page()) {
2302         WindowFeatures features;
2303         NavigationAction action;
2304         FrameLoadRequest request = frameLoadRequest(url, frame);
2305         if (Page* newPage = oldPage->chrome()->createWindow(frame, request, features, action)) {
2306             newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, MaybeSendReferrer);
2307             newPage->chrome()->show();
2308         }
2309     }
2310 }
2311
2312 static void collectChildFrames(QWebFrame* frame, QList<QWebFrame*>& list)
2313 {
2314     list << frame->childFrames();
2315     QListIterator<QWebFrame*> it(frame->childFrames());
2316     while (it.hasNext()) {
2317         collectChildFrames(it.next(), list);
2318     }
2319 }
2320
2321 /*!
2322     This function can be called to trigger the specified \a action.
2323     It is also called by QtWebKit if the user triggers the action, for example
2324     through a context menu item.
2325
2326     If \a action is a checkable action then \a checked specified whether the action
2327     is toggled or not.
2328
2329     \sa action()
2330 */
2331 void QWebPage::triggerAction(WebAction action, bool)
2332 {
2333     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
2334     if (!frame)
2335         return;
2336     WebCore::Editor *editor = frame->editor();
2337     const char *command = 0;
2338
2339     switch (action) {
2340         case OpenLink:
2341             if (QWebFrame *targetFrame = d->hitTestResult.linkTargetFrame()) {
2342                 WTF::RefPtr<WebCore::Frame> wcFrame = targetFrame->d->frame;
2343                 targetFrame->d->frame->loader()->loadFrameRequest(frameLoadRequest(d->hitTestResult.linkUrl(), wcFrame.get()),
2344                                                                   /*lockHistory*/ false, /*lockBackForwardList*/ false, /*event*/ 0,
2345                                                                   /*FormState*/ 0, MaybeSendReferrer);
2346                 break;
2347             }
2348             // fall through
2349         case OpenLinkInNewWindow:
2350             openNewWindow(d->hitTestResult.linkUrl(), frame);
2351             break;
2352         case OpenFrameInNewWindow: {
2353             KURL url = frame->loader()->documentLoader()->unreachableURL();
2354             if (url.isEmpty())
2355                 url = frame->loader()->documentLoader()->url();
2356             openNewWindow(url, frame);
2357             break;
2358         }
2359         case CopyLinkToClipboard: {
2360 #if defined(Q_WS_X11)
2361             bool oldSelectionMode = Pasteboard::generalPasteboard()->isSelectionMode();
2362             Pasteboard::generalPasteboard()->setSelectionMode(true);
2363             editor->copyURL(d->hitTestResult.linkUrl(), d->hitTestResult.linkText());
2364             Pasteboard::generalPasteboard()->setSelectionMode(oldSelectionMode);
2365 #endif
2366             editor->copyURL(d->hitTestResult.linkUrl(), d->hitTestResult.linkText());
2367             break;
2368         }
2369         case OpenImageInNewWindow:
2370             openNewWindow(d->hitTestResult.imageUrl(), frame);
2371             break;
2372         case DownloadImageToDisk:
2373             frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.imageUrl(), frame->loader()->outgoingReferrer()));
2374             break;
2375         case DownloadLinkToDisk:
2376             frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.linkUrl(), frame->loader()->outgoingReferrer()));
2377             break;
2378 #ifndef QT_NO_CLIPBOARD
2379         case CopyImageToClipboard:
2380             QApplication::clipboard()->setPixmap(d->hitTestResult.pixmap());
2381             break;
2382         case CopyImageUrlToClipboard:
2383             QApplication::clipboard()->setText(d->hitTestResult.imageUrl().toString());
2384             break;
2385 #endif
2386         case Back:
2387             d->page->goBack();
2388             break;
2389         case Forward:
2390             d->page->goForward();
2391             break;
2392         case Stop:
2393             mainFrame()->d->frame->loader()->stopForUserCancel();
2394             d->updateNavigationActions();
2395             break;
2396         case Reload:
2397             mainFrame()->d->frame->loader()->reload(/*endtoendreload*/false);
2398             break;
2399         case ReloadAndBypassCache:
2400             mainFrame()->d->frame->loader()->reload(/*endtoendreload*/true);
2401             break;
2402         case SetTextDirectionDefault:
2403             editor->setBaseWritingDirection(NaturalWritingDirection);
2404             break;
2405         case SetTextDirectionLeftToRight:
2406             editor->setBaseWritingDirection(LeftToRightWritingDirection);
2407             break;
2408         case SetTextDirectionRightToLeft:
2409             editor->setBaseWritingDirection(RightToLeftWritingDirection);
2410             break;
2411         case InspectElement: {
2412 #if ENABLE(INSPECTOR)
2413             if (!d->hitTestResult.isNull()) {
2414                 d->getOrCreateInspector(); // Make sure the inspector is created
2415                 d->inspector->show(); // The inspector is expected to be shown on inspection
2416                 d->page->inspectorController()->inspect(d->hitTestResult.d->innerNonSharedNode.get());
2417             }
2418 #endif
2419             break;
2420         }
2421         case StopScheduledPageRefresh: {
2422             QWebFrame* topFrame = mainFrame();
2423             topFrame->d->frame->navigationScheduler()->cancel();
2424             QList<QWebFrame*> childFrames;
2425             collectChildFrames(topFrame, childFrames);
2426             QListIterator<QWebFrame*> it(childFrames);
2427             while (it.hasNext())
2428                 it.next()->d->frame->navigationScheduler()->cancel();
2429             break;
2430         }
2431         default:
2432             command = QWebPagePrivate::editorCommandForWebActions(action);
2433             break;
2434     }
2435
2436     if (command)
2437         editor->command(command).execute();
2438 }
2439
2440
2441 QColor QWebPagePrivate::colorSelectionRequested(const QColor &selectedColor)
2442 {
2443     QColor ret = selectedColor;
2444 #ifndef QT_NO_COLORDIALOG
2445     QWidget* parent = (client) ? client->ownerWidget() : 0;
2446     ret = QColorDialog::getColor(selectedColor, parent);
2447     if (!ret.isValid())
2448         ret = selectedColor;
2449 #endif
2450     return ret;
2451 }
2452
2453 QSize QWebPage::viewportSize() const
2454 {
2455     if (d->mainFrame && d->mainFrame.data()->d->frame->view())
2456         return d->mainFrame.data()->d->frame->view()->frameRect().size();
2457
2458     return d->viewportSize;
2459 }
2460
2461 /*!
2462     \property QWebPage::viewportSize
2463     \brief the size of the viewport
2464
2465     The size affects for example the visibility of scrollbars
2466     if the document is larger than the viewport.
2467
2468     By default, for a newly-created Web page, this property contains a size with
2469     zero width and height.
2470
2471     \sa QWebFrame::render(), preferredContentsSize
2472 */
2473 void QWebPage::setViewportSize(const QSize &size) const
2474 {
2475     d->viewportSize = size;
2476
2477     QWebFrame *frame = mainFrame();
2478     if (frame->d->frame && frame->d->frame->view()) {
2479         WebCore::FrameView* view = frame->d->frame->view();
2480         view->resize(size);
2481         view->adjustViewSize();
2482     }
2483 }
2484
2485 static int getintenv(const char* variable)
2486 {
2487     bool ok;
2488     int value = qgetenv(variable).toInt(&ok);
2489     return (ok) ? value : -1;
2490 }
2491
2492 static QSize queryDeviceSizeForScreenContainingWidget(const QWidget* widget)
2493 {
2494     QDesktopWidget* desktop = QApplication::desktop();
2495     if (!desktop)
2496         return QSize();
2497
2498     QSize size;
2499
2500     if (widget) {
2501         // Returns the available geometry of the screen which contains widget.
2502         // NOTE: this must be the the full screen size including any fixed status areas etc.
2503         size = desktop->availableGeometry(widget).size();
2504     } else
2505         size = desktop->availableGeometry().size();
2506
2507     // This must be in portrait mode, adjust if not.
2508     if (size.width() > size.height()) {
2509         int width = size.width();
2510         size.setWidth(size.height());
2511         size.setHeight(width);
2512     }
2513
2514     return size;
2515 }
2516
2517 /*!
2518     Computes the optimal viewport configuration given the \a availableSize, when
2519     user interface components are disregarded.
2520
2521     The configuration is also dependent on the device screen size which is obtained
2522     automatically. For testing purposes the size can be overridden by setting two
2523     environment variables QTWEBKIT_DEVICE_WIDTH and QTWEBKIT_DEVICE_HEIGHT, which
2524     both needs to be set.
2525
2526     The ViewportAttributes includes a pixel density ratio, which will also be exposed to
2527     the web author though the -webkit-pixel-ratio media feature. This is the ratio
2528     between 1 density-independent pixel (DPI) and physical pixels.
2529
2530     A density-independent pixel is equivalent to one physical pixel on a 160 DPI screen,
2531     so on our platform assumes that as the baseline density.
2532
2533     The conversion of DIP units to screen pixels is quite simple:
2534
2535     pixels = DIPs * (density / 160).
2536
2537     Thus, on a 240 DPI screen, 1 DIPs would equal 1.5 physical pixels.
2538
2539     An invalid instance will be returned in the case an empty size is passed to the
2540     method.
2541
2542     \note The density is automatically obtained from the DPI of the screen where the page
2543     is being shown, but as many X11 servers are reporting wrong DPI, it is possible to
2544     override it using QX11Info::setAppDpiY().
2545 */
2546
2547 QWebPage::ViewportAttributes QWebPage::viewportAttributesForSize(const QSize& availableSize) const
2548 {
2549     static int desktopWidth = 980;
2550
2551     ViewportAttributes result;
2552
2553      if (availableSize.isEmpty())
2554          return result; // Returns an invalid instance.
2555
2556     int deviceWidth = getintenv("QTWEBKIT_DEVICE_WIDTH");
2557     int deviceHeight = getintenv("QTWEBKIT_DEVICE_HEIGHT");
2558
2559     // Both environment variables need to be set - or they will be ignored.
2560     if (deviceWidth < 0 && deviceHeight < 0) {
2561         QSize size = queryDeviceSizeForScreenContainingWidget((d->client) ? d->client->ownerWidget() : 0);
2562         deviceWidth = size.width();
2563         deviceHeight = size.height();
2564     }
2565
2566     WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(d->viewportArguments(), desktopWidth, deviceWidth, deviceHeight, qt_defaultDpi() / WebCore::ViewportArguments::deprecatedTargetDPI, availableSize);
2567     WebCore::restrictMinimumScaleFactorToViewportSize(conf, availableSize);
2568     WebCore::restrictScaleFactorToInitialScaleIfNotUserScalable(conf);
2569
2570     result.m_isValid = true;
2571     result.m_size = QSizeF(conf.layoutSize.width(), conf.layoutSize.height());
2572     result.m_initialScaleFactor = conf.initialScale;
2573     result.m_minimumScaleFactor = conf.minimumScale;
2574     result.m_maximumScaleFactor = conf.maximumScale;
2575     result.m_devicePixelRatio = conf.devicePixelRatio;
2576     result.m_isUserScalable = static_cast<bool>(conf.userScalable);
2577
2578     d->page->setDeviceScaleFactor(conf.devicePixelRatio);
2579
2580     return result;
2581 }
2582
2583 QSize QWebPage::preferredContentsSize() const
2584 {
2585     QWebFrame* frame = d->mainFrame.data();
2586     if (frame) {
2587         WebCore::FrameView* view = frame->d->frame->view();
2588         if (view && view->useFixedLayout())
2589             return d->mainFrame.data()->d->frame->view()->fixedLayoutSize();
2590     }
2591
2592     return d->fixedLayoutSize;
2593 }
2594
2595 /*!
2596     \property QWebPage::preferredContentsSize
2597     \since 4.6
2598     \brief a custom size used for laying out the page contents.
2599
2600     By default all pages are laid out using the viewport of the page as the base.
2601
2602     As pages mostly are designed for desktop usage, they often do not layout properly
2603     on small devices as the contents require a certain view width. For this reason
2604     it is common to use a different layout size and then scale the contents to fit
2605     within the actual view.
2606
2607     If this property is set to a valid size, this size is used for all layout needs
2608     instead of the size of the viewport.
2609
2610     Setting an invalid size, makes the page fall back to using the viewport size for layout.
2611
2612     \sa viewportSize
2613 */
2614 void QWebPage::setPreferredContentsSize(const QSize& size) const
2615 {
2616     // FIXME: Rename this method to setCustomLayoutSize
2617
2618     d->fixedLayoutSize = size;
2619
2620     QWebFrame* frame = mainFrame();
2621     if (!frame->d->frame || !frame->d->frame->view())
2622         return;
2623
2624     WebCore::FrameView* view = frame->d->frame->view();
2625
2626     if (size.isValid()) {
2627         view->setUseFixedLayout(true);
2628         view->setFixedLayoutSize(size);
2629     } else if (view->useFixedLayout())
2630         view->setUseFixedLayout(false);
2631
2632     view->layout();
2633 }
2634
2635 /*
2636     This function is to be called after any (animated) scroll/pan has ended, in the case the application handles the
2637     scrolling/panning of the web contents. This is commonly used in combination with tiling where is it common for
2638     the application to pan the actual view, which then resizes itself to the size of the contents.
2639
2640     \note Calling this function makes WebKit stop trying to calculate the visibleContentRect. To turn that on
2641     again, call this method with an empty rect.
2642
2643     \sa QGraphicsWebView::resizesToContents, QWebSettings::TiledBackingStoreEnabled
2644 */
2645 void QWebPage::setActualVisibleContentRect(const QRect& rect) const
2646 {
2647     QWebFrame* frame = mainFrame();
2648     if (!frame->d->frame || !frame->d->frame->view())
2649         return;
2650
2651     WebCore::FrameView* view = frame->d->frame->view();
2652     view->setFixedVisibleContentRect(rect);
2653 }
2654
2655 /*!
2656     \fn bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2657
2658     This function is called whenever WebKit requests to navigate \a frame to the resource specified by \a request by means of
2659     the specified navigation type \a type.
2660
2661     If \a frame is a null pointer then navigation to a new window is requested. If the request is
2662     accepted createWindow() will be called.
2663
2664     The default implementation interprets the page's linkDelegationPolicy and emits linkClicked accordingly or returns true
2665     to let QWebPage handle the navigation itself.
2666
2667     \sa createWindow()
2668 */
2669 bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2670 {
2671     Q_UNUSED(frame)
2672     if (type == NavigationTypeLinkClicked) {
2673         switch (d->linkPolicy) {
2674             case DontDelegateLinks:
2675                 return true;
2676
2677             case DelegateExternalLinks:
2678                 if (WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal(request.url().scheme()))
2679                     return true;
2680                 emit linkClicked(request.url());
2681                 return false;
2682
2683             case DelegateAllLinks:
2684                 emit linkClicked(request.url());
2685                 return false;
2686         }
2687     }
2688     return true;
2689 }
2690
2691 /*!
2692     \property QWebPage::hasSelection
2693     \brief whether this page contains selected content or not.
2694
2695     \sa selectionChanged()
2696 */
2697 bool QWebPage::hasSelection() const
2698 {
2699     d->createMainFrame();
2700     WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2701     if (frame)
2702         return (frame->selection()->selection().selectionType() != VisibleSelection::NoSelection);
2703     return false;
2704 }
2705
2706 /*!
2707     \property QWebPage::selectedText
2708     \brief the text currently selected
2709
2710     By default, this property contains an empty string.
2711
2712     \sa selectionChanged(), selectedHtml()
2713 */
2714 QString QWebPage::selectedText() const
2715 {
2716     d->createMainFrame();
2717     WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2718     if (frame->selection()->selection().selectionType() == VisibleSelection::NoSelection)
2719         return QString();
2720     return frame->editor()->selectedText();
2721 }
2722
2723 /*!
2724     \since 4.8
2725     \property QWebPage::selectedHtml
2726     \brief the HTML currently selected
2727
2728     By default, this property contains an empty string.
2729
2730     \sa selectionChanged(), selectedText()
2731 */
2732 QString QWebPage::selectedHtml() const
2733 {
2734     d->createMainFrame();
2735     return d->page->focusController()->focusedOrMainFrame()->editor()->selectedRange()->toHTML();
2736 }
2737
2738 #ifndef QT_NO_ACTION
2739 /*!
2740    Returns a QAction for the specified WebAction \a action.
2741
2742    The action is owned by the QWebPage but you can customize the look by
2743    changing its properties.
2744
2745    QWebPage also takes care of implementing the action, so that upon
2746    triggering the corresponding action is performed on the page.
2747
2748    \sa triggerAction()
2749 */
2750 QAction *QWebPage::action(WebAction action) const
2751 {
2752     if (action == QWebPage::NoWebAction) return 0;
2753     if (d->actions[action])
2754         return d->actions[action];
2755
2756     QString text;
2757     QIcon icon;
2758     QStyle *style = d->client ? d->client->style() : qApp->style();
2759     bool checkable = false;
2760
2761     switch (action) {
2762         case OpenLink:
2763             text = contextMenuItemTagOpenLink();
2764             break;
2765         case OpenLinkInNewWindow:
2766             text = contextMenuItemTagOpenLinkInNewWindow();
2767             break;
2768         case OpenFrameInNewWindow:
2769             text = contextMenuItemTagOpenFrameInNewWindow();
2770             break;
2771
2772         case DownloadLinkToDisk:
2773             text = contextMenuItemTagDownloadLinkToDisk();
2774             break;
2775         case CopyLinkToClipboard:
2776             text = contextMenuItemTagCopyLinkToClipboard();
2777             break;
2778
2779         case OpenImageInNewWindow:
2780             text = contextMenuItemTagOpenImageInNewWindow();
2781             break;
2782         case DownloadImageToDisk:
2783             text = contextMenuItemTagDownloadImageToDisk();
2784             break;
2785         case CopyImageToClipboard:
2786             text = contextMenuItemTagCopyImageToClipboard();
2787             break;
2788         case CopyImageUrlToClipboard:
2789             text = contextMenuItemTagCopyImageUrlToClipboard();
2790             break;
2791
2792         case Back:
2793             text = contextMenuItemTagGoBack();
2794             icon = style->standardIcon(QStyle::SP_ArrowBack);
2795             break;
2796         case Forward:
2797             text = contextMenuItemTagGoForward();
2798             icon = style->standardIcon(QStyle::SP_ArrowForward);
2799             break;
2800         case Stop:
2801             text = contextMenuItemTagStop();
2802             icon = style->standardIcon(QStyle::SP_BrowserStop);
2803             break;
2804         case Reload:
2805             text = contextMenuItemTagReload();
2806             icon = style->standardIcon(QStyle::SP_BrowserReload);
2807             break;
2808
2809         case Cut:
2810             text = contextMenuItemTagCut();
2811             break;
2812         case Copy:
2813             text = contextMenuItemTagCopy();
2814             break;
2815         case Paste:
2816             text = contextMenuItemTagPaste();
2817             break;
2818         case SelectAll:
2819             text = contextMenuItemTagSelectAll();
2820             break;
2821 #ifndef QT_NO_UNDOSTACK
2822         case Undo: {
2823             QAction *a = undoStack()->createUndoAction(d->q);
2824             d->actions[action] = a;
2825             return a;
2826         }
2827         case Redo: {
2828             QAction *a = undoStack()->createRedoAction(d->q);
2829             d->actions[action] = a;
2830             return a;
2831         }
2832 #endif // QT_NO_UNDOSTACK
2833         case MoveToNextChar:
2834             text = tr("Move the cursor to the next character");
2835             break;
2836         case MoveToPreviousChar:
2837             text = tr("Move the cursor to the previous character");
2838             break;
2839         case MoveToNextWord:
2840             text = tr("Move the cursor to the next word");
2841             break;
2842         case MoveToPreviousWord:
2843             text = tr("Move the cursor to the previous word");
2844             break;
2845         case MoveToNextLine:
2846             text = tr("Move the cursor to the next line");
2847             break;
2848         case MoveToPreviousLine:
2849             text = tr("Move the cursor to the previous line");
2850             break;
2851         case MoveToStartOfLine:
2852             text = tr("Move the cursor to the start of the line");
2853             break;
2854         case MoveToEndOfLine:
2855             text = tr("Move the cursor to the end of the line");
2856             break;
2857         case MoveToStartOfBlock:
2858             text = tr("Move the cursor to the start of the block");
2859             break;
2860         case MoveToEndOfBlock:
2861             text = tr("Move the cursor to the end of the block");
2862             break;
2863         case MoveToStartOfDocument:
2864             text = tr("Move the cursor to the start of the document");
2865             break;
2866         case MoveToEndOfDocument:
2867             text = tr("Move the cursor to the end of the document");
2868             break;
2869         case SelectNextChar:
2870             text = tr("Select to the next character");
2871             break;
2872         case SelectPreviousChar:
2873             text = tr("Select to the previous character");
2874             break;
2875         case SelectNextWord:
2876             text = tr("Select to the next word");
2877             break;
2878         case SelectPreviousWord:
2879             text = tr("Select to the previous word");
2880             break;
2881         case SelectNextLine:
2882             text = tr("Select to the next line");
2883             break;
2884         case SelectPreviousLine:
2885             text = tr("Select to the previous line");
2886             break;
2887         case SelectStartOfLine:
2888             text = tr("Select to the start of the line");
2889             break;
2890         case SelectEndOfLine:
2891             text = tr("Select to the end of the line");
2892             break;
2893         case SelectStartOfBlock:
2894             text = tr("Select to the start of the block");
2895             break;
2896         case SelectEndOfBlock:
2897             text = tr("Select to the end of the block");
2898             break;
2899         case SelectStartOfDocument:
2900             text = tr("Select to the start of the document");
2901             break;
2902         case SelectEndOfDocument:
2903             text = tr("Select to the end of the document");
2904             break;
2905         case DeleteStartOfWord:
2906             text = tr("Delete to the start of the word");
2907             break;
2908         case DeleteEndOfWord:
2909             text = tr("Delete to the end of the word");
2910             break;
2911
2912         case SetTextDirectionDefault:
2913             text = contextMenuItemTagDefaultDirection();
2914             break;
2915         case SetTextDirectionLeftToRight:
2916             text = contextMenuItemTagLeftToRight();
2917             checkable = true;
2918             break;
2919         case SetTextDirectionRightToLeft:
2920             text = contextMenuItemTagRightToLeft();
2921             checkable = true;
2922             break;
2923
2924         case ToggleBold:
2925             text = contextMenuItemTagBold();
2926             checkable = true;
2927             break;
2928         case ToggleItalic:
2929             text = contextMenuItemTagItalic();
2930             checkable = true;
2931             break;
2932         case ToggleUnderline:
2933             text = contextMenuItemTagUnderline();
2934             checkable = true;
2935             break;
2936
2937         case InspectElement:
2938             text = contextMenuItemTagInspectElement();
2939             break;
2940
2941         case InsertParagraphSeparator:
2942             text = tr("Insert a new paragraph");
2943             break;
2944         case InsertLineSeparator:
2945             text = tr("Insert a new line");
2946             break;
2947
2948         case PasteAndMatchStyle:
2949             text = tr("Paste and Match Style");
2950             break;
2951         case RemoveFormat:
2952             text = tr("Remove formatting");
2953             break;
2954
2955         case ToggleStrikethrough:
2956             text = tr("Strikethrough");
2957             checkable = true;
2958             break;
2959         case ToggleSubscript:
2960             text = tr("Subscript");
2961             checkable = true;
2962             break;
2963         case ToggleSuperscript:
2964             text = tr("Superscript");
2965             checkable = true;
2966             break;
2967         case InsertUnorderedList:
2968             text = tr("Insert Bulleted List");
2969             checkable = true;
2970             break;
2971         case InsertOrderedList:
2972             text = tr("Insert Numbered List");
2973             checkable = true;
2974             break;
2975         case Indent:
2976             text = tr("Indent");
2977             break;
2978         case Outdent:
2979             text = tr("Outdent");
2980             break;
2981         case AlignCenter:
2982             text = tr("Center");
2983             break;
2984         case AlignJustified:
2985             text = tr("Justify");
2986             break;
2987         case AlignLeft:
2988             text = tr("Align Left");
2989             break;
2990         case AlignRight:
2991             text = tr("Align Right");
2992             break;
2993         case NoWebAction:
2994             return 0;
2995         default:
2996             break;
2997     }
2998
2999     if (text.isEmpty())
3000         return 0;
3001
3002     QAction *a = new QAction(d->q);
3003     a->setText(text);
3004     a->setData(action);
3005     a->setCheckable(checkable);
3006     a->setIcon(icon);
3007
3008     connect(a, SIGNAL(triggered(bool)),
3009             this, SLOT(_q_webActionTriggered(bool)));
3010
3011     d->actions[action] = a;
3012     d->updateAction(action);
3013     return a;
3014 }
3015 #endif // QT_NO_ACTION
3016
3017 /*!
3018     \property QWebPage::modified
3019     \brief whether the page contains unsubmitted form data, or the contents have been changed.
3020
3021     By default, this property is false.
3022
3023     \sa contentsChanged(), contentEditable, undoStack()
3024 */
3025 bool QWebPage::isModified() const
3026 {
3027 #ifdef QT_NO_UNDOSTACK
3028     return false;
3029 #else
3030     if (!d->undoStack)
3031         return false;
3032     return d->undoStack->canUndo();
3033 #endif // QT_NO_UNDOSTACK
3034 }
3035
3036 #ifndef QT_NO_UNDOSTACK
3037 /*!
3038     Returns a pointer to the undo stack used for editable content.
3039
3040     \sa modified
3041 */
3042 QUndoStack *QWebPage::undoStack() const
3043 {
3044     if (!d->undoStack)
3045         d->undoStack = new QUndoStack(const_cast<QWebPage *>(this));
3046
3047     return d->undoStack;
3048 }
3049 #endif // QT_NO_UNDOSTACK
3050
3051 /*! \reimp
3052 */
3053 bool QWebPage::event(QEvent *ev)
3054 {
3055     switch (ev->type()) {
3056     case QEvent::Timer:
3057         d->timerEvent(static_cast<QTimerEvent*>(ev));
3058         break;
3059     case QEvent::MouseMove:
3060         d->mouseMoveEvent(static_cast<QMouseEvent*>(ev));
3061         break;
3062     case QEvent::MouseButtonPress:
3063         d->mousePressEvent(static_cast<QMouseEvent*>(ev));
3064         break;
3065     case QEvent::MouseButtonDblClick:
3066         d->mouseDoubleClickEvent(static_cast<QMouseEvent*>(ev));
3067         break;
3068     case QEvent::MouseButtonRelease:
3069         d->mouseReleaseEvent(static_cast<QMouseEvent*>(ev));
3070         break;
3071 #if !defined(QT_NO_GRAPHICSVIEW)
3072     case QEvent::GraphicsSceneMouseMove:
3073         d->mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3074         break;
3075     case QEvent::GraphicsSceneMousePress:
3076         d->mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3077         break;
3078     case QEvent::GraphicsSceneMouseDoubleClick:
3079         d->mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3080         break;
3081     case QEvent::GraphicsSceneMouseRelease:
3082         d->mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3083         break;
3084 #endif
3085 #ifndef QT_NO_CONTEXTMENU
3086     case QEvent::ContextMenu:
3087         d->contextMenuEvent(static_cast<QContextMenuEvent*>(ev)->globalPos());
3088         break;
3089 #if !defined(QT_NO_GRAPHICSVIEW)
3090     case QEvent::GraphicsSceneContextMenu:
3091         d->contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(ev)->screenPos());
3092         break;
3093 #endif
3094 #endif
3095 #ifndef QT_NO_WHEELEVENT
3096     case QEvent::Wheel:
3097         d->wheelEvent(static_cast<QWheelEvent*>(ev));
3098         break;
3099 #if !defined(QT_NO_GRAPHICSVIEW)
3100     case QEvent::GraphicsSceneWheel:
3101         d->wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(ev));
3102         break;
3103 #endif
3104 #endif
3105     case QEvent::KeyPress:
3106         d->keyPressEvent(static_cast<QKeyEvent*>(ev));
3107         break;
3108     case QEvent::KeyRelease:
3109         d->keyReleaseEvent(static_cast<QKeyEvent*>(ev));
3110         break;
3111     case QEvent::FocusIn:
3112         d->focusInEvent(static_cast<QFocusEvent*>(ev));
3113         break;
3114     case QEvent::FocusOut:
3115         d->focusOutEvent(static_cast<QFocusEvent*>(ev));
3116         break;
3117 #ifndef QT_NO_DRAGANDDROP
3118     case QEvent::DragEnter:
3119         d->dragEnterEvent(static_cast<QDragEnterEvent*>(ev));
3120         break;
3121     case QEvent::DragLeave:
3122         d->dragLeaveEvent(static_cast<QDragLeaveEvent*>(ev));
3123         break;
3124     case QEvent::DragMove:
3125         d->dragMoveEvent(static_cast<QDragMoveEvent*>(ev));
3126         break;
3127     case QEvent::Drop:
3128         d->dropEvent(static_cast<QDropEvent*>(ev));
3129         break;
3130 #if !defined(QT_NO_GRAPHICSVIEW)
3131     case QEvent::GraphicsSceneDragEnter:
3132         d->dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3133         break;
3134     case QEvent::GraphicsSceneDragMove:
3135         d->dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3136         break;
3137     case QEvent::GraphicsSceneDragLeave:
3138         d->dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3139         break;
3140     case QEvent::GraphicsSceneDrop:
3141         d->dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3142         break;
3143 #endif
3144
3145 #endif
3146     case QEvent::InputMethod:
3147         d->inputMethodEvent(static_cast<QInputMethodEvent*>(ev));
3148         break;
3149     case QEvent::ShortcutOverride:
3150         d->shortcutOverrideEvent(static_cast<QKeyEvent*>(ev));
3151         break;
3152     case QEvent::Leave:
3153         d->leaveEvent(ev);
3154         break;
3155     case QEvent::TouchBegin:
3156     case QEvent::TouchUpdate:
3157     case QEvent::TouchEnd:
3158     case QEvent::TouchCancel:
3159         // Return whether the default action was cancelled in the JS event handler
3160         return d->touchEvent(static_cast<QTouchEvent*>(ev));
3161 #ifndef QT_NO_PROPERTIES
3162     case QEvent::DynamicPropertyChange:
3163         d->dynamicPropertyChangeEvent(static_cast<QDynamicPropertyChangeEvent*>(ev));
3164         break;
3165 #endif
3166     default:
3167         return QObject::event(ev);
3168     }
3169
3170     return true;
3171 }
3172
3173 /*!
3174     Similar to QWidget::focusNextPrevChild() it focuses the next focusable web element
3175     if \a next is true; otherwise the previous element is focused.
3176
3177     Returns true if it can find a new focusable element, or false if it can't.
3178 */
3179 bool QWebPage::focusNextPrevChild(bool next)
3180 {
3181     QKeyEvent ev(QEvent::KeyPress, Qt::Key_Tab, Qt::KeyboardModifiers(next ? Qt::NoModifier : Qt::ShiftModifier));
3182     d->keyPressEvent(&ev);
3183     bool hasFocusedNode = false;
3184     Frame *frame = d->page->focusController()->focusedFrame();
3185     if (frame) {
3186         Document *document = frame->document();
3187         hasFocusedNode = document && document->focusedNode();
3188     }
3189     //qDebug() << "focusNextPrevChild(" << next << ") =" << ev.isAccepted() << "focusedNode?" << hasFocusedNode;
3190     return hasFocusedNode;
3191 }
3192
3193 /*!
3194     \property QWebPage::contentEditable
3195     \brief whether the content in this QWebPage is editable or not
3196     \since 4.5
3197
3198     If this property is enabled the contents of the page can be edited by the user through a visible
3199     cursor. If disabled (the default) only HTML elements in the web page with their
3200     \c{contenteditable} attribute set are editable.
3201
3202     \sa modified, contentsChanged(), WebAction
3203 */
3204 void QWebPage::setContentEditable(bool editable)
3205 {
3206     if (isContentEditable() != editable) {
3207         d->page->setEditable(editable);
3208         d->page->setTabKeyCyclesThroughElements(!editable);
3209         if (d->mainFrame) {
3210             WebCore::Frame* frame = d->mainFrame.data()->d->frame;
3211             if (editable) {
3212                 frame->editor()->applyEditingStyleToBodyElement();
3213                 // FIXME: mac port calls this if there is no selectedDOMRange
3214                 //frame->setSelectionFromNone();
3215             }
3216         }
3217
3218         d->updateEditorActions();
3219     }
3220 }
3221
3222 bool QWebPage::isContentEditable() const
3223 {
3224     return d->page->isEditable();
3225 }
3226
3227 /*!
3228     \property QWebPage::forwardUnsupportedContent
3229     \brief whether QWebPage should forward unsupported content
3230
3231     If enabled, the unsupportedContent() signal is emitted with a network reply that
3232     can be used to read the content.
3233
3234     If disabled, the download of such content is aborted immediately.
3235
3236     By default unsupported content is not forwarded.
3237 */
3238
3239 void QWebPage::setForwardUnsupportedContent(bool forward)
3240 {
3241     d->forwardUnsupportedContent = forward;
3242 }
3243
3244 bool QWebPage::forwardUnsupportedContent() const
3245 {
3246     return d->forwardUnsupportedContent;
3247 }
3248
3249 /*!
3250     \property QWebPage::linkDelegationPolicy
3251     \brief how QWebPage should delegate the handling of links through the
3252     linkClicked() signal
3253
3254     The default is to delegate no links.
3255 */
3256
3257 void QWebPage::setLinkDelegationPolicy(LinkDelegationPolicy policy)
3258 {
3259     d->linkPolicy = policy;
3260 }
3261
3262 QWebPage::LinkDelegationPolicy QWebPage::linkDelegationPolicy() const
3263 {
3264     return d->linkPolicy;
3265 }
3266
3267 #ifndef QT_NO_CONTEXTMENU
3268
3269 static bool handleScrollbarContextMenuEvent(Scrollbar* scrollBar, QContextMenuEvent* event)
3270 {
3271     if (!QApplication::style()->styleHint(QStyle::SH_ScrollBar_ContextMenu))
3272         return true;
3273
3274     bool horizontal = (scrollBar->orientation() == HorizontalScrollbar);
3275
3276     QMenu menu;
3277     QAction* actScrollHere = menu.addAction(QCoreApplication::translate("QWebPage", "Scroll here"));
3278     menu.addSeparator();
3279
3280     QAction* actScrollTop = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Left edge") : QCoreApplication::translate("QWebPage", "Top"));
3281     QAction* actScrollBottom = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Right edge") : QCoreApplication::translate("QWebPage", "Bottom"));
3282     menu.addSeparator();
3283
3284     QAction* actPageUp = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Page left") : QCoreApplication::translate("QWebPage", "Page up"));
3285     QAction* actPageDown = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Page right") : QCoreApplication::translate("QWebPage", "Page down"));
3286     menu.addSeparator();
3287
3288     QAction* actScrollUp = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Scroll left") : QCoreApplication::translate("QWebPage", "Scroll up"));
3289     QAction* actScrollDown = menu.addAction(horizontal ? QCoreApplication::translate("QWebPage", "Scroll right") : QCoreApplication::translate("QWebPage", "Scroll down"));
3290
3291     QAction* actionSelected = menu.exec(event->globalPos());
3292
3293     if (actionSelected == actScrollHere) {
3294         ScrollbarTheme* theme = scrollBar->theme();
3295         // Set the pressed position to the middle of the thumb so that when we
3296         // do move, the delta will be from the current pixel position of the
3297         // thumb to the new position
3298         int position = theme->trackPosition(scrollBar) + theme->thumbPosition(scrollBar) + theme->thumbLength(scrollBar) / 2;
3299         scrollBar->setPressedPos(position);
3300         const QPoint pos = scrollBar->convertFromContainingWindow(event->pos());
3301         scrollBar->moveThumb(horizontal ? pos.x() : pos.y());
3302     } else if (actionSelected == actScrollTop)
3303         scrollBar->scrollableArea()->scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByDocument);
3304     else if (actionSelected == actScrollBottom)
3305         scrollBar->scrollableArea()->scroll(horizontal ? ScrollRight : ScrollDown, ScrollByDocument);
3306     else if (actionSelected == actPageUp)
3307         scrollBar->scrollableArea()->scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByPage);
3308     else if (actionSelected == actPageDown)
3309         scrollBar->scrollableArea()->scroll(horizontal ? ScrollRight : ScrollDown, ScrollByPage);
3310     else if (actionSelected == actScrollUp)
3311         scrollBar->scrollableArea()->scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByLine);
3312     else if (actionSelected == actScrollDown)
3313         scrollBar->scrollableArea()->scroll(horizontal ? ScrollRight : ScrollDown, ScrollByLine);
3314     return true;
3315 }
3316
3317 /*!
3318     Filters the context menu event, \a event, through handlers for scrollbars and
3319     custom event handlers in the web page. Returns true if the event was handled;
3320     otherwise false.
3321
3322     A web page may swallow a context menu event through a custom event handler, allowing for context
3323     menus to be implemented in HTML/JavaScript. This is used by \l{http://maps.google.com/}{Google
3324     Maps}, for example.
3325 */
3326 bool QWebPage::swallowContextMenuEvent(QContextMenuEvent *event)
3327 {
3328     d->page->contextMenuController()->clearContextMenu();
3329
3330     if (QWebFrame* webFrame = frameAt(event->pos())) {
3331         Frame* frame = QWebFramePrivate::core(webFrame);
3332         if (Scrollbar* scrollbar = frame->view()->scrollbarAtPoint(convertMouseEvent(event, 1).position()))
3333             return handleScrollbarContextMenuEvent(scrollbar, event);
3334     }
3335
3336     WebCore::Frame* focusedFrame = d->page->focusController()->focusedOrMainFrame();
3337     focusedFrame->eventHandler()->sendContextMenuEvent(convertMouseEvent(event, 1));
3338     ContextMenu *menu = d->page->contextMenuController()->contextMenu();
3339     // If the website defines its own handler then sendContextMenuEvent takes care of
3340     // calling/showing it and the context menu pointer will be zero. This is the case
3341     // on maps.google.com for example.
3342
3343     return !menu;
3344 }
3345 #endif // QT_NO_CONTEXTMENU
3346
3347 /*!
3348     Updates the page's actions depending on the position \a pos. For example if \a pos is over an image
3349     element the CopyImageToClipboard action is enabled.
3350 */
3351 void QWebPage::updatePositionDependentActions(const QPoint &pos)
3352 {
3353 #ifndef QT_NO_ACTION
3354     // First we disable all actions, but keep track of which ones were originally enabled.
3355     QBitArray originallyEnabledWebActions(QWebPage::WebActionCount);
3356     for (int i = ContextMenuItemTagNoAction; i < ContextMenuItemBaseApplicationTag; ++i) {
3357         QWebPage::WebAction action = webActionForContextMenuAction(WebCore::ContextMenuAction(i));
3358         if (QAction *a = this->action(action)) {
3359             originallyEnabledWebActions.setBit(action, a->isEnabled());
3360             a->setEnabled(false);
3361         }
3362     }
3363 #endif // QT_NO_ACTION
3364
3365     d->createMainFrame();
3366     WebCore::Frame* focusedFrame = d->page->focusController()->focusedOrMainFrame();
3367
3368     HitTestResult result = focusedFrame->eventHandler()->hitTestResultAtPoint(focusedFrame->view()->windowToContents(pos), /*allowShadowContent*/ false);
3369     if (result.scrollbar())
3370         d->hitTestResult = QWebHitTestResult();
3371     else
3372         d->hitTestResult = QWebHitTestResult(new QWebHitTestResultPrivate(result));
3373     d->page->contextMenuController()->setHitTestResult(result);
3374
3375 #if ENABLE(INSPECTOR)
3376     if (d->page->inspectorController()->enabled())
3377         d->page->contextMenuController()->addInspectElementItem();
3378 #endif
3379
3380     QBitArray visitedWebActions(QWebPage::WebActionCount);
3381
3382 #ifndef QT_NO_CONTEXTMENU
3383     delete d->currentContextMenu.data();
3384
3385     // Then we let createContextMenu() enable the actions that are put into the menu
3386     d->currentContextMenu = d->createContextMenu(d->page->contextMenuController()->contextMenu(), d->page->contextMenuController()->contextMenu()->platformDescription(), &visitedWebActions);
3387 #endif // QT_NO_CONTEXTMENU
3388
3389 #ifndef QT_NO_ACTION
3390     // Finally, we restore the original enablement for the actions that were not put into the menu.
3391     originallyEnabledWebActions &= ~visitedWebActions; // Mask out visited actions (they're part of the menu)
3392     for (int i = 0; i < QWebPage::WebActionCount; ++i) {
3393         if (originallyEnabledWebActions.at(i)) {
3394             if (QAction *a = this->action(QWebPage::WebAction(i)))
3395                 a->setEnabled(true);
3396         }
3397     }
3398 #endif // QT_NO_ACTION
3399
3400     // This whole process ensures that any actions put into to the context menu has the right
3401     // enablement, while also keeping the correct enablement for actions that were left out of
3402     // the menu.
3403
3404 }
3405
3406
3407
3408 /*!
3409     \enum QWebPage::Extension
3410
3411     This enum describes the types of extensions that the page can support. Before using these extensions, you
3412     should verify that the extension is supported by calling supportsExtension().
3413
3414     \value ChooseMultipleFilesExtension Whether the web page supports multiple file selection.
3415     This extension is invoked when the web content requests one or more file names, for example
3416     as a result of the user clicking on a "file upload" button in a HTML form where multiple
3417     file selection is allowed.
3418
3419     \value ErrorPageExtension Whether the web page can provide an error page when loading fails.
3420     (introduced in Qt 4.6)
3421
3422     \sa ChooseMultipleFilesExtensionOption, ChooseMultipleFilesExtensionReturn, ErrorPageExtensionOption, ErrorPageExtensionReturn
3423 */
3424
3425 /*!
3426     \enum QWebPage::ErrorDomain
3427     \since 4.6
3428
3429     This enum describes the domain of an ErrorPageExtensionOption object (i.e. the layer in which the error occurred).
3430
3431     \value QtNetwork The error occurred in the QtNetwork layer; the error code is of type QNetworkReply::NetworkError.
3432     \value Http The error occurred in the HTTP layer; the error code is a HTTP status code (see QNetworkRequest::HttpStatusCodeAttribute).
3433     \value WebKit The error is an internal WebKit error.
3434 */
3435
3436 /*!
3437     \class QWebPage::ExtensionOption
3438     \since 4.4
3439     \brief The ExtensionOption class provides an extended input argument to QWebPage's extension support.
3440
3441     \inmodule QtWebKit
3442
3443     \sa QWebPage::extension(), QWebPage::ExtensionReturn
3444 */
3445
3446
3447 /*!
3448     \class QWebPage::ExtensionReturn
3449     \since 4.4
3450     \brief The ExtensionReturn class provides an output result from a QWebPage's extension.
3451
3452     \inmodule QtWebKit
3453
3454     \sa QWebPage::extension(), QWebPage::ExtensionOption
3455 */
3456
3457 /*!
3458     \class QWebPage::ErrorPageExtensionOption
3459     \since 4.6
3460     \brief The ErrorPageExtensionOption class describes the option
3461     for the error page extension.
3462
3463     \inmodule QtWebKit
3464
3465     The ErrorPageExtensionOption class holds the \a url for which an error occurred as well as
3466     the associated \a frame.
3467
3468     The error itself is reported by an error \a domain, the \a error code as well as \a errorString.
3469
3470     \sa QWebPage::extension(), QWebPage::ErrorPageExtensionReturn
3471 */
3472
3473 /*!
3474     \variable QWebPage::ErrorPageExtensionOption::url
3475     \brief the url for which an error occurred
3476 */
3477
3478 /*!
3479     \variable QWebPage::ErrorPageExtensionOption::frame
3480     \brief the frame associated with the error
3481 */
3482
3483 /*!
3484     \variable QWebPage::ErrorPageExtensionOption::domain
3485     \brief the domain that reported the error
3486 */
3487
3488 /*!
3489     \variable QWebPage::ErrorPageExtensionOption::error
3490     \brief the error code. Interpretation of the value depends on the \a domain
3491     \sa QWebPage::ErrorDomain
3492 */
3493
3494 /*!
3495     \variable QWebPage::ErrorPageExtensionOption::errorString
3496     \brief a string that describes the error
3497 */
3498
3499 /*!
3500     \class QWebPage::ErrorPageExtensionReturn
3501     \since 4.6
3502     \brief The ErrorPageExtensionReturn describes the error page, which will be shown for the
3503     frame for which the error occured.
3504
3505     \inmodule QtWebKit
3506
3507     The ErrorPageExtensionReturn class holds the data needed for creating an error page. Some are
3508     optional such as \a contentType, which defaults to "text/html", as well as the \a encoding, which
3509     is assumed to be UTF-8 if not indicated otherwise.
3510
3511     The error page is stored in the \a content byte array, as HTML content. In order to convert a
3512   &