1/*
2    Copyright (C) 2010 Robert Hogan <robert@roberthogan.net>
3    Copyright (C) 2008,2009,2010 Nokia Corporation and/or its subsidiary(-ies)
4    Copyright (C) 2007 Staikos Computing Services Inc.
5    Copyright (C) 2007, 2012 Apple Inc.
6
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Library General Public
9    License as published by the Free Software Foundation; either
10    version 2 of the License, or (at your option) any later version.
11
12    This library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Library General Public License for more details.
16
17    You should have received a copy of the GNU Library General Public License
18    along with this library; see the file COPYING.LIB.  If not, write to
19    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.
21*/
22
23#include "config.h"
24#include "DumpRenderTreeSupportQt.h"
25
26#include "APICast.h"
27#include "ApplicationCacheStorage.h"
28#include "ChromeClientQt.h"
29#include "ContainerNode.h"
30#include "ContextMenu.h"
31#include "ContextMenuClientQt.h"
32#include "ContextMenuController.h"
33#include "DeviceOrientationClientMock.h"
34#include "DeviceOrientationController.h"
35#include "DeviceOrientationData.h"
36#include "DocumentLoader.h"
37#include "Editor.h"
38#include "EditorClientQt.h"
39#include "Element.h"
40#include "FocusController.h"
41#include "Font.h"
42#include "Frame.h"
43#include "FrameLoadRequest.h"
44#include "FrameLoaderClientQt.h"
45#include "FrameView.h"
46#include "GCController.h"
47#include "GeolocationClient.h"
48#include "GeolocationClientMock.h"
49#include "GeolocationController.h"
50#include "GeolocationError.h"
51#include "GeolocationPosition.h"
52#include "HTMLFormElement.h"
53#include "HTMLInputElement.h"
54#include "HistoryItem.h"
55#include "InspectorController.h"
56#include "JSNode.h"
57#include "NodeList.h"
58#include "NotificationPresenterClientQt.h"
59#include "Page.h"
60#include "PageGroup.h"
61#include "PluginDatabase.h"
62#include "PluginView.h"
63#include "PositionError.h"
64#include "PrintContext.h"
65#include "QWebFrameAdapter.h"
66#include "QWebPageAdapter.h"
67#include "RenderListItem.h"
68#include "RenderTreeAsText.h"
69#include "RuntimeEnabledFeatures.h"
70#include "SchemeRegistry.h"
71#include "ScriptController.h"
72#include "ScriptSourceCode.h"
73#include "ScriptValue.h"
74#include "SecurityOrigin.h"
75#include "SecurityPolicy.h"
76#include "Settings.h"
77#include "TextIterator.h"
78#include "ThirdPartyCookiesQt.h"
79#include "WebCoreTestSupport.h"
80#include "qt_runtime.h"
81#include "qwebelement.h"
82#include "qwebhistory.h"
83#include "qwebhistory_p.h"
84#include "qwebscriptworld.h"
85
86#if ENABLE(VIDEO) && USE(QT_MULTIMEDIA)
87#include "HTMLVideoElement.h"
88#include "MediaPlayerPrivateQt.h"
89#endif
90
91#include <QPainter>
92#include <wtf/CurrentTime.h>
93
94using namespace WebCore;
95
96QMap<int, QWebScriptWorld*> m_worldMap;
97
98#if ENABLE(GEOLOCATION)
99GeolocationClientMock* toGeolocationClientMock(GeolocationClient* client)
100{
101    ASSERT(QWebPageAdapter::drtRun);
102    return static_cast<GeolocationClientMock*>(client);
103}
104#endif
105
106#if ENABLE(DEVICE_ORIENTATION)
107DeviceOrientationClientMock* toDeviceOrientationClientMock(DeviceOrientationClient* client)
108{
109    ASSERT(QWebPageAdapter::drtRun);
110    return static_cast<DeviceOrientationClientMock*>(client);
111}
112#endif
113
114QDRTNode::QDRTNode()
115    : m_node(0)
116{
117}
118
119QDRTNode::QDRTNode(WebCore::Node* node)
120    : m_node(0)
121{
122    if (node) {
123        m_node = node;
124        m_node->ref();
125    }
126}
127
128QDRTNode::~QDRTNode()
129{
130    if (m_node)
131        m_node->deref();
132}
133
134QDRTNode::QDRTNode(const QDRTNode& other)
135    :m_node(other.m_node)
136{
137    if (m_node)
138        m_node->ref();
139}
140
141QDRTNode& QDRTNode::operator=(const QDRTNode& other)
142{
143    if (this != &other) {
144        Node* otherNode = other.m_node;
145        if (otherNode)
146            otherNode->ref();
147        if (m_node)
148            m_node->deref();
149        m_node = otherNode;
150    }
151    return *this;
152}
153
154QDRTNode QtDRTNodeRuntime::create(WebCore::Node* node)
155{
156    return QDRTNode(node);
157}
158
159WebCore::Node* QtDRTNodeRuntime::get(const QDRTNode& node)
160{
161    return node.m_node;
162}
163
164static QVariant convertJSValueToNodeVariant(JSC::JSObject* object, int *distance, HashSet<JSObjectRef>*)
165{
166    if (!object || !object->inherits(&JSNode::s_info))
167        return QVariant();
168    return QVariant::fromValue<QDRTNode>(QtDRTNodeRuntime::create((static_cast<JSNode*>(object))->impl()));
169}
170
171static JSC::JSValue convertNodeVariantToJSValue(JSC::ExecState* exec, WebCore::JSDOMGlobalObject* globalObject, const QVariant& variant)
172{
173    return toJS(exec, globalObject, QtDRTNodeRuntime::get(variant.value<QDRTNode>()));
174}
175
176void QtDRTNodeRuntime::initialize()
177{
178    static bool initialized = false;
179    if (initialized)
180        return;
181    initialized = true;
182    int id = qRegisterMetaType<QDRTNode>();
183    JSC::Bindings::registerCustomType(id, convertJSValueToNodeVariant, convertNodeVariantToJSValue);
184}
185
186DumpRenderTreeSupportQt::DumpRenderTreeSupportQt()
187{
188}
189
190DumpRenderTreeSupportQt::~DumpRenderTreeSupportQt()
191{
192}
193
194void DumpRenderTreeSupportQt::initialize()
195{
196    QtDRTNodeRuntime::initialize();
197}
198
199void DumpRenderTreeSupportQt::overwritePluginDirectories()
200{
201    PluginDatabase* db = PluginDatabase::installedPlugins(/* populate */ false);
202
203    Vector<String> paths;
204    String qtPath(qgetenv("QTWEBKIT_PLUGIN_PATH").data());
205    qtPath.split(UChar(':'), /* allowEmptyEntries */ false, paths);
206
207    db->setPluginDirectories(paths);
208    db->refresh();
209}
210
211void DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(bool b)
212{
213    QWebPageAdapter::drtRun = b;
214#if ENABLE(NETSCAPE_PLUGIN_API) && defined(XP_UNIX)
215    // PluginViewQt (X11) needs a few workarounds when running under DRT
216    PluginView::setIsRunningUnderDRT(b);
217#endif
218}
219
220void DumpRenderTreeSupportQt::setFrameFlatteningEnabled(QWebPageAdapter* adapter, bool enabled)
221{
222    adapter->page->settings()->setFrameFlatteningEnabled(enabled);
223}
224
225void DumpRenderTreeSupportQt::webPageSetGroupName(QWebPageAdapter *adapter, const QString& groupName)
226{
227    adapter->page->setGroupName(groupName);
228}
229
230QString DumpRenderTreeSupportQt::webPageGroupName(QWebPageAdapter* adapter)
231{
232    return adapter->page->groupName();
233}
234
235void DumpRenderTreeSupportQt::webInspectorExecuteScript(QWebPageAdapter* adapter, long callId, const QString& script)
236{
237#if ENABLE(INSPECTOR)
238    if (!adapter->page->inspectorController())
239        return;
240    adapter->page->inspectorController()->evaluateForTestInFrontend(callId, script);
241#endif
242}
243
244void DumpRenderTreeSupportQt::webInspectorShow(QWebPageAdapter* adapter)
245{
246#if ENABLE(INSPECTOR)
247    if (!adapter->page->inspectorController())
248        return;
249    adapter->page->inspectorController()->show();
250#endif
251}
252
253void DumpRenderTreeSupportQt::webInspectorClose(QWebPageAdapter* adapter)
254{
255#if ENABLE(INSPECTOR)
256    if (!adapter->page->inspectorController())
257        return;
258    adapter->page->inspectorController()->close();
259#endif
260}
261
262bool DumpRenderTreeSupportQt::hasDocumentElement(QWebFrameAdapter *adapter)
263{
264    return adapter->frame->document()->documentElement();
265}
266
267void DumpRenderTreeSupportQt::setValueForUser(const QWebElement& element, const QString& value)
268{
269    WebCore::Element* webElement = element.m_element;
270    if (!webElement)
271        return;
272    HTMLInputElement* inputElement = webElement->toInputElement();
273    if (!inputElement)
274        return;
275
276    inputElement->setValueForUser(value);
277}
278
279void DumpRenderTreeSupportQt::clearFrameName(QWebFrameAdapter *adapter)
280{
281    Frame* coreFrame = adapter->frame;
282    coreFrame->tree()->clearName();
283}
284
285int DumpRenderTreeSupportQt::javaScriptObjectsCount()
286{
287    return JSDOMWindowBase::commonVM()->heap.globalObjectCount();
288}
289
290void DumpRenderTreeSupportQt::garbageCollectorCollect()
291{
292    gcController().garbageCollectNow();
293}
294
295void DumpRenderTreeSupportQt::garbageCollectorCollectOnAlternateThread(bool waitUntilDone)
296{
297    gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
298}
299
300void DumpRenderTreeSupportQt::whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
301{
302    SecurityPolicy::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
303}
304
305void DumpRenderTreeSupportQt::removeWhiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
306{
307    SecurityPolicy::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
308}
309
310void DumpRenderTreeSupportQt::resetOriginAccessWhiteLists()
311{
312    SecurityPolicy::resetOriginAccessWhitelists();
313}
314
315void DumpRenderTreeSupportQt::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme)
316{
317    SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
318}
319
320void DumpRenderTreeSupportQt::setCaretBrowsingEnabled(QWebPageAdapter* adapter, bool value)
321{
322    adapter->page->settings()->setCaretBrowsingEnabled(value);
323}
324
325void DumpRenderTreeSupportQt::setAuthorAndUserStylesEnabled(QWebPageAdapter* adapter, bool value)
326{
327    adapter->page->settings()->setAuthorAndUserStylesEnabled(value);
328}
329
330void DumpRenderTreeSupportQt::executeCoreCommandByName(QWebPageAdapter* adapter, const QString& name, const QString& value)
331{
332    adapter->page->focusController()->focusedOrMainFrame()->editor().command(name).execute(value);
333}
334
335bool DumpRenderTreeSupportQt::isCommandEnabled(QWebPageAdapter *adapter, const QString& name)
336{
337    return adapter->page->focusController()->focusedOrMainFrame()->editor().command(name).isEnabled();
338}
339
340QVariantList DumpRenderTreeSupportQt::selectedRange(QWebPageAdapter *adapter)
341{
342    WebCore::Frame* frame = adapter->page->focusController()->focusedOrMainFrame();
343    QVariantList selectedRange;
344    RefPtr<Range> range = frame->selection()->toNormalizedRange().get();
345
346    Element* selectionRoot = frame->selection()->rootEditableElement();
347    Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
348
349    RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
350    ASSERT(testRange->startContainer() == scope);
351    int startPosition = TextIterator::rangeLength(testRange.get());
352
353    ExceptionCode ec;
354    testRange->setEnd(range->endContainer(), range->endOffset(), ec);
355    ASSERT(testRange->startContainer() == scope);
356    int endPosition = TextIterator::rangeLength(testRange.get());
357
358    selectedRange << startPosition << (endPosition - startPosition);
359
360    return selectedRange;
361
362}
363
364QVariantList DumpRenderTreeSupportQt::firstRectForCharacterRange(QWebPageAdapter *adapter, int location, int length)
365{
366    WebCore::Frame* frame = adapter->page->focusController()->focusedOrMainFrame();
367    QVariantList rect;
368
369    if ((location + length < location) && (location + length))
370        length = 0;
371
372    RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(frame->selection()->rootEditableElementOrDocumentElement(), location, length);
373
374    if (!range)
375        return QVariantList();
376
377    QRect resultRect = frame->editor().firstRectForRange(range.get());
378    rect << resultRect.x() << resultRect.y() << resultRect.width() << resultRect.height();
379    return rect;
380}
381
382void DumpRenderTreeSupportQt::setWindowsBehaviorAsEditingBehavior(QWebPageAdapter* adapter)
383{
384    Page* corePage = adapter->page;
385    if (!corePage)
386        return;
387    corePage->settings()->setEditingBehaviorType(EditingWindowsBehavior);
388}
389
390void DumpRenderTreeSupportQt::clearAllApplicationCaches()
391{
392    WebCore::cacheStorage().empty();
393    WebCore::cacheStorage().vacuumDatabaseFile();
394}
395
396void DumpRenderTreeSupportQt::dumpFrameLoader(bool b)
397{
398    FrameLoaderClientQt::dumpFrameLoaderCallbacks = b;
399}
400
401void DumpRenderTreeSupportQt::dumpProgressFinishedCallback(bool b)
402{
403    FrameLoaderClientQt::dumpProgressFinishedCallback = b;
404}
405
406void DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(bool b)
407{
408    FrameLoaderClientQt::dumpUserGestureInFrameLoaderCallbacks = b;
409}
410
411void DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(bool b)
412{
413    FrameLoaderClientQt::dumpResourceLoadCallbacks = b;
414}
415
416void DumpRenderTreeSupportQt::dumpResourceLoadCallbacksPath(const QString& path)
417{
418    FrameLoaderClientQt::dumpResourceLoadCallbacksPath = path;
419}
420
421void DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(bool b)
422{
423    FrameLoaderClientQt::dumpResourceResponseMIMETypes = b;
424}
425
426void DumpRenderTreeSupportQt::dumpWillCacheResponseCallbacks(bool b)
427{
428    FrameLoaderClientQt::dumpWillCacheResponseCallbacks = b;
429}
430
431void DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(bool b)
432{
433    FrameLoaderClientQt::sendRequestReturnsNullOnRedirect = b;
434}
435
436void DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(bool b)
437{
438    FrameLoaderClientQt::sendRequestReturnsNull = b;
439}
440
441void DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(const QStringList& headers)
442{
443    FrameLoaderClientQt::sendRequestClearHeaders = headers;
444}
445
446void DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(bool b)
447{
448    FrameLoaderClientQt::deferMainResourceDataLoad = b;
449}
450
451void DumpRenderTreeSupportQt::setCustomPolicyDelegate(bool enabled, bool permissive)
452{
453    FrameLoaderClientQt::policyDelegateEnabled = enabled;
454    FrameLoaderClientQt::policyDelegatePermissive = permissive;
455}
456
457void DumpRenderTreeSupportQt::dumpHistoryCallbacks(bool b)
458{
459    FrameLoaderClientQt::dumpHistoryCallbacks = b;
460}
461
462void DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(bool b)
463{
464    ChromeClientQt::dumpVisitedLinksCallbacks = b;
465}
466
467void DumpRenderTreeSupportQt::dumpEditingCallbacks(bool b)
468{
469    EditorClientQt::dumpEditingCallbacks = b;
470}
471
472void DumpRenderTreeSupportQt::dumpSetAcceptsEditing(bool b)
473{
474    EditorClientQt::acceptsEditing = b;
475}
476
477void DumpRenderTreeSupportQt::dumpNotification(bool b)
478{
479#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
480    NotificationPresenterClientQt::dumpNotification = b;
481#endif
482}
483
484QString DumpRenderTreeSupportQt::viewportAsText(QWebPageAdapter* adapter, int deviceDPI, const QSize& deviceSize, const QSize& availableSize)
485{
486    WebCore::ViewportArguments args = adapter->viewportArguments();
487
488    float devicePixelRatio = deviceDPI / WebCore::ViewportArguments::deprecatedTargetDPI;
489    WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(args,
490        /* desktop-width    */980,
491        /* device-width     */deviceSize.width(),
492        /* device-height    */deviceSize.height(),
493        devicePixelRatio,
494        availableSize);
495    WebCore::restrictMinimumScaleFactorToViewportSize(conf, availableSize, devicePixelRatio);
496    WebCore::restrictScaleFactorToInitialScaleIfNotUserScalable(conf);
497
498    QString res;
499    res = res.sprintf("viewport size %dx%d scale %f with limits [%f, %f] and userScalable %f\n",
500        static_cast<int>(conf.layoutSize.width()),
501        static_cast<int>(conf.layoutSize.height()),
502        conf.initialScale,
503        conf.minimumScale,
504        conf.maximumScale,
505        conf.userScalable);
506
507    return res;
508}
509
510void DumpRenderTreeSupportQt::scalePageBy(QWebFrameAdapter* adapter, float scalefactor, const QPoint& origin)
511{
512    WebCore::Frame* coreFrame = adapter->frame;
513    if (Page* page = coreFrame->page())
514        page->setPageScaleFactor(scalefactor, origin);
515}
516
517void DumpRenderTreeSupportQt::setMockDeviceOrientation(QWebPageAdapter* adapter, bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
518{
519#if ENABLE(DEVICE_ORIENTATION)
520    Page* corePage = adapter->page;
521    DeviceOrientationClientMock* mockClient = toDeviceOrientationClientMock(DeviceOrientationController::from(corePage)->deviceOrientationClient());
522    mockClient->setOrientation(DeviceOrientationData::create(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma));
523#endif
524}
525
526void DumpRenderTreeSupportQt::resetGeolocationMock(QWebPageAdapter* adapter)
527{
528#if ENABLE(GEOLOCATION)
529    Page* corePage = adapter->page;
530    GeolocationClientMock* mockClient = toGeolocationClientMock(GeolocationController::from(corePage)->client());
531    mockClient->reset();
532#endif
533}
534
535void DumpRenderTreeSupportQt::setMockGeolocationPermission(QWebPageAdapter* adapter, bool allowed)
536{
537#if ENABLE(GEOLOCATION)
538    Page* corePage = adapter->page;
539    GeolocationClientMock* mockClient = toGeolocationClientMock(GeolocationController::from(corePage)->client());
540    mockClient->setPermission(allowed);
541#endif
542}
543
544void DumpRenderTreeSupportQt::setMockGeolocationPosition(QWebPageAdapter* adapter, double latitude, double longitude, double accuracy)
545{
546#if ENABLE(GEOLOCATION)
547    Page* corePage = adapter->page;
548    GeolocationClientMock* mockClient = toGeolocationClientMock(GeolocationController::from(corePage)->client());
549    mockClient->setPosition(GeolocationPosition::create(currentTime(), latitude, longitude, accuracy));
550#endif
551}
552
553void DumpRenderTreeSupportQt::setMockGeolocationPositionUnavailableError(QWebPageAdapter* adapter, const QString& message)
554{
555#if ENABLE(GEOLOCATION)
556    Page* corePage = adapter->page;
557    GeolocationClientMock* mockClient = static_cast<GeolocationClientMock*>(GeolocationController::from(corePage)->client());
558    mockClient->setPositionUnavailableError(message);
559#endif
560}
561
562int DumpRenderTreeSupportQt::numberOfPendingGeolocationPermissionRequests(QWebPageAdapter* adapter)
563{
564#if ENABLE(GEOLOCATION)
565    Page* corePage = adapter->page;
566    GeolocationClientMock* mockClient = toGeolocationClientMock(GeolocationController::from(corePage)->client());
567    return mockClient->numberOfPendingPermissionRequests();
568#else
569    return -1;
570#endif
571}
572
573bool DumpRenderTreeSupportQt::isTargetItem(const QWebHistoryItem& historyItem)
574{
575    QWebHistoryItem it = historyItem;
576    if (QWebHistoryItemPrivate::core(&it)->isTargetItem())
577        return true;
578    return false;
579}
580
581QString DumpRenderTreeSupportQt::historyItemTarget(const QWebHistoryItem& historyItem)
582{
583    QWebHistoryItem it = historyItem;
584    return (QWebHistoryItemPrivate::core(&it)->target());
585}
586
587QMap<QString, QWebHistoryItem> DumpRenderTreeSupportQt::getChildHistoryItems(const QWebHistoryItem& historyItem)
588{
589    QWebHistoryItem it = historyItem;
590    HistoryItem* item = QWebHistoryItemPrivate::core(&it);
591    const WebCore::HistoryItemVector& children = item->children();
592
593    unsigned size = children.size();
594    QMap<QString, QWebHistoryItem> kids;
595    for (unsigned i = 0; i < size; ++i) {
596        QWebHistoryItem kid(new QWebHistoryItemPrivate(children[i].get()));
597        kids.insert(DumpRenderTreeSupportQt::historyItemTarget(kid), kid);
598    }
599    return kids;
600}
601
602bool DumpRenderTreeSupportQt::shouldClose(QWebFrameAdapter *adapter)
603{
604    WebCore::Frame* coreFrame = adapter->frame;
605    return coreFrame->loader()->shouldClose();
606}
607
608void DumpRenderTreeSupportQt::clearScriptWorlds()
609{
610    m_worldMap.clear();
611}
612
613void DumpRenderTreeSupportQt::evaluateScriptInIsolatedWorld(QWebFrameAdapter *adapter, int worldID, const QString& script)
614{
615    QWebScriptWorld* scriptWorld;
616    if (!worldID) {
617        scriptWorld = new QWebScriptWorld();
618    } else if (!m_worldMap.contains(worldID)) {
619        scriptWorld = new QWebScriptWorld();
620        m_worldMap.insert(worldID, scriptWorld);
621    } else
622        scriptWorld = m_worldMap.value(worldID);
623
624    WebCore::Frame* coreFrame = adapter->frame;
625
626    ScriptController* proxy = coreFrame->script();
627
628    if (!proxy)
629        return;
630    proxy->executeScriptInWorld(scriptWorld->world(), script, true);
631}
632
633void DumpRenderTreeSupportQt::addUserStyleSheet(QWebPageAdapter* adapter, const QString& sourceCode)
634{
635    adapter->page->group().addUserStyleSheetToWorld(mainThreadNormalWorld(), sourceCode, QUrl(), Vector<String>(), Vector<String>(), WebCore::InjectInAllFrames);
636}
637
638void DumpRenderTreeSupportQt::removeUserStyleSheets(QWebPageAdapter* adapter)
639{
640    adapter->page->group().removeUserStyleSheetsFromWorld(mainThreadNormalWorld());
641}
642
643void DumpRenderTreeSupportQt::simulateDesktopNotificationClick(const QString& title)
644{
645#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
646    NotificationPresenterClientQt::notificationPresenter()->notificationClicked(title);
647#endif
648}
649
650void DumpRenderTreeSupportQt::setDefersLoading(QWebPageAdapter* adapter, bool flag)
651{
652    Page* corePage = adapter->page;
653    if (corePage)
654        corePage->setDefersLoading(flag);
655}
656
657void DumpRenderTreeSupportQt::goBack(QWebPageAdapter* adapter)
658{
659    Page* corePage = adapter->page;
660    if (corePage)
661        corePage->goBack();
662}
663
664// API Candidate?
665QString DumpRenderTreeSupportQt::responseMimeType(QWebFrameAdapter* adapter)
666{
667    WebCore::Frame* coreFrame = adapter->frame;
668    WebCore::DocumentLoader* docLoader = coreFrame->loader()->documentLoader();
669    return docLoader->responseMIMEType();
670}
671
672void DumpRenderTreeSupportQt::clearOpener(QWebFrameAdapter* adapter)
673{
674    WebCore::Frame* coreFrame = adapter->frame;
675    coreFrame->loader()->setOpener(0);
676}
677
678void DumpRenderTreeSupportQt::addURLToRedirect(const QString& origin, const QString& destination)
679{
680    FrameLoaderClientQt::URLsToRedirect[origin] = destination;
681}
682
683void DumpRenderTreeSupportQt::setInteractiveFormValidationEnabled(QWebPageAdapter* adapter, bool enable)
684{
685    Page* corePage = adapter->page;
686    if (corePage)
687        corePage->settings()->setInteractiveFormValidationEnabled(enable);
688}
689
690QStringList DumpRenderTreeSupportQt::contextMenu(QWebPageAdapter* page)
691{
692    return page->menuActionsAsText();
693}
694
695bool DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(QWebPageAdapter *adapter, const QUrl& url, const QUrl& firstPartyUrl)
696{
697    Page* corePage = adapter->page;
698    return thirdPartyCookiePolicyPermits(corePage->mainFrame()->loader()->networkingContext(), url, firstPartyUrl);
699}
700
701void DumpRenderTreeSupportQt::enableMockScrollbars()
702{
703    Settings::setMockScrollbarsEnabled(true);
704}
705
706QUrl DumpRenderTreeSupportQt::mediaContentUrlByElementId(QWebFrameAdapter* adapter, const QString& elementId)
707{
708    QUrl res;
709
710#if ENABLE(VIDEO) && USE(QT_MULTIMEDIA)
711    Frame* coreFrame = adapter->frame;
712    if (!coreFrame)
713        return res;
714
715    Document* doc = coreFrame->document();
716    if (!doc)
717        return res;
718
719    Node* coreNode = doc->getElementById(elementId);
720    if (!coreNode)
721        return res;
722
723    HTMLVideoElement* videoElement = static_cast<HTMLVideoElement*>(coreNode);
724    PlatformMedia platformMedia = videoElement->platformMedia();
725    if (platformMedia.type != PlatformMedia::QtMediaPlayerType)
726        return res;
727
728    MediaPlayerPrivateQt* mediaPlayerQt = static_cast<MediaPlayerPrivateQt*>(platformMedia.media.qtMediaPlayer);
729    if (mediaPlayerQt && mediaPlayerQt->mediaPlayer())
730        res = mediaPlayerQt->mediaPlayer()->media().canonicalUrl();
731#endif
732
733    return res;
734}
735
736// API Candidate?
737void DumpRenderTreeSupportQt::setAlternateHtml(QWebFrameAdapter* adapter, const QString& html, const QUrl& baseUrl, const QUrl& failingUrl)
738{
739    KURL kurl(baseUrl);
740    WebCore::Frame* coreFrame = adapter->frame;
741    WebCore::ResourceRequest request(kurl);
742    const QByteArray utf8 = html.toUtf8();
743    WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(utf8.constData(), utf8.length());
744    WebCore::SubstituteData substituteData(data, WTF::String("text/html"), WTF::String("utf-8"), failingUrl);
745    coreFrame->loader()->load(WebCore::FrameLoadRequest(coreFrame, request, substituteData));
746}
747
748void DumpRenderTreeSupportQt::confirmComposition(QWebPageAdapter *adapter, const char* text)
749{
750    Frame* frame = adapter->page->focusController()->focusedOrMainFrame();
751    if (!frame)
752        return;
753
754    Editor& editor = frame->editor();
755    if (!editor.hasComposition() && !text)
756        return;
757
758    if (editor.hasComposition()) {
759        if (text)
760            editor.confirmComposition(String::fromUTF8(text));
761        else
762            editor.confirmComposition();
763    } else
764        editor.insertText(String::fromUTF8(text), 0);
765}
766
767void DumpRenderTreeSupportQt::injectInternalsObject(QWebFrameAdapter* adapter)
768{
769    WebCore::Frame* coreFrame = adapter->frame;
770    JSDOMWindow* window = toJSDOMWindow(coreFrame, mainThreadNormalWorld());
771    Q_ASSERT(window);
772
773    JSC::ExecState* exec = window->globalExec();
774    Q_ASSERT(exec);
775    JSC::JSLockHolder lock(exec);
776
777    JSContextRef context = toRef(exec);
778    WebCoreTestSupport::injectInternalsObject(context);
779}
780
781void DumpRenderTreeSupportQt::injectInternalsObject(JSContextRef context)
782{
783    WebCoreTestSupport::injectInternalsObject(context);
784}
785
786void DumpRenderTreeSupportQt::resetInternalsObject(QWebFrameAdapter* adapter)
787{
788    WebCore::Frame* coreFrame = adapter->frame;
789    JSDOMWindow* window = toJSDOMWindow(coreFrame, mainThreadNormalWorld());
790    Q_ASSERT(window);
791
792    JSC::ExecState* exec = window->globalExec();
793    Q_ASSERT(exec);
794    JSC::JSLockHolder lock(exec);
795
796    JSContextRef context = toRef(exec);
797    WebCoreTestSupport::resetInternalsObject(context);
798}
799
800void DumpRenderTreeSupportQt::resetInternalsObject(JSContextRef context)
801{
802    WebCoreTestSupport::resetInternalsObject(context);
803}
804
805QImage DumpRenderTreeSupportQt::paintPagesWithBoundaries(QWebFrameAdapter* adapter)
806{
807    Frame* frame = adapter->frame;
808    PrintContext printContext(frame);
809
810    QRect rect = frame->view()->frameRect();
811
812    IntRect pageRect(0, 0, rect.width(), rect.height());
813
814    printContext.begin(pageRect.width(), pageRect.height());
815    float pageHeight = 0;
816    printContext.computePageRects(pageRect, /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight);
817
818    QPainter painter;
819    int pageCount = printContext.pageCount();
820    // pages * pageHeight and 1px line between each page
821    int totalHeight = pageCount * (pageRect.height() + 1) - 1;
822    QImage image(pageRect.width(), totalHeight, QImage::Format_ARGB32);
823    image.fill(Qt::white);
824    painter.begin(&image);
825
826    GraphicsContext ctx(&painter);
827    for (int i = 0; i < printContext.pageCount(); ++i) {
828        printContext.spoolPage(ctx, i, pageRect.width());
829        // translate to next page coordinates
830        ctx.translate(0, pageRect.height() + 1);
831
832        // if there is a next page, draw a blue line between these two
833        if (i + 1 < printContext.pageCount()) {
834            ctx.save();
835            ctx.setStrokeColor(Color(0, 0, 255), ColorSpaceDeviceRGB);
836            ctx.setFillColor(Color(0, 0, 255), ColorSpaceDeviceRGB);
837            ctx.drawLine(IntPoint(0, -1), IntPoint(pageRect.width(), -1));
838            ctx.restore();
839        }
840    }
841
842    painter.end();
843    printContext.end();
844
845    return image;
846}
847
848void DumpRenderTreeSupportQt::setTrackRepaintRects(QWebFrameAdapter* adapter, bool enable)
849{
850    adapter->frame->view()->setTracksRepaints(enable);
851}
852
853bool DumpRenderTreeSupportQt::trackRepaintRects(QWebFrameAdapter* adapter)
854{
855    return adapter->frame->view()->isTrackingRepaints();
856}
857
858void DumpRenderTreeSupportQt::getTrackedRepaintRects(QWebFrameAdapter* adapter, QVector<QRect>& result)
859{
860    Frame* coreFrame = adapter->frame;
861    const Vector<IntRect>& rects = coreFrame->view()->trackedRepaintRects();
862    result.resize(rects.size());
863    for (size_t i = 0; i < rects.size(); ++i)
864        result.append(rects[i]);
865}
866
867void DumpRenderTreeSupportQt::setSeamlessIFramesEnabled(bool enabled)
868{
869#if ENABLE(IFRAME_SEAMLESS)
870    WebCore::RuntimeEnabledFeatures::setSeamlessIFramesEnabled(enabled);
871#else
872    UNUSED_PARAM(enabled);
873#endif
874}
875
876void DumpRenderTreeSupportQt::setShouldUseFontSmoothing(bool enabled)
877{
878    WebCore::Font::setShouldUseSmoothing(enabled);
879}
880
881QString DumpRenderTreeSupportQt::frameRenderTreeDump(QWebFrameAdapter* adapter)
882{
883    if (adapter->frame->view() && adapter->frame->view()->layoutPending())
884        adapter->frame->view()->layout();
885
886    return externalRepresentation(adapter->frame);
887}
888
889void DumpRenderTreeSupportQt::clearNotificationPermissions()
890{
891#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
892    WebCore::NotificationPresenterClientQt::notificationPresenter()->clearCachedPermissions();
893#endif
894}
895
896void DumpRenderTreeSupportQt::disableDefaultTypesettingFeatures()
897{
898    WebCore::Font::setDefaultTypesettingFeatures(0);
899}
900
901void DumpRenderTreeSupportQt::getJSWindowObject(QWebFrameAdapter* adapter, JSContextRef* context, JSObjectRef* object)
902{
903    JSDOMWindow* window = toJSDOMWindow(adapter->frame, mainThreadNormalWorld());
904    *object = toRef(window);
905    *context = toRef(window->globalExec());
906}
907