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 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 "ApplicationCacheStorage.h"
27#include "CSSComputedStyleDeclaration.h"
28#include "ChromeClientQt.h"
29#include "ContainerNode.h"
30#include "ContextMenu.h"
31#include "ContextMenuClientQt.h"
32#include "ContextMenuController.h"
33#include "DeviceOrientation.h"
34#include "DeviceOrientationClientMockQt.h"
35#include "DocumentLoader.h"
36#include "Editor.h"
37#include "EditorClientQt.h"
38#include "Element.h"
39#include "FocusController.h"
40#include "Frame.h"
41#include "FrameLoaderClientQt.h"
42#include "FrameView.h"
43#if USE(JSC)
44#include "GCController.h"
45#elif USE(V8)
46#include "V8GCController.h"
47#include "V8Proxy.h"
48#endif
49#include "GeolocationClient.h"
50#include "GeolocationClientMock.h"
51#include "GeolocationController.h"
52#include "GeolocationError.h"
53#include "GeolocationPosition.h"
54#include "HistoryItem.h"
55#include "HTMLInputElement.h"
56#include "InspectorController.h"
57#include "NodeList.h"
58#include "NotificationPresenterClientQt.h"
59#include "Page.h"
60#include "PageGroup.h"
61#include "PluginDatabase.h"
62#include "PositionError.h"
63#include "PrintContext.h"
64#include "RenderListItem.h"
65#include "RenderTreeAsText.h"
66#include "ScriptController.h"
67#include "SecurityOrigin.h"
68#include "Settings.h"
69#if ENABLE(SVG)
70#include "SVGDocumentExtensions.h"
71#include "SVGSMILElement.h"
72#endif
73#include "TextIterator.h"
74#include "WorkerThread.h"
75#include <wtf/CurrentTime.h>
76
77#include "qwebelement.h"
78#include "qwebframe.h"
79#include "qwebframe_p.h"
80#include "qwebhistory.h"
81#include "qwebhistory_p.h"
82#include "qwebpage.h"
83#include "qwebpage_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
91using namespace WebCore;
92
93QMap<int, QWebScriptWorld*> m_worldMap;
94
95#if ENABLE(CLIENT_BASED_GEOLOCATION)
96GeolocationClientMock* toGeolocationClientMock(GeolocationClient* client)
97{
98     ASSERT(QWebPagePrivate::drtRun);
99     return static_cast<GeolocationClientMock*>(client);
100}
101#endif
102
103QDRTNode::QDRTNode()
104    : m_node(0)
105{
106}
107
108QDRTNode::QDRTNode(WebCore::Node* node)
109    : m_node(0)
110{
111    if (node) {
112        m_node = node;
113        m_node->ref();
114    }
115}
116
117QDRTNode::~QDRTNode()
118{
119    if (m_node)
120        m_node->deref();
121}
122
123QDRTNode::QDRTNode(const QDRTNode& other)
124    :m_node(other.m_node)
125{
126    if (m_node)
127        m_node->ref();
128}
129
130QDRTNode& QDRTNode::operator=(const QDRTNode& other)
131{
132    if (this != &other) {
133        Node* otherNode = other.m_node;
134        if (otherNode)
135            otherNode->ref();
136        if (m_node)
137            m_node->deref();
138        m_node = otherNode;
139    }
140    return *this;
141}
142
143
144DumpRenderTreeSupportQt::DumpRenderTreeSupportQt()
145{
146}
147
148DumpRenderTreeSupportQt::~DumpRenderTreeSupportQt()
149{
150}
151
152void DumpRenderTreeSupportQt::overwritePluginDirectories()
153{
154    PluginDatabase* db = PluginDatabase::installedPlugins(/* populate */ false);
155
156    Vector<String> paths;
157    String qtPath(qgetenv("QTWEBKIT_PLUGIN_PATH").data());
158    qtPath.split(UChar(':'), /* allowEmptyEntries */ false, paths);
159
160    db->setPluginDirectories(paths);
161    db->refresh();
162}
163
164int DumpRenderTreeSupportQt::workerThreadCount()
165{
166#if ENABLE(WORKERS)
167    return WebCore::WorkerThread::workerThreadCount();
168#else
169    return 0;
170#endif
171}
172
173void DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(bool b)
174{
175    QWebPagePrivate::drtRun = b;
176}
177
178void DumpRenderTreeSupportQt::setFrameFlatteningEnabled(QWebPage* page, bool enabled)
179{
180    QWebPagePrivate::core(page)->settings()->setFrameFlatteningEnabled(enabled);
181}
182
183void DumpRenderTreeSupportQt::webPageSetGroupName(QWebPage* page, const QString& groupName)
184{
185    page->handle()->page->setGroupName(groupName);
186}
187
188QString DumpRenderTreeSupportQt::webPageGroupName(QWebPage* page)
189{
190    return page->handle()->page->groupName();
191}
192
193void DumpRenderTreeSupportQt::webInspectorExecuteScript(QWebPage* page, long callId, const QString& script)
194{
195#if ENABLE(INSPECTOR)
196    if (!page->handle()->page->inspectorController())
197        return;
198    page->handle()->page->inspectorController()->evaluateForTestInFrontend(callId, script);
199#endif
200}
201
202void DumpRenderTreeSupportQt::webInspectorClose(QWebPage* page)
203{
204#if ENABLE(INSPECTOR)
205    if (!page->handle()->page->inspectorController())
206        return;
207    page->handle()->page->inspectorController()->close();
208#endif
209}
210
211void DumpRenderTreeSupportQt::webInspectorShow(QWebPage* page)
212{
213#if ENABLE(INSPECTOR)
214    if (!page->handle()->page->inspectorController())
215        return;
216    page->handle()->page->inspectorController()->show();
217#endif
218}
219
220void DumpRenderTreeSupportQt::setTimelineProfilingEnabled(QWebPage* page, bool enabled)
221{
222#if ENABLE(INSPECTOR)
223    InspectorController* controller = page->handle()->page->inspectorController();
224    if (!controller)
225        return;
226    if (enabled)
227        controller->startTimelineProfiler();
228    else
229        controller->stopTimelineProfiler();
230#endif
231}
232
233bool DumpRenderTreeSupportQt::hasDocumentElement(QWebFrame* frame)
234{
235    return QWebFramePrivate::core(frame)->document()->documentElement();
236}
237
238void DumpRenderTreeSupportQt::setJavaScriptProfilingEnabled(QWebFrame* frame, bool enabled)
239{
240#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
241    Frame* coreFrame = QWebFramePrivate::core(frame);
242    InspectorController* controller = coreFrame->page()->inspectorController();
243    if (!controller)
244        return;
245    if (enabled)
246        controller->enableProfiler();
247    else
248        controller->disableProfiler();
249#endif
250}
251
252// Pause a given CSS animation or transition on the target node at a specific time.
253// If the animation or transition is already paused, it will update its pause time.
254// This method is only intended to be used for testing the CSS animation and transition system.
255bool DumpRenderTreeSupportQt::pauseAnimation(QWebFrame *frame, const QString &animationName, double time, const QString &elementId)
256{
257    Frame* coreFrame = QWebFramePrivate::core(frame);
258    if (!coreFrame)
259        return false;
260
261    AnimationController* controller = coreFrame->animation();
262    if (!controller)
263        return false;
264
265    Document* doc = coreFrame->document();
266    Q_ASSERT(doc);
267
268    Node* coreNode = doc->getElementById(elementId);
269    if (!coreNode || !coreNode->renderer())
270        return false;
271
272    return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time);
273}
274
275bool DumpRenderTreeSupportQt::pauseTransitionOfProperty(QWebFrame *frame, const QString &propertyName, double time, const QString &elementId)
276{
277    Frame* coreFrame = QWebFramePrivate::core(frame);
278    if (!coreFrame)
279        return false;
280
281    AnimationController* controller = coreFrame->animation();
282    if (!controller)
283        return false;
284
285    Document* doc = coreFrame->document();
286    Q_ASSERT(doc);
287
288    Node* coreNode = doc->getElementById(elementId);
289    if (!coreNode || !coreNode->renderer())
290        return false;
291
292    return controller->pauseTransitionAtTime(coreNode->renderer(), propertyName, time);
293}
294
295// Pause a given SVG animation on the target node at a specific time.
296// This method is only intended to be used for testing the SVG animation system.
297bool DumpRenderTreeSupportQt::pauseSVGAnimation(QWebFrame *frame, const QString &animationId, double time, const QString &elementId)
298{
299#if !ENABLE(SVG)
300    return false;
301#else
302    Frame* coreFrame = QWebFramePrivate::core(frame);
303    if (!coreFrame)
304        return false;
305
306    Document* doc = coreFrame->document();
307    Q_ASSERT(doc);
308
309    if (!doc->svgExtensions())
310        return false;
311
312    Node* coreNode = doc->getElementById(animationId);
313    if (!coreNode || !SVGSMILElement::isSMILElement(coreNode))
314        return false;
315
316    return doc->accessSVGExtensions()->sampleAnimationAtTime(elementId, static_cast<SVGSMILElement*>(coreNode), time);
317#endif
318}
319
320// Returns the total number of currently running animations (includes both CSS transitions and CSS animations).
321int DumpRenderTreeSupportQt::numberOfActiveAnimations(QWebFrame *frame)
322{
323    Frame* coreFrame = QWebFramePrivate::core(frame);
324    if (!coreFrame)
325        return false;
326
327    AnimationController* controller = coreFrame->animation();
328    if (!controller)
329        return false;
330
331    return controller->numberOfActiveAnimations();
332}
333
334void DumpRenderTreeSupportQt::suspendAnimations(QWebFrame *frame)
335{
336    Frame* coreFrame = QWebFramePrivate::core(frame);
337    if (!coreFrame)
338        return;
339
340    AnimationController* controller = coreFrame->animation();
341    if (!controller)
342        return;
343
344    controller->suspendAnimations();
345}
346
347void DumpRenderTreeSupportQt::resumeAnimations(QWebFrame *frame)
348{
349    Frame* coreFrame = QWebFramePrivate::core(frame);
350    if (!coreFrame)
351        return;
352
353    AnimationController* controller = coreFrame->animation();
354    if (!controller)
355        return;
356
357    controller->resumeAnimations();
358}
359
360void DumpRenderTreeSupportQt::clearFrameName(QWebFrame* frame)
361{
362    Frame* coreFrame = QWebFramePrivate::core(frame);
363    coreFrame->tree()->clearName();
364}
365
366int DumpRenderTreeSupportQt::javaScriptObjectsCount()
367{
368#if USE(JSC)
369    return JSDOMWindowBase::commonJSGlobalData()->heap.globalObjectCount();
370#elif USE(V8)
371    // FIXME: Find a way to do this using V8.
372    return 1;
373#endif
374}
375
376void DumpRenderTreeSupportQt::garbageCollectorCollect()
377{
378#if USE(JSC)
379    gcController().garbageCollectNow();
380#elif USE(V8)
381    v8::V8::LowMemoryNotification();
382#endif
383}
384
385void DumpRenderTreeSupportQt::garbageCollectorCollectOnAlternateThread(bool waitUntilDone)
386{
387#if USE(JSC)
388    gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
389#elif USE(V8)
390    // FIXME: Find a way to do this using V8.
391    garbageCollectorCollect();
392#endif
393}
394
395// Returns the value of counter in the element specified by \a id.
396QString DumpRenderTreeSupportQt::counterValueForElementById(QWebFrame* frame, const QString& id)
397{
398    Frame* coreFrame = QWebFramePrivate::core(frame);
399    if (Document* document = coreFrame->document()) {
400        if (Element* element = document->getElementById(id))
401            return WebCore::counterValueForElement(element);
402    }
403    return QString();
404}
405
406int DumpRenderTreeSupportQt::pageNumberForElementById(QWebFrame* frame, const QString& id, float width, float height)
407{
408    Frame* coreFrame = QWebFramePrivate::core(frame);
409    if (!coreFrame)
410        return -1;
411
412    Element* element = coreFrame->document()->getElementById(AtomicString(id));
413    if (!element)
414        return -1;
415
416    return PrintContext::pageNumberForElement(element, FloatSize(width, height));
417}
418
419int DumpRenderTreeSupportQt::numberOfPages(QWebFrame* frame, float width, float height)
420{
421    Frame* coreFrame = QWebFramePrivate::core(frame);
422    if (!coreFrame)
423        return -1;
424
425    return PrintContext::numberOfPages(coreFrame, FloatSize(width, height));
426}
427
428// Suspend active DOM objects in this frame.
429void DumpRenderTreeSupportQt::suspendActiveDOMObjects(QWebFrame* frame)
430{
431    Frame* coreFrame = QWebFramePrivate::core(frame);
432    if (coreFrame->document())
433        // FIXME: This function should be changed take a ReasonForSuspension parameter
434        // https://bugs.webkit.org/show_bug.cgi?id=45732
435        coreFrame->document()->suspendActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused);
436}
437
438// Resume active DOM objects in this frame.
439void DumpRenderTreeSupportQt::resumeActiveDOMObjects(QWebFrame* frame)
440{
441    Frame* coreFrame = QWebFramePrivate::core(frame);
442    if (coreFrame->document())
443        coreFrame->document()->resumeActiveDOMObjects();
444}
445
446void DumpRenderTreeSupportQt::whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
447{
448    SecurityOrigin::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
449}
450
451void DumpRenderTreeSupportQt::removeWhiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
452{
453    SecurityOrigin::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
454}
455
456void DumpRenderTreeSupportQt::resetOriginAccessWhiteLists()
457{
458    SecurityOrigin::resetOriginAccessWhitelists();
459}
460
461void DumpRenderTreeSupportQt::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme)
462{
463    SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
464}
465
466void DumpRenderTreeSupportQt::setCaretBrowsingEnabled(QWebPage* page, bool value)
467{
468    page->handle()->page->settings()->setCaretBrowsingEnabled(value);
469}
470
471void DumpRenderTreeSupportQt::setMediaType(QWebFrame* frame, const QString& type)
472{
473    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
474    WebCore::FrameView* view = coreFrame->view();
475    view->setMediaType(type);
476    coreFrame->document()->styleSelectorChanged(RecalcStyleImmediately);
477    view->layout();
478}
479
480void DumpRenderTreeSupportQt::setSmartInsertDeleteEnabled(QWebPage* page, bool enabled)
481{
482    page->d->smartInsertDeleteEnabled = enabled;
483}
484
485
486void DumpRenderTreeSupportQt::setSelectTrailingWhitespaceEnabled(QWebPage* page, bool enabled)
487{
488    page->d->selectTrailingWhitespaceEnabled = enabled;
489}
490
491
492void DumpRenderTreeSupportQt::executeCoreCommandByName(QWebPage* page, const QString& name, const QString& value)
493{
494    page->handle()->page->focusController()->focusedOrMainFrame()->editor()->command(name).execute(value);
495}
496
497bool DumpRenderTreeSupportQt::isCommandEnabled(QWebPage* page, const QString& name)
498{
499    return page->handle()->page->focusController()->focusedOrMainFrame()->editor()->command(name).isEnabled();
500}
501
502bool DumpRenderTreeSupportQt::findString(QWebPage* page, const QString& string, const QStringList& optionArray)
503{
504    // 1. Parse the options from the array
505    WebCore::FindOptions options = 0;
506    const int optionCount = optionArray.size();
507    for (int i = 0; i < optionCount; ++i) {
508        const QString& option = optionArray.at(i);
509        if (option == QLatin1String("CaseInsensitive"))
510            options |= WebCore::CaseInsensitive;
511        else if (option == QLatin1String("AtWordStarts"))
512            options |= WebCore::AtWordStarts;
513        else if (option == QLatin1String("TreatMedialCapitalAsWordStart"))
514            options |= WebCore::TreatMedialCapitalAsWordStart;
515        else if (option == QLatin1String("Backwards"))
516            options |= WebCore::Backwards;
517        else if (option == QLatin1String("WrapAround"))
518            options |= WebCore::WrapAround;
519        else if (option == QLatin1String("StartInSelection"))
520            options |= WebCore::StartInSelection;
521    }
522
523    // 2. find the string
524    WebCore::Frame* frame = page->handle()->page->focusController()->focusedOrMainFrame();
525    return frame && frame->editor()->findString(string, options);
526}
527
528QString DumpRenderTreeSupportQt::markerTextForListItem(const QWebElement& listItem)
529{
530    return WebCore::markerTextForListItem(listItem.m_element);
531}
532
533static QString convertToPropertyName(const QString& name)
534{
535    QStringList parts = name.split(QLatin1Char('-'));
536    QString camelCaseName;
537    for (int j = 0; j < parts.count(); ++j) {
538        QString part = parts.at(j);
539        if (j)
540            camelCaseName.append(part.replace(0, 1, part.left(1).toUpper()));
541        else
542            camelCaseName.append(part);
543    }
544    return camelCaseName;
545}
546
547QVariantMap DumpRenderTreeSupportQt::computedStyleIncludingVisitedInfo(const QWebElement& element)
548{
549    QVariantMap res;
550
551    WebCore::Element* webElement = element.m_element;
552    if (!webElement)
553        return res;
554
555    RefPtr<WebCore::CSSComputedStyleDeclaration> style = computedStyle(webElement, true);
556    for (int i = 0; i < style->length(); i++) {
557        QString name = style->item(i);
558        QString value = (static_cast<WebCore::CSSStyleDeclaration*>(style.get()))->getPropertyValue(name);
559        res[convertToPropertyName(name)] = QVariant(value);
560    }
561    return res;
562}
563
564QVariantList DumpRenderTreeSupportQt::selectedRange(QWebPage* page)
565{
566    WebCore::Frame* frame = page->handle()->page->focusController()->focusedOrMainFrame();
567    QVariantList selectedRange;
568    RefPtr<Range> range = frame->selection()->toNormalizedRange().get();
569
570    Element* selectionRoot = frame->selection()->rootEditableElement();
571    Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
572
573    RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
574    ASSERT(testRange->startContainer() == scope);
575    int startPosition = TextIterator::rangeLength(testRange.get());
576
577    ExceptionCode ec;
578    testRange->setEnd(range->endContainer(), range->endOffset(), ec);
579    ASSERT(testRange->startContainer() == scope);
580    int endPosition = TextIterator::rangeLength(testRange.get());
581
582    selectedRange << startPosition << (endPosition - startPosition);
583
584    return selectedRange;
585
586}
587
588QVariantList DumpRenderTreeSupportQt::firstRectForCharacterRange(QWebPage* page, int location, int length)
589{
590    WebCore::Frame* frame = page->handle()->page->focusController()->focusedOrMainFrame();
591    QVariantList rect;
592
593    if ((location + length < location) && (location + length))
594        length = 0;
595
596    Element* selectionRoot = frame->selection()->rootEditableElement();
597    Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
598    RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(scope, location, length);
599
600    if (!range)
601        return QVariantList();
602
603    QRect resultRect = frame->editor()->firstRectForRange(range.get());
604    rect << resultRect.x() << resultRect.y() << resultRect.width() << resultRect.height();
605    return rect;
606}
607
608bool DumpRenderTreeSupportQt::elementDoesAutoCompleteForElementWithId(QWebFrame* frame, const QString& elementId)
609{
610    Frame* coreFrame = QWebFramePrivate::core(frame);
611    if (!coreFrame)
612        return false;
613
614    Document* doc = coreFrame->document();
615    Q_ASSERT(doc);
616
617    Node* coreNode = doc->getElementById(elementId);
618    if (!coreNode || !coreNode->renderer())
619        return false;
620
621    HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(coreNode);
622
623    return inputElement->isTextField() && !inputElement->isPasswordField() && inputElement->autoComplete();
624}
625
626void DumpRenderTreeSupportQt::setEditingBehavior(QWebPage* page, const QString& editingBehavior)
627{
628    WebCore::EditingBehaviorType coreEditingBehavior;
629
630    if (editingBehavior == QLatin1String("win"))
631        coreEditingBehavior = EditingWindowsBehavior;
632    else if (editingBehavior == QLatin1String("mac"))
633        coreEditingBehavior = EditingMacBehavior;
634    else if (editingBehavior == QLatin1String("unix"))
635        coreEditingBehavior = EditingUnixBehavior;
636    else {
637        ASSERT_NOT_REACHED();
638        return;
639    }
640
641    Page* corePage = QWebPagePrivate::core(page);
642    if (!corePage)
643        return;
644
645    corePage->settings()->setEditingBehaviorType(coreEditingBehavior);
646}
647
648void DumpRenderTreeSupportQt::clearAllApplicationCaches()
649{
650#if ENABLE(OFFLINE_WEB_APPLICATIONS)
651    WebCore::cacheStorage().empty();
652    WebCore::cacheStorage().vacuumDatabaseFile();
653#endif
654}
655
656void DumpRenderTreeSupportQt::dumpFrameLoader(bool b)
657{
658    FrameLoaderClientQt::dumpFrameLoaderCallbacks = b;
659}
660
661void DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(bool b)
662{
663    FrameLoaderClientQt::dumpUserGestureInFrameLoaderCallbacks = b;
664}
665
666void DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(bool b)
667{
668    FrameLoaderClientQt::dumpResourceLoadCallbacks = b;
669}
670
671void DumpRenderTreeSupportQt::dumpResourceLoadCallbacksPath(const QString& path)
672{
673    FrameLoaderClientQt::dumpResourceLoadCallbacksPath = path;
674}
675
676void DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(bool b)
677{
678    FrameLoaderClientQt::dumpResourceResponseMIMETypes = b;
679}
680
681void DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(bool b)
682{
683    FrameLoaderClientQt::sendRequestReturnsNullOnRedirect = b;
684}
685
686void DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(bool b)
687{
688    FrameLoaderClientQt::sendRequestReturnsNull = b;
689}
690
691void DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(const QStringList& headers)
692{
693    FrameLoaderClientQt::sendRequestClearHeaders = headers;
694}
695
696void DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(bool b)
697{
698    FrameLoaderClientQt::deferMainResourceDataLoad = b;
699}
700
701void DumpRenderTreeSupportQt::setCustomPolicyDelegate(bool enabled, bool permissive)
702{
703    FrameLoaderClientQt::policyDelegateEnabled = enabled;
704    FrameLoaderClientQt::policyDelegatePermissive = permissive;
705}
706
707void DumpRenderTreeSupportQt::dumpHistoryCallbacks(bool b)
708{
709    FrameLoaderClientQt::dumpHistoryCallbacks = b;
710}
711
712void DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(bool b)
713{
714    ChromeClientQt::dumpVisitedLinksCallbacks = b;
715}
716
717void DumpRenderTreeSupportQt::dumpEditingCallbacks(bool b)
718{
719    EditorClientQt::dumpEditingCallbacks = b;
720}
721
722void DumpRenderTreeSupportQt::dumpSetAcceptsEditing(bool b)
723{
724    EditorClientQt::acceptsEditing = b;
725}
726
727void DumpRenderTreeSupportQt::dumpNotification(bool b)
728{
729#if ENABLE(NOTIFICATIONS)
730    NotificationPresenterClientQt::dumpNotification = b;
731#endif
732}
733
734QString DumpRenderTreeSupportQt::viewportAsText(QWebPage* page, int deviceDPI, const QSize& deviceSize, const QSize& availableSize)
735{
736    WebCore::ViewportArguments args = page->d->viewportArguments();
737
738    WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(args,
739        /* desktop-width */ 980,
740        /* device-width  */ deviceSize.width(),
741        /* device-height */ deviceSize.height(),
742        /* device-dpi    */ deviceDPI,
743        availableSize);
744
745    QString res;
746    res = res.sprintf("viewport size %dx%d scale %f with limits [%f, %f] and userScalable %f\n",
747            conf.layoutSize.width(),
748            conf.layoutSize.height(),
749            conf.initialScale,
750            conf.minimumScale,
751            conf.maximumScale,
752            conf.userScalable);
753
754    return res;
755}
756
757void DumpRenderTreeSupportQt::activeMockDeviceOrientationClient(bool b)
758{
759#if ENABLE(DEVICE_ORIENTATION)
760    DeviceOrientationClientMockQt::mockIsActive = b;
761#endif
762}
763
764void DumpRenderTreeSupportQt::removeMockDeviceOrientation()
765{
766#if ENABLE(DEVICE_ORIENTATION)
767    DeviceOrientationClientMockQt* client = DeviceOrientationClientMockQt::client();
768    delete client;
769#endif
770}
771
772void DumpRenderTreeSupportQt::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
773{
774#if ENABLE(DEVICE_ORIENTATION)
775    DeviceOrientationClientMockQt::client()->setOrientation(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma);
776#endif
777}
778
779void DumpRenderTreeSupportQt::resetGeolocationMock(QWebPage* page)
780{
781#if ENABLE(CLIENT_BASED_GEOLOCATION)
782    Page* corePage = QWebPagePrivate::core(page);
783    GeolocationClientMock* mockClient = toGeolocationClientMock(corePage->geolocationController()->client());
784    mockClient->reset();
785#endif
786}
787
788void DumpRenderTreeSupportQt::setMockGeolocationPermission(QWebPage* page, bool allowed)
789{
790#if ENABLE(CLIENT_BASED_GEOLOCATION)
791    Page* corePage = QWebPagePrivate::core(page);
792    GeolocationClientMock* mockClient = toGeolocationClientMock(corePage->geolocationController()->client());
793    mockClient->setPermission(allowed);
794#endif
795}
796
797void DumpRenderTreeSupportQt::setMockGeolocationPosition(QWebPage* page, double latitude, double longitude, double accuracy)
798{
799#if ENABLE(CLIENT_BASED_GEOLOCATION)
800    Page* corePage = QWebPagePrivate::core(page);
801    GeolocationClientMock* mockClient = toGeolocationClientMock(corePage->geolocationController()->client());
802    mockClient->setPosition(GeolocationPosition::create(currentTime(), latitude, longitude, accuracy));
803#endif
804}
805
806void DumpRenderTreeSupportQt::setMockGeolocationError(QWebPage* page, int errorCode, const QString& message)
807{
808#if ENABLE(CLIENT_BASED_GEOLOCATION)
809    Page* corePage = QWebPagePrivate::core(page);
810
811    GeolocationError::ErrorCode code = GeolocationError::PositionUnavailable;
812    switch (errorCode) {
813    case PositionError::PERMISSION_DENIED:
814        code = GeolocationError::PermissionDenied;
815        break;
816    case PositionError::POSITION_UNAVAILABLE:
817        code = GeolocationError::PositionUnavailable;
818        break;
819    }
820
821    GeolocationClientMock* mockClient = static_cast<GeolocationClientMock*>(corePage->geolocationController()->client());
822    mockClient->setError(GeolocationError::create(code, message));
823#endif
824}
825
826int DumpRenderTreeSupportQt::numberOfPendingGeolocationPermissionRequests(QWebPage* page)
827{
828#if ENABLE(CLIENT_BASED_GEOLOCATION)
829    Page* corePage = QWebPagePrivate::core(page);
830    GeolocationClientMock* mockClient = toGeolocationClientMock(corePage->geolocationController()->client());
831    return mockClient->numberOfPendingPermissionRequests();
832#else
833    return -1;
834#endif
835}
836
837bool DumpRenderTreeSupportQt::isTargetItem(const QWebHistoryItem& historyItem)
838{
839    QWebHistoryItem it = historyItem;
840    if (QWebHistoryItemPrivate::core(&it)->isTargetItem())
841        return true;
842    return false;
843}
844
845QString DumpRenderTreeSupportQt::historyItemTarget(const QWebHistoryItem& historyItem)
846{
847    QWebHistoryItem it = historyItem;
848    return (QWebHistoryItemPrivate::core(&it)->target());
849}
850
851QMap<QString, QWebHistoryItem> DumpRenderTreeSupportQt::getChildHistoryItems(const QWebHistoryItem& historyItem)
852{
853    QWebHistoryItem it = historyItem;
854    HistoryItem* item = QWebHistoryItemPrivate::core(&it);
855    const WebCore::HistoryItemVector& children = item->children();
856
857    unsigned size = children.size();
858    QMap<QString, QWebHistoryItem> kids;
859    for (unsigned i = 0; i < size; ++i) {
860        QWebHistoryItem kid(new QWebHistoryItemPrivate(children[i].get()));
861        kids.insert(DumpRenderTreeSupportQt::historyItemTarget(kid), kid);
862    }
863    return kids;
864}
865
866bool DumpRenderTreeSupportQt::shouldClose(QWebFrame* frame)
867{
868    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
869    return coreFrame->loader()->shouldClose();
870}
871
872void DumpRenderTreeSupportQt::clearScriptWorlds()
873{
874    m_worldMap.clear();
875}
876
877void DumpRenderTreeSupportQt::evaluateScriptInIsolatedWorld(QWebFrame* frame, int worldID, const QString& script)
878{
879    QWebScriptWorld* scriptWorld;
880    if (!worldID) {
881        scriptWorld = new QWebScriptWorld();
882    } else if (!m_worldMap.contains(worldID)) {
883        scriptWorld = new QWebScriptWorld();
884        m_worldMap.insert(worldID, scriptWorld);
885    } else
886        scriptWorld = m_worldMap.value(worldID);
887
888    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
889
890    ScriptController* proxy = coreFrame->script();
891
892    if (!proxy)
893        return;
894#if USE(JSC)
895    proxy->executeScriptInWorld(scriptWorld->world(), script, true);
896#elif USE(V8)
897    ScriptSourceCode source(script);
898    Vector<ScriptSourceCode> sources;
899    sources.append(source);
900    proxy->evaluateInIsolatedWorld(0, sources, true);
901#endif
902}
903
904bool DumpRenderTreeSupportQt::isPageBoxVisible(QWebFrame* frame, int pageIndex)
905{
906    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
907    return coreFrame->document()->isPageBoxVisible(pageIndex);
908}
909
910QString DumpRenderTreeSupportQt::pageSizeAndMarginsInPixels(QWebFrame* frame, int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft)
911{
912    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
913    return PrintContext::pageSizeAndMarginsInPixels(coreFrame, pageIndex, width, height,
914                                                    marginTop, marginRight, marginBottom, marginLeft);
915}
916
917QString DumpRenderTreeSupportQt::pageProperty(QWebFrame* frame, const QString& propertyName, int pageNumber)
918{
919    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
920    return PrintContext::pageProperty(coreFrame, propertyName.toUtf8().constData(), pageNumber);
921}
922
923void DumpRenderTreeSupportQt::addUserStyleSheet(QWebPage* page, const QString& sourceCode)
924{
925    page->handle()->page->group().addUserStyleSheetToWorld(mainThreadNormalWorld(), sourceCode, QUrl(), 0, 0, WebCore::InjectInAllFrames);
926}
927
928void DumpRenderTreeSupportQt::simulateDesktopNotificationClick(const QString& title)
929{
930#if ENABLE(NOTIFICATIONS)
931    NotificationPresenterClientQt::notificationPresenter()->notificationClicked(title);
932#endif
933}
934
935QString DumpRenderTreeSupportQt::plainText(const QVariant& range)
936{
937    QMap<QString, QVariant> map = range.toMap();
938    QVariant startContainer  = map.value(QLatin1String("startContainer"));
939    map = startContainer.toMap();
940
941    return map.value(QLatin1String("innerText")).toString();
942}
943
944QVariantList DumpRenderTreeSupportQt::nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
945{
946    QVariantList res;
947    WebCore::Element* webElement = document.m_element;
948    if (!webElement)
949        return res;
950
951    Document* doc = webElement->document();
952    if (!doc)
953        return res;
954    RefPtr<NodeList> nodes = doc->nodesFromRect(x, y, top, right, bottom, left, ignoreClipping);
955    for (int i = 0; i < nodes->length(); i++) {
956        // QWebElement will be null if the Node is not an HTML Element
957        if (nodes->item(i)->isHTMLElement())
958            res << QVariant::fromValue(QWebElement(nodes->item(i)));
959        else
960            res << QVariant::fromValue(QDRTNode(nodes->item(i)));
961    }
962    return res;
963}
964
965// API Candidate?
966QString DumpRenderTreeSupportQt::responseMimeType(QWebFrame* frame)
967{
968    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
969    WebCore::DocumentLoader* docLoader = coreFrame->loader()->documentLoader();
970    return docLoader->responseMIMEType();
971}
972
973void DumpRenderTreeSupportQt::clearOpener(QWebFrame* frame)
974{
975    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
976    coreFrame->loader()->setOpener(0);
977}
978
979void DumpRenderTreeSupportQt::addURLToRedirect(const QString& origin, const QString& destination)
980{
981    FrameLoaderClientQt::URLsToRedirect[origin] = destination;
982}
983
984static QStringList iterateContextMenu(QMenu* menu)
985{
986    if (!menu)
987        return QStringList();
988
989    QStringList items;
990    QList<QAction *> actions = menu->actions();
991    for (int i = 0; i < actions.count(); ++i) {
992        if (actions.at(i)->isSeparator())
993            items << QLatin1String("<separator>");
994        else
995            items << actions.at(i)->text();
996        if (actions.at(i)->menu())
997            items << iterateContextMenu(actions.at(i)->menu());
998    }
999    return items;
1000}
1001
1002QStringList DumpRenderTreeSupportQt::contextMenu(QWebPage* page)
1003{
1004#ifndef QT_NO_CONTEXTMENU
1005    return iterateContextMenu(page->d->currentContextMenu);
1006#else
1007    return QStringList();
1008#endif
1009}
1010
1011double DumpRenderTreeSupportQt::defaultMinimumTimerInterval()
1012{
1013    return Settings::defaultMinDOMTimerInterval();
1014}
1015
1016void DumpRenderTreeSupportQt::setMinimumTimerInterval(QWebPage* page, double interval)
1017{
1018    Page* corePage = QWebPagePrivate::core(page);
1019    if (!corePage)
1020        return;
1021
1022    corePage->settings()->setMinDOMTimerInterval(interval);
1023}
1024
1025QUrl DumpRenderTreeSupportQt::mediaContentUrlByElementId(QWebFrame* frame, const QString& elementId)
1026{
1027    QUrl res;
1028
1029#if ENABLE(VIDEO) && USE(QT_MULTIMEDIA)
1030    Frame* coreFrame = QWebFramePrivate::core(frame);
1031    if (!coreFrame)
1032        return res;
1033
1034    Document* doc = coreFrame->document();
1035    if (!doc)
1036        return res;
1037
1038    Node* coreNode = doc->getElementById(elementId);
1039    if (!coreNode)
1040        return res;
1041
1042    HTMLVideoElement* videoElement = static_cast<HTMLVideoElement*>(coreNode);
1043    PlatformMedia platformMedia = videoElement->platformMedia();
1044    if (platformMedia.type != PlatformMedia::QtMediaPlayerType)
1045        return res;
1046
1047    MediaPlayerPrivateQt* mediaPlayerQt = static_cast<MediaPlayerPrivateQt*>(platformMedia.media.qtMediaPlayer);
1048    if (mediaPlayerQt && mediaPlayerQt->mediaPlayer())
1049        res = mediaPlayerQt->mediaPlayer()->media().canonicalUrl();
1050#endif
1051
1052    return res;
1053}
1054
1055// API Candidate?
1056void DumpRenderTreeSupportQt::setAlternateHtml(QWebFrame* frame, const QString& html, const QUrl& baseUrl, const QUrl& failingUrl)
1057{
1058    KURL kurl(baseUrl);
1059    WebCore::Frame* coreFrame = QWebFramePrivate::core(frame);
1060    WebCore::ResourceRequest request(kurl);
1061    const QByteArray utf8 = html.toUtf8();
1062    WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(utf8.constData(), utf8.length());
1063    WebCore::SubstituteData substituteData(data, WTF::String("text/html"), WTF::String("utf-8"), failingUrl);
1064    coreFrame->loader()->load(request, substituteData, false);
1065}
1066
1067QVariant DumpRenderTreeSupportQt::shadowRoot(const QWebElement& element)
1068{
1069    WebCore::Element* webElement = element.m_element;
1070    if (!webElement)
1071        return QVariant();
1072
1073    ContainerNode* webShadowRoot = webElement->shadowRoot();
1074    if (!webShadowRoot)
1075        return QVariant();
1076
1077    return QVariant::fromValue(QDRTNode(webShadowRoot));
1078}
1079
1080// Provide a backward compatibility with previously exported private symbols as of QtWebKit 4.6 release
1081
1082void QWEBKIT_EXPORT qt_resumeActiveDOMObjects(QWebFrame* frame)
1083{
1084    DumpRenderTreeSupportQt::resumeActiveDOMObjects(frame);
1085}
1086
1087void QWEBKIT_EXPORT qt_suspendActiveDOMObjects(QWebFrame* frame)
1088{
1089    DumpRenderTreeSupportQt::suspendActiveDOMObjects(frame);
1090}
1091
1092void QWEBKIT_EXPORT qt_drt_clearFrameName(QWebFrame* frame)
1093{
1094    DumpRenderTreeSupportQt::clearFrameName(frame);
1095}
1096
1097void QWEBKIT_EXPORT qt_drt_garbageCollector_collect()
1098{
1099    DumpRenderTreeSupportQt::garbageCollectorCollect();
1100}
1101
1102void QWEBKIT_EXPORT qt_drt_garbageCollector_collectOnAlternateThread(bool waitUntilDone)
1103{
1104    DumpRenderTreeSupportQt::garbageCollectorCollectOnAlternateThread(waitUntilDone);
1105}
1106
1107int QWEBKIT_EXPORT qt_drt_javaScriptObjectsCount()
1108{
1109    return DumpRenderTreeSupportQt::javaScriptObjectsCount();
1110}
1111
1112int QWEBKIT_EXPORT qt_drt_numberOfActiveAnimations(QWebFrame* frame)
1113{
1114    return DumpRenderTreeSupportQt::numberOfActiveAnimations(frame);
1115}
1116
1117void QWEBKIT_EXPORT qt_drt_overwritePluginDirectories()
1118{
1119    DumpRenderTreeSupportQt::overwritePluginDirectories();
1120}
1121
1122bool QWEBKIT_EXPORT qt_drt_pauseAnimation(QWebFrame* frame, const QString& animationName, double time, const QString& elementId)
1123{
1124    return DumpRenderTreeSupportQt::pauseAnimation(frame, animationName, time, elementId);
1125}
1126
1127bool QWEBKIT_EXPORT qt_drt_pauseTransitionOfProperty(QWebFrame* frame, const QString& propertyName, double time, const QString &elementId)
1128{
1129    return DumpRenderTreeSupportQt::pauseTransitionOfProperty(frame, propertyName, time, elementId);
1130}
1131
1132void QWEBKIT_EXPORT qt_drt_resetOriginAccessWhiteLists()
1133{
1134    DumpRenderTreeSupportQt::resetOriginAccessWhiteLists();
1135}
1136
1137void QWEBKIT_EXPORT qt_drt_run(bool b)
1138{
1139    DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(b);
1140}
1141
1142void QWEBKIT_EXPORT qt_drt_setJavaScriptProfilingEnabled(QWebFrame* frame, bool enabled)
1143{
1144    DumpRenderTreeSupportQt::setJavaScriptProfilingEnabled(frame, enabled);
1145}
1146
1147void QWEBKIT_EXPORT qt_drt_whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
1148{
1149    DumpRenderTreeSupportQt::whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
1150}
1151
1152QString QWEBKIT_EXPORT qt_webpage_groupName(QWebPage* page)
1153{
1154    return DumpRenderTreeSupportQt::webPageGroupName(page);
1155}
1156
1157void QWEBKIT_EXPORT qt_webpage_setGroupName(QWebPage* page, const QString& groupName)
1158{
1159    DumpRenderTreeSupportQt::webPageSetGroupName(page, groupName);
1160}
1161
1162void QWEBKIT_EXPORT qt_dump_frame_loader(bool b)
1163{
1164    DumpRenderTreeSupportQt::dumpFrameLoader(b);
1165}
1166
1167void QWEBKIT_EXPORT qt_dump_resource_load_callbacks(bool b)
1168{
1169    DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(b);
1170}
1171
1172void QWEBKIT_EXPORT qt_dump_editing_callbacks(bool b)
1173{
1174    DumpRenderTreeSupportQt::dumpEditingCallbacks(b);
1175}
1176
1177void QWEBKIT_EXPORT qt_dump_set_accepts_editing(bool b)
1178{
1179    DumpRenderTreeSupportQt::dumpSetAcceptsEditing(b);
1180}
1181
1182