initial import
[vuplus_webkit] / Source / WebKit / qt / Api / qwebpage.cpp
1 /*
2     Copyright (C) 2008, 2009 Nokia Corporation and/or its subsidiary(-ies)
3     Copyright (C) 2007 Staikos Computing Services Inc.
4     Copyright (C) 2007 Apple Inc.
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20 */
21
22 #include "config.h"
23 #include "qwebpage.h"
24
25 #include "qwebview.h"
26 #include "qwebframe.h"
27 #include "qwebpage_p.h"
28 #include "qwebframe_p.h"
29 #include "qwebhistory.h"
30 #include "qwebhistory_p.h"
31 #include "qwebinspector.h"
32 #include "qwebinspector_p.h"
33 #include "qwebsettings.h"
34 #include "qwebkitplatformplugin.h"
35 #include "qwebkitversion.h"
36
37 #include "CSSComputedStyleDeclaration.h"
38 #include "CSSParser.h"
39 #include "ApplicationCacheStorage.h"
40 #include "BackForwardListImpl.h"
41 #include "MemoryCache.h"
42 #include "Chrome.h"
43 #include "ChromeClientQt.h"
44 #include "ClientRect.h"
45 #include "ContextMenu.h"
46 #include "ContextMenuClientQt.h"
47 #include "ContextMenuController.h"
48 #include "DeviceMotionClientQt.h"
49 #include "DeviceOrientationClientQt.h"
50 #include "DocumentLoader.h"
51 #include "DragClientQt.h"
52 #include "DragController.h"
53 #include "DragData.h"
54 #include "Editor.h"
55 #include "EditorClientQt.h"
56 #include "FocusController.h"
57 #include "FormState.h"
58 #include "Frame.h"
59 #include "FrameLoadRequest.h"
60 #include "FrameLoader.h"
61 #include "FrameLoader.h"
62 #include "FrameLoaderClientQt.h"
63 #include "FrameTree.h"
64 #include "FrameView.h"
65 #if ENABLE(CLIENT_BASED_GEOLOCATION)
66 #include "GeolocationClientMock.h"
67 #include "GeolocationClientQt.h"
68 #endif // CLIENT_BASED_GEOLOCATION
69 #include "GeolocationPermissionClientQt.h"
70 #include "HTMLFormElement.h"
71 #include "HTMLFrameOwnerElement.h"
72 #include "HTMLInputElement.h"
73 #include "HTMLNames.h"
74 #include "HashMap.h"
75 #include "HitTestResult.h"
76 #include "Image.h"
77 #include "InspectorClientQt.h"
78 #include "InspectorController.h"
79 #include "InspectorServerQt.h"
80 #include "KURL.h"
81 #include "LocalizedStrings.h"
82 #include "Logging.h"
83 #include "MIMETypeRegistry.h"
84 #include "NavigationAction.h"
85 #include "NetworkingContext.h"
86 #include "NodeList.h"
87 #include "NotificationPresenterClientQt.h"
88 #include "NotImplemented.h"
89 #include "Page.h"
90 #include "PageClientQt.h"
91 #include "PageGroup.h"
92 #include "Pasteboard.h"
93 #include "PlatformKeyboardEvent.h"
94 #include "PlatformTouchEvent.h"
95 #include "PlatformWheelEvent.h"
96 #include "PluginDatabase.h"
97 #include "PluginDatabase.h"
98 #include "PluginPackage.h"
99 #include "ProgressTracker.h"
100 #include "QtPlatformPlugin.h"
101 #include "RefPtr.h"
102 #include "RenderTextControl.h"
103 #include "SchemeRegistry.h"
104 #include "Scrollbar.h"
105 #include "SecurityOrigin.h"
106 #include "Settings.h"
107 #if defined Q_OS_WIN32
108 #include "SystemInfo.h"
109 #endif // Q_OS_WIN32
110 #include "TextIterator.h"
111 #include "WebPlatformStrategies.h"
112 #if USE(QTKIT)
113 #include "WebSystemInterface.h"
114 #endif
115 #include "WindowFeatures.h"
116 #include "WorkerThread.h"
117 #include <runtime/InitializeThreading.h>
118 #include <wtf/MainThread.h>
119
120 #include <QApplication>
121 #include <QBasicTimer>
122 #include <QBitArray>
123 #include <QDebug>
124 #include <QDesktopWidget>
125 #include <QDragEnterEvent>
126 #include <QDragLeaveEvent>
127 #include <QDragMoveEvent>
128 #include <QDropEvent>
129 #include <QFileDialog>
130 #include <QHttpRequestHeader>
131 #include <QInputDialog>
132 #include <QMessageBox>
133 #include <QNetworkProxy>
134 #include <QUndoStack>
135 #include <QUrl>
136 #include <QPainter>
137 #include <QClipboard>
138 #include <QSslSocket>
139 #include <QStyle>
140 #include <QSysInfo>
141 #include <QTextCharFormat>
142 #include <QTextDocument>
143 #include <QTouchEvent>
144 #include <QNetworkAccessManager>
145 #include <QNetworkRequest>
146 #if defined(Q_WS_X11)
147 #include <QX11Info>
148 #endif
149 #if USE(QT_MOBILITY_SYSTEMINFO)
150 #include <qsysteminfo.h>
151 #endif
152
153 using namespace WebCore;
154
155 // from text/qfont.cpp
156 QT_BEGIN_NAMESPACE
157 extern Q_GUI_EXPORT int qt_defaultDpi();
158 QT_END_NAMESPACE
159
160 bool QWebPagePrivate::drtRun = false;
161
162 // Lookup table mapping QWebPage::WebActions to the associated Editor commands
163 static const char* editorCommandWebActions[] =
164 {
165     0, // OpenLink,
166
167     0, // OpenLinkInNewWindow,
168     0, // OpenFrameInNewWindow,
169
170     0, // DownloadLinkToDisk,
171     0, // CopyLinkToClipboard,
172
173     0, // OpenImageInNewWindow,
174     0, // DownloadImageToDisk,
175     0, // CopyImageToClipboard,
176
177     0, // Back,
178     0, // Forward,
179     0, // Stop,
180     0, // Reload,
181
182     "Cut", // Cut,
183     "Copy", // Copy,
184     "Paste", // Paste,
185
186     "Undo", // Undo,
187     "Redo", // Redo,
188     "MoveForward", // MoveToNextChar,
189     "MoveBackward", // MoveToPreviousChar,
190     "MoveWordForward", // MoveToNextWord,
191     "MoveWordBackward", // MoveToPreviousWord,
192     "MoveDown", // MoveToNextLine,
193     "MoveUp", // MoveToPreviousLine,
194     "MoveToBeginningOfLine", // MoveToStartOfLine,
195     "MoveToEndOfLine", // MoveToEndOfLine,
196     "MoveToBeginningOfParagraph", // MoveToStartOfBlock,
197     "MoveToEndOfParagraph", // MoveToEndOfBlock,
198     "MoveToBeginningOfDocument", // MoveToStartOfDocument,
199     "MoveToEndOfDocument", // MoveToEndOfDocument,
200     "MoveForwardAndModifySelection", // SelectNextChar,
201     "MoveBackwardAndModifySelection", // SelectPreviousChar,
202     "MoveWordForwardAndModifySelection", // SelectNextWord,
203     "MoveWordBackwardAndModifySelection", // SelectPreviousWord,
204     "MoveDownAndModifySelection", // SelectNextLine,
205     "MoveUpAndModifySelection", // SelectPreviousLine,
206     "MoveToBeginningOfLineAndModifySelection", // SelectStartOfLine,
207     "MoveToEndOfLineAndModifySelection", // SelectEndOfLine,
208     "MoveToBeginningOfParagraphAndModifySelection", // SelectStartOfBlock,
209     "MoveToEndOfParagraphAndModifySelection", // SelectEndOfBlock,
210     "MoveToBeginningOfDocumentAndModifySelection", //SelectStartOfDocument,
211     "MoveToEndOfDocumentAndModifySelection", // SelectEndOfDocument,
212     "DeleteWordBackward", // DeleteStartOfWord,
213     "DeleteWordForward", // DeleteEndOfWord,
214
215     0, // SetTextDirectionDefault,
216     0, // SetTextDirectionLeftToRight,
217     0, // SetTextDirectionRightToLeft,
218
219     "ToggleBold", // ToggleBold,
220     "ToggleItalic", // ToggleItalic,
221     "ToggleUnderline", // ToggleUnderline,
222
223     0, // InspectElement,
224
225     "InsertNewline", // InsertParagraphSeparator
226     "InsertLineBreak", // InsertLineSeparator
227
228     "SelectAll", // SelectAll
229     0, // ReloadAndBypassCache,
230
231     "PasteAndMatchStyle", // PasteAndMatchStyle
232     "RemoveFormat", // RemoveFormat
233     "Strikethrough", // ToggleStrikethrough,
234     "Subscript", // ToggleSubscript
235     "Superscript", // ToggleSuperscript
236     "InsertUnorderedList", // InsertUnorderedList
237     "InsertOrderedList", // InsertOrderedList
238     "Indent", // Indent
239     "Outdent", // Outdent,
240
241     "AlignCenter", // AlignCenter,
242     "AlignJustified", // AlignJustified,
243     "AlignLeft", // AlignLeft,
244     "AlignRight", // AlignRight,
245
246     0, // StopScheduledPageRefresh,
247
248     0, // CopyImageUrlToClipboard,
249
250     0 // WebActionCount
251 };
252
253 // Lookup the appropriate editor command to use for WebAction \a action
254 const char* QWebPagePrivate::editorCommandForWebActions(QWebPage::WebAction action)
255 {
256     if ((action > QWebPage::NoWebAction) && (action < int(sizeof(editorCommandWebActions) / sizeof(const char*))))
257         return editorCommandWebActions[action];
258     return 0;
259 }
260
261 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
262 {
263     unsigned result = 0;
264     if (actions & Qt::CopyAction)
265         result |= DragOperationCopy;
266     // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
267     // hence it should be considered as "move"
268     if (actions & Qt::MoveAction)
269         result |= (DragOperationMove | DragOperationGeneric);
270     if (actions & Qt::LinkAction)
271         result |= DragOperationLink;
272     if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink))
273         result = DragOperationEvery;
274     return (DragOperation)result;
275 }
276
277 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
278 {
279     Qt::DropAction result = Qt::IgnoreAction;
280     if (actions & DragOperationCopy)
281         result = Qt::CopyAction;
282     else if (actions & DragOperationMove)
283         result = Qt::MoveAction;
284     // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
285     // hence it should be considered as "move"
286     else if (actions & DragOperationGeneric)
287         result = Qt::MoveAction;
288     else if (actions & DragOperationLink)
289         result = Qt::LinkAction;
290     return result;
291 }
292
293 QWebPagePrivate::QWebPagePrivate(QWebPage *qq)
294     : q(qq)
295     , page(0)
296 #ifndef QT_NO_UNDOSTACK
297     , undoStack(0)
298 #endif
299     , insideOpenCall(false)
300     , m_totalBytes(0)
301     , m_bytesReceived()
302     , clickCausedFocus(false)
303     , networkManager(0)
304     , forwardUnsupportedContent(false)
305     , smartInsertDeleteEnabled(true)
306     , selectTrailingWhitespaceEnabled(false)
307     , linkPolicy(QWebPage::DontDelegateLinks)
308     , viewportSize(QSize(0, 0))
309     , settings(0)
310     , useFixedLayout(false)
311     , pluginFactory(0)
312     , inspectorFrontend(0)
313     , inspector(0)
314     , inspectorIsInternalOnly(false)
315     , m_lastDropAction(Qt::IgnoreAction)
316 {
317     WebCore::InitializeLoggingChannelsIfNecessary();
318     ScriptController::initializeThreading();
319     WTF::initializeMainThread();
320     WebCore::SecurityOrigin::setLocalLoadPolicy(WebCore::SecurityOrigin::AllowLocalLoadsForLocalAndSubstituteData);
321
322     WebPlatformStrategies::initialize();
323
324 #if USE(QTKIT)
325     InitWebCoreSystemInterface();
326 #endif
327
328     Page::PageClients pageClients;
329     pageClients.chromeClient = new ChromeClientQt(q);
330     pageClients.contextMenuClient = new ContextMenuClientQt();
331     pageClients.editorClient = new EditorClientQt(q);
332     pageClients.dragClient = new DragClientQt(q);
333     pageClients.inspectorClient = new InspectorClientQt(q);
334 #if ENABLE(DEVICE_ORIENTATION)
335     pageClients.deviceOrientationClient = new DeviceOrientationClientQt(q);
336     pageClients.deviceMotionClient = new DeviceMotionClientQt(q);
337 #endif
338 #if ENABLE(CLIENT_BASED_GEOLOCATION)
339     if (QWebPagePrivate::drtRun)
340         pageClients.geolocationClient = new GeolocationClientMock();
341     else
342         pageClients.geolocationClient = new GeolocationClientQt(q);
343 #endif
344     page = new Page(pageClients);
345
346     // By default each page is put into their own unique page group, which affects popup windows
347     // and visited links. Page groups (per process only) is a feature making it possible to use
348     // separate settings for each group, so that for instance an integrated browser/email reader
349     // can use different settings for displaying HTML pages and HTML email. To make QtWebKit work
350     // as expected out of the box, we use a default group similar to what other ports are doing.
351     page->setGroupName("Default Group");
352
353 #if ENABLE(CLIENT_BASED_GEOLOCATION)
354     // In case running in DumpRenderTree mode set the controller to mock provider.
355     if (QWebPagePrivate::drtRun)
356         static_cast<GeolocationClientMock*>(pageClients.geolocationClient)->setController(page->geolocationController());
357 #endif
358     settings = new QWebSettings(page->settings());
359
360     history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList()));
361     memset(actions, 0, sizeof(actions));
362
363     PageGroup::setShouldTrackVisitedLinks(true);
364     
365 #if ENABLE(NOTIFICATIONS)    
366     NotificationPresenterClientQt::notificationPresenter()->addClient();
367 #endif
368 }
369
370 QWebPagePrivate::~QWebPagePrivate()
371 {
372     if (inspector && inspectorIsInternalOnly) {
373         // Since we have to delete an internal inspector,
374         // call setInspector(0) directly to prevent potential crashes
375         setInspector(0);
376     }
377 #ifndef QT_NO_CONTEXTMENU
378     delete currentContextMenu.data();
379 #endif
380 #ifndef QT_NO_UNDOSTACK
381     delete undoStack;
382 #endif
383     delete settings;
384     delete page;
385     
386     if (inspector)
387         inspector->setPage(0);
388
389 #if ENABLE(NOTIFICATIONS)
390     NotificationPresenterClientQt::notificationPresenter()->removeClient();
391 #endif
392 }
393
394 WebCore::ViewportArguments QWebPagePrivate::viewportArguments()
395 {
396     return page ? page->viewportArguments() : WebCore::ViewportArguments();
397 }
398
399 WebCore::Page* QWebPagePrivate::core(const QWebPage* page)
400 {
401     return page->d->page;
402 }
403
404 QWebPagePrivate* QWebPagePrivate::priv(QWebPage* page)
405 {
406     return page->d;
407 }
408
409 bool QWebPagePrivate::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
410 {
411     if (insideOpenCall
412         && frame == mainFrame.data())
413         return true;
414     return q->acceptNavigationRequest(frame, request, type);
415 }
416
417 void QWebPagePrivate::createMainFrame()
418 {
419     if (!mainFrame) {
420         QWebFrameData frameData(page);
421         mainFrame = new QWebFrame(q, &frameData);
422
423         emit q->frameCreated(mainFrame.data());
424     }
425 }
426
427 static QWebPage::WebAction webActionForContextMenuAction(WebCore::ContextMenuAction action)
428 {
429     switch (action) {
430         case WebCore::ContextMenuItemTagOpenLink: return QWebPage::OpenLink;
431         case WebCore::ContextMenuItemTagOpenLinkInNewWindow: return QWebPage::OpenLinkInNewWindow;
432         case WebCore::ContextMenuItemTagDownloadLinkToDisk: return QWebPage::DownloadLinkToDisk;
433         case WebCore::ContextMenuItemTagCopyLinkToClipboard: return QWebPage::CopyLinkToClipboard;
434         case WebCore::ContextMenuItemTagOpenImageInNewWindow: return QWebPage::OpenImageInNewWindow;
435         case WebCore::ContextMenuItemTagDownloadImageToDisk: return QWebPage::DownloadImageToDisk;
436         case WebCore::ContextMenuItemTagCopyImageToClipboard: return QWebPage::CopyImageToClipboard;
437         case WebCore::ContextMenuItemTagCopyImageUrlToClipboard: return QWebPage::CopyImageUrlToClipboard;
438         case WebCore::ContextMenuItemTagOpenFrameInNewWindow: return QWebPage::OpenFrameInNewWindow;
439         case WebCore::ContextMenuItemTagCopy: return QWebPage::Copy;
440         case WebCore::ContextMenuItemTagGoBack: return QWebPage::Back;
441         case WebCore::ContextMenuItemTagGoForward: return QWebPage::Forward;
442         case WebCore::ContextMenuItemTagStop: return QWebPage::Stop;
443         case WebCore::ContextMenuItemTagReload: return QWebPage::Reload;
444         case WebCore::ContextMenuItemTagCut: return QWebPage::Cut;
445         case WebCore::ContextMenuItemTagPaste: return QWebPage::Paste;
446         case WebCore::ContextMenuItemTagDefaultDirection: return QWebPage::SetTextDirectionDefault;
447         case WebCore::ContextMenuItemTagLeftToRight: return QWebPage::SetTextDirectionLeftToRight;
448         case WebCore::ContextMenuItemTagRightToLeft: return QWebPage::SetTextDirectionRightToLeft;
449         case WebCore::ContextMenuItemTagBold: return QWebPage::ToggleBold;
450         case WebCore::ContextMenuItemTagItalic: return QWebPage::ToggleItalic;
451         case WebCore::ContextMenuItemTagUnderline: return QWebPage::ToggleUnderline;
452         case WebCore::ContextMenuItemTagSelectAll: return QWebPage::SelectAll;
453 #if ENABLE(INSPECTOR)
454         case WebCore::ContextMenuItemTagInspectElement: return QWebPage::InspectElement;
455 #endif
456         default: break;
457     }
458     return QWebPage::NoWebAction;
459 }
460
461 #ifndef QT_NO_CONTEXTMENU
462 QMenu *QWebPagePrivate::createContextMenu(const WebCore::ContextMenu *webcoreMenu,
463         const QList<WebCore::ContextMenuItem> *items, QBitArray *visitedWebActions)
464 {
465     if (!client || !webcoreMenu)
466         return 0;
467
468     QMenu* menu = new QMenu(client->ownerWidget());
469     for (int i = 0; i < items->count(); ++i) {
470         const ContextMenuItem &item = items->at(i);
471         switch (item.type()) {
472             case WebCore::CheckableActionType: /* fall through */
473             case WebCore::ActionType: {
474                 QWebPage::WebAction action = webActionForContextMenuAction(item.action());
475                 QAction *a = q->action(action);
476                 if (a) {
477                     ContextMenuItem it(item);
478                     page->contextMenuController()->checkOrEnableIfNeeded(it);
479                     PlatformMenuItemDescription desc = it.releasePlatformDescription();
480                     a->setEnabled(desc.enabled);
481                     a->setChecked(desc.checked);
482                     a->setCheckable(item.type() == WebCore::CheckableActionType);
483
484                     menu->addAction(a);
485                     visitedWebActions->setBit(action);
486                 }
487                 break;
488             }
489             case WebCore::SeparatorType:
490                 menu->addSeparator();
491                 break;
492             case WebCore::SubmenuType: {
493                 QMenu *subMenu = createContextMenu(webcoreMenu, item.platformSubMenu(), visitedWebActions);
494
495                 bool anyEnabledAction = false;
496
497                 QList<QAction *> actions = subMenu->actions();
498                 for (int i = 0; i < actions.count(); ++i) {
499                     if (actions.at(i)->isVisible())
500                         anyEnabledAction |= actions.at(i)->isEnabled();
501                 }
502
503                 // don't show sub-menus with just disabled actions
504                 if (anyEnabledAction) {
505                     subMenu->setTitle(item.title());
506                     menu->addAction(subMenu->menuAction());
507                 } else
508                     delete subMenu;
509                 break;
510             }
511         }
512     }
513     return menu;
514 }
515 #endif // QT_NO_CONTEXTMENU
516
517 #ifndef QT_NO_ACTION
518 void QWebPagePrivate::_q_webActionTriggered(bool checked)
519 {
520     QAction *a = qobject_cast<QAction *>(q->sender());
521     if (!a)
522         return;
523     QWebPage::WebAction action = static_cast<QWebPage::WebAction>(a->data().toInt());
524     q->triggerAction(action, checked);
525 }
526 #endif // QT_NO_ACTION
527
528 void QWebPagePrivate::_q_cleanupLeakMessages()
529 {
530 #ifndef NDEBUG
531     // Need this to make leak messages accurate.
532     memoryCache()->setCapacities(0, 0, 0);
533 #endif
534 }
535
536 void QWebPagePrivate::updateAction(QWebPage::WebAction action)
537 {
538 #ifdef QT_NO_ACTION
539     Q_UNUSED(action)
540 #else
541     QAction *a = actions[action];
542     if (!a || !mainFrame)
543         return;
544
545     WebCore::FrameLoader *loader = mainFrame.data()->d->frame->loader();
546     WebCore::Editor *editor = page->focusController()->focusedOrMainFrame()->editor();
547
548     bool enabled = a->isEnabled();
549     bool checked = a->isChecked();
550
551     switch (action) {
552         case QWebPage::Back:
553             enabled = page->canGoBackOrForward(-1);
554             break;
555         case QWebPage::Forward:
556             enabled = page->canGoBackOrForward(1);
557             break;
558         case QWebPage::Stop:
559             enabled = loader->isLoading();
560             break;
561         case QWebPage::Reload:
562         case QWebPage::ReloadAndBypassCache:
563             enabled = !loader->isLoading();
564             break;
565 #ifndef QT_NO_UNDOSTACK
566         case QWebPage::Undo:
567         case QWebPage::Redo:
568             // those two are handled by QUndoStack
569             break;
570 #endif // QT_NO_UNDOSTACK
571         case QWebPage::SelectAll: // editor command is always enabled
572             break;
573         case QWebPage::SetTextDirectionDefault:
574         case QWebPage::SetTextDirectionLeftToRight:
575         case QWebPage::SetTextDirectionRightToLeft:
576             enabled = editor->canEdit();
577             checked = false;
578             break;
579         default: {
580             // see if it's an editor command
581             const char* commandName = editorCommandForWebActions(action);
582
583             // if it's an editor command, let it's logic determine state
584             if (commandName) {
585                 Editor::Command command = editor->command(commandName);
586                 enabled = command.isEnabled();
587                 if (enabled)
588                     checked = command.state() != FalseTriState;
589                 else
590                     checked = false;
591             }
592             break;
593         }
594     }
595
596     a->setEnabled(enabled);
597
598     if (a->isCheckable())
599         a->setChecked(checked);
600 #endif // QT_NO_ACTION
601 }
602
603 void QWebPagePrivate::updateNavigationActions()
604 {
605     updateAction(QWebPage::Back);
606     updateAction(QWebPage::Forward);
607     updateAction(QWebPage::Stop);
608     updateAction(QWebPage::Reload);
609     updateAction(QWebPage::ReloadAndBypassCache);
610 }
611
612 void QWebPagePrivate::updateEditorActions()
613 {
614     updateAction(QWebPage::Cut);
615     updateAction(QWebPage::Copy);
616     updateAction(QWebPage::Paste);
617     updateAction(QWebPage::MoveToNextChar);
618     updateAction(QWebPage::MoveToPreviousChar);
619     updateAction(QWebPage::MoveToNextWord);
620     updateAction(QWebPage::MoveToPreviousWord);
621     updateAction(QWebPage::MoveToNextLine);
622     updateAction(QWebPage::MoveToPreviousLine);
623     updateAction(QWebPage::MoveToStartOfLine);
624     updateAction(QWebPage::MoveToEndOfLine);
625     updateAction(QWebPage::MoveToStartOfBlock);
626     updateAction(QWebPage::MoveToEndOfBlock);
627     updateAction(QWebPage::MoveToStartOfDocument);
628     updateAction(QWebPage::MoveToEndOfDocument);
629     updateAction(QWebPage::SelectNextChar);
630     updateAction(QWebPage::SelectPreviousChar);
631     updateAction(QWebPage::SelectNextWord);
632     updateAction(QWebPage::SelectPreviousWord);
633     updateAction(QWebPage::SelectNextLine);
634     updateAction(QWebPage::SelectPreviousLine);
635     updateAction(QWebPage::SelectStartOfLine);
636     updateAction(QWebPage::SelectEndOfLine);
637     updateAction(QWebPage::SelectStartOfBlock);
638     updateAction(QWebPage::SelectEndOfBlock);
639     updateAction(QWebPage::SelectStartOfDocument);
640     updateAction(QWebPage::SelectEndOfDocument);
641     updateAction(QWebPage::DeleteStartOfWord);
642     updateAction(QWebPage::DeleteEndOfWord);
643     updateAction(QWebPage::SetTextDirectionDefault);
644     updateAction(QWebPage::SetTextDirectionLeftToRight);
645     updateAction(QWebPage::SetTextDirectionRightToLeft);
646     updateAction(QWebPage::ToggleBold);
647     updateAction(QWebPage::ToggleItalic);
648     updateAction(QWebPage::ToggleUnderline);
649     updateAction(QWebPage::InsertParagraphSeparator);
650     updateAction(QWebPage::InsertLineSeparator);
651     updateAction(QWebPage::PasteAndMatchStyle);
652     updateAction(QWebPage::RemoveFormat);
653     updateAction(QWebPage::ToggleStrikethrough);
654     updateAction(QWebPage::ToggleSubscript);
655     updateAction(QWebPage::ToggleSuperscript);
656     updateAction(QWebPage::InsertUnorderedList);
657     updateAction(QWebPage::InsertOrderedList);
658     updateAction(QWebPage::Indent);
659     updateAction(QWebPage::Outdent);
660     updateAction(QWebPage::AlignCenter);
661     updateAction(QWebPage::AlignJustified);
662     updateAction(QWebPage::AlignLeft);
663     updateAction(QWebPage::AlignRight);
664 }
665
666 void QWebPagePrivate::timerEvent(QTimerEvent *ev)
667 {
668     int timerId = ev->timerId();
669     if (timerId == tripleClickTimer.timerId())
670         tripleClickTimer.stop();
671     else
672         q->timerEvent(ev);
673 }
674
675 template<class T>
676 void QWebPagePrivate::mouseMoveEvent(T* ev)
677 {
678     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
679     if (!frame->view())
680         return;
681
682     bool accepted = frame->eventHandler()->mouseMoved(PlatformMouseEvent(ev, 0));
683     ev->setAccepted(accepted);
684 }
685
686 template<class T>
687 void QWebPagePrivate::mousePressEvent(T* ev)
688 {
689     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
690     if (!frame->view())
691         return;
692
693     RefPtr<WebCore::Node> oldNode;
694     Frame* focusedFrame = page->focusController()->focusedFrame();
695     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
696         oldNode = focusedDocument->focusedNode();
697
698     if (tripleClickTimer.isActive()
699             && (ev->pos() - tripleClick).manhattanLength()
700                 < QApplication::startDragDistance()) {
701         mouseTripleClickEvent(ev);
702         return;
703     }
704
705     bool accepted = false;
706     adjustPointForClicking(ev);
707     PlatformMouseEvent mev(ev, 1);
708     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
709     if (mev.button() != NoButton)
710         accepted = frame->eventHandler()->handleMousePressEvent(mev);
711     ev->setAccepted(accepted);
712
713     RefPtr<WebCore::Node> newNode;
714     focusedFrame = page->focusController()->focusedFrame();
715     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
716         newNode = focusedDocument->focusedNode();
717
718     if (newNode && oldNode != newNode)
719         clickCausedFocus = true;
720 }
721
722 template<class T>
723 void QWebPagePrivate::mouseDoubleClickEvent(T *ev)
724 {
725     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
726     if (!frame->view())
727         return;
728
729     bool accepted = false;
730     PlatformMouseEvent mev(ev, 2);
731     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
732     if (mev.button() != NoButton)
733         accepted = frame->eventHandler()->handleMousePressEvent(mev);
734     ev->setAccepted(accepted);
735
736     tripleClickTimer.start(QApplication::doubleClickInterval(), q);
737     tripleClick = QPointF(ev->pos()).toPoint();
738 }
739
740 template<class T>
741 void QWebPagePrivate::mouseTripleClickEvent(T *ev)
742 {
743     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
744     if (!frame->view())
745         return;
746
747     bool accepted = false;
748     PlatformMouseEvent mev(ev, 3);
749     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
750     if (mev.button() != NoButton)
751         accepted = frame->eventHandler()->handleMousePressEvent(mev);
752     ev->setAccepted(accepted);
753 }
754
755 void QWebPagePrivate::handleClipboard(QEvent* ev, Qt::MouseButton button)
756 {
757 #ifndef QT_NO_CLIPBOARD
758     if (QApplication::clipboard()->supportsSelection()) {
759         bool oldSelectionMode = Pasteboard::generalPasteboard()->isSelectionMode();
760         Pasteboard::generalPasteboard()->setSelectionMode(true);
761         WebCore::Frame* focusFrame = page->focusController()->focusedOrMainFrame();
762         if (button == Qt::LeftButton) {
763             if (focusFrame && (focusFrame->editor()->canCopy() || focusFrame->editor()->canDHTMLCopy())) {
764                 Pasteboard::generalPasteboard()->writeSelection(focusFrame->editor()->selectedRange().get(), focusFrame->editor()->canSmartCopyOrDelete(), focusFrame);
765                 ev->setAccepted(true);
766             }
767         } else if (button == Qt::MidButton) {
768             if (focusFrame && (focusFrame->editor()->canPaste() || focusFrame->editor()->canDHTMLPaste())) {
769                 focusFrame->editor()->paste();
770                 ev->setAccepted(true);
771             }
772         }
773         Pasteboard::generalPasteboard()->setSelectionMode(oldSelectionMode);
774     }
775 #endif
776 }
777
778 template<class T>
779 void QWebPagePrivate::mouseReleaseEvent(T *ev)
780 {
781     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
782     if (!frame->view())
783         return;
784
785     bool accepted = false;
786     adjustPointForClicking(ev);
787     PlatformMouseEvent mev(ev, 0);
788     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
789     if (mev.button() != NoButton)
790         accepted = frame->eventHandler()->handleMouseReleaseEvent(mev);
791     ev->setAccepted(accepted);
792
793     handleClipboard(ev, ev->button());
794     handleSoftwareInputPanel(ev->button(), QPointF(ev->pos()).toPoint());
795 }
796
797 void QWebPagePrivate::handleSoftwareInputPanel(Qt::MouseButton button, const QPoint& pos)
798 {
799     Frame* frame = page->focusController()->focusedFrame();
800     if (!frame)
801         return;
802
803     if (client && client->inputMethodEnabled()
804         && frame->document()->focusedNode()
805         && button == Qt::LeftButton && qApp->autoSipEnabled()) {
806         QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel(
807             client->ownerWidget()->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
808         if (!clickCausedFocus || behavior == QStyle::RSIP_OnMouseClick) {
809             HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(frame->view()->windowToContents(pos), false);
810             if (result.isContentEditable()) {
811                 QEvent event(QEvent::RequestSoftwareInputPanel);
812                 QApplication::sendEvent(client->ownerWidget(), &event);
813             }
814         }
815     }
816
817     clickCausedFocus = false;
818 }
819
820 #ifndef QT_NO_CONTEXTMENU
821 void QWebPagePrivate::contextMenuEvent(const QPoint& globalPos)
822 {
823     QMenu *menu = q->createStandardContextMenu();
824     if (menu) {
825         menu->exec(globalPos);
826         delete menu;
827     }
828 }
829 #endif // QT_NO_CONTEXTMENU
830
831 /*!
832     \since 4.5
833     This function creates the standard context menu which is shown when
834     the user clicks on the web page with the right mouse button. It is
835     called from the default contextMenuEvent() handler. The popup menu's
836     ownership is transferred to the caller.
837  */
838 QMenu *QWebPage::createStandardContextMenu()
839 {
840 #ifndef QT_NO_CONTEXTMENU
841     QMenu* menu = d->currentContextMenu.data();
842     d->currentContextMenu.clear();
843     return menu;
844 #else
845     return 0;
846 #endif
847 }
848
849 #ifndef QT_NO_WHEELEVENT
850 template<class T>
851 void QWebPagePrivate::wheelEvent(T *ev)
852 {
853     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
854     if (!frame->view())
855         return;
856
857     WebCore::PlatformWheelEvent pev(ev);
858     bool accepted = frame->eventHandler()->handleWheelEvent(pev);
859     ev->setAccepted(accepted);
860 }
861 #endif // QT_NO_WHEELEVENT
862
863 #ifndef QT_NO_SHORTCUT
864 QWebPage::WebAction QWebPagePrivate::editorActionForKeyEvent(QKeyEvent* event)
865 {
866     static struct {
867         QKeySequence::StandardKey standardKey;
868         QWebPage::WebAction action;
869     } editorActions[] = {
870         { QKeySequence::Cut, QWebPage::Cut },
871         { QKeySequence::Copy, QWebPage::Copy },
872         { QKeySequence::Paste, QWebPage::Paste },
873         { QKeySequence::Undo, QWebPage::Undo },
874         { QKeySequence::Redo, QWebPage::Redo },
875         { QKeySequence::MoveToNextChar, QWebPage::MoveToNextChar },
876         { QKeySequence::MoveToPreviousChar, QWebPage::MoveToPreviousChar },
877         { QKeySequence::MoveToNextWord, QWebPage::MoveToNextWord },
878         { QKeySequence::MoveToPreviousWord, QWebPage::MoveToPreviousWord },
879         { QKeySequence::MoveToNextLine, QWebPage::MoveToNextLine },
880         { QKeySequence::MoveToPreviousLine, QWebPage::MoveToPreviousLine },
881         { QKeySequence::MoveToStartOfLine, QWebPage::MoveToStartOfLine },
882         { QKeySequence::MoveToEndOfLine, QWebPage::MoveToEndOfLine },
883         { QKeySequence::MoveToStartOfBlock, QWebPage::MoveToStartOfBlock },
884         { QKeySequence::MoveToEndOfBlock, QWebPage::MoveToEndOfBlock },
885         { QKeySequence::MoveToStartOfDocument, QWebPage::MoveToStartOfDocument },
886         { QKeySequence::MoveToEndOfDocument, QWebPage::MoveToEndOfDocument },
887         { QKeySequence::SelectNextChar, QWebPage::SelectNextChar },
888         { QKeySequence::SelectPreviousChar, QWebPage::SelectPreviousChar },
889         { QKeySequence::SelectNextWord, QWebPage::SelectNextWord },
890         { QKeySequence::SelectPreviousWord, QWebPage::SelectPreviousWord },
891         { QKeySequence::SelectNextLine, QWebPage::SelectNextLine },
892         { QKeySequence::SelectPreviousLine, QWebPage::SelectPreviousLine },
893         { QKeySequence::SelectStartOfLine, QWebPage::SelectStartOfLine },
894         { QKeySequence::SelectEndOfLine, QWebPage::SelectEndOfLine },
895         { QKeySequence::SelectStartOfBlock, QWebPage::SelectStartOfBlock },
896         { QKeySequence::SelectEndOfBlock,  QWebPage::SelectEndOfBlock },
897         { QKeySequence::SelectStartOfDocument, QWebPage::SelectStartOfDocument },
898         { QKeySequence::SelectEndOfDocument, QWebPage::SelectEndOfDocument },
899         { QKeySequence::DeleteStartOfWord, QWebPage::DeleteStartOfWord },
900         { QKeySequence::DeleteEndOfWord, QWebPage::DeleteEndOfWord },
901         { QKeySequence::InsertParagraphSeparator, QWebPage::InsertParagraphSeparator },
902         { QKeySequence::InsertLineSeparator, QWebPage::InsertLineSeparator },
903         { QKeySequence::SelectAll, QWebPage::SelectAll },
904         { QKeySequence::UnknownKey, QWebPage::NoWebAction }
905     };
906
907     for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
908         if (event == editorActions[i].standardKey)
909             return editorActions[i].action;
910
911     return QWebPage::NoWebAction;
912 }
913 #endif // QT_NO_SHORTCUT
914
915 void QWebPagePrivate::keyPressEvent(QKeyEvent *ev)
916 {
917     bool handled = false;
918     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
919     // we forward the key event to WebCore first to handle potential DOM
920     // defined event handlers and later on end up in EditorClientQt::handleKeyboardEvent
921     // to trigger editor commands via triggerAction().
922     if (!handled)
923         handled = frame->eventHandler()->keyEvent(ev);
924     if (!handled) {
925         handled = true;
926         if (!handleScrolling(ev, frame)) {
927             switch (ev->key()) {
928             case Qt::Key_Back:
929                 q->triggerAction(QWebPage::Back);
930                 break;
931             case Qt::Key_Forward:
932                 q->triggerAction(QWebPage::Forward);
933                 break;
934             case Qt::Key_Stop:
935                 q->triggerAction(QWebPage::Stop);
936                 break;
937             case Qt::Key_Refresh:
938                 q->triggerAction(QWebPage::Reload);
939                 break;
940             case Qt::Key_Backspace:
941                 if (ev->modifiers() == Qt::ShiftModifier)
942                     q->triggerAction(QWebPage::Forward);
943                 else
944                     q->triggerAction(QWebPage::Back);
945                 break;
946             default:
947                 handled = false;
948                 break;
949             }
950         }
951     }
952
953     ev->setAccepted(handled);
954 }
955
956 void QWebPagePrivate::keyReleaseEvent(QKeyEvent *ev)
957 {
958     if (ev->isAutoRepeat()) {
959         ev->setAccepted(true);
960         return;
961     }
962
963     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
964     bool handled = frame->eventHandler()->keyEvent(ev);
965     ev->setAccepted(handled);
966 }
967
968 void QWebPagePrivate::focusInEvent(QFocusEvent*)
969 {
970     FocusController *focusController = page->focusController();
971     focusController->setActive(true);
972     focusController->setFocused(true);
973     if (!focusController->focusedFrame())
974         focusController->setFocusedFrame(QWebFramePrivate::core(mainFrame.data()));
975 }
976
977 void QWebPagePrivate::focusOutEvent(QFocusEvent*)
978 {
979     // only set the focused frame inactive so that we stop painting the caret
980     // and the focus frame. But don't tell the focus controller so that upon
981     // focusInEvent() we can re-activate the frame.
982     FocusController *focusController = page->focusController();
983     // Call setFocused first so that window.onblur doesn't get called twice
984     focusController->setFocused(false);
985     focusController->setActive(false);
986 }
987
988 template<class T>
989 void QWebPagePrivate::dragEnterEvent(T* ev)
990 {
991 #ifndef QT_NO_DRAGANDDROP
992     DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
993             QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
994     Qt::DropAction action = dragOpToDropAction(page->dragController()->dragEntered(&dragData));
995     ev->setDropAction(action);
996     ev->acceptProposedAction();
997 #endif
998 }
999
1000 template<class T>
1001 void QWebPagePrivate::dragLeaveEvent(T *ev)
1002 {
1003 #ifndef QT_NO_DRAGANDDROP
1004     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
1005     page->dragController()->dragExited(&dragData);
1006     ev->accept();
1007 #endif
1008 }
1009
1010 template<class T>
1011 void QWebPagePrivate::dragMoveEvent(T *ev)
1012 {
1013 #ifndef QT_NO_DRAGANDDROP
1014     DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
1015             QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
1016     m_lastDropAction = dragOpToDropAction(page->dragController()->dragUpdated(&dragData));
1017     ev->setDropAction(m_lastDropAction);
1018     if (m_lastDropAction != Qt::IgnoreAction)
1019         ev->accept();
1020 #endif
1021 }
1022
1023 template<class T>
1024 void QWebPagePrivate::dropEvent(T *ev)
1025 {
1026 #ifndef QT_NO_DRAGANDDROP
1027     DragData dragData(ev->mimeData(), QPointF(ev->pos()).toPoint(),
1028             QCursor::pos(), dropActionToDragOp(ev->possibleActions()));
1029     if (page->dragController()->performDrag(&dragData)) {
1030         ev->setDropAction(m_lastDropAction);
1031         ev->accept();
1032     }
1033 #endif
1034 }
1035
1036 void QWebPagePrivate::leaveEvent(QEvent*)
1037 {
1038     // Fake a mouse move event just outside of the widget, since all
1039     // the interesting mouse-out behavior like invalidating scrollbars
1040     // is handled by the WebKit event handler's mouseMoved function.
1041     QMouseEvent fakeEvent(QEvent::MouseMove, QCursor::pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
1042     mouseMoveEvent(&fakeEvent);
1043 }
1044
1045 /*!
1046     \property QWebPage::palette
1047     \brief the page's palette
1048
1049     The base brush of the palette is used to draw the background of the main frame.
1050
1051     By default, this property contains the application's default palette.
1052 */
1053 void QWebPage::setPalette(const QPalette &pal)
1054 {
1055     d->palette = pal;
1056     if (!d->mainFrame || !d->mainFrame.data()->d->frame->view())
1057         return;
1058
1059     QBrush brush = pal.brush(QPalette::Base);
1060     QColor backgroundColor = brush.style() == Qt::SolidPattern ? brush.color() : QColor();
1061     QWebFramePrivate::core(d->mainFrame.data())->view()->updateBackgroundRecursively(backgroundColor, !backgroundColor.alpha());
1062 }
1063
1064 QPalette QWebPage::palette() const
1065 {
1066     return d->palette;
1067 }
1068
1069 void QWebPagePrivate::inputMethodEvent(QInputMethodEvent *ev)
1070 {
1071     WebCore::Frame *frame = page->focusController()->focusedOrMainFrame();
1072     WebCore::Editor *editor = frame->editor();
1073
1074     if (!editor->canEdit()) {
1075         ev->ignore();
1076         return;
1077     }
1078
1079     Node* node = 0;
1080     if (frame->selection()->rootEditableElement())
1081         node = frame->selection()->rootEditableElement()->shadowAncestorNode();
1082
1083     Vector<CompositionUnderline> underlines;
1084     bool hasSelection = false;
1085
1086     for (int i = 0; i < ev->attributes().size(); ++i) {
1087         const QInputMethodEvent::Attribute& a = ev->attributes().at(i);
1088         switch (a.type) {
1089         case QInputMethodEvent::TextFormat: {
1090             QTextCharFormat textCharFormat = a.value.value<QTextFormat>().toCharFormat();
1091             QColor qcolor = textCharFormat.underlineColor();
1092             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));
1093             break;
1094         }
1095         case QInputMethodEvent::Cursor: {
1096             frame->selection()->setCaretVisible(a.length); //if length is 0 cursor is invisible
1097             if (a.length > 0) {
1098                 RenderObject* caretRenderer = frame->selection()->caretRenderer();
1099                 if (caretRenderer) {
1100                     QColor qcolor = a.value.value<QColor>();
1101                     caretRenderer->style()->setColor(Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())));
1102                 }
1103             }
1104             break;
1105         }
1106         case QInputMethodEvent::Selection: {
1107             hasSelection = true;
1108             // A selection in the inputMethodEvent is always reflected in the visible text
1109             if (node) {
1110                 if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
1111                     textControl->setSelectionRange(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
1112             }
1113
1114             if (!ev->preeditString().isEmpty())
1115                 editor->setComposition(ev->preeditString(), underlines, qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
1116             else {
1117                 // If we are in the middle of a composition, an empty pre-edit string and a selection of zero
1118                 // cancels the current composition
1119                 if (editor->hasComposition() && (a.start + a.length == 0))
1120                     editor->setComposition(QString(), underlines, 0, 0);
1121             }
1122             break;
1123         }
1124         default:
1125             break;
1126         }
1127     }
1128
1129     if (node && ev->replacementLength() > 0) {
1130         int cursorPos = frame->selection()->extent().offsetInContainerNode();
1131         int start = cursorPos + ev->replacementStart();
1132         if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
1133             textControl->setSelectionRange(start, start + ev->replacementLength());
1134         // Commit regardless of whether commitString is empty, to get rid of selection.
1135         editor->confirmComposition(ev->commitString());
1136     } else if (!ev->commitString().isEmpty()) {
1137         if (editor->hasComposition())
1138             editor->confirmComposition(ev->commitString());
1139         else
1140             editor->insertText(ev->commitString(), 0);
1141     } else if (!hasSelection && !ev->preeditString().isEmpty())
1142         editor->setComposition(ev->preeditString(), underlines, 0, 0);
1143     else if (ev->preeditString().isEmpty() && editor->hasComposition())
1144         editor->confirmComposition(String());
1145
1146     ev->accept();
1147 }
1148
1149 #ifndef QT_NO_PROPERTIES
1150 typedef struct {
1151     const char* name;
1152     double deferredRepaintDelay;
1153     double initialDeferredRepaintDelayDuringLoading;
1154     double maxDeferredRepaintDelayDuringLoading;
1155     double deferredRepaintDelayIncrementDuringLoading;
1156 } QRepaintThrottlingPreset;
1157
1158 void QWebPagePrivate::dynamicPropertyChangeEvent(QDynamicPropertyChangeEvent* event)
1159 {
1160     if (event->propertyName() == "_q_viewMode") {
1161         page->setViewMode(Page::stringToViewMode(q->property("_q_viewMode").toString()));
1162     } else if (event->propertyName() == "_q_HTMLTokenizerChunkSize") {
1163         int chunkSize = q->property("_q_HTMLTokenizerChunkSize").toInt();
1164         q->handle()->page->setCustomHTMLTokenizerChunkSize(chunkSize);
1165     } else if (event->propertyName() == "_q_HTMLTokenizerTimeDelay") {
1166         double timeDelay = q->property("_q_HTMLTokenizerTimeDelay").toDouble();
1167         q->handle()->page->setCustomHTMLTokenizerTimeDelay(timeDelay);
1168     } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelay") {
1169         double p = q->property("_q_RepaintThrottlingDeferredRepaintDelay").toDouble();
1170         FrameView::setRepaintThrottlingDeferredRepaintDelay(p);
1171     } else if (event->propertyName() == "_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading") {
1172         double p = q->property("_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading").toDouble();
1173         FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(p);
1174     } else if (event->propertyName() == "_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading") {
1175         double p = q->property("_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading").toDouble();
1176         FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(p);
1177     } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading") {
1178         double p = q->property("_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading").toDouble();
1179         FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(p);
1180     } else if (event->propertyName() == "_q_RepaintThrottlingPreset") {
1181         static const QRepaintThrottlingPreset presets[] = {
1182             {   "NoThrottling",     0,      0,      0,      0 },
1183             {   "Legacy",       0.025,      0,    2.5,    0.5 },
1184             {   "Minimal",       0.01,      0,      1,    0.2 },
1185             {   "Medium",       0.025,      1,      5,    0.5 },
1186             {   "Heavy",          0.1,      2,     10,      1 }
1187         };
1188
1189         QString p = q->property("_q_RepaintThrottlingPreset").toString();
1190         for (size_t i = 0; i < sizeof(presets) / sizeof(presets[0]); i++) {
1191             if (p == QLatin1String(presets[i].name)) {
1192                 FrameView::setRepaintThrottlingDeferredRepaintDelay(
1193                         presets[i].deferredRepaintDelay);
1194                 FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(
1195                         presets[i].initialDeferredRepaintDelayDuringLoading);
1196                 FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(
1197                         presets[i].maxDeferredRepaintDelayDuringLoading);
1198                 FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(
1199                         presets[i].deferredRepaintDelayIncrementDuringLoading);
1200                 break;
1201             }
1202         }
1203     }
1204 #if ENABLE(TILED_BACKING_STORE)
1205     else if (event->propertyName() == "_q_TiledBackingStoreTileSize") {
1206         WebCore::Frame* frame = QWebFramePrivate::core(q->mainFrame());
1207         if (!frame->tiledBackingStore())
1208             return;
1209         QSize tileSize = q->property("_q_TiledBackingStoreTileSize").toSize();
1210         frame->tiledBackingStore()->setTileSize(tileSize);
1211     } else if (event->propertyName() == "_q_TiledBackingStoreTileCreationDelay") {
1212         WebCore::Frame* frame = QWebFramePrivate::core(q->mainFrame());
1213         if (!frame->tiledBackingStore())
1214             return;
1215         int tileCreationDelay = q->property("_q_TiledBackingStoreTileCreationDelay").toInt();
1216         frame->tiledBackingStore()->setTileCreationDelay(static_cast<double>(tileCreationDelay) / 1000.);
1217     } else if (event->propertyName() == "_q_TiledBackingStoreKeepAreaMultiplier") {
1218         WebCore::Frame* frame = QWebFramePrivate::core(q->mainFrame());
1219         if (!frame->tiledBackingStore())
1220             return;
1221         float keepMultiplier;
1222         float coverMultiplier;
1223         frame->tiledBackingStore()->getKeepAndCoverAreaMultipliers(keepMultiplier, coverMultiplier);
1224         QSizeF qSize = q->property("_q_TiledBackingStoreKeepAreaMultiplier").toSizeF();
1225         // setKeepAndCoverAreaMultipliers do not use FloatSize anymore, keep only the height part.
1226         keepMultiplier = qSize.height();
1227         frame->tiledBackingStore()->setKeepAndCoverAreaMultipliers(keepMultiplier, coverMultiplier);
1228     } else if (event->propertyName() == "_q_TiledBackingStoreCoverAreaMultiplier") {
1229         WebCore::Frame* frame = QWebFramePrivate::core(q->mainFrame());
1230         if (!frame->tiledBackingStore())
1231             return;
1232         float keepMultiplier;
1233         float coverMultiplier;
1234         frame->tiledBackingStore()->getKeepAndCoverAreaMultipliers(keepMultiplier, coverMultiplier);
1235         QSizeF qSize = q->property("_q_TiledBackingStoreCoverAreaMultiplier").toSizeF();
1236         // setKeepAndCoverAreaMultipliers do not use FloatSize anymore, keep only the height part.
1237         coverMultiplier = qSize.height();
1238         frame->tiledBackingStore()->setKeepAndCoverAreaMultipliers(keepMultiplier, coverMultiplier);
1239     }
1240 #endif
1241     else if (event->propertyName() == "_q_webInspectorServerPort") {
1242         InspectorServerQt* inspectorServer = InspectorServerQt::server();
1243         inspectorServer->listen(inspectorServerPort());
1244     } else if (event->propertyName() == "_q_deadDecodedDataDeletionInterval") {
1245         double interval = q->property("_q_deadDecodedDataDeletionInterval").toDouble();
1246         memoryCache()->setDeadDecodedDataDeletionInterval(interval);
1247     }
1248 }
1249 #endif
1250
1251 void QWebPagePrivate::shortcutOverrideEvent(QKeyEvent* event)
1252 {
1253     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
1254     WebCore::Editor* editor = frame->editor();
1255     if (editor->canEdit()) {
1256         if (event->modifiers() == Qt::NoModifier
1257             || event->modifiers() == Qt::ShiftModifier
1258             || event->modifiers() == Qt::KeypadModifier) {
1259                 if (event->key() < Qt::Key_Escape) {
1260                     event->accept();
1261                 } else {
1262                     switch (event->key()) {
1263                     case Qt::Key_Return:
1264                     case Qt::Key_Enter:
1265                     case Qt::Key_Delete:
1266                     case Qt::Key_Home:
1267                     case Qt::Key_End:
1268                     case Qt::Key_Backspace:
1269                     case Qt::Key_Left:
1270                     case Qt::Key_Right:
1271                     case Qt::Key_Up:
1272                     case Qt::Key_Down:
1273                     case Qt::Key_Tab:
1274                         event->accept();
1275                     default:
1276                         break;
1277                     }
1278                 }
1279         }
1280 #ifndef QT_NO_SHORTCUT
1281         else if (editorActionForKeyEvent(event) != QWebPage::NoWebAction)
1282             event->accept();
1283 #endif
1284     }
1285 }
1286
1287 bool QWebPagePrivate::handleScrolling(QKeyEvent *ev, Frame *frame)
1288 {
1289     ScrollDirection direction;
1290     ScrollGranularity granularity;
1291
1292 #ifndef QT_NO_SHORTCUT
1293     if (ev == QKeySequence::MoveToNextPage
1294         || (ev->key() == Qt::Key_Space && !(ev->modifiers() & Qt::ShiftModifier))) {
1295         granularity = ScrollByPage;
1296         direction = ScrollDown;
1297     } else if (ev == QKeySequence::MoveToPreviousPage
1298                || ((ev->key() == Qt::Key_Space) && (ev->modifiers() & Qt::ShiftModifier))) {
1299         granularity = ScrollByPage;
1300         direction = ScrollUp;
1301     } else
1302 #endif // QT_NO_SHORTCUT
1303     if ((ev->key() == Qt::Key_Up && ev->modifiers() & Qt::ControlModifier)
1304                || ev->key() == Qt::Key_Home) {
1305         granularity = ScrollByDocument;
1306         direction = ScrollUp;
1307     } else if ((ev->key() == Qt::Key_Down && ev->modifiers() & Qt::ControlModifier)
1308                || ev->key() == Qt::Key_End) {
1309         granularity = ScrollByDocument;
1310         direction = ScrollDown;
1311     } else {
1312         switch (ev->key()) {
1313             case Qt::Key_Up:
1314                 granularity = ScrollByLine;
1315                 direction = ScrollUp;
1316                 break;
1317             case Qt::Key_Down:
1318                 granularity = ScrollByLine;
1319                 direction = ScrollDown;
1320                 break;
1321             case Qt::Key_Left:
1322                 granularity = ScrollByLine;
1323                 direction = ScrollLeft;
1324                 break;
1325             case Qt::Key_Right:
1326                 granularity = ScrollByLine;
1327                 direction = ScrollRight;
1328                 break;
1329             default:
1330                 return false;
1331         }
1332     }
1333
1334     return frame->eventHandler()->scrollRecursively(direction, granularity);
1335 }
1336
1337 void QWebPagePrivate::adjustPointForClicking(QMouseEvent*)
1338 {
1339     notImplemented();
1340 }
1341
1342 #if !defined(QT_NO_GRAPHICSVIEW)
1343 void QWebPagePrivate::adjustPointForClicking(QGraphicsSceneMouseEvent* ev)
1344 {
1345     QtPlatformPlugin platformPlugin;
1346     OwnPtr<QWebTouchModifier> touchModifier = platformPlugin.createTouchModifier();
1347     if (!touchModifier)
1348         return;
1349
1350     unsigned topPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Up);
1351     unsigned rightPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Right);
1352     unsigned bottomPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Down);
1353     unsigned leftPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Left);
1354
1355     touchModifier = nullptr;
1356
1357     if (!topPadding && !rightPadding && !bottomPadding && !leftPadding)
1358         return;
1359
1360     Document* startingDocument = page->mainFrame()->document();
1361     if (!startingDocument)
1362         return;
1363
1364     IntPoint originalPoint(QPointF(ev->pos()).toPoint());
1365     TouchAdjuster touchAdjuster(topPadding, rightPadding, bottomPadding, leftPadding);
1366     IntPoint adjustedPoint = touchAdjuster.findCandidatePointForTouch(originalPoint, startingDocument);
1367     if (adjustedPoint == IntPoint::zero())
1368         return;
1369
1370     ev->setPos(QPointF(adjustedPoint));
1371 }
1372 #endif
1373
1374 bool QWebPagePrivate::touchEvent(QTouchEvent* event)
1375 {
1376 #if ENABLE(TOUCH_EVENTS)
1377     WebCore::Frame* frame = QWebFramePrivate::core(mainFrame.data());
1378     if (!frame->view())
1379         return false;
1380
1381     // Always accept the QTouchEvent so that we'll receive also TouchUpdate and TouchEnd events
1382     event->setAccepted(true);
1383
1384     // Return whether the default action was cancelled in the JS event handler
1385     return frame->eventHandler()->handleTouchEvent(PlatformTouchEvent(event));
1386 #else
1387     event->ignore();
1388     return false;
1389 #endif
1390 }
1391
1392 /*!
1393   This method is used by the input method to query a set of properties of the page
1394   to be able to support complex input method operations as support for surrounding
1395   text and reconversions.
1396
1397   \a property specifies which property is queried.
1398
1399   \sa QWidget::inputMethodEvent(), QInputMethodEvent, QInputContext
1400 */
1401 QVariant QWebPage::inputMethodQuery(Qt::InputMethodQuery property) const
1402 {
1403     Frame* frame = d->page->focusController()->focusedFrame();
1404     if (!frame)
1405         return QVariant();
1406
1407     WebCore::Editor* editor = frame->editor();
1408
1409     RenderObject* renderer = 0;
1410     RenderTextControl* renderTextControl = 0;
1411
1412     if (frame->selection()->rootEditableElement())
1413         renderer = frame->selection()->rootEditableElement()->shadowAncestorNode()->renderer();
1414
1415     if (renderer && renderer->isTextControl())
1416         renderTextControl = toRenderTextControl(renderer);
1417
1418     switch (property) {
1419         case Qt::ImMicroFocus: {
1420             WebCore::FrameView* view = frame->view();
1421             if (view && view->needsLayout()) {
1422                 // We can't access absoluteCaretBounds() while the view needs to layout.
1423                 return QVariant();
1424             }
1425             return QVariant(view->contentsToWindow(frame->selection()->absoluteCaretBounds()));
1426         }
1427         case Qt::ImFont: {
1428             if (renderTextControl) {
1429                 RenderStyle* renderStyle = renderTextControl->style();
1430                 return QVariant(QFont(renderStyle->font().font()));
1431             }
1432             return QVariant(QFont());
1433         }
1434         case Qt::ImCursorPosition: {
1435             if (editor->hasComposition())
1436                 return QVariant(frame->selection()->end().offsetInContainerNode());
1437             return QVariant(frame->selection()->extent().offsetInContainerNode());
1438         }
1439         case Qt::ImSurroundingText: {
1440             if (renderTextControl && renderTextControl->textFormControlElement()) {
1441                 QString text = renderTextControl->textFormControlElement()->value();
1442                 RefPtr<Range> range = editor->compositionRange();
1443                 if (range)
1444                     text.remove(range->startPosition().offsetInContainerNode(), TextIterator::rangeLength(range.get()));
1445                 return QVariant(text);
1446             }
1447             return QVariant();
1448         }
1449         case Qt::ImCurrentSelection: {
1450             if (!editor->hasComposition() && renderTextControl && renderTextControl->textFormControlElement()) {
1451                 int start = frame->selection()->start().offsetInContainerNode();
1452                 int end = frame->selection()->end().offsetInContainerNode();
1453                 if (end > start)
1454                     return QVariant(QString(renderTextControl->textFormControlElement()->value()).mid(start, end - start));
1455             }
1456             return QVariant();
1457
1458         }
1459         case Qt::ImAnchorPosition: {
1460             if (editor->hasComposition())
1461                 return QVariant(frame->selection()->start().offsetInContainerNode());
1462             return QVariant(frame->selection()->base().offsetInContainerNode());
1463         }
1464         case Qt::ImMaximumTextLength: {
1465             if (frame->selection()->isContentEditable()) {
1466                 if (frame->document() && frame->document()->focusedNode()) {
1467                     if (frame->document()->focusedNode()->hasTagName(HTMLNames::inputTag)) {
1468                         HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(frame->document()->focusedNode());
1469                         return QVariant(inputElement->maxLength());
1470                     }
1471                 }
1472                 return QVariant(HTMLInputElement::maximumLength);
1473             }
1474             return QVariant(0);
1475         }
1476         default:
1477             return QVariant();
1478     }
1479 }
1480
1481 /*!
1482     \internal
1483 */
1484 void QWebPagePrivate::setInspector(QWebInspector* insp)
1485 {
1486     if (inspector)
1487         inspector->d->setFrontend(0);
1488
1489     if (inspectorIsInternalOnly) {
1490         QWebInspector* inspToDelete = inspector;
1491         inspector = 0;
1492         inspectorIsInternalOnly = false;
1493         delete inspToDelete;    // Delete after to prevent infinite recursion
1494     }
1495
1496     inspector = insp;
1497
1498     // Give inspector frontend web view if previously created
1499     if (inspector && inspectorFrontend)
1500         inspector->d->setFrontend(inspectorFrontend);
1501 }
1502
1503 /*!
1504     \internal
1505     Returns the inspector and creates it if it wasn't created yet.
1506     The instance created here will not be available through QWebPage's API.
1507 */
1508 QWebInspector* QWebPagePrivate::getOrCreateInspector()
1509 {
1510 #if ENABLE(INSPECTOR)
1511     if (!inspector) {
1512         QWebInspector* insp = new QWebInspector;
1513         insp->setPage(q);
1514         inspectorIsInternalOnly = true;
1515
1516         Q_ASSERT(inspector); // Associated through QWebInspector::setPage(q)
1517     }
1518 #endif
1519     return inspector;
1520 }
1521
1522 /*! \internal */
1523 InspectorController* QWebPagePrivate::inspectorController()
1524 {
1525 #if ENABLE(INSPECTOR)
1526     return page->inspectorController();
1527 #else
1528     return 0;
1529 #endif
1530 }
1531
1532 quint16 QWebPagePrivate::inspectorServerPort()
1533 {
1534 #if ENABLE(INSPECTOR) && !defined(QT_NO_PROPERTIES)
1535     if (q && q->property("_q_webInspectorServerPort").isValid())
1536         return q->property("_q_webInspectorServerPort").toInt();
1537 #endif
1538     return 0;
1539 }
1540
1541 static bool hasMouseListener(Element* element)
1542 {
1543     ASSERT(element);
1544     return element->hasEventListeners(eventNames().clickEvent)
1545         || element->hasEventListeners(eventNames().mousedownEvent)
1546         || element->hasEventListeners(eventNames().mouseupEvent);
1547 }
1548
1549 static bool isClickableElement(Element* element, RefPtr<NodeList> list)
1550 {
1551     ASSERT(element);
1552     bool isClickable = hasMouseListener(element);
1553     if (!isClickable && list) {
1554         Element* parent = element->parentElement();
1555         unsigned count = list->length();
1556         for (unsigned i = 0; i < count && parent; i++) {
1557             if (list->item(i) != parent)
1558                 continue;
1559
1560             isClickable = hasMouseListener(parent);
1561             if (isClickable)
1562                 break;
1563
1564             parent = parent->parentElement();
1565         }
1566     }
1567
1568     ExceptionCode ec = 0;
1569     return isClickable
1570         || element->webkitMatchesSelector("a,*:link,*:visited,*[role=button],button,input,select,label", ec)
1571         || computedStyle(element)->getPropertyValue(cssPropertyID("cursor")) == "pointer";
1572 }
1573
1574 static bool isValidFrameOwner(Element* element)
1575 {
1576     ASSERT(element);
1577     return element->isFrameOwnerElement() && static_cast<HTMLFrameOwnerElement*>(element)->contentFrame();
1578 }
1579
1580 static Element* nodeToElement(Node* node)
1581 {
1582     if (node && node->isElementNode())
1583         return static_cast<Element*>(node);
1584     return 0;
1585 }
1586
1587 QWebPagePrivate::TouchAdjuster::TouchAdjuster(unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
1588     : m_topPadding(topPadding)
1589     , m_rightPadding(rightPadding)
1590     , m_bottomPadding(bottomPadding)
1591     , m_leftPadding(leftPadding)
1592 {
1593 }
1594
1595 IntPoint QWebPagePrivate::TouchAdjuster::findCandidatePointForTouch(const IntPoint& touchPoint, Document* document) const
1596 {
1597     if (!document)
1598         return IntPoint();
1599
1600     int x = touchPoint.x();
1601     int y = touchPoint.y();
1602
1603     RefPtr<NodeList> intersectedNodes = document->nodesFromRect(x, y, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding, false);
1604     if (!intersectedNodes)
1605         return IntPoint();
1606
1607     Element* closestClickableElement = 0;
1608     IntRect largestIntersectionRect;
1609     FrameView* view = document->frame()->view();
1610
1611     // Touch rect in contents coordinates.
1612     IntRect touchRect(HitTestResult::rectForPoint(view->windowToContents(IntPoint(x, y)), m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding));
1613
1614     // Iterate over the list of nodes hit looking for the one whose bounding area
1615     // has largest intersection with the touch area (point + padding).
1616     for (unsigned i = 0; i < intersectedNodes->length(); i++) {
1617         Node* currentNode = intersectedNodes->item(i);
1618
1619         Element* currentElement = nodeToElement(currentNode);
1620         if (!currentElement || (!isClickableElement(currentElement, 0) && !isValidFrameOwner(currentElement)))
1621             continue;
1622
1623         IntRect currentElementBoundingRect = currentElement->getRect();
1624         currentElementBoundingRect.intersect(touchRect);
1625
1626         if (currentElementBoundingRect.isEmpty())
1627             continue;
1628
1629         int currentIntersectionRectArea = currentElementBoundingRect.width() * currentElementBoundingRect.height();
1630         int largestIntersectionRectArea = largestIntersectionRect.width() * largestIntersectionRect.height();
1631         if (currentIntersectionRectArea > largestIntersectionRectArea) {
1632             closestClickableElement = currentElement;
1633             largestIntersectionRect = currentElementBoundingRect;
1634         }
1635     }
1636
1637     if (largestIntersectionRect.isEmpty())
1638         return IntPoint();
1639
1640     // Handle the case when user taps a inner frame. It is done in three steps:
1641     // 1) Transform the original touch point to the inner document coordinates;
1642     // 1) Call nodesFromRect for the inner document in case;
1643     // 3) Re-add the inner frame offset (location) before passing the new clicking
1644     //    position to WebCore.
1645     if (closestClickableElement->isFrameOwnerElement()) {
1646         // Adjust client coordinates' origin to be top left of inner frame viewport.
1647         PassRefPtr<ClientRect> rect = closestClickableElement->getBoundingClientRect();
1648         IntPoint newTouchPoint = touchPoint;
1649         IntSize offset =  IntSize(rect->left(), rect->top());
1650         newTouchPoint -= offset;
1651
1652         HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(closestClickableElement);
1653         Document* childDocument = owner->contentFrame()->document();
1654         return findCandidatePointForTouch(newTouchPoint, childDocument);
1655     }
1656     return view->contentsToWindow(largestIntersectionRect).center();
1657 }
1658
1659 /*!
1660    \enum QWebPage::FindFlag
1661
1662    This enum describes the options available to the findText() function. The options
1663    can be OR-ed together from the following list:
1664
1665    \value FindBackward Searches backwards instead of forwards.
1666    \value FindCaseSensitively By default findText() works case insensitive. Specifying this option
1667    changes the behaviour to a case sensitive find operation.
1668    \value FindWrapsAroundDocument Makes findText() restart from the beginning of the document if the end
1669    was reached and the text was not found.
1670    \value HighlightAllOccurrences Highlights all existing occurrences of a specific string.
1671 */
1672
1673 /*!
1674     \enum QWebPage::LinkDelegationPolicy
1675
1676     This enum defines the delegation policies a webpage can have when activating links and emitting
1677     the linkClicked() signal.
1678
1679     \value DontDelegateLinks No links are delegated. Instead, QWebPage tries to handle them all.
1680     \value DelegateExternalLinks When activating links that point to documents not stored on the
1681     local filesystem or an equivalent - such as the Qt resource system - then linkClicked() is emitted.
1682     \value DelegateAllLinks Whenever a link is activated the linkClicked() signal is emitted.
1683
1684     \sa QWebPage::linkDelegationPolicy
1685 */
1686
1687 /*!
1688     \enum QWebPage::NavigationType
1689
1690     This enum describes the types of navigation available when browsing through hyperlinked
1691     documents.
1692
1693     \value NavigationTypeLinkClicked The user clicked on a link or pressed return on a focused link.
1694     \value NavigationTypeFormSubmitted The user activated a submit button for an HTML form.
1695     \value NavigationTypeBackOrForward Navigation to a previously shown document in the back or forward history is requested.
1696     \value NavigationTypeReload The user activated the reload action.
1697     \value NavigationTypeFormResubmitted An HTML form was submitted a second time.
1698     \value NavigationTypeOther A navigation to another document using a method not listed above.
1699
1700     \sa acceptNavigationRequest()
1701 */
1702
1703 /*!
1704     \enum QWebPage::WebAction
1705
1706     This enum describes the types of action which can be performed on the web page.
1707
1708     Actions only have an effect when they are applicable. The availability of
1709     actions can be be determined by checking \l{QAction::}{isEnabled()} on the
1710     action returned by action().
1711
1712     One method of enabling the text editing, cursor movement, and text selection actions
1713     is by setting \l contentEditable to true.
1714
1715     \value NoWebAction No action is triggered.
1716     \value OpenLink Open the current link.
1717     \value OpenLinkInNewWindow Open the current link in a new window.
1718     \value OpenFrameInNewWindow Replicate the current frame in a new window.
1719     \value DownloadLinkToDisk Download the current link to the disk.
1720     \value CopyLinkToClipboard Copy the current link to the clipboard.
1721     \value OpenImageInNewWindow Open the highlighted image in a new window.
1722     \value DownloadImageToDisk Download the highlighted image to the disk.
1723     \value CopyImageToClipboard Copy the highlighted image to the clipboard.
1724     \value CopyImageUrlToClipboard Copy the highlighted image's URL to the clipboard.
1725     \value Back Navigate back in the history of navigated links.
1726     \value Forward Navigate forward in the history of navigated links.
1727     \value Stop Stop loading the current page.
1728     \value StopScheduledPageRefresh Stop all pending page refresh/redirect requests.
1729     \value Reload Reload the current page.
1730     \value ReloadAndBypassCache Reload the current page, but do not use any local cache. (Added in Qt 4.6)
1731     \value Cut Cut the content currently selected into the clipboard.
1732     \value Copy Copy the content currently selected into the clipboard.
1733     \value Paste Paste content from the clipboard.
1734     \value Undo Undo the last editing action.
1735     \value Redo Redo the last editing action.
1736     \value MoveToNextChar Move the cursor to the next character.
1737     \value MoveToPreviousChar Move the cursor to the previous character.
1738     \value MoveToNextWord Move the cursor to the next word.
1739     \value MoveToPreviousWord Move the cursor to the previous word.
1740     \value MoveToNextLine Move the cursor to the next line.
1741     \value MoveToPreviousLine Move the cursor to the previous line.
1742     \value MoveToStartOfLine Move the cursor to the start of the line.
1743     \value MoveToEndOfLine Move the cursor to the end of the line.
1744     \value MoveToStartOfBlock Move the cursor to the start of the block.
1745     \value MoveToEndOfBlock Move the cursor to the end of the block.
1746     \value MoveToStartOfDocument Move the cursor to the start of the document.
1747     \value MoveToEndOfDocument Move the cursor to the end of the document.
1748     \value SelectNextChar Select to the next character.
1749     \value SelectPreviousChar Select to the previous character.
1750     \value SelectNextWord Select to the next word.
1751     \value SelectPreviousWord Select to the previous word.
1752     \value SelectNextLine Select to the next line.
1753     \value SelectPreviousLine Select to the previous line.
1754     \value SelectStartOfLine Select to the start of the line.
1755     \value SelectEndOfLine Select to the end of the line.
1756     \value SelectStartOfBlock Select to the start of the block.
1757     \value SelectEndOfBlock Select to the end of the block.
1758     \value SelectStartOfDocument Select to the start of the document.
1759     \value SelectEndOfDocument Select to the end of the document.
1760     \value DeleteStartOfWord Delete to the start of the word.
1761     \value DeleteEndOfWord Delete to the end of the word.
1762     \value SetTextDirectionDefault Set the text direction to the default direction.
1763     \value SetTextDirectionLeftToRight Set the text direction to left-to-right.
1764     \value SetTextDirectionRightToLeft Set the text direction to right-to-left.
1765     \value ToggleBold Toggle the formatting between bold and normal weight.
1766     \value ToggleItalic Toggle the formatting between italic and normal style.
1767     \value ToggleUnderline Toggle underlining.
1768     \value InspectElement Show the Web Inspector with the currently highlighted HTML element.
1769     \value InsertParagraphSeparator Insert a new paragraph.
1770     \value InsertLineSeparator Insert a new line.
1771     \value SelectAll Selects all content.
1772     \value PasteAndMatchStyle Paste content from the clipboard with current style.
1773     \value RemoveFormat Removes formatting and style.
1774     \value ToggleStrikethrough Toggle the formatting between strikethrough and normal style.
1775     \value ToggleSubscript Toggle the formatting between subscript and baseline.
1776     \value ToggleSuperscript Toggle the formatting between supercript and baseline.
1777     \value InsertUnorderedList Toggles the selection between an ordered list and a normal block.
1778     \value InsertOrderedList Toggles the selection between an ordered list and a normal block.
1779     \value Indent Increases the indentation of the currently selected format block by one increment.
1780     \value Outdent Decreases the indentation of the currently selected format block by one increment.
1781     \value AlignCenter Applies center alignment to content.
1782     \value AlignJustified Applies full justification to content.
1783     \value AlignLeft Applies left justification to content.
1784     \value AlignRight Applies right justification to content.
1785
1786
1787     \omitvalue WebActionCount
1788
1789 */
1790
1791 /*!
1792     \enum QWebPage::WebWindowType
1793
1794     This enum describes the types of window that can be created by the createWindow() function.
1795
1796     \value WebBrowserWindow The window is a regular web browser window.
1797     \value WebModalDialog The window acts as modal dialog.
1798 */
1799
1800
1801 /*!
1802     \class QWebPage::ViewportAttributes
1803     \since 4.7
1804     \brief The QWebPage::ViewportAttributes class describes hints that can be applied to a viewport.
1805
1806     QWebPage::ViewportAttributes provides a description of a viewport, such as viewport geometry,
1807     initial scale factor with limits, plus information about whether a user should be able
1808     to scale the contents in the viewport or not, ie. by zooming.
1809
1810     ViewportAttributes can be set by a web author using the viewport meta tag extension, documented
1811     at \l{http://developer.apple.com/safari/library/documentation/appleapplications/reference/safariwebcontent/usingtheviewport/usingtheviewport.html}{Safari Reference Library: Using the Viewport Meta Tag}.
1812
1813     All values might not be set, as such when dealing with the hints, the developer needs to
1814     check whether the values are valid. Negative values denote an invalid qreal value.
1815
1816     \inmodule QtWebKit
1817 */
1818
1819 /*!
1820     Constructs an empty QWebPage::ViewportAttributes.
1821 */
1822 QWebPage::ViewportAttributes::ViewportAttributes()
1823     : d(0)
1824     , m_initialScaleFactor(-1.0)
1825     , m_minimumScaleFactor(-1.0)
1826     , m_maximumScaleFactor(-1.0)
1827     , m_devicePixelRatio(-1.0)
1828     , m_isUserScalable(true)
1829     , m_isValid(false)
1830 {
1831
1832 }
1833
1834 /*!
1835     Constructs a QWebPage::ViewportAttributes which is a copy from \a other .
1836 */
1837 QWebPage::ViewportAttributes::ViewportAttributes(const QWebPage::ViewportAttributes& other)
1838     : d(other.d)
1839     , m_initialScaleFactor(other.m_initialScaleFactor)
1840     , m_minimumScaleFactor(other.m_minimumScaleFactor)
1841     , m_maximumScaleFactor(other.m_maximumScaleFactor)
1842     , m_devicePixelRatio(other.m_devicePixelRatio)
1843     , m_isUserScalable(other.m_isUserScalable)
1844     , m_isValid(other.m_isValid)
1845     , m_size(other.m_size)
1846 {
1847
1848 }
1849
1850 /*!
1851     Destroys the QWebPage::ViewportAttributes.
1852 */
1853 QWebPage::ViewportAttributes::~ViewportAttributes()
1854 {
1855
1856 }
1857
1858 /*!
1859     Assigns the given QWebPage::ViewportAttributes to this viewport hints and returns a
1860     reference to this.
1861 */
1862 QWebPage::ViewportAttributes& QWebPage::ViewportAttributes::operator=(const QWebPage::ViewportAttributes& other)
1863 {
1864     if (this != &other) {
1865         d = other.d;
1866         m_initialScaleFactor = other.m_initialScaleFactor;
1867         m_minimumScaleFactor = other.m_minimumScaleFactor;
1868         m_maximumScaleFactor = other.m_maximumScaleFactor;
1869         m_isUserScalable = other.m_isUserScalable;
1870         m_isValid = other.m_isValid;
1871         m_size = other.m_size;
1872     }
1873
1874     return *this;
1875 }
1876
1877 /*! \fn inline bool QWebPage::ViewportAttributes::isValid() const
1878     Returns whether this is a valid ViewportAttributes or not.
1879
1880     An invalid ViewportAttributes will have an empty QSize, negative values for scale factors and
1881     true for the boolean isUserScalable.
1882 */
1883
1884 /*! \fn inline QSize QWebPage::ViewportAttributes::size() const
1885     Returns the size of the viewport.
1886 */
1887
1888 /*! \fn inline qreal QWebPage::ViewportAttributes::initialScaleFactor() const
1889     Returns the initial scale of the viewport as a multiplier.
1890 */
1891
1892 /*! \fn inline qreal QWebPage::ViewportAttributes::minimumScaleFactor() const
1893     Returns the minimum scale value of the viewport as a multiplier.
1894 */
1895
1896 /*! \fn inline qreal QWebPage::ViewportAttributes::maximumScaleFactor() const
1897     Returns the maximum scale value of the viewport as a multiplier.
1898 */
1899
1900 /*! \fn inline bool QWebPage::ViewportAttributes::isUserScalable() const
1901     Determines whether or not the scale can be modified by the user.
1902 */
1903
1904
1905 /*!
1906     \class QWebPage
1907     \since 4.4
1908     \brief The QWebPage class provides an object to view and edit web documents.
1909
1910     \inmodule QtWebKit
1911
1912     QWebPage holds a main frame responsible for web content, settings, the history
1913     of navigated links and actions. This class can be used, together with QWebFrame,
1914     to provide functionality like QWebView in a widget-less environment.
1915
1916     QWebPage's API is very similar to QWebView, as you are still provided with
1917     common functions like action() (known as
1918     \l{QWebView::pageAction()}{pageAction}() in QWebView), triggerAction(),
1919     findText() and settings(). More QWebView-like functions can be found in the
1920     main frame of QWebPage, obtained via the mainFrame() function. For example,
1921     the \l{QWebFrame::load()}{load}(), \l{QWebFrame::setUrl()}{setUrl}() and
1922     \l{QWebFrame::setHtml()}{setHtml}() functions for QWebPage can be accessed
1923     using QWebFrame.
1924
1925     The loadStarted() signal is emitted when the page begins to load.The
1926     loadProgress() signal, on the other hand, is emitted whenever an element
1927     of the web page completes loading, such as an embedded image, a script,
1928     etc. Finally, the loadFinished() signal is emitted when the page contents
1929     are loaded completely, independent of script execution or page rendering.
1930     Its argument, either true or false, indicates whether or not the load
1931     operation succeeded.
1932
1933     \section1 Using QWebPage in a Widget-less Environment
1934
1935     Before you begin painting a QWebPage object, you need to set the size of
1936     the viewport by calling setViewportSize(). Then, you invoke the main
1937     frame's render function (QWebFrame::render()). An example of this
1938     is shown in the code snippet below.
1939
1940     Suppose we have a \c Thumbnail class as follows:
1941
1942     \snippet webkitsnippets/webpage/main.cpp 0
1943
1944     The \c Thumbnail's constructor takes in a \a url. We connect our QWebPage
1945     object's \l{QWebPage::}{loadFinished()} signal to our private slot,
1946     \c render().
1947
1948     \snippet webkitsnippets/webpage/main.cpp 1
1949
1950     The \c render() function shows how we can paint a thumbnail using a
1951     QWebPage object.
1952
1953     \snippet webkitsnippets/webpage/main.cpp 2
1954
1955     We begin by setting the \l{QWebPage::viewportSize()}{viewportSize} and
1956     then we instantiate a QImage object, \c image, with the same size as our
1957     \l{QWebPage::viewportSize()}{viewportSize}. This image is then sent
1958     as a parameter to \c painter. Next, we render the contents of the main
1959     frame and its subframes into \c painter. Finally, we save the scaled image.
1960
1961     \sa QWebFrame
1962 */
1963
1964 /*!
1965     Constructs an empty QWebPage with parent \a parent.
1966 */
1967 QWebPage::QWebPage(QObject *parent)
1968     : QObject(parent)
1969     , d(new QWebPagePrivate(this))
1970 {
1971     setView(qobject_cast<QWidget*>(parent));
1972
1973     connect(this, SIGNAL(loadProgress(int)), this, SLOT(_q_onLoadProgressChanged(int)));
1974 #ifndef NDEBUG
1975     connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), this, SLOT(_q_cleanupLeakMessages()));
1976 #endif
1977 }
1978
1979 /*!
1980     Destroys the web page.
1981 */
1982 QWebPage::~QWebPage()
1983 {
1984     d->createMainFrame();
1985     FrameLoader* loader = d->mainFrame.data()->d->frame->loader();
1986     if (loader)
1987         loader->detachFromParent();
1988     delete d;
1989 }
1990
1991 /*!
1992     Returns the main frame of the page.
1993
1994     The main frame provides access to the hierarchy of sub-frames and is also needed if you
1995     want to explicitly render a web page into a given painter.
1996
1997     \sa currentFrame()
1998 */
1999 QWebFrame *QWebPage::mainFrame() const
2000 {
2001     d->createMainFrame();
2002     return d->mainFrame.data();
2003 }
2004
2005 /*!
2006     Returns the frame currently active.
2007
2008     \sa mainFrame(), frameCreated()
2009 */
2010 QWebFrame *QWebPage::currentFrame() const
2011 {
2012     d->createMainFrame();
2013     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
2014     return qobject_cast<QWebFrame*>(frame->loader()->networkingContext()->originatingObject());
2015 }
2016
2017
2018 /*!
2019     \since 4.6
2020
2021     Returns the frame at the given point \a pos, or 0 if there is no frame at
2022     that position.
2023
2024     \sa mainFrame(), currentFrame()
2025 */
2026 QWebFrame* QWebPage::frameAt(const QPoint& pos) const
2027 {
2028     QWebFrame* webFrame = mainFrame();
2029     if (!webFrame->geometry().contains(pos))
2030         return 0;
2031     QWebHitTestResult hitTestResult = webFrame->hitTestContent(pos);
2032     return hitTestResult.frame();
2033 }
2034
2035 /*!
2036     Returns a pointer to the view's history of navigated web pages.
2037 */
2038 QWebHistory *QWebPage::history() const
2039 {
2040     d->createMainFrame();
2041     return &d->history;
2042 }
2043
2044 /*!
2045     Sets the \a view that is associated with the web page.
2046
2047     \sa view()
2048 */
2049 void QWebPage::setView(QWidget* view)
2050 {
2051     if (this->view() == view)
2052         return;
2053
2054     d->view = view;
2055     setViewportSize(view ? view->size() : QSize(0, 0));
2056
2057     // If we have no client, we install a special client delegating
2058     // the responsibility to the QWidget. This is the code path
2059     // handling a.o. the "legacy" QWebView.
2060     //
2061     // If such a special delegate already exist, we substitute the view.
2062
2063     if (d->client) {
2064         if (d->client->isQWidgetClient())
2065             static_cast<PageClientQWidget*>(d->client.get())->view = view;
2066         return;
2067     }
2068
2069     if (view)
2070         d->client = adoptPtr(new PageClientQWidget(view, this));
2071 }
2072
2073 /*!
2074     Returns the view widget that is associated with the web page.
2075
2076     \sa setView()
2077 */
2078 QWidget *QWebPage::view() const
2079 {
2080     return d->view.data();
2081 }
2082
2083 /*!
2084     This function is called whenever a JavaScript program tries to print a \a message to the web browser's console.
2085
2086     For example in case of evaluation errors the source URL may be provided in \a sourceID as well as the \a lineNumber.
2087
2088     The default implementation prints nothing.
2089 */
2090 void QWebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID)
2091 {
2092     Q_UNUSED(sourceID)
2093
2094     // Catch plugin logDestroy message for LayoutTests/plugins/open-and-close-window-with-plugin.html
2095     // At this point DRT's WebPage has already been destroyed
2096     if (QWebPagePrivate::drtRun) {
2097         if (message == QLatin1String("PLUGIN: NPP_Destroy"))
2098             fprintf (stdout, "CONSOLE MESSAGE: line %d: %s\n", lineNumber, message.toUtf8().constData());
2099     }
2100 }
2101
2102 /*!
2103     This function is called whenever a JavaScript program running inside \a frame calls the alert() function with
2104     the message \a msg.
2105
2106     The default implementation shows the message, \a msg, with QMessageBox::information.
2107 */
2108 void QWebPage::javaScriptAlert(QWebFrame *frame, const QString& msg)
2109 {
2110     Q_UNUSED(frame)
2111 #ifndef QT_NO_MESSAGEBOX
2112     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2113     QMessageBox::information(parent, tr("JavaScript Alert - %1").arg(mainFrame()->url().host()), Qt::escape(msg), QMessageBox::Ok);
2114 #endif
2115 }
2116
2117 /*!
2118     This function is called whenever a JavaScript program running inside \a frame calls the confirm() function
2119     with the message, \a msg. Returns true if the user confirms the message; otherwise returns false.
2120
2121     The default implementation executes the query using QMessageBox::information with QMessageBox::Yes and QMessageBox::No buttons.
2122 */
2123 bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg)
2124 {
2125     Q_UNUSED(frame)
2126 #ifdef QT_NO_MESSAGEBOX
2127     return true;
2128 #else
2129     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2130     return QMessageBox::Yes == QMessageBox::information(parent, tr("JavaScript Confirm - %1").arg(mainFrame()->url().host()), Qt::escape(msg), QMessageBox::Yes, QMessageBox::No);
2131 #endif
2132 }
2133
2134 /*!
2135     This function is called whenever a JavaScript program running inside \a frame tries to prompt the user for input.
2136     The program may provide an optional message, \a msg, as well as a default value for the input in \a defaultValue.
2137
2138     If the prompt was cancelled by the user the implementation should return false; otherwise the
2139     result should be written to \a result and true should be returned. If the prompt was not cancelled by the
2140     user, the implementation should return true and the result string must not be null.
2141
2142     The default implementation uses QInputDialog::getText().
2143 */
2144 bool QWebPage::javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result)
2145 {
2146     Q_UNUSED(frame)
2147     bool ok = false;
2148 #ifndef QT_NO_INPUTDIALOG
2149     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2150     QString x = QInputDialog::getText(parent, tr("JavaScript Prompt - %1").arg(mainFrame()->url().host()), Qt::escape(msg), QLineEdit::Normal, defaultValue, &ok);
2151     if (ok && result)
2152         *result = x;
2153 #endif
2154     return ok;
2155 }
2156
2157 /*!
2158     \fn bool QWebPage::shouldInterruptJavaScript()
2159     \since 4.6
2160     This function is called when a JavaScript program is running for a long period of time.
2161
2162     If the user wanted to stop the JavaScript the implementation should return true; otherwise false.
2163
2164     The default implementation executes the query using QMessageBox::information with QMessageBox::Yes and QMessageBox::No buttons.
2165
2166     \warning Because of binary compatibility constraints, this function is not virtual. If you want to
2167     provide your own implementation in a QWebPage subclass, reimplement the shouldInterruptJavaScript()
2168     slot in your subclass instead. QtWebKit will dynamically detect the slot and call it.
2169 */
2170 bool QWebPage::shouldInterruptJavaScript()
2171 {
2172 #ifdef QT_NO_MESSAGEBOX
2173     return false;
2174 #else
2175     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
2176     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);
2177 #endif
2178 }
2179
2180 void QWebPage::setFeaturePermission(QWebFrame* frame, Feature feature, PermissionPolicy policy)
2181 {
2182     switch (feature) {
2183     case Notifications:
2184 #if ENABLE(NOTIFICATIONS)
2185         if (policy == PermissionGrantedByUser)
2186             NotificationPresenterClientQt::notificationPresenter()->allowNotificationForFrame(frame->d->frame);
2187 #endif
2188         break;
2189     case Geolocation:
2190 #if ENABLE(GEOLOCATION)
2191         GeolocationPermissionClientQt::geolocationPermissionClient()->setPermission(frame, policy);
2192 #endif
2193         break;
2194
2195     default:
2196         break;
2197     }
2198 }
2199
2200 /*!
2201     This function is called whenever WebKit wants to create a new window of the given \a type, for
2202     example when a JavaScript program requests to open a document in a new window.
2203
2204     If the new window can be created, the new window's QWebPage is returned; otherwise a null pointer is returned.
2205
2206     If the view associated with the web page is a QWebView object, then the default implementation forwards
2207     the request to QWebView's createWindow() function; otherwise it returns a null pointer.
2208
2209     If \a type is WebModalDialog, the application must call setWindowModality(Qt::ApplicationModal) on the new window.
2210
2211     \note In the cases when the window creation is being triggered by JavaScript, apart from
2212     reimplementing this method application must also set the JavaScriptCanOpenWindows attribute
2213     of QWebSettings to true in order for it to get called.
2214
2215     \sa acceptNavigationRequest(), QWebView::createWindow()
2216 */
2217 QWebPage *QWebPage::createWindow(WebWindowType type)
2218 {
2219     QWebView *webView = qobject_cast<QWebView*>(view());
2220     if (webView) {
2221         QWebView *newView = webView->createWindow(type);
2222         if (newView)
2223             return newView->page();
2224     }
2225     return 0;
2226 }
2227
2228 /*!
2229     This function is called whenever WebKit encounters a HTML object element with type "application/x-qt-plugin". It is
2230     called regardless of the value of QWebSettings::PluginsEnabled. The \a classid, \a url, \a paramNames and \a paramValues
2231     correspond to the HTML object element attributes and child elements to configure the embeddable object.
2232 */
2233 QObject *QWebPage::createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
2234 {
2235     Q_UNUSED(classid)
2236     Q_UNUSED(url)
2237     Q_UNUSED(paramNames)
2238     Q_UNUSED(paramValues)
2239     return 0;
2240 }
2241
2242 static void extractContentTypeFromHash(const HashSet<String>& types, QStringList* list)
2243 {
2244     if (!list)
2245         return;
2246
2247     HashSet<String>::const_iterator endIt = types.end();
2248     for (HashSet<String>::const_iterator it = types.begin(); it != endIt; ++it)
2249         *list << *it;
2250 }
2251
2252 static void extractContentTypeFromPluginVector(const Vector<PluginPackage*>& plugins, QStringList* list)
2253 {
2254     if (!list)
2255         return;
2256
2257     for (unsigned int i = 0; i < plugins.size(); ++i) {
2258         MIMEToDescriptionsMap::const_iterator map_it = plugins[i]->mimeToDescriptions().begin();
2259         MIMEToDescriptionsMap::const_iterator map_end = plugins[i]->mimeToDescriptions().end();
2260         for (; map_it != map_end; ++map_it)
2261             *list << map_it->first;
2262     }
2263 }
2264
2265 /*!
2266  *  Returns the list of all content types supported by QWebPage.
2267  */
2268 QStringList QWebPage::supportedContentTypes() const
2269 {
2270     QStringList mimeTypes;
2271
2272     extractContentTypeFromHash(MIMETypeRegistry::getSupportedImageMIMETypes(), &mimeTypes);
2273     extractContentTypeFromHash(MIMETypeRegistry::getSupportedNonImageMIMETypes(), &mimeTypes);
2274     if (d->page->settings() && d->page->settings()->arePluginsEnabled())
2275         extractContentTypeFromPluginVector(PluginDatabase::installedPlugins()->plugins(), &mimeTypes);
2276
2277     return mimeTypes;
2278 }
2279
2280 /*!
2281  *  Returns true if QWebPage can handle the given \a mimeType; otherwise, returns false.
2282  */
2283 bool QWebPage::supportsContentType(const QString& mimeType) const
2284 {
2285     const String type = mimeType.toLower();
2286     if (MIMETypeRegistry::isSupportedImageMIMEType(type))
2287         return true;
2288
2289     if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
2290         return true;
2291
2292     if (d->page->settings() && d->page->settings()->arePluginsEnabled()
2293         && PluginDatabase::installedPlugins()->isMIMETypeRegistered(type))
2294         return true;
2295
2296     return false;
2297 }
2298
2299 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
2300 {
2301     return WebCore::FrameLoadRequest(frame->document()->securityOrigin(),
2302         WebCore::ResourceRequest(url, frame->loader()->outgoingReferrer()));
2303 }
2304
2305 static void openNewWindow(const QUrl& url, WebCore::Frame* frame)
2306 {
2307     if (Page* oldPage = frame->page()) {
2308         WindowFeatures features;
2309         NavigationAction action;
2310         FrameLoadRequest request = frameLoadRequest(url, frame);
2311         if (Page* newPage = oldPage->chrome()->createWindow(frame, request, features, action)) {
2312             newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer);
2313             newPage->chrome()->show();
2314         }
2315     }
2316 }
2317
2318 static void collectChildFrames(QWebFrame* frame, QList<QWebFrame*>& list)
2319 {
2320     list << frame->childFrames();
2321     QListIterator<QWebFrame*> it(frame->childFrames());
2322     while (it.hasNext()) {
2323         collectChildFrames(it.next(), list);
2324     }
2325 }
2326
2327 /*!
2328     This function can be called to trigger the specified \a action.
2329     It is also called by QtWebKit if the user triggers the action, for example
2330     through a context menu item.
2331
2332     If \a action is a checkable action then \a checked specified whether the action
2333     is toggled or not.
2334
2335     \sa action()
2336 */
2337 void QWebPage::triggerAction(WebAction action, bool)
2338 {
2339     WebCore::Frame *frame = d->page->focusController()->focusedOrMainFrame();
2340     if (!frame)
2341         return;
2342     WebCore::Editor *editor = frame->editor();
2343     const char *command = 0;
2344
2345     switch (action) {
2346         case OpenLink:
2347             if (QWebFrame *targetFrame = d->hitTestResult.linkTargetFrame()) {
2348                 WTF::RefPtr<WebCore::Frame> wcFrame = targetFrame->d->frame;
2349                 targetFrame->d->frame->loader()->loadFrameRequest(frameLoadRequest(d->hitTestResult.linkUrl(), wcFrame.get()),
2350                                                                   /*lockHistory*/ false, /*lockBackForwardList*/ false, /*event*/ 0,
2351                                                                   /*FormState*/ 0, SendReferrer);
2352                 break;
2353             }
2354             // fall through
2355         case OpenLinkInNewWindow:
2356             openNewWindow(d->hitTestResult.linkUrl(), frame);
2357             break;
2358         case OpenFrameInNewWindow: {
2359             KURL url = frame->loader()->documentLoader()->unreachableURL();
2360             if (url.isEmpty())
2361                 url = frame->loader()->documentLoader()->url();
2362             openNewWindow(url, frame);
2363             break;
2364         }
2365         case CopyLinkToClipboard: {
2366 #if defined(Q_WS_X11)
2367             bool oldSelectionMode = Pasteboard::generalPasteboard()->isSelectionMode();
2368             Pasteboard::generalPasteboard()->setSelectionMode(true);
2369             editor->copyURL(d->hitTestResult.linkUrl(), d->hitTestResult.linkText());
2370             Pasteboard::generalPasteboard()->setSelectionMode(oldSelectionMode);
2371 #endif
2372             editor->copyURL(d->hitTestResult.linkUrl(), d->hitTestResult.linkText());
2373             break;
2374         }
2375         case OpenImageInNewWindow:
2376             openNewWindow(d->hitTestResult.imageUrl(), frame);
2377             break;
2378         case DownloadImageToDisk:
2379             frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.imageUrl(), frame->loader()->outgoingReferrer()));
2380             break;
2381         case DownloadLinkToDisk:
2382             frame->loader()->client()->startDownload(WebCore::ResourceRequest(d->hitTestResult.linkUrl(), frame->loader()->outgoingReferrer()));
2383             break;
2384 #ifndef QT_NO_CLIPBOARD
2385         case CopyImageToClipboard:
2386             QApplication::clipboard()->setPixmap(d->hitTestResult.pixmap());
2387             break;
2388         case CopyImageUrlToClipboard:
2389             QApplication::clipboard()->setText(d->hitTestResult.imageUrl().toString());
2390             break;
2391 #endif
2392         case Back:
2393             d->page->goBack();
2394             break;
2395         case Forward:
2396             d->page->goForward();
2397             break;
2398         case Stop:
2399             mainFrame()->d->frame->loader()->stopForUserCancel();
2400             d->updateNavigationActions();
2401             break;
2402         case Reload:
2403             mainFrame()->d->frame->loader()->reload(/*endtoendreload*/false);
2404             break;
2405         case ReloadAndBypassCache:
2406             mainFrame()->d->frame->loader()->reload(/*endtoendreload*/true);
2407             break;
2408         case SetTextDirectionDefault:
2409             editor->setBaseWritingDirection(NaturalWritingDirection);
2410             break;
2411         case SetTextDirectionLeftToRight:
2412             editor->setBaseWritingDirection(LeftToRightWritingDirection);
2413             break;
2414         case SetTextDirectionRightToLeft:
2415             editor->setBaseWritingDirection(RightToLeftWritingDirection);
2416             break;
2417         case InspectElement: {
2418 #if ENABLE(INSPECTOR)
2419             if (!d->hitTestResult.isNull()) {
2420                 d->getOrCreateInspector(); // Make sure the inspector is created
2421                 d->inspector->show(); // The inspector is expected to be shown on inspection
2422                 d->page->inspectorController()->inspect(d->hitTestResult.d->innerNonSharedNode.get());
2423             }
2424 #endif
2425             break;
2426         }
2427         case StopScheduledPageRefresh: {
2428             QWebFrame* topFrame = mainFrame();
2429             topFrame->d->frame->navigationScheduler()->cancel();
2430             QList<QWebFrame*> childFrames;
2431             collectChildFrames(topFrame, childFrames);
2432             QListIterator<QWebFrame*> it(childFrames);
2433             while (it.hasNext())
2434                 it.next()->d->frame->navigationScheduler()->cancel();
2435             break;
2436         }
2437         default:
2438             command = QWebPagePrivate::editorCommandForWebActions(action);
2439             break;
2440     }
2441
2442     if (command)
2443         editor->command(command).execute();
2444 }
2445
2446 QSize QWebPage::viewportSize() const
2447 {
2448     if (d->mainFrame && d->mainFrame.data()->d->frame->view())
2449         return d->mainFrame.data()->d->frame->view()->frameRect().size();
2450
2451     return d->viewportSize;
2452 }
2453
2454 /*!
2455     \property QWebPage::viewportSize
2456     \brief the size of the viewport
2457
2458     The size affects for example the visibility of scrollbars
2459     if the document is larger than the viewport.
2460
2461     By default, for a newly-created Web page, this property contains a size with
2462     zero width and height.
2463
2464     \sa QWebFrame::render(), preferredContentsSize
2465 */
2466 void QWebPage::setViewportSize(const QSize &size) const
2467 {
2468     d->viewportSize = size;
2469
2470     QWebFrame *frame = mainFrame();
2471     if (frame->d->frame && frame->d->frame->view()) {
2472         WebCore::FrameView* view = frame->d->frame->view();
2473         view->resize(size);
2474         view->adjustViewSize();
2475     }
2476 }
2477
2478 static int getintenv(const char* variable)
2479 {
2480     bool ok;
2481     int value = qgetenv(variable).toInt(&ok);
2482     return (ok) ? value : -1;
2483 }
2484
2485 static QSize queryDeviceSizeForScreenContainingWidget(const QWidget* widget)
2486 {
2487     QDesktopWidget* desktop = QApplication::desktop();
2488     if (!desktop)
2489         return QSize();
2490
2491     QSize size;
2492
2493     if (widget) {
2494         // Returns the available geometry of the screen which contains widget.
2495         // NOTE: this must be the the full screen size including any fixed status areas etc.
2496         size = desktop->availableGeometry(widget).size();
2497     } else
2498         size = desktop->availableGeometry().size();
2499
2500     // This must be in portrait mode, adjust if not.
2501     if (size.width() > size.height()) {
2502         int width = size.width();
2503         size.setWidth(size.height());
2504         size.setHeight(width);
2505     }
2506
2507     return size;
2508 }
2509
2510 /*!
2511     Computes the optimal viewport configuration given the \a availableSize, when
2512     user interface components are disregarded.
2513
2514     The configuration is also dependent on the device screen size which is obtained
2515     automatically. For testing purposes the size can be overridden by setting two
2516     environment variables QTWEBKIT_DEVICE_WIDTH and QTWEBKIT_DEVICE_HEIGHT, which
2517     both needs to be set.
2518
2519     The ViewportAttributes includes a pixel density ratio, which will also be exposed to
2520     the web author though the -webkit-pixel-ratio media feature. This is the ratio
2521     between 1 density-independent pixel (DPI) and physical pixels.
2522
2523     A density-independent pixel is equivalent to one physical pixel on a 160 DPI screen,
2524     so on our platform assumes that as the baseline density.
2525
2526     The conversion of DIP units to screen pixels is quite simple:
2527
2528     pixels = DIPs * (density / 160).
2529
2530     Thus, on a 240 DPI screen, 1 DIPs would equal 1.5 physical pixels.
2531
2532     An invalid instance will be returned in the case an empty size is passed to the
2533     method.
2534
2535     \note The density is automatically obtained from the DPI of the screen where the page
2536     is being shown, but as many X11 servers are reporting wrong DPI, it is possible to
2537     override it using QX11Info::setAppDpiY().
2538 */
2539
2540 QWebPage::ViewportAttributes QWebPage::viewportAttributesForSize(const QSize& availableSize) const
2541 {
2542     static int desktopWidth = 980;
2543
2544     ViewportAttributes result;
2545
2546      if (availableSize.isEmpty())
2547          return result; // Returns an invalid instance.
2548
2549     int deviceWidth = getintenv("QTWEBKIT_DEVICE_WIDTH");
2550     int deviceHeight = getintenv("QTWEBKIT_DEVICE_HEIGHT");
2551
2552     // Both environment variables need to be set - or they will be ignored.
2553     if (deviceWidth < 0 && deviceHeight < 0) {
2554         QSize size = queryDeviceSizeForScreenContainingWidget((d->client) ? d->client->ownerWidget() : 0);
2555         deviceWidth = size.width();
2556         deviceHeight = size.height();
2557     }
2558
2559     WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(d->viewportArguments(), desktopWidth, deviceWidth, deviceHeight, qt_defaultDpi(), availableSize);
2560
2561     result.m_isValid = true;
2562     result.m_size = conf.layoutSize;
2563     result.m_initialScaleFactor = conf.initialScale;
2564     result.m_minimumScaleFactor = conf.minimumScale;
2565     result.m_maximumScaleFactor = conf.maximumScale;
2566     result.m_devicePixelRatio = conf.devicePixelRatio;
2567     result.m_isUserScalable = static_cast<bool>(conf.userScalable);
2568
2569     d->page->setDeviceScaleFactor(conf.devicePixelRatio);
2570
2571     return result;
2572 }
2573
2574 QSize QWebPage::preferredContentsSize() const
2575 {
2576     QWebFrame* frame = d->mainFrame.data();
2577     if (frame) {
2578         WebCore::FrameView* view = frame->d->frame->view();
2579         if (view && view->useFixedLayout())
2580             return d->mainFrame.data()->d->frame->view()->fixedLayoutSize();
2581     }
2582
2583     return d->fixedLayoutSize;
2584 }
2585
2586 /*!
2587     \property QWebPage::preferredContentsSize
2588     \since 4.6
2589     \brief a custom size used for laying out the page contents.
2590
2591     By default all pages are laid out using the viewport of the page as the base.
2592
2593     As pages mostly are designed for desktop usage, they often do not layout properly
2594     on small devices as the contents require a certain view width. For this reason
2595     it is common to use a different layout size and then scale the contents to fit
2596     within the actual view.
2597
2598     If this property is set to a valid size, this size is used for all layout needs
2599     instead of the size of the viewport.
2600
2601     Setting an invalid size, makes the page fall back to using the viewport size for layout.
2602
2603     \sa viewportSize
2604 */
2605 void QWebPage::setPreferredContentsSize(const QSize& size) const
2606 {
2607     // FIXME: Rename this method to setCustomLayoutSize
2608
2609     d->fixedLayoutSize = size;
2610
2611     QWebFrame* frame = mainFrame();
2612     if (!frame->d->frame || !frame->d->frame->view())
2613         return;
2614
2615     WebCore::FrameView* view = frame->d->frame->view();
2616
2617     if (size.isValid()) {
2618         view->setUseFixedLayout(true);
2619         view->setFixedLayoutSize(size);
2620     } else if (view->useFixedLayout())
2621         view->setUseFixedLayout(false);
2622
2623     view->layout();
2624 }
2625
2626 /*
2627     This function is to be called after any (animated) scroll/pan has ended, in the case the application handles the
2628     scrolling/panning of the web contents. This is commonly used in combination with tiling where is it common for
2629     the application to pan the actual view, which then resizes itself to the size of the contents.
2630
2631     \note Calling this function makes WebKit stop trying to calculate the visibleContentRect. To turn that on
2632     again, call this method with an empty rect.
2633
2634     \sa QGraphicsWebView::resizesToContents, QWebSettings::TiledBackingStoreEnabled
2635 */
2636 void QWebPage::setActualVisibleContentRect(const QRect& rect) const
2637 {
2638     QWebFrame* frame = mainFrame();
2639     if (!frame->d->frame || !frame->d->frame->view())
2640         return;
2641
2642     WebCore::FrameView* view = frame->d->frame->view();
2643     view->setFixedVisibleContentRect(rect);
2644 }
2645
2646 /*!
2647     \fn bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2648
2649     This function is called whenever WebKit requests to navigate \a frame to the resource specified by \a request by means of
2650     the specified navigation type \a type.
2651
2652     If \a frame is a null pointer then navigation to a new window is requested. If the request is
2653     accepted createWindow() will be called.
2654
2655     The default implementation interprets the page's linkDelegationPolicy and emits linkClicked accordingly or returns true
2656     to let QWebPage handle the navigation itself.
2657
2658     \sa createWindow()
2659 */
2660 bool QWebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
2661 {
2662     Q_UNUSED(frame)
2663     if (type == NavigationTypeLinkClicked) {
2664         switch (d->linkPolicy) {
2665             case DontDelegateLinks:
2666                 return true;
2667
2668             case DelegateExternalLinks:
2669                 if (WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal(request.url().scheme()))
2670                     return true;
2671                 emit linkClicked(request.url());
2672                 return false;
2673
2674             case DelegateAllLinks:
2675                 emit linkClicked(request.url());
2676                 return false;
2677         }
2678     }
2679     return true;
2680 }
2681
2682 /*!
2683     \property QWebPage::hasSelection
2684     \brief whether this page contains selected content or not.
2685
2686     \sa selectionChanged()
2687 */
2688 bool QWebPage::hasSelection() const
2689 {
2690     d->createMainFrame();
2691     WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2692     if (frame)
2693         return (frame->selection()->selection().selectionType() != VisibleSelection::NoSelection);
2694     return false;
2695 }
2696
2697 /*!
2698     \property QWebPage::selectedText
2699     \brief the text currently selected
2700
2701     By default, this property contains an empty string.
2702
2703     \sa selectionChanged(), selectedHtml()
2704 */
2705 QString QWebPage::selectedText() const
2706 {
2707     d->createMainFrame();
2708     WebCore::Frame* frame = d->page->focusController()->focusedOrMainFrame();
2709     if (frame->selection()->selection().selectionType() == VisibleSelection::NoSelection)
2710         return QString();
2711     return frame->editor()->selectedText();
2712 }
2713
2714 /*!
2715     \since 4.8
2716     \property QWebPage::selectedHtml
2717     \brief the HTML currently selected
2718
2719     By default, this property contains an empty string.
2720
2721     \sa selectionChanged(), selectedText()
2722 */
2723 QString QWebPage::selectedHtml() const
2724 {
2725     d->createMainFrame();
2726     return d->page->focusController()->focusedOrMainFrame()->editor()->selectedRange()->toHTML();
2727 }
2728
2729 #ifndef QT_NO_ACTION
2730 /*!
2731    Returns a QAction for the specified WebAction \a action.
2732
2733    The action is owned by the QWebPage but you can customize the look by
2734    changing its properties.
2735
2736    QWebPage also takes care of implementing the action, so that upon
2737    triggering the corresponding action is performed on the page.
2738
2739    \sa triggerAction()
2740 */
2741 QAction *QWebPage::action(WebAction action) const
2742 {
2743     if (action == QWebPage::NoWebAction) return 0;
2744     if (d->actions[action])
2745         return d->actions[action];
2746
2747     QString text;
2748     QIcon icon;
2749     QStyle *style = d->client ? d->client->style() : qApp->style();
2750     bool checkable = false;
2751
2752     switch (action) {
2753         case OpenLink:
2754             text = contextMenuItemTagOpenLink();
2755             break;
2756         case OpenLinkInNewWindow:
2757             text = contextMenuItemTagOpenLinkInNewWindow();
2758             break;
2759         case OpenFrameInNewWindow:
2760             text = contextMenuItemTagOpenFrameInNewWindow();
2761             break;
2762
2763         case DownloadLinkToDisk:
2764             text = contextMenuItemTagDownloadLinkToDisk();
2765             break;
2766         case CopyLinkToClipboard:
2767             text = contextMenuItemTagCopyLinkToClipboard();
2768             break;
2769
2770         case OpenImageInNewWindow:
2771             text = contextMenuItemTagOpenImageInNewWindow();
2772             break;
2773         case DownloadImageToDisk:
2774             text = contextMenuItemTagDownloadImageToDisk();
2775             break;
2776         case CopyImageToClipboard:
2777             text = contextMenuItemTagCopyImageToClipboard();
2778             break;
2779         case CopyImageUrlToClipboard:
2780             text = contextMenuItemTagCopyImageUrlToClipboard();
2781             break;
2782
2783         case Back:
2784             text = contextMenuItemTagGoBack();
2785             icon = style->standardIcon(QStyle::SP_ArrowBack);
2786             break;
2787         case Forward:
2788             text = contextMenuItemTagGoForward();
2789             icon = style->standardIcon(QStyle::SP_ArrowForward);
2790             break;
2791         case Stop:
2792             text = contextMenuItemTagStop();
2793             icon = style->standardIcon(QStyle::SP_BrowserStop);
2794             break;
2795         case Reload:
2796             text = contextMenuItemTagReload();
2797             icon = style->standardIcon(QStyle::SP_BrowserReload);
2798             break;
2799
2800         case Cut:
2801             text = contextMenuItemTagCut();
2802             break;
2803         case Copy:
2804             text = contextMenuItemTagCopy();
2805             break;
2806         case Paste:
2807             text = contextMenuItemTagPaste();
2808             break;
2809         case SelectAll:
2810             text = contextMenuItemTagSelectAll();
2811             break;
2812 #ifndef QT_NO_UNDOSTACK
2813         case Undo: {
2814             QAction *a = undoStack()->createUndoAction(d->q);
2815             d->actions[action] = a;
2816             return a;
2817         }
2818         case Redo: {
2819             QAction *a = undoStack()->createRedoAction(d->q);
2820             d->actions[action] = a;
2821             return a;
2822         }
2823 #endif // QT_NO_UNDOSTACK
2824         case MoveToNextChar:
2825             text = tr("Move the cursor to the next character");
2826             break;
2827         case MoveToPreviousChar:
2828             text = tr("Move the cursor to the previous character");
2829             break;
2830         case MoveToNextWord:
2831             text = tr("Move the cursor to the next word");
2832             break;
2833         case MoveToPreviousWord:
2834             text = tr("Move the cursor to the previous word");
2835             break;
2836         case MoveToNextLine:
2837             text = tr("Move the cursor to the next line");
2838             break;
2839         case MoveToPreviousLine:
2840             text = tr("Move the cursor to the previous line");
2841             break;
2842         case MoveToStartOfLine:
2843             text = tr("Move the cursor to the start of the line");
2844             break;
2845         case MoveToEndOfLine:
2846             text = tr("Move the cursor to the end of the line");
2847             break;
2848         case MoveToStartOfBlock:
2849             text = tr("Move the cursor to the start of the block");
2850             break;
2851         case MoveToEndOfBlock:
2852             text = tr("Move the cursor to the end of the block");
2853             break;
2854         case MoveToStartOfDocument:
2855             text = tr("Move the cursor to the start of the document");
2856             break;
2857         case MoveToEndOfDocument:
2858             text = tr("Move the cursor to the end of the document");
2859             break;
2860         case SelectNextChar:
2861             text = tr("Select to the next character");
2862             break;
2863         case SelectPreviousChar:
2864             text = tr("Select to the previous character");
2865             break;
2866         case SelectNextWord:
2867             text = tr("Select to the next word");
2868             break;
2869         case SelectPreviousWord:
2870             text = tr("Select to the previous word");
2871             break;
2872         case SelectNextLine:
2873             text = tr("Select to the next line");
2874             break;
2875         case SelectPreviousLine:
2876             text = tr("Select to the previous line");
2877             break;
2878         case SelectStartOfLine:
2879             text = tr("Select to the start of the line");
2880             break;
2881         case SelectEndOfLine:
2882             text = tr("Select to the end of the line");
2883             break;
2884         case SelectStartOfBlock:
2885             text = tr("Select to the start of the block");
2886             break;
2887         case SelectEndOfBlock:
2888             text = tr("Select to the end of the block");
2889             break;
2890         case SelectStartOfDocument:
2891             text = tr("Select to the start of the document");
2892             break;
2893         case SelectEndOfDocument:
2894             text = tr("Select to the end of the document");
2895             break;
2896         case DeleteStartOfWord:
2897             text = tr("Delete to the start of the word");
2898             break;
2899         case DeleteEndOfWord:
2900             text = tr("Delete to the end of the word");
2901             break;
2902
2903         case SetTextDirectionDefault:
2904             text = contextMenuItemTagDefaultDirection();
2905             break;
2906         case SetTextDirectionLeftToRight:
2907             text = contextMenuItemTagLeftToRight();
2908             checkable = true;
2909             break;
2910         case SetTextDirectionRightToLeft:
2911             text = contextMenuItemTagRightToLeft();
2912             checkable = true;
2913             break;
2914
2915         case ToggleBold:
2916             text = contextMenuItemTagBold();
2917             checkable = true;
2918             break;
2919         case ToggleItalic:
2920             text = contextMenuItemTagItalic();
2921             checkable = true;
2922             break;
2923         case ToggleUnderline:
2924             text = contextMenuItemTagUnderline();
2925             checkable = true;
2926             break;
2927
2928         case InspectElement:
2929             text = contextMenuItemTagInspectElement();
2930             break;
2931
2932         case InsertParagraphSeparator:
2933             text = tr("Insert a new paragraph");
2934             break;
2935         case InsertLineSeparator:
2936             text = tr("Insert a new line");
2937             break;
2938
2939         case PasteAndMatchStyle:
2940             text = tr("Paste and Match Style");
2941             break;
2942         case RemoveFormat:
2943             text = tr("Remove formatting");
2944             break;
2945
2946         case ToggleStrikethrough:
2947             text = tr("Strikethrough");
2948             checkable = true;
2949             break;
2950         case ToggleSubscript:
2951             text = tr("Subscript");
2952             checkable = true;
2953             break;
2954         case ToggleSuperscript:
2955             text = tr("Superscript");
2956             checkable = true;
2957             break;
2958         case InsertUnorderedList:
2959             text = tr("Insert Bulleted List");
2960             checkable = true;
2961             break;
2962         case InsertOrderedList:
2963             text = tr("Insert Numbered List");
2964             checkable = true;
2965             break;
2966         case Indent:
2967             text = tr("Indent");
2968             break;
2969         case Outdent:
2970             text = tr("Outdent");
2971             break;
2972         case AlignCenter:
2973             text = tr("Center");
2974             break;
2975         case AlignJustified:
2976             text = tr("Justify");
2977             break;
2978         case AlignLeft:
2979             text = tr("Align Left");
2980             break;
2981         case AlignRight:
2982             text = tr("Align Right");
2983             break;
2984         case NoWebAction:
2985             return 0;
2986         default:
2987             break;
2988     }
2989
2990     if (text.isEmpty())
2991         return 0;
2992
2993     QAction *a = new QAction(d->q);
2994     a->setText(text);
2995     a->setData(action);
2996     a->setCheckable(checkable);
2997     a->setIcon(icon);
2998
2999     connect(a, SIGNAL(triggered(bool)),
3000             this, SLOT(_q_webActionTriggered(bool)));
3001
3002     d->actions[action] = a;
3003     d->updateAction(action);
3004     return a;
3005 }
3006 #endif // QT_NO_ACTION
3007
3008 /*!
3009     \property QWebPage::modified
3010     \brief whether the page contains unsubmitted form data, or the contents have been changed.
3011
3012     By default, this property is false.
3013
3014     \sa contentsChanged(), contentEditable, undoStack()
3015 */
3016 bool QWebPage::isModified() const
3017 {
3018 #ifdef QT_NO_UNDOSTACK
3019     return false;
3020 #else
3021     if (!d->undoStack)
3022         return false;
3023     return d->undoStack->canUndo();
3024 #endif // QT_NO_UNDOSTACK
3025 }
3026
3027 #ifndef QT_NO_UNDOSTACK
3028 /*!
3029     Returns a pointer to the undo stack used for editable content.
3030
3031     \sa modified
3032 */
3033 QUndoStack *QWebPage::undoStack() const
3034 {
3035     if (!d->undoStack)
3036         d->undoStack = new QUndoStack(const_cast<QWebPage *>(this));
3037
3038     return d->undoStack;
3039 }
3040 #endif // QT_NO_UNDOSTACK
3041
3042 /*! \reimp
3043 */
3044 bool QWebPage::event(QEvent *ev)
3045 {
3046     switch (ev->type()) {
3047     case QEvent::Timer:
3048         d->timerEvent(static_cast<QTimerEvent*>(ev));
3049         break;
3050     case QEvent::MouseMove:
3051         d->mouseMoveEvent(static_cast<QMouseEvent*>(ev));
3052         break;
3053     case QEvent::MouseButtonPress:
3054         d->mousePressEvent(static_cast<QMouseEvent*>(ev));
3055         break;
3056     case QEvent::MouseButtonDblClick:
3057         d->mouseDoubleClickEvent(static_cast<QMouseEvent*>(ev));
3058         break;
3059     case QEvent::MouseButtonRelease:
3060         d->mouseReleaseEvent(static_cast<QMouseEvent*>(ev));
3061         break;
3062 #if !defined(QT_NO_GRAPHICSVIEW)
3063     case QEvent::GraphicsSceneMouseMove:
3064         d->mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3065         break;
3066     case QEvent::GraphicsSceneMousePress:
3067         d->mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3068         break;
3069     case QEvent::GraphicsSceneMouseDoubleClick:
3070         d->mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3071         break;
3072     case QEvent::GraphicsSceneMouseRelease:
3073         d->mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(ev));
3074         break;
3075 #endif
3076 #ifndef QT_NO_CONTEXTMENU
3077     case QEvent::ContextMenu:
3078         d->contextMenuEvent(static_cast<QContextMenuEvent*>(ev)->globalPos());
3079         break;
3080 #if !defined(QT_NO_GRAPHICSVIEW)
3081     case QEvent::GraphicsSceneContextMenu:
3082         d->contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent*>(ev)->screenPos());
3083         break;
3084 #endif
3085 #endif
3086 #ifndef QT_NO_WHEELEVENT
3087     case QEvent::Wheel:
3088         d->wheelEvent(static_cast<QWheelEvent*>(ev));
3089         break;
3090 #if !defined(QT_NO_GRAPHICSVIEW)
3091     case QEvent::GraphicsSceneWheel:
3092         d->wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(ev));
3093         break;
3094 #endif
3095 #endif
3096     case QEvent::KeyPress:
3097         d->keyPressEvent(static_cast<QKeyEvent*>(ev));
3098         break;
3099     case QEvent::KeyRelease:
3100         d->keyReleaseEvent(static_cast<QKeyEvent*>(ev));
3101         break;
3102     case QEvent::FocusIn:
3103         d->focusInEvent(static_cast<QFocusEvent*>(ev));
3104         break;
3105     case QEvent::FocusOut:
3106         d->focusOutEvent(static_cast<QFocusEvent*>(ev));
3107         break;
3108 #ifndef QT_NO_DRAGANDDROP
3109     case QEvent::DragEnter:
3110         d->dragEnterEvent(static_cast<QDragEnterEvent*>(ev));
3111         break;
3112     case QEvent::DragLeave:
3113         d->dragLeaveEvent(static_cast<QDragLeaveEvent*>(ev));
3114         break;
3115     case QEvent::DragMove:
3116         d->dragMoveEvent(static_cast<QDragMoveEvent*>(ev));
3117         break;
3118     case QEvent::Drop:
3119         d->dropEvent(static_cast<QDropEvent*>(ev));
3120         break;
3121 #if !defined(QT_NO_GRAPHICSVIEW)
3122     case QEvent::GraphicsSceneDragEnter:
3123         d->dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3124         break;
3125     case QEvent::GraphicsSceneDragMove:
3126         d->dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3127         break;
3128     case QEvent::GraphicsSceneDragLeave:
3129         d->dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3130         break;
3131     case QEvent::GraphicsSceneDrop:
3132         d->dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(ev));
3133         break;
3134 #endif
3135
3136 #endif
3137     case QEvent::InputMethod:
3138         d->inputMethodEvent(static_cast<QInputMethodEvent*>(ev));
3139         break;
3140     case QEvent::ShortcutOverride:
3141         d->shortcutOverrideEvent(static_cast<QKeyEvent*>(ev));
3142         break;
3143     case QEvent::Leave:
3144         d->leaveEvent(ev);
3145         break;
3146     case QEvent::TouchBegin:
3147     case QEvent::TouchUpdate:
3148     case QEvent::TouchEnd:
3149         // Return whether the default action was cancelled in the JS event handler
3150         return d->touchEvent(static_cast<QTouchEvent*>(ev));
3151 #ifndef QT_NO_PROPERTIES
3152     case QEvent::DynamicPropertyChange:
3153         d->dynamicPropertyChangeEvent(static_cast<QDynamicPropertyChangeEvent*>(ev));
3154         break;
3155 #endif
3156     default:
3157         return QObject::event(ev);
3158     }
3159
3160     return true;
3161 }
3162
3163 /*!
3164     Similar to QWidget::focusNextPrevChild() it focuses the next focusable web element
3165     if \a next is true; otherwise the previous element is focused.
3166
3167     Returns true if it can find a new focusable element, or false if it can't.
3168 */
3169 bool QWebPage::focusNextPrevChild(bool next)
3170 {
3171     QKeyEvent ev(QEvent::KeyPress, Qt::Key_Tab, Qt::KeyboardModifiers(next ? Qt::NoModifier : Qt::ShiftModifier));
3172     d->keyPressEvent(&ev);
3173     bool hasFocusedNode = false;
3174     Frame *frame = d->page->focusController()->focusedFrame();
3175     if (frame) {
3176         Document *document = frame->document();
3177         hasFocusedNode = document && document->focusedNode();
3178     }
3179     //qDebug() << "focusNextPrevChild(" << next << ") =" << ev.isAccepted() << "focusedNode?" << hasFocusedNode;
3180     return hasFocusedNode;
3181 }
3182
3183 /*!
3184     \property QWebPage::contentEditable
3185     \brief whether the content in this QWebPage is editable or not
3186     \since 4.5
3187
3188     If this property is enabled the contents of the page can be edited by the user through a visible
3189     cursor. If disabled (the default) only HTML elements in the web page with their
3190     \c{contenteditable} attribute set are editable.
3191
3192     \sa modified, contentsChanged(), WebAction
3193 */
3194 void QWebPage::setContentEditable(bool editable)
3195 {
3196     if (isContentEditable() != editable) {
3197         d->page->setEditable(editable);
3198         d->page->setTabKeyCyclesThroughElements(!editable);
3199         if (d->mainFrame) {
3200             WebCore::Frame* frame = d->mainFrame.data()->d->frame;
3201             if (editable) {
3202                 frame->editor()->applyEditingStyleToBodyElement();
3203                 // FIXME: mac port calls this if there is no selectedDOMRange
3204                 //frame->setSelectionFromNone();
3205             }
3206         }
3207
3208         d->updateEditorActions();
3209     }
3210 }
3211
3212 bool QWebPage::isContentEditable() const
3213 {
3214     return d->page->isEditable();
3215 }
3216
3217 /*!
3218     \property QWebPage::forwardUnsupportedContent
3219     \brief whether QWebPage should forward unsupported content
3220
3221     If enabled, the unsupportedContent() signal is emitted with a network reply that
3222     can be used to read the content.
3223
3224     If disabled, the download of such content is aborted immediately.
3225
3226     By default unsupported content is not forwarded.
3227 */
3228
3229 void QWebPage::setForwardUnsupportedContent(bool forward)
3230 {
3231     d->forwardUnsupportedContent = forward;
3232 }
3233
3234 bool QWebPage::forwardUnsupportedContent() const
3235 {
3236     return d->forwardUnsupportedContent;
3237 }
3238
3239 /*!
3240     \property QWebPage::linkDelegationPolicy
3241     \brief how QWebPage should delegate the handling of links through the
3242     linkClicked() signal
3243
3244     The default is to delegate no links.
3245 */
3246
3247 void QWebPage::setLinkDelegationPolicy(LinkDelegationPolicy policy)
3248 {
3249     d->linkPolicy = policy;
3250 }
3251
3252 QWebPage::LinkDelegationPolicy QWebPage::linkDelegationPolicy() const
3253 {
3254     return d->linkPolicy;
3255 }
3256
3257 #ifndef QT_NO_CONTEXTMENU
3258 /*!
3259     Filters the context menu event, \a event, through handlers for scrollbars and
3260     custom event handlers in the web page. Returns true if the event was handled;
3261     otherwise false.
3262
3263     A web page may swallow a context menu event through a custom event handler, allowing for context
3264     menus to be implemented in HTML/JavaScript. This is used by \l{http://maps.google.com/}{Google
3265     Maps}, for example.
3266 */
3267 bool QWebPage::swallowContextMenuEvent(QContextMenuEvent *event)
3268 {
3269     d->page->contextMenuController()->clearContextMenu();
3270
3271     if (QWebFrame* webFrame = frameAt(event->pos())) {
3272         Frame* frame = QWebFramePrivate::core(webFrame);
3273         if (Scrollbar* scrollbar = frame->view()->scrollbarAtPoint(PlatformMouseEvent(event, 1).pos()))
3274             return scrollbar->contextMenu(PlatformMouseEvent(event, 1));
3275     }
3276
3277     WebCore::Frame* focusedFrame = d->page->focusController()->focusedOrMainFrame();
3278     focusedFrame->eventHandler()->sendContextMenuEvent(PlatformMouseEvent(event, 1));
3279     ContextMenu *menu = d->page->contextMenuController()->contextMenu();
3280     // If the website defines its own handler then sendContextMenuEvent takes care of
3281     // calling/showing it and the context menu pointer will be zero. This is the case
3282     // on maps.google.com for example.
3283
3284     return !menu;
3285 }
3286 #endif // QT_NO_CONTEXTMENU
3287
3288 /*!
3289     Updates the page's actions depending on the position \a pos. For example if \a pos is over an image
3290     element the CopyImageToClipboard action is enabled.
3291 */
3292 void QWebPage::updatePositionDependentActions(const QPoint &pos)
3293 {
3294 #ifndef QT_NO_ACTION
3295     // First we disable all actions, but keep track of which ones were originally enabled.
3296     QBitArray originallyEnabledWebActions(QWebPage::WebActionCount);
3297     for (int i = ContextMenuItemTagNoAction; i < ContextMenuItemBaseApplicationTag; ++i) {
3298         QWebPage::WebAction action = webActionForContextMenuAction(WebCore::ContextMenuAction(i));
3299         if (QAction *a = this->action(action)) {
3300             originallyEnabledWebActions.setBit(action, a->isEnabled());
3301             a->setEnabled(false);
3302         }
3303     }
3304 #endif // QT_NO_ACTION
3305
3306     d->createMainFrame();
3307     WebCore::Frame* focusedFrame = d->page->focusController()->focusedOrMainFrame();
3308
3309     HitTestResult result = focusedFrame->eventHandler()->hitTestResultAtPoint(focusedFrame->view()->windowToContents(pos), /*allowShadowContent*/ false);
3310     if (result.scrollbar())
3311         d->hitTestResult = QWebHitTestResult();
3312     else
3313         d->hitTestResult = QWebHitTestResult(new QWebHitTestResultPrivate(result));
3314     d->page->contextMenuController()->setHitTestResult(result);
3315
3316 #if ENABLE(INSPECTOR)
3317     if (d->page->inspectorController()->enabled())
3318         d->page->contextMenuController()->addInspectElementItem();
3319 #endif
3320
3321     QBitArray visitedWebActions(QWebPage::WebActionCount);
3322
3323 #ifndef QT_NO_CONTEXTMENU
3324     delete d->currentContextMenu.data();
3325
3326     // Then we let createContextMenu() enable the actions that are put into the menu
3327     d->currentContextMenu = d->createContextMenu(d->page->contextMenuController()->contextMenu(), d->page->contextMenuController()->contextMenu()->platformDescription(), &visitedWebActions);
3328 #endif // QT_NO_CONTEXTMENU
3329
3330 #ifndef QT_NO_ACTION
3331     // Finally, we restore the original enablement for the actions that were not put into the menu.
3332     originallyEnabledWebActions &= ~visitedWebActions; // Mask out visited actions (they're part of the menu)
3333     for (int i = 0; i < QWebPage::WebActionCount; ++i) {
3334         if (originallyEnabledWebActions.at(i)) {
3335             if (QAction *a = this->action(QWebPage::WebAction(i)))
3336                 a->setEnabled(true);
3337         }
3338     }
3339 #endif // QT_NO_ACTION
3340
3341     // This whole process ensures that any actions put into to the context menu has the right
3342     // enablement, while also keeping the correct enablement for actions that were left out of
3343     // the menu.
3344
3345 }
3346
3347
3348
3349 /*!
3350     \enum QWebPage::Extension
3351
3352     This enum describes the types of extensions that the page can support. Before using these extensions, you
3353     should verify that the extension is supported by calling supportsExtension().
3354
3355     \value ChooseMultipleFilesExtension Whether the web page supports multiple file selection.
3356     This extension is invoked when the web content requests one or more file names, for example
3357     as a result of the user clicking on a "file upload" button in a HTML form where multiple
3358     file selection is allowed.
3359
3360     \value ErrorPageExtension Whether the web page can provide an error page when loading fails.
3361     (introduced in Qt 4.6)
3362
3363     \sa ChooseMultipleFilesExtensionOption, ChooseMultipleFilesExtensionReturn, ErrorPageExtensionOption, ErrorPageExtensionReturn
3364 */
3365
3366 /*!
3367     \enum QWebPage::ErrorDomain
3368     \since 4.6
3369
3370     This enum describes the domain of an ErrorPageExtensionOption object (i.e. the layer in which the error occurred).
3371
3372     \value QtNetwork The error occurred in the QtNetwork layer; the error code is of type QNetworkReply::NetworkError.
3373     \value Http The error occurred in the HTTP layer; the error code is a HTTP status code (see QNetworkRequest::HttpStatusCodeAttribute).
3374     \value WebKit The error is an internal WebKit error.
3375 */
3376
3377 /*!
3378     \class QWebPage::ExtensionOption
3379     \since 4.4
3380     \brief The ExtensionOption class provides an extended input argument to QWebPage's extension support.
3381
3382     \inmodule QtWebKit
3383
3384     \sa QWebPage::extension() QWebPage::ExtensionReturn
3385 */
3386
3387
3388 /*!
3389     \class QWebPage::ExtensionReturn
3390     \since 4.4
3391     \brief The ExtensionReturn class provides an output result from a QWebPage's extension.
3392
3393     \inmodule QtWebKit
3394
3395     \sa QWebPage::extension() QWebPage::ExtensionOption
3396 */
3397
3398 /*!
3399     \class QWebPage::ErrorPageExtensionOption
3400     \since 4.6
3401     \brief The ErrorPageExtensionOption class describes the option
3402     for the error page extension.
3403
3404     \inmodule QtWebKit
3405
3406     The ErrorPageExtensionOption class holds the \a url for which an error occurred as well as
3407     the associated \a frame.
3408
3409     The error itself is reported by an error \a domain, the \a error code as well as \a errorString.
3410
3411     \sa QWebPage::extension() QWebPage::ErrorPageExtensionReturn
3412 */
3413
3414 /*!
3415     \variable QWebPage::ErrorPageExtensionOption::url
3416     \brief the url for which an error occurred
3417 */
3418
3419 /*!
3420     \variable QWebPage::ErrorPageExtensionOption::frame
3421     \brief the frame associated with the error
3422 */
3423
3424 /*!
3425     \variable QWebPage::ErrorPageExtensionOption::domain
3426     \brief the domain that reported the error
3427 */
3428
3429 /*!
3430     \variable QWebPage::ErrorPageExtensionOption::error
3431     \brief the error code. Interpretation of the value depends on the \a domain
3432     \sa QWebPage::ErrorDomain
3433 */
3434
3435 /*!
3436     \variable QWebPage::ErrorPageExtensionOption::errorString
3437     \brief a string that describes the error
3438 */
3439
3440 /*!
3441     \class QWebPage::ErrorPageExtensionReturn
3442     \since 4.6
3443     \brief The ErrorPageExtensionReturn describes the error page, which will be shown for the
3444     frame for which the error occured.
3445
3446     \inmodule QtWebKit
3447
3448     The ErrorPageExtensionReturn class holds the data needed for creating an error page. Some are
3449     optional such as \a contentType, which defaults to "text/html", as well as the \a encoding, which
3450     is assumed to be UTF-8 if not indicated otherwise.
3451
3452     The error page is stored in the \a content byte array, as HTML content. In order to convert a
3453     QString to a byte array, the QString::toUtf8() method can be used.
3454
3455     External objects such as stylesheets or images referenced in the HTML are located relative to
3456     \a baseUrl.
3457
3458     \sa QWebPage::extension() QWebPage::ErrorPageExtensionOption, QString::toUtf8()
3459 */
3460
3461 /*!
3462     \fn QWebPage::ErrorPageExtensionReturn::ErrorPageExtensionReturn()
3463
3464     Constructs a new error page object.
3465 */
3466
3467
3468 /*!
3469     \variable QWebPage::ErrorPageExtensionReturn::contentType
3470     \brief the error page's content type
3471 */
3472
3473 /*!
3474     \variable QWebPage::ErrorPageExtensionReturn::encoding
3475     \brief the error page encoding
3476 */
3477
3478 /*!
3479     \variable QWebPage::ErrorPageExtensionReturn::baseUrl
3480     \brief the base url
3481
3482     External objects such as stylesheets or images referenced in the HTML are located relative to this url.
3483 */
3484
3485 /*!
3486     \variable QWebPage::ErrorPageExtensionReturn::content
3487     \brief the HTML content of the error page
3488 */
3489
3490 /*!
3491     \class QWebPage::ChooseMultipleFilesExtensionOption
3492     \since 4.5
3493     \brief The ChooseMultipleFilesExtensionOption class describes the option
3494     for the multiple files selection extension.
3495
3496     \inmodule QtWebKit
3497
3498     The ChooseMultipleFilesExtensionOption class holds the frame originating the request
3499     and the suggested filenames which might be provided.
3500
3501     \sa QWebPage::extension() QWebPage::chooseFile(), QWebPage::ChooseMultipleFilesExtensionReturn
3502 */
3503
3504 /*!
3505     \variable QWebPage::ChooseMultipleFilesExtensionOption::parentFrame
3506     \brief The frame in which the request originated
3507 */
3508
3509 /*!
3510     \variable QWebPage::ChooseMultipleFilesExtensionOption::suggestedFileNames
3511     \brief The suggested filenames
3512 */
3513
3514 /*!
3515     \variable QWebPage::ChooseMultipleFilesExtensionReturn::fileNames
3516     \brief The selected filenames
3517 */
3518
3519 /*!
3520     \class QWebPage::ChooseMultipleFilesExtensionReturn
3521     \since 4.5
3522     \brief The ChooseMultipleFilesExtensionReturn describes the return value
3523     for the multiple files selection extension.
3524
3525     \inmodule QtWebKit
3526
3527     The ChooseMultipleFilesExtensionReturn class holds the filenames selected by the user
3528     when the extension is invoked.
3529
3530     \sa QWebPage::extension() QWebPage::ChooseMultipleFilesExtensionOption
3531 */
3532
3533 /*!
3534     This virtual function can be reimplemented in a QWebPage subclass to provide support for extensions. The \a option
3535     argument is provided as input to the extension; the output results can be stored in \a output.
3536
3537     The behavior of this function is determined by \a extension. The \a option
3538     and \a output values are typically casted to the corresponding types (for
3539     example, ChooseMultipleFilesExtensionOption and
3540     ChooseMultipleFilesExtensionReturn for ChooseMultipleFilesExtension).
3541
3542     You can call supportsExtension() to check if an extension is supported by the page.
3543
3544     Returns true if the extension was called successfully; otherwise returns false.
3545
3546     \sa supportsExtension(), Extension
3547 */
3548 bool QWebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
3549 {
3550 #ifndef QT_NO_FILEDIALOG
3551     if (extension == ChooseMultipleFilesExtension) {
3552         // FIXME: do not ignore suggestedFiles
3553         QStringList suggestedFiles = static_cast<const ChooseMultipleFilesExtensionOption*>(option)->suggestedFileNames;
3554         QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
3555         QStringList names = QFileDialog::getOpenFileNames(parent, QString::null);
3556         static_cast<ChooseMultipleFilesExtensionReturn*>(output)->fileNames = names;
3557         return true;
3558     }
3559 #endif
3560
3561     return false;
3562 }
3563
3564 /*!
3565     This virtual function returns true if the web page supports \a extension; otherwise false is returned.
3566
3567     \sa extension()
3568 */
3569 bool QWebPage::supportsExtension(Extension extension) const
3570 {
3571 #ifndef QT_NO_FILEDIALOG
3572     return extension == ChooseMultipleFilesExtension;
3573 #else
3574     Q_UNUSED(extension);
3575     return false;
3576 #endif
3577 }
3578
3579 /*!
3580     Finds the specified string, \a subString, in the page, using the given \a options.
3581
3582     If the HighlightAllOccurrences flag is passed, the function will highlight all occurrences
3583     that exist in the page. All subsequent calls will extend the highlight, rather than
3584     replace it, with occurrences of the new string.
3585
3586     If the HighlightAllOccurrences flag is not passed, the function will select an occurrence
3587     and all subsequent calls will replace the current occurrence with the next one.
3588
3589     To clear the selection, just pass an empty string.
3590
3591     Returns true if \a subString was found; otherwise returns false.
3592 */
3593 bool QWebPage::findText(const QString &subString, FindFlags options)
3594 {
3595     ::TextCaseSensitivity caseSensitivity = ::TextCaseInsensitive;
3596     if (options & FindCaseSensitively)
3597         caseSensitivity = ::TextCaseSensitive;
3598
3599     if (options & HighlightAllOccurrences) {
3600         if (subString.isEmpty()) {
3601             d->page->unmarkAllTextMatches();
3602             return true;
3603         } else
3604             return d->page->markAllMatchesForText(subString, caseSensitivity, true, 0);
3605     } else {
3606         if (subString.isEmpty()) {
3607             d->page->mainFrame()->selection()->clear();
3608             Frame* frame = d->page->mainFrame()->tree()->firstChild();
3609             while (frame) {
3610                 frame->selection()->clear();
3611                 frame = frame->tree()->traverseNextWithWrap(false);
3612             }
3613         }
3614         ::FindDirection direction = ::FindDirectionForward;
3615         if (options & FindBackward)
3616             direction = ::FindDirectionBackward;
3617
3618         const bool shouldWrap = options & FindWrapsAroundDocument;
3619
3620         return d->page->findString(subString, caseSensitivity, direction, shouldWrap);
3621     }
3622 }
3623
3624 /*!
3625     Returns a pointer to the page's settings object.
3626
3627     \sa QWebSettings::globalSettings()
3628 */
3629 QWebSettings *QWebPage::settings() const
3630 {
3631     return d->settings;
3632 }
3633
3634 /*!
3635     This function is called when the web content requests a file name, for example
3636     as a result of the user clicking on a "file upload" button in a HTML form.
3637
3638     A suggested filename may be provided in \a suggestedFile. The frame originating the
3639     request is provided as \a parentFrame.
3640
3641     \sa ChooseMultipleFilesExtension
3642 */
3643 QString QWebPage::chooseFile(QWebFrame *parentFrame, const QString& suggestedFile)
3644 {
3645     Q_UNUSED(parentFrame)
3646 #ifndef QT_NO_FILEDIALOG
3647     QWidget* parent = (d->client) ? d->client->ownerWidget() : 0;
3648     return QFileDialog::getOpenFileName(parent, QString::null, suggestedFile);
3649 #else
3650     return QString::null;
3651 #endif
3652 }
3653
3654 /*!
3655     Sets the QNetworkAccessManager \a manager responsible for serving network requests for this
3656     QWebPage.
3657
3658     \note It is currently not supported to change the network access manager after the
3659     QWebPage has used it. The results of doing this are undefined.
3660
3661     \sa networkAccessManager()
3662 */
3663 void QWebPage::setNetworkAccessManager(QNetworkAccessManager *manager)
3664 {
3665     if (manager == d->networkManager)
3666         return;
3667     if (d->networkManager && d->networkManager->parent() == this)
3668         delete d->networkManager;
3669     d->networkManager = manager;
3670 }
3671
3672 /*!
3673     Returns the QNetworkAccessManager that is responsible for serving network
3674     requests for this QWebPage.
3675
3676     \sa setNetworkAccessManager()
3677 */
3678 QNetworkAccessManager *QWebPage::networkAccessManager() const
3679 {
3680     if (!d->networkManager) {
3681         QWebPage *that = const_cast<QWebPage *>(this);
3682         that->d->networkManager = new QNetworkAccessManager(that);
3683     }
3684     return d->networkManager;
3685 }
3686
3687 /*!
3688     Sets the QWebPluginFactory \a factory responsible for creating plugins embedded into this
3689     QWebPage.
3690
3691     Note: The plugin factory is only used if the QWebSettings::PluginsEnabled attribute is enabled.
3692
3693     \sa pluginFactory()
3694 */
3695 void QWebPage::setPluginFactory(QWebPluginFactory *factory)
3696 {
3697     d->pluginFactory = factory;
3698 }
3699
3700 /*!
3701     Returns the QWebPluginFactory that is responsible for creating plugins embedded into
3702     this QWebPage. If no plugin factory is installed a null pointer is returned.
3703
3704     \sa setPluginFactory()
3705 */
3706 QWebPluginFactory *QWebPage::pluginFactory() const
3707 {
3708     return d->pluginFactory;
3709 }
3710
3711 /*!
3712     This function is called when a user agent for HTTP requests is needed. You can reimplement this
3713     function to dynamically return different user agents for different URLs, based on the \a url parameter.
3714
3715     The default implementation returns the following value:
3716
3717     "Mozilla/5.0 (%Platform%%Security%%Subplatform%) AppleWebKit/%WebKitVersion% (KHTML, like Gecko) %AppVersion Safari/%WebKitVersion%"
3718
3719     On mobile platforms such as Symbian S60 and Maemo, "Mobile Safari" is used instead of "Safari".
3720
3721     In this string the following values are replaced at run-time:
3722     \list
3723     \o %Platform% expands to the windowing system followed by "; " if it is not Windows (e.g. "X11; ").
3724     \o %Security% expands to "N; " if SSL is disabled.
3725     \o %Subplatform% expands to the operating system version (e.g. "Windows NT 6.1" or "Intel Mac OS X 10.5").
3726     \o %WebKitVersion% is the version of WebKit the application was compiled against.
3727     \o %AppVersion% expands to QCoreApplication::applicationName()/QCoreApplication::applicationVersion() if they're set; otherwise defaulting to Qt and the current Qt version.
3728     \endlist
3729 */
3730 QString QWebPage::userAgentForUrl(const QUrl&) const
3731 {
3732     // splitting the string in three and user QStringBuilder is better than using QString::arg()
3733     static QString firstPart;
3734     static QString secondPart;
3735     static QString thirdPart;
3736
3737     if (firstPart.isNull() || secondPart.isNull() || thirdPart.isNull()) {
3738         QString firstPartTemp;
3739         firstPartTemp.reserve(150);
3740         firstPartTemp += QString::fromLatin1("Mozilla/5.0 ("
3741
3742     // Platform
3743 #ifdef Q_WS_MAC
3744         "Macintosh; "
3745 #elif defined Q_WS_QWS
3746         "QtEmbedded; "
3747 #elif defined Q_WS_MAEMO_5
3748         "Maemo"
3749 #elif defined Q_WS_MAEMO_6
3750         "MeeGo"
3751 #elif defined Q_WS_WIN
3752         // Nothing
3753 #elif defined Q_WS_X11
3754         "X11; "
3755 #elif defined Q_OS_SYMBIAN
3756         "Symbian"
3757 #else
3758         "Unknown; "
3759 #endif
3760     );
3761
3762 #if defined Q_OS_SYMBIAN
3763         QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
3764         switch (symbianVersion) {
3765         case QSysInfo::SV_9_2:
3766             firstPartTemp += QString::fromLatin1("OS/9.2; ");
3767             break;
3768         case QSysInfo::SV_9_3:
3769             firstPartTemp += QString::fromLatin1("OS/9.3; ");
3770             break;                
3771         case QSysInfo::SV_9_4:
3772             firstPartTemp += QString::fromLatin1("OS/9.4; ");
3773             break;
3774         case QSysInfo::SV_SF_2:
3775             firstPartTemp += QString::fromLatin1("/2; ");
3776             break;
3777         case QSysInfo::SV_SF_3:
3778             firstPartTemp += QString::fromLatin1("/3; ");
3779             break;
3780         case QSysInfo::SV_SF_4:
3781             firstPartTemp += QString::fromLatin1("/4; ");
3782             break;
3783         default:
3784             firstPartTemp += QString::fromLatin1("; ");
3785             break;
3786         }
3787 #endif
3788
3789 #if defined(QT_NO_OPENSSL)
3790         // No SSL support
3791         firstPartTemp += QString::fromLatin1("N; ");
3792 #endif
3793
3794         // Operating system
3795 #ifdef Q_OS_AIX
3796         firstPartTemp += QString::fromLatin1("AIX");
3797 #elif defined Q_OS_WIN32
3798         firstPartTemp += windowsVersionForUAString();
3799 #elif defined Q_OS_DARWIN
3800 #ifdef __i386__ || __x86_64__
3801         firstPartTemp += QString::fromLatin1("Intel Mac OS X");
3802 #else
3803         firstPartTemp += QString::fromLatin1("PPC Mac OS X");
3804 #endif
3805
3806 #elif defined Q_OS_BSDI
3807         firstPartTemp += QString::fromLatin1("BSD");
3808 #elif defined Q_OS_BSD4
3809         firstPartTemp += QString::fromLatin1("BSD Four");
3810 #elif defined Q_OS_CYGWIN
3811         firstPartTemp += QString::fromLatin1("Cygwin");
3812 #elif defined Q_OS_DGUX
3813         firstPartTemp += QString::fromLatin1("DG/UX");
3814 #elif defined Q_OS_DYNIX
3815         firstPartTemp += QString::fromLatin1("DYNIX/ptx");
3816 #elif defined Q_OS_FREEBSD
3817         firstPartTemp += QString::fromLatin1("FreeBSD");
3818 #elif defined Q_OS_HPUX
3819         firstPartTemp += QString::fromLatin1("HP-UX");
3820 #elif defined Q_OS_HURD
3821         firstPartTemp += QString::fromLatin1("GNU Hurd");
3822 #elif defined Q_OS_IRIX
3823         firstPartTemp += QString::fromLatin1("SGI Irix");
3824 #elif defined Q_OS_LINUX
3825 #if !defined(Q_WS_MAEMO_5) && !defined(Q_WS_MAEMO_6)
3826
3827 #if defined(__x86_64__)
3828         firstPartTemp += QString::fromLatin1("Linux x86_64");
3829 #elif defined(__i386__)
3830         firstPartTemp += QString::fromLatin1("Linux i686");
3831 #else
3832         firstPartTemp += QString::fromLatin1("Linux");
3833 #endif
3834 #endif
3835
3836 #elif defined Q_OS_LYNX
3837         firstPartTemp += QString::fromLatin1("LynxOS");
3838 #elif defined Q_OS_NETBSD
3839         firstPartTemp += QString::fromLatin1("NetBSD");
3840 #elif defined Q_OS_OS2
3841         firstPartTemp += QString::fromLatin1("OS/2");
3842 #elif defined Q_OS_OPENBSD
3843         firstPartTemp += QString::fromLatin1("OpenBSD");
3844 #elif defined Q_OS_OS2EMX
3845         firstPartTemp += QString::fromLatin1("OS/2");
3846 #elif defined Q_OS_OSF
3847         firstPartTemp += QString::fromLatin1("HP Tru64 UNIX");
3848 #elif defined Q_OS_QNX6
3849         firstPartTemp += QString::fromLatin1("QNX RTP Six");
3850 #elif defined Q_OS_QNX
3851         firstPartTemp += QString::fromLatin1("QNX");
3852 #elif defined Q_OS_RELIANT
3853         firstPartTemp += QString::fromLatin1("Reliant UNIX");
3854 #elif defined Q_OS_SCO
3855         firstPartTemp += QString::fromLatin1("SCO OpenServer");
3856 #elif defined Q_OS_SOLARIS
3857         firstPartTemp += QString::fromLatin1("Sun Solaris");
3858 #elif defined Q_OS_ULTRIX
3859         firstPartTemp += QString::fromLatin1("DEC Ultrix");
3860 #elif defined Q_OS_SYMBIAN
3861         firstPartTemp += QLatin1Char(' ');
3862         QSysInfo::S60Version s60Version = QSysInfo::s60Version();
3863         switch (s60Version) {
3864         case QSysInfo::SV_S60_3_1:
3865             firstPartTemp += QString::fromLatin1("Series60/3.1");
3866             break;
3867         case QSysInfo::SV_S60_3_2:
3868             firstPartTemp += QString::fromLatin1("Series60/3.2");
3869             break;
3870         case QSysInfo::SV_S60_5_0:
3871             firstPartTemp += QString::fromLatin1("Series60/5.0");
3872             break;
3873         default:
3874             break;
3875         }
3876 #elif defined Q_OS_UNIX
3877         firstPartTemp += QString::fromLatin1("UNIX BSD/SYSV system");
3878 #elif defined Q_OS_UNIXWARE
3879         firstPartTemp += QString::fromLatin1("UnixWare Seven, Open UNIX Eight");
3880 #else
3881         firstPartTemp += QString::fromLatin1("Unknown");
3882 #endif
3883
3884 #if USE(QT_MOBILITY_SYSTEMINFO)
3885         // adding Model Number
3886         QtMobility::QSystemDeviceInfo systemDeviceInfo;
3887
3888         QString model = systemDeviceInfo.model();
3889         if (!model.isEmpty()) {
3890             if (!firstPartTemp.endsWith("; "))
3891                 firstPartTemp += QString::fromLatin1("; ");
3892             firstPartTemp += systemDeviceInfo.model();
3893         }
3894 #endif
3895         firstPartTemp.squeeze();
3896         firstPart = firstPartTemp;
3897
3898         QString secondPartTemp;
3899         secondPartTemp.reserve(150);
3900         secondPartTemp += QString::fromLatin1(") ");
3901
3902         // webkit/qt version
3903         secondPartTemp += QString::fromLatin1("AppleWebKit/");
3904         secondPartTemp += qWebKitVersion();
3905         secondPartTemp += QString::fromLatin1(" (KHTML, like Gecko) ");
3906
3907
3908         // Application name split the third part
3909         secondPartTemp.squeeze();
3910         secondPart = secondPartTemp;
3911
3912         QString thirdPartTemp;
3913         thirdPartTemp.reserve(150);
3914 #if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
3915         thirdPartTemp += QLatin1String(" Mobile Safari/");
3916 #else
3917         thirdPartTemp += QLatin1String(" Safari/");
3918 #endif
3919         thirdPartTemp += qWebKitVersion();
3920         thirdPartTemp.squeeze();
3921         thirdPart = thirdPartTemp;
3922         Q_ASSERT(!firstPart.isNull());
3923         Q_ASSERT(!secondPart.isNull());
3924         Q_ASSERT(!thirdPart.isNull());
3925     }
3926
3927     // Application name/version
3928     QString appName = QCoreApplication::applicationName();
3929     if (!appName.isEmpty()) {
3930         QString appVer = QCoreApplication::applicationVersion();
3931         if (!appVer.isEmpty())
3932             appName.append(QLatin1Char('/') + appVer);
3933     } else {
3934         // Qt version
3935         appName = QString::fromLatin1("Qt/") + QString::fromLatin1(qVersion());
3936     }
3937
3938     return firstPart + secondPart + appName + thirdPart;
3939 }
3940
3941
3942 void QWebPagePrivate::_q_onLoadProgressChanged(int)
3943 {
3944     m_totalBytes = page->progress()->totalPageAndResourceBytesToLoad();
3945     m_bytesReceived = page->progress()->totalBytesReceived();
3946 }
3947
3948
3949 /*!
3950     Returns the total number of bytes that were received from the network to render the current page,
3951     including extra content such as embedded images.
3952
3953     \sa bytesReceived()
3954 */
3955 quint64 QWebPage::totalBytes() const
3956 {
3957     return d->m_totalBytes;
3958 }
3959
3960
3961 /*!
3962     Returns the number of bytes that were received from the network to render the current page.
3963
3964     \sa totalBytes(), loadProgress()
3965 */
3966 quint64 QWebPage::bytesReceived() const
3967 {
3968     return d->m_bytesReceived;
3969 }
3970
3971 /*!
3972     \since 4.7
3973     \fn void QWebPage::viewportChangeRequested()
3974
3975     Page authors can provide the supplied values by using the viewport meta tag. More information
3976     about this can be found at \l{http://developer.apple.com/safari/library/documentation/appleapplications/reference/safariwebcontent/usingtheviewport/usingtheviewport.html}{Safari Reference Library: Using the Viewport Meta Tag}.
3977
3978     \sa QWebPage::ViewportAttributes, setPreferredContentsSize(), QGraphicsWebView::setScale()
3979 */
3980
3981 /*!
3982     \fn void QWebPage::loadStarted()
3983
3984     This signal is emitted when a page starts loading content.
3985
3986     \sa loadFinished()
3987 */
3988
3989 /*!
3990     \fn void QWebPage::loadProgress(int progress)
3991
3992     This signal is emitted when the global progress status changes.
3993     The current value is provided by \a progress and scales from 0 to 100,
3994     which is the default range of QProgressBar.
3995     It accumulates changes from all the child frames.
3996
3997     \sa bytesReceived()
3998 */
3999
4000 /*!
4001     \fn void QWebPage::loadFinished(bool ok)
4002
4003     This signal is emitted when the page finishes loading content. This signal
4004     is independant of script execution or page rendering.
4005     \a ok will indicate whether the load was successful or any error occurred.
4006
4007     \sa loadStarted(), ErrorPageExtension
4008 */
4009
4010 /*!
4011     \fn void QWebPage::linkHovered(const QString &link, const QString &title, const QString &textContent)
4012
4013     This signal is emitted when the mouse hovers over a link.
4014
4015     \a link contains the link url.
4016     \a title is the link element's title, if it is specified in the markup.
4017     \a textContent provides text within the link element, e.g., text inside an HTML anchor tag.
4018
4019     When the mouse leaves the link element the signal is emitted with empty parameters.
4020
4021     \sa linkClicked()
4022 */
4023
4024 /*!
4025     \fn void QWebPage::statusBarMessage(const QString& text)
4026
4027     This signal is emitted when the statusbar \a text is changed by the page.
4028 */
4029
4030 /*!
4031     \fn void QWebPage::frameCreated(QWebFrame *frame)
4032
4033     This signal is emitted whenever the page creates a new \a frame.
4034
4035     \sa currentFrame()
4036 */
4037
4038 /*!
4039     \fn void QWebPage::selectionChanged()
4040
4041     This signal is emitted whenever the selection changes, either interactively
4042     or programmatically (e.g. by calling triggerAction() with a selection action).
4043
4044     \sa selectedText()
4045 */
4046
4047 /*!
4048     \fn void QWebPage::contentsChanged()
4049     \since 4.5
4050
4051     This signal is emitted whenever the text in form elements changes
4052     as well as other editable content.
4053
4054     \sa contentEditable, modified, QWebFrame::toHtml(), QWebFrame::toPlainText()
4055 */
4056
4057 /*!
4058     \fn void QWebPage::geometryChangeRequested(const QRect& geom)
4059
4060     This signal is emitted whenever the document wants to change the position and size of the
4061     page to \a geom. This can happen for example through JavaScript.
4062 */
4063
4064 /*!
4065     \fn void QWebPage::repaintRequested(const QRect& dirtyRect)
4066
4067     This signal is emitted whenever this QWebPage should be updated. It's useful
4068     when rendering a QWebPage without a QWebView or QGraphicsWebView.
4069     \a dirtyRect contains the area that needs to be updated. To paint the QWebPage get
4070     the mainFrame() and call the render(QPainter*, const QRegion&) method with the
4071     \a dirtyRect as the second parameter.
4072
4073     \sa mainFrame()
4074     \sa view()
4075 */
4076
4077 /*!
4078     \fn void QWebPage::scrollRequested(int dx, int dy, const QRect& rectToScroll)
4079
4080     This signal is emitted whenever the content given by \a rectToScroll needs
4081     to be scrolled \a dx and \a dy downwards and no view was set.
4082
4083     \sa view()
4084 */
4085
4086 /*!
4087     \fn void QWebPage::windowCloseRequested()
4088
4089     This signal is emitted whenever the page requests the web browser window to be closed,
4090     for example through the JavaScript \c{window.close()} call.
4091 */
4092
4093 /*!
4094     \fn void QWebPage::printRequested(QWebFrame *frame)
4095
4096     This signal is emitted whenever the page requests the web browser to print \a frame,
4097     for example through the JavaScript \c{window.print()} call.
4098
4099     \sa QWebFrame::print(), QPrintPreviewDialog
4100 */
4101
4102 /*!
4103     \fn void QWebPage::unsupportedContent(QNetworkReply *reply)
4104
4105     This signal is emitted when WebKit cannot handle a link the user navigated to or a
4106     web server's response includes a "Content-Disposition" header with the 'attachment' 
4107     directive. If "Content-Disposition" is present in \a reply, the web server is indicating
4108     that the client should prompt the user to save the content regardless of content-type. 
4109     See RFC 2616 sections 19.5.1 for details about Content-Disposition.
4110
4111     At signal emission time the meta-data of the QNetworkReply \a reply is available.
4112
4113     \note The receiving slot is responsible for deleting the QNetworkReply \a reply.
4114
4115     \note This signal is only emitted if the forwardUnsupportedContent property is set to true.
4116
4117     \sa downloadRequested()
4118 */
4119
4120 /*!
4121     \fn void QWebPage::downloadRequested(const QNetworkRequest &request)
4122
4123     This signal is emitted when the user decides to download a link. The url of
4124     the link as well as additional meta-information is contained in \a request.
4125
4126     \sa unsupportedContent()
4127 */
4128
4129 /*!
4130     \fn void QWebPage::microFocusChanged()
4131
4132     This signal is emitted when for example the position of the cursor in an editable form
4133     element changes. It is used to inform input methods about the new on-screen position where
4134     the user is able to enter text. This signal is usually connected to the
4135     QWidget::updateMicroFocus() slot.
4136 */
4137
4138 /*!
4139     \fn void QWebPage::linkClicked(const QUrl &url)
4140
4141     This signal is emitted whenever the user clicks on a link and the page's linkDelegationPolicy
4142     property is set to delegate the link handling for the specified \a url.
4143
4144     By default no links are delegated and are handled by QWebPage instead.
4145
4146     \note This signal possibly won't be emitted for clicked links which use
4147     JavaScript to trigger navigation.
4148
4149     \sa linkHovered()
4150 */
4151
4152 /*!
4153     \fn void QWebPage::toolBarVisibilityChangeRequested(bool visible)
4154
4155     This signal is emitted whenever the visibility of the toolbar in a web browser
4156     window that hosts QWebPage should be changed to \a visible.
4157 */
4158
4159 /*!
4160     \fn void QWebPage::statusBarVisibilityChangeRequested(bool visible)
4161
4162     This signal is emitted whenever the visibility of the statusbar in a web browser
4163     window that hosts QWebPage should be changed to \a visible.
4164 */
4165
4166 /*!
4167     \fn void QWebPage::menuBarVisibilityChangeRequested(bool visible)
4168
4169     This signal is emitted whenever the visibility of the menubar in a web browser
4170     window that hosts QWebPage should be changed to \a visible.
4171 */
4172
4173 /*!
4174     \fn void QWebPage::databaseQuotaExceeded(QWebFrame* frame, QString databaseName);
4175     \since 4.5
4176
4177     This signal is emitted whenever the web site shown in \a frame is asking to store data
4178     to the database \a databaseName and the quota allocated to that web site is exceeded.
4179
4180     \sa QWebDatabase
4181 */
4182 /*!
4183     \fn void QWebPage::applicationCacheQuotaExceeded(QWebSecurityOrigin* origin, quint64 defaultOriginQuota, quint64 totalSpaceNeeded);
4184
4185     This signal is emitted whenever the web site is asking to store data to the application cache
4186     database databaseName and the quota allocated to that web site is exceeded.
4187
4188 */
4189
4190 /*!
4191   \since 4.5
4192   \fn void QWebPage::saveFrameStateRequested(QWebFrame* frame, QWebHistoryItem* item);
4193
4194   This signal is emitted shortly before the history of navigated pages
4195   in \a frame is changed, for example when navigating back in the history.
4196
4197   The provided QWebHistoryItem, \a item, holds the history entry of the frame before
4198   the change.
4199
4200   A potential use-case for this signal is to store custom data in
4201   the QWebHistoryItem associated to the frame, using QWebHistoryItem::setUserData().
4202 */
4203
4204 /*!
4205   \since 4.5
4206   \fn void QWebPage::restoreFrameStateRequested(QWebFrame* frame);
4207
4208   This signal is emitted when the load of \a frame is finished and the application may now update its state accordingly.
4209 */
4210
4211 /*!
4212   \fn QWebPagePrivate* QWebPage::handle() const
4213   \internal
4214 */
4215
4216 #include "moc_qwebpage.cpp"