2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3 * Copyright (C) 2010 Joone Hur <joone@kldp.org>
4 * Copyright (C) 2009 Google Inc. All rights reserved.
5 * Copyright (C) 2011 Igalia S.L.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser 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.
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 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "DumpRenderTreeSupportGtk.h"
26 #include "AXObjectCache.h"
27 #include "AccessibilityObjectWrapperAtk.h"
28 #include "AnimationController.h"
29 #include "DOMWrapperWorld.h"
31 #include "FocusController.h"
32 #include "FrameLoaderClientGtk.h"
33 #include "FrameTree.h"
34 #include "FrameView.h"
35 #include "GCController.h"
36 #include "GraphicsContext.h"
37 #include "HTMLInputElement.h"
38 #include "InputElement.h"
39 #include "JSDOMWindow.h"
40 #include "JSDocument.h"
41 #include "JSElement.h"
43 #include "JSNodeList.h"
46 #include "PageGroup.h"
47 #include "PlatformString.h"
48 #include "PrintContext.h"
49 #include "RenderListItem.h"
50 #include "RenderTreeAsText.h"
51 #include "RenderView.h"
52 #include "SecurityOrigin.h"
54 #include "TextIterator.h"
55 #include "WorkerThread.h"
56 #include "webkitglobalsprivate.h"
57 #include "webkitwebframe.h"
58 #include "webkitwebframeprivate.h"
59 #include "webkitwebview.h"
60 #include "webkitwebviewprivate.h"
61 #include <JavaScriptCore/APICast.h>
64 #include "SVGDocumentExtensions.h"
65 #include "SVGSMILElement.h"
69 using namespace WebCore;
70 using namespace WebKit;
72 bool DumpRenderTreeSupportGtk::s_drtRun = false;
73 bool DumpRenderTreeSupportGtk::s_linksIncludedInTabChain = true;
74 bool DumpRenderTreeSupportGtk::s_selectTrailingWhitespaceEnabled = false;
76 DumpRenderTreeSupportGtk::DumpRenderTreeSupportGtk()
80 DumpRenderTreeSupportGtk::~DumpRenderTreeSupportGtk()
84 void DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(bool enabled)
89 bool DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled()
93 void DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(bool enabled)
95 s_linksIncludedInTabChain = enabled;
98 bool DumpRenderTreeSupportGtk::linksIncludedInFocusChain()
100 return s_linksIncludedInTabChain;
103 void DumpRenderTreeSupportGtk::setSelectTrailingWhitespaceEnabled(bool enabled)
105 s_selectTrailingWhitespaceEnabled = enabled;
108 bool DumpRenderTreeSupportGtk::selectTrailingWhitespaceEnabled()
110 return s_selectTrailingWhitespaceEnabled;
113 JSValueRef DumpRenderTreeSupportGtk::nodesFromRect(JSContextRef context, JSValueRef value, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
115 JSLock lock(SilenceAssertionsOnly);
116 ExecState* exec = toJS(context);
118 return JSValueMakeUndefined(context);
119 JSValue jsValue = toJS(exec, value);
120 if (!jsValue.inherits(&JSDocument::s_info))
121 return JSValueMakeUndefined(context);
123 JSDocument* jsDocument = static_cast<JSDocument*>(asObject(jsValue));
124 Document* document = jsDocument->impl();
125 RefPtr<NodeList> nodes = document->nodesFromRect(x, y, top, right, bottom, left, ignoreClipping);
126 return toRef(exec, toJS(exec, jsDocument->globalObject(), nodes.get()));
131 * @frame: a #WebKitWebFrame
133 * Return value: child frames of @frame
135 GSList* DumpRenderTreeSupportGtk::getFrameChildren(WebKitWebFrame* frame)
137 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
139 Frame* coreFrame = core(frame);
143 GSList* children = 0;
144 for (Frame* child = coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
145 FrameLoader* loader = child->loader();
146 WebKit::FrameLoaderClient* client = static_cast<WebKit::FrameLoaderClient*>(loader->client());
148 children = g_slist_append(children, client->webFrame());
156 * @frame: a #WebKitWebFrame
158 * Return value: inner text of @frame
160 CString DumpRenderTreeSupportGtk::getInnerText(WebKitWebFrame* frame)
162 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), CString(""));
164 Frame* coreFrame = core(frame);
168 FrameView* view = coreFrame->view();
170 if (view && view->layoutPending())
173 Element* documentElement = coreFrame->document()->documentElement();
174 return documentElement->innerText().utf8();
179 * @frame: a #WebKitWebFrame
181 * Return value: Non-recursive render tree dump of @frame
183 CString DumpRenderTreeSupportGtk::dumpRenderTree(WebKitWebFrame* frame)
185 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), CString(""));
187 Frame* coreFrame = core(frame);
191 FrameView* view = coreFrame->view();
193 if (view && view->layoutPending())
196 return externalRepresentation(coreFrame).utf8();
200 * counterValueForElementById:
201 * @frame: a #WebKitWebFrame
202 * @id: an element ID string
204 * Return value: The counter value of element @id in @frame
206 CString DumpRenderTreeSupportGtk::counterValueForElementById(WebKitWebFrame* frame, const char* id)
208 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), CString());
210 Frame* coreFrame = core(frame);
214 Element* coreElement = coreFrame->document()->getElementById(AtomicString(id));
218 return counterValueForElement(coreElement).utf8();
222 * numberForElementById
223 * @frame: a #WebKitWebFrame
224 * @id: an element ID string
225 * @pageWidth: width of a page
226 * @pageHeight: height of a page
228 * Return value: The number of page where the specified element will be put
230 int DumpRenderTreeSupportGtk::pageNumberForElementById(WebKitWebFrame* frame, const char* id, float pageWidth, float pageHeight)
232 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
234 Frame* coreFrame = core(frame);
238 Element* coreElement = coreFrame->document()->getElementById(AtomicString(id));
241 return PrintContext::pageNumberForElement(coreElement, FloatSize(pageWidth, pageHeight));
245 * numberOfPagesForFrame
246 * @frame: a #WebKitWebFrame
247 * @pageWidth: width of a page
248 * @pageHeight: height of a page
250 * Return value: The number of pages to be printed.
252 int DumpRenderTreeSupportGtk::numberOfPagesForFrame(WebKitWebFrame* frame, float pageWidth, float pageHeight)
254 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
256 Frame* coreFrame = core(frame);
260 return PrintContext::numberOfPages(coreFrame, FloatSize(pageWidth, pageHeight));
265 * @frame: a #WebKitWebFrame
266 * @propertyName: name of a property
267 * @pageNumber: number of a page
269 * Return value: The value of the given property name.
271 CString DumpRenderTreeSupportGtk::pageProperty(WebKitWebFrame* frame, const char* propertyName, int pageNumber)
273 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), CString());
275 Frame* coreFrame = core(frame);
279 return PrintContext::pageProperty(coreFrame, propertyName, pageNumber).utf8();
284 * @frame: a #WebKitWebFrame
285 * @pageNumber: number of a page
287 * Return value: TRUE if a page box is visible.
289 bool DumpRenderTreeSupportGtk::isPageBoxVisible(WebKitWebFrame* frame, int pageNumber)
291 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), false);
293 Frame* coreFrame = core(frame);
297 return coreFrame->document()->isPageBoxVisible(pageNumber);
301 * pageSizeAndMarginsInPixels
302 * @frame: a #WebKitWebFrame
303 * @pageNumber: number of a page
304 * @width: width of a page
305 * @height: height of a page
306 * @marginTop: top margin of a page
307 * @marginRight: right margin of a page
308 * @marginBottom: bottom margin of a page
309 * @marginLeft: left margin of a page
311 * Return value: The value of page size and margin.
313 CString DumpRenderTreeSupportGtk::pageSizeAndMarginsInPixels(WebKitWebFrame* frame, int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft)
315 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), CString());
317 Frame* coreFrame = core(frame);
321 return PrintContext::pageSizeAndMarginsInPixels(coreFrame, pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft).utf8();
326 * @frame: a #WebKitWebFrame
327 * @sourceCode: code of a user stylesheet
330 void DumpRenderTreeSupportGtk::addUserStyleSheet(WebKitWebFrame* frame, const char* sourceCode, bool allFrames)
332 g_return_if_fail(WEBKIT_IS_WEB_FRAME(frame));
334 Frame* coreFrame = core(frame);
338 WebKitWebView* webView = getViewFromFrame(frame);
339 Page* page = core(webView);
340 page->group().addUserStyleSheetToWorld(mainThreadNormalWorld(), sourceCode, KURL(), 0, 0, allFrames ? InjectInAllFrames : InjectInTopFrameOnly);
344 * getPendingUnloadEventCount:
345 * @frame: a #WebKitWebFrame
347 * Return value: number of pending unload events
349 guint DumpRenderTreeSupportGtk::getPendingUnloadEventCount(WebKitWebFrame* frame)
351 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
353 return core(frame)->domWindow()->pendingUnloadEventListeners();
356 bool DumpRenderTreeSupportGtk::pauseAnimation(WebKitWebFrame* frame, const char* name, double time, const char* element)
359 Element* coreElement = core(frame)->document()->getElementById(AtomicString(element));
360 if (!coreElement || !coreElement->renderer())
362 return core(frame)->animation()->pauseAnimationAtTime(coreElement->renderer(), AtomicString(name), time);
365 bool DumpRenderTreeSupportGtk::pauseTransition(WebKitWebFrame* frame, const char* name, double time, const char* element)
368 Element* coreElement = core(frame)->document()->getElementById(AtomicString(element));
369 if (!coreElement || !coreElement->renderer())
371 return core(frame)->animation()->pauseTransitionAtTime(coreElement->renderer(), AtomicString(name), time);
374 bool DumpRenderTreeSupportGtk::pauseSVGAnimation(WebKitWebFrame* frame, const char* animationId, double time, const char* elementId)
378 Document* document = core(frame)->document();
379 if (!document || !document->svgExtensions())
381 Element* coreElement = document->getElementById(AtomicString(animationId));
382 if (!coreElement || !SVGSMILElement::isSMILElement(coreElement))
384 return document->accessSVGExtensions()->sampleAnimationAtTime(elementId, static_cast<SVGSMILElement*>(coreElement), time);
390 CString DumpRenderTreeSupportGtk::markerTextForListItem(WebKitWebFrame* frame, JSContextRef context, JSValueRef nodeObject)
392 JSC::ExecState* exec = toJS(context);
393 Element* element = toElement(toJS(exec, nodeObject));
397 return WebCore::markerTextForListItem(element).utf8();
400 unsigned int DumpRenderTreeSupportGtk::numberOfActiveAnimations(WebKitWebFrame* frame)
402 Frame* coreFrame = core(frame);
406 return coreFrame->animation()->numberOfActiveAnimations();
409 void DumpRenderTreeSupportGtk::suspendAnimations(WebKitWebFrame* frame)
411 Frame* coreFrame = core(frame);
415 return coreFrame->animation()->suspendAnimations();
418 void DumpRenderTreeSupportGtk::resumeAnimations(WebKitWebFrame* frame)
420 Frame* coreFrame = core(frame);
424 return coreFrame->animation()->resumeAnimations();
427 void DumpRenderTreeSupportGtk::clearMainFrameName(WebKitWebFrame* frame)
429 g_return_if_fail(WEBKIT_IS_WEB_FRAME(frame));
431 core(frame)->tree()->clearName();
434 AtkObject* DumpRenderTreeSupportGtk::getRootAccessibleElement(WebKitWebFrame* frame)
436 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
438 #if HAVE(ACCESSIBILITY)
439 if (!AXObjectCache::accessibilityEnabled())
440 AXObjectCache::enableAccessibility();
442 WebKitWebFramePrivate* priv = frame->priv;
443 if (!priv->coreFrame || !priv->coreFrame->document())
446 AtkObject* wrapper = priv->coreFrame->document()->axObjectCache()->rootObject()->wrapper();
456 AtkObject* DumpRenderTreeSupportGtk::getFocusedAccessibleElement(WebKitWebFrame* frame)
458 #if HAVE(ACCESSIBILITY)
459 AtkObject* wrapper = getRootAccessibleElement(frame);
463 return webkit_accessible_get_focused_element(WEBKIT_ACCESSIBLE(wrapper));
469 void DumpRenderTreeSupportGtk::executeCoreCommandByName(WebKitWebView* webView, const gchar* name, const gchar* value)
471 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
472 g_return_if_fail(name);
473 g_return_if_fail(value);
475 core(webView)->focusController()->focusedOrMainFrame()->editor()->command(name).execute(value);
478 bool DumpRenderTreeSupportGtk::isCommandEnabled(WebKitWebView* webView, const gchar* name)
480 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
481 g_return_val_if_fail(name, FALSE);
483 return core(webView)->focusController()->focusedOrMainFrame()->editor()->command(name).isEnabled();
486 void DumpRenderTreeSupportGtk::setComposition(WebKitWebView* webView, const char* text, int start, int end)
488 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
489 g_return_if_fail(text);
491 Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
495 Editor* editor = frame->editor();
498 if (!editor->canEdit() && !editor->hasComposition())
501 String compositionString = String::fromUTF8(text);
502 Vector<CompositionUnderline> underlines;
503 underlines.append(CompositionUnderline(0, compositionString.length(), Color(0, 0, 0), false));
504 editor->setComposition(compositionString, underlines, start, end);
507 void DumpRenderTreeSupportGtk::confirmComposition(WebKitWebView* webView, const char* text)
509 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
511 Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
515 Editor* editor = frame->editor();
516 if (!editor || (!editor->hasComposition() && !text))
519 if (editor->hasComposition()) {
521 editor->confirmComposition(String::fromUTF8(text));
523 editor->confirmComposition();
525 editor->insertText(String::fromUTF8(text), 0);
528 bool DumpRenderTreeSupportGtk::firstRectForCharacterRange(WebKitWebView* webView, int location, int length, GdkRectangle* rect)
530 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), false);
531 g_return_val_if_fail(rect, false);
533 if ((location + length < location) && (location + length))
536 Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
540 Editor* editor = frame->editor();
544 Element* selectionRoot = frame->selection()->rootEditableElement();
545 Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
546 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(scope, location, length);
550 *rect = editor->firstRectForRange(range.get());
555 bool DumpRenderTreeSupportGtk::selectedRange(WebKitWebView* webView, int* start, int* end)
557 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), false);
558 g_return_val_if_fail(start, false);
559 g_return_val_if_fail(end, false);
561 Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
565 RefPtr<Range> range = frame->selection()->toNormalizedRange().get();
567 Element* selectionRoot = frame->selection()->rootEditableElement();
568 Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
570 RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
571 ASSERT(testRange->startContainer() == scope);
572 *start = TextIterator::rangeLength(testRange.get());
575 testRange->setEnd(range->endContainer(), range->endOffset(), ec);
576 ASSERT(testRange->startContainer() == scope);
577 *end = TextIterator::rangeLength(testRange.get());
582 void DumpRenderTreeSupportGtk::whiteListAccessFromOrigin(const gchar* sourceOrigin, const gchar* destinationProtocol, const gchar* destinationHost, bool allowDestinationSubdomains)
584 SecurityOrigin::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
587 void DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists()
589 SecurityOrigin::resetOriginAccessWhitelists();
592 void DumpRenderTreeSupportGtk::gcCollectJavascriptObjects()
594 gcController().garbageCollectNow();
597 void DumpRenderTreeSupportGtk::gcCollectJavascriptObjectsOnAlternateThread(bool waitUntilDone)
599 gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
602 unsigned long DumpRenderTreeSupportGtk::gcCountJavascriptObjects()
604 JSC::JSLock lock(JSC::SilenceAssertionsOnly);
605 return JSDOMWindow::commonJSGlobalData()->heap.objectCount();
608 void DumpRenderTreeSupportGtk::layoutFrame(WebKitWebFrame* frame)
610 Frame* coreFrame = core(frame);
614 FrameView* view = coreFrame->view();
621 // For testing fast/viewport.
622 void DumpRenderTreeSupportGtk::dumpConfigurationForViewport(WebKitWebView* webView, gint deviceDPI, gint deviceWidth, gint deviceHeight, gint availableWidth, gint availableHeight)
624 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
626 ViewportArguments arguments = webView->priv->corePage->mainFrame()->document()->viewportArguments();
627 ViewportAttributes attrs = computeViewportAttributes(arguments, /* default layout width for non-mobile pages */ 980, deviceWidth, deviceHeight, deviceDPI, IntSize(availableWidth, availableHeight));
629 fprintf(stdout, "viewport size %dx%d scale %f with limits [%f, %f] and userScalable %f\n", attrs.layoutSize.width(), attrs.layoutSize.height(), attrs.initialScale, attrs.minimumScale, attrs.maximumScale, attrs.userScalable);
632 void DumpRenderTreeSupportGtk::clearOpener(WebKitWebFrame* frame)
634 Frame* coreFrame = core(frame);
636 coreFrame->loader()->setOpener(0);
639 unsigned int DumpRenderTreeSupportGtk::workerThreadCount()
642 return WebCore::WorkerThread::workerThreadCount();
648 bool DumpRenderTreeSupportGtk::webkitWebFrameSelectionHasSpellingMarker(WebKitWebFrame *frame, gint from, gint length)
650 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), FALSE);
652 return core(frame)->editor()->selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
655 bool DumpRenderTreeSupportGtk::findString(WebKitWebView* webView, const gchar* targetString, WebKitFindOptions findOptions)
657 return core(webView)->findString(String::fromUTF8(targetString), findOptions);
660 double DumpRenderTreeSupportGtk::defaultMinimumTimerInterval()
662 return Settings::defaultMinDOMTimerInterval();
665 void DumpRenderTreeSupportGtk::setMinimumTimerInterval(WebKitWebView* webView, double interval)
667 core(webView)->settings()->setMinDOMTimerInterval(interval);
670 void DumpRenderTreeSupportGtk::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool autofilled)
672 JSC::ExecState* exec = toJS(context);
673 Element* element = toElement(toJS(exec, nodeObject));
676 InputElement* inputElement = element->toInputElement();
680 static_cast<HTMLInputElement*>(inputElement)->setAutofilled(autofilled);
683 void DumpRenderTreeSupportGtk::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value)
685 JSC::ExecState* exec = toJS(context);
686 Element* element = toElement(toJS(exec, nodeObject));
689 InputElement* inputElement = element->toInputElement();
693 size_t bufferSize = JSStringGetMaximumUTF8CStringSize(value);
694 GOwnPtr<gchar> valueBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
695 JSStringGetUTF8CString(value, valueBuffer.get(), bufferSize);
696 inputElement->setValueForUser(String::fromUTF8(valueBuffer.get()));