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.
6 * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "DumpRenderTreeSupportGtk.h"
27 #include "AXObjectCache.h"
28 #include "AccessibilityObject.h"
29 #include "AnimationController.h"
30 #include "ApplicationCacheStorage.h"
32 #include "ChromeClientGtk.h"
33 #include "DOMWrapperWorld.h"
36 #include "EditorClientGtk.h"
38 #include "FocusController.h"
39 #include "FrameTree.h"
40 #include "FrameView.h"
41 #include "GCController.h"
42 #include "GeolocationClientMock.h"
43 #include "GeolocationController.h"
44 #include "GeolocationError.h"
45 #include "GeolocationPosition.h"
46 #include "GraphicsContext.h"
47 #include "HTMLInputElement.h"
48 #include "JSCJSValue.h"
49 #include "JSCSSStyleDeclaration.h"
50 #include "JSDOMWindow.h"
51 #include "JSDocument.h"
52 #include "JSElement.h"
54 #include "JSNodeList.h"
55 #include "MemoryCache.h"
56 #include "MutationObserver.h"
58 #include "PageGroup.h"
59 #include "PrintContext.h"
60 #include "RenderListItem.h"
61 #include "RenderTreeAsText.h"
62 #include "RenderView.h"
63 #include "ResourceLoadScheduler.h"
64 #include "RuntimeEnabledFeatures.h"
65 #include "SchemeRegistry.h"
66 #include "SecurityOrigin.h"
67 #include "SecurityPolicy.h"
69 #include "TextIterator.h"
70 #include "WebKitAccessibleWrapperAtk.h"
71 #include "webkitglobalsprivate.h"
72 #include "webkitwebframe.h"
73 #include "webkitwebframeprivate.h"
74 #include "webkitwebview.h"
75 #include "webkitwebviewprivate.h"
76 #include <JavaScriptCore/APICast.h>
77 #include <wtf/text/WTFString.h>
80 using namespace WebCore;
81 using namespace WebKit;
83 bool DumpRenderTreeSupportGtk::s_drtRun = false;
84 bool DumpRenderTreeSupportGtk::s_linksIncludedInTabChain = true;
85 DumpRenderTreeSupportGtk::FrameLoadEventCallback DumpRenderTreeSupportGtk::s_frameLoadEventCallback = 0;
86 DumpRenderTreeSupportGtk::AuthenticationCallback DumpRenderTreeSupportGtk::s_authenticationCallback = 0;
88 DumpRenderTreeSupportGtk::DumpRenderTreeSupportGtk()
92 DumpRenderTreeSupportGtk::~DumpRenderTreeSupportGtk()
96 void DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(bool enabled)
101 bool DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled()
105 void DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(bool enabled)
107 s_linksIncludedInTabChain = enabled;
110 bool DumpRenderTreeSupportGtk::linksIncludedInFocusChain()
112 return s_linksIncludedInTabChain;
117 * @frame: a #WebKitWebFrame
119 * Return value: child frames of @frame
121 GSList* DumpRenderTreeSupportGtk::getFrameChildren(WebKitWebFrame* frame)
123 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
125 Frame* coreFrame = core(frame);
129 GSList* children = 0;
130 for (Frame* child = coreFrame->tree().firstChild(); child; child = child->tree().nextSibling()) {
131 WebKitWebFrame* kitFrame = kit(child);
133 children = g_slist_append(children, kitFrame);
141 * @frame: a #WebKitWebFrame
143 * Return value: inner text of @frame
145 CString DumpRenderTreeSupportGtk::getInnerText(WebKitWebFrame* frame)
147 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), CString(""));
149 Frame* coreFrame = core(frame);
153 FrameView* view = coreFrame->view();
154 if (view && view->layoutPending())
157 Element* documentElement = coreFrame->document()->documentElement();
158 if (!documentElement)
160 return documentElement->innerText().utf8();
165 * @frame: a #WebKitWebFrame
167 * Return value: Non-recursive render tree dump of @frame
169 CString DumpRenderTreeSupportGtk::dumpRenderTree(WebKitWebFrame* frame)
171 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), CString(""));
173 Frame* coreFrame = core(frame);
177 FrameView* view = coreFrame->view();
179 if (view && view->layoutPending())
182 return externalRepresentation(coreFrame).utf8();
185 void DumpRenderTreeSupportGtk::addUserScript(WebKitWebFrame* frame, const char* sourceCode, bool runAtStart, bool allFrames)
187 g_return_if_fail(WEBKIT_IS_WEB_FRAME(frame));
189 Frame* coreFrame = core(frame);
193 WebKitWebView* webView = getViewFromFrame(frame);
194 Page* page = core(webView);
195 page->group().addUserScriptToWorld(mainThreadNormalWorld(), sourceCode, URL(), Vector<String>(), Vector<String>(),
196 runAtStart ? InjectAtDocumentStart : InjectAtDocumentEnd, allFrames ? InjectInAllFrames : InjectInTopFrameOnly);
201 * @frame: a #WebKitWebFrame
202 * @sourceCode: code of a user stylesheet
205 void DumpRenderTreeSupportGtk::addUserStyleSheet(WebKitWebFrame* frame, const char* sourceCode, bool allFrames)
207 g_return_if_fail(WEBKIT_IS_WEB_FRAME(frame));
209 Frame* coreFrame = core(frame);
213 WebKitWebView* webView = getViewFromFrame(frame);
214 Page* page = core(webView);
215 page->group().addUserStyleSheetToWorld(mainThreadNormalWorld(), sourceCode, URL(), Vector<String>(), Vector<String>(), allFrames ? InjectInAllFrames : InjectInTopFrameOnly);
219 * getPendingUnloadEventCount:
220 * @frame: a #WebKitWebFrame
222 * Return value: number of pending unload events
224 guint DumpRenderTreeSupportGtk::getPendingUnloadEventCount(WebKitWebFrame* frame)
226 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
228 return core(frame)->document()->domWindow()->pendingUnloadEventListeners();
231 void DumpRenderTreeSupportGtk::clearMainFrameName(WebKitWebFrame* frame)
233 g_return_if_fail(WEBKIT_IS_WEB_FRAME(frame));
235 core(frame)->tree().clearName();
238 AtkObject* DumpRenderTreeSupportGtk::getRootAccessibleElement(WebKitWebFrame* frame)
240 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
242 #if HAVE(ACCESSIBILITY)
243 if (!AXObjectCache::accessibilityEnabled())
244 AXObjectCache::enableAccessibility();
246 WebKitWebFramePrivate* priv = frame->priv;
247 if (!priv->coreFrame || !priv->coreFrame->document())
250 AtkObject* wrapper = priv->coreFrame->document()->axObjectCache()->rootObject()->wrapper();
260 AtkObject* DumpRenderTreeSupportGtk::getFocusedAccessibleElement(WebKitWebFrame* frame)
262 #if HAVE(ACCESSIBILITY)
263 AtkObject* wrapper = getRootAccessibleElement(frame);
267 return webkitAccessibleGetFocusedElement(WEBKIT_ACCESSIBLE(wrapper));
273 void DumpRenderTreeSupportGtk::executeCoreCommandByName(WebKitWebView* webView, const gchar* name, const gchar* value)
275 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
276 g_return_if_fail(name);
277 g_return_if_fail(value);
279 core(webView)->focusController().focusedOrMainFrame().editor().command(name).execute(value);
282 bool DumpRenderTreeSupportGtk::isCommandEnabled(WebKitWebView* webView, const gchar* name)
284 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
285 g_return_val_if_fail(name, FALSE);
287 return core(webView)->focusController().focusedOrMainFrame().editor().command(name).isEnabled();
290 void DumpRenderTreeSupportGtk::setComposition(WebKitWebView* webView, const char* text, int start, int length)
292 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
293 g_return_if_fail(text);
295 Frame& frame = core(webView)->focusController().focusedOrMainFrame();
296 Editor& editor = frame.editor();
297 if (!editor.canEdit() && !editor.hasComposition())
300 String compositionString = String::fromUTF8(text);
301 Vector<CompositionUnderline> underlines;
302 underlines.append(CompositionUnderline(0, compositionString.length(), Color(0, 0, 0), false));
303 editor.setComposition(compositionString, underlines, start, start + length);
306 bool DumpRenderTreeSupportGtk::hasComposition(WebKitWebView* webView)
308 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), false);
309 Frame& frame = core(webView)->focusController().focusedOrMainFrame();
310 return frame.editor().hasComposition();
313 bool DumpRenderTreeSupportGtk::compositionRange(WebKitWebView* webView, int* start, int* length)
315 g_return_val_if_fail(start && length, false);
316 *start = *length = 0;
318 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), false);
319 Frame& frame = core(webView)->focusController().focusedOrMainFrame();
320 Editor& editor = frame.editor();
321 if (!editor.hasComposition())
324 *start = editor.compositionStart();
325 *length = editor.compositionEnd() - *start;
329 void DumpRenderTreeSupportGtk::confirmComposition(WebKitWebView* webView, const char* text)
331 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
333 Frame& frame = core(webView)->focusController().focusedOrMainFrame();
334 Editor& editor = frame.editor();
336 if (!editor.hasComposition()) {
337 editor.insertText(String::fromUTF8(text), 0);
341 editor.confirmComposition(String::fromUTF8(text));
344 editor.confirmComposition();
347 void DumpRenderTreeSupportGtk::doCommand(WebKitWebView* webView, const char* command)
349 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
350 Frame& frame = core(webView)->focusController().focusedOrMainFrame();
351 Editor& editor = frame.editor();
353 String commandString(command);
354 // Remove ending : here.
355 if (commandString.endsWith(":", true))
356 commandString = commandString.left(commandString.length() - 1);
358 // Make the first char in upper case.
359 String firstChar = commandString.left(1);
360 commandString = commandString.right(commandString.length() - 1);
361 commandString.insert(firstChar.upper(), 0);
363 editor.command(commandString).execute();
366 bool DumpRenderTreeSupportGtk::firstRectForCharacterRange(WebKitWebView* webView, int location, int length, cairo_rectangle_int_t* rect)
368 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), false);
369 g_return_val_if_fail(rect, false);
371 if ((location + length < location) && (location + length))
374 Frame& frame = core(webView)->focusController().focusedOrMainFrame();
375 Editor& editor = frame.editor();
377 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(frame.selection().rootEditableElementOrDocumentElement(), location, length);
381 *rect = editor.firstRectForRange(range.get());
385 bool DumpRenderTreeSupportGtk::selectedRange(WebKitWebView* webView, int* start, int* length)
387 g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), false);
388 g_return_val_if_fail(start && length, false);
390 Frame& frame = core(webView)->focusController().focusedOrMainFrame();
392 RefPtr<Range> range = frame.selection().toNormalizedRange().get();
396 Element* selectionRoot = frame.selection().rootEditableElement();
397 Element* scope = selectionRoot ? selectionRoot : frame.document()->documentElement();
399 RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
400 ASSERT(testRange->startContainer() == scope);
401 *start = TextIterator::rangeLength(testRange.get());
404 testRange->setEnd(range->endContainer(), range->endOffset(), ec);
405 ASSERT(testRange->startContainer() == scope);
406 *length = TextIterator::rangeLength(testRange.get());
411 void DumpRenderTreeSupportGtk::setDefersLoading(WebKitWebView* webView, bool defers)
413 core(webView)->setDefersLoading(defers);
416 void DumpRenderTreeSupportGtk::forceWebViewPaint(WebKitWebView* webView)
418 g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
420 static_cast<WebKit::ChromeClient&>(core(webView)->chrome().client()).forcePaint();
423 void DumpRenderTreeSupportGtk::whiteListAccessFromOrigin(const gchar* sourceOrigin, const gchar* destinationProtocol, const gchar* destinationHost, bool allowDestinationSubdomains)
425 SecurityPolicy::addOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
428 void DumpRenderTreeSupportGtk::removeWhiteListAccessFromOrigin(const char* sourceOrigin, const char* destinationProtocol, const char* destinationHost, bool allowDestinationSubdomains)
430 SecurityPolicy::removeOriginAccessWhitelistEntry(*SecurityOrigin::createFromString(sourceOrigin), destinationProtocol, destinationHost, allowDestinationSubdomains);
433 void DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists()
435 SecurityPolicy::resetOriginAccessWhitelists();
438 void DumpRenderTreeSupportGtk::gcCollectJavascriptObjects()
440 gcController().garbageCollectNow();
443 void DumpRenderTreeSupportGtk::gcCollectJavascriptObjectsOnAlternateThread(bool waitUntilDone)
445 gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
448 unsigned long DumpRenderTreeSupportGtk::gcCountJavascriptObjects()
450 JSC::JSLockHolder lock(JSDOMWindow::commonVM());
451 return JSDOMWindow::commonVM()->heap.objectCount();
454 void DumpRenderTreeSupportGtk::layoutFrame(WebKitWebFrame* frame)
456 Frame* coreFrame = core(frame);
460 FrameView* view = coreFrame->view();
467 void DumpRenderTreeSupportGtk::clearOpener(WebKitWebFrame* frame)
469 Frame* coreFrame = core(frame);
471 coreFrame->loader().setOpener(0);
474 bool DumpRenderTreeSupportGtk::findString(WebKitWebView* webView, const gchar* targetString, WebKitFindOptions findOptions)
476 return core(webView)->findString(String::fromUTF8(targetString), findOptions);
479 void DumpRenderTreeSupportGtk::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value)
481 JSC::ExecState* exec = toJS(context);
482 Element* element = toElement(toJS(exec, nodeObject));
485 HTMLInputElement* inputElement = element->toInputElement();
489 size_t bufferSize = JSStringGetMaximumUTF8CStringSize(value);
490 GOwnPtr<gchar> valueBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
491 JSStringGetUTF8CString(value, valueBuffer.get(), bufferSize);
492 inputElement->setValueForUser(String::fromUTF8(valueBuffer.get()));
495 void DumpRenderTreeSupportGtk::rectangleForSelection(WebKitWebFrame* frame, cairo_rectangle_int_t* rectangle)
497 Frame* coreFrame = core(frame);
501 IntRect bounds = enclosingIntRect(coreFrame->selection().bounds());
502 rectangle->x = bounds.x();
503 rectangle->y = bounds.y();
504 rectangle->width = bounds.width();
505 rectangle->height = bounds.height();
508 bool DumpRenderTreeSupportGtk::shouldClose(WebKitWebFrame* frame)
510 Frame* coreFrame = core(frame);
513 return coreFrame->loader().shouldClose();
516 void DumpRenderTreeSupportGtk::scalePageBy(WebKitWebView* webView, float scaleFactor, float x, float y)
518 core(webView)->setPageScaleFactor(scaleFactor, IntPoint(x, y));
521 void DumpRenderTreeSupportGtk::resetGeolocationClientMock(WebKitWebView* webView)
523 #if ENABLE(GEOLOCATION)
524 GeolocationClientMock* mock = static_cast<GeolocationClientMock*>(GeolocationController::from(core(webView))->client());
529 void DumpRenderTreeSupportGtk::setMockGeolocationPermission(WebKitWebView* webView, bool allowed)
531 #if ENABLE(GEOLOCATION)
532 GeolocationClientMock* mock = static_cast<GeolocationClientMock*>(GeolocationController::from(core(webView))->client());
533 mock->setPermission(allowed);
537 void DumpRenderTreeSupportGtk::setMockGeolocationPosition(WebKitWebView* webView, double latitude, double longitude, double accuracy)
539 #if ENABLE(GEOLOCATION)
540 GeolocationClientMock* mock = static_cast<GeolocationClientMock*>(GeolocationController::from(core(webView))->client());
542 double timestamp = g_get_real_time() / 1000000.0;
543 mock->setPosition(GeolocationPosition::create(timestamp, latitude, longitude, accuracy));
547 void DumpRenderTreeSupportGtk::setMockGeolocationPositionUnavailableError(WebKitWebView* webView, const gchar* errorMessage)
549 #if ENABLE(GEOLOCATION)
550 GeolocationClientMock* mock = static_cast<GeolocationClientMock*>(GeolocationController::from(core(webView))->client());
551 mock->setPositionUnavailableError(errorMessage);
555 int DumpRenderTreeSupportGtk::numberOfPendingGeolocationPermissionRequests(WebKitWebView* webView)
557 #if ENABLE(GEOLOCATION)
558 GeolocationClientMock* mock = static_cast<GeolocationClientMock*>(GeolocationController::from(core(webView))->client());
559 return mock->numberOfPendingPermissionRequests();
565 void DumpRenderTreeSupportGtk::setPageCacheSupportsPlugins(WebKitWebView* webView, bool enabled)
567 core(webView)->settings().setPageCacheSupportsPlugins(enabled);
570 void DumpRenderTreeSupportGtk::setCSSGridLayoutEnabled(WebKitWebView* webView, bool enabled)
572 core(webView)->settings().setCSSGridLayoutEnabled(enabled);
575 void DumpRenderTreeSupportGtk::setCSSRegionsEnabled(WebKitWebView* webView, bool enabled)
577 RuntimeEnabledFeatures::sharedFeatures().setCSSRegionsEnabled(enabled);
580 void DumpRenderTreeSupportGtk::setCSSCustomFilterEnabled(WebKitWebView* webView, bool enabled)
582 #if ENABLE(CSS_SHADERS)
583 core(webView)->settings().setCSSCustomFilterEnabled(enabled);
587 void DumpRenderTreeSupportGtk::setExperimentalContentSecurityPolicyFeaturesEnabled(bool enabled)
590 RuntimeEnabledFeatures::sharedFeatures().setExperimentalContentSecurityPolicyFeaturesEnabled(enabled);
594 void DumpRenderTreeSupportGtk::setSeamlessIFramesEnabled(bool enabled)
596 #if ENABLE(IFRAME_SEAMLESS)
597 RuntimeEnabledFeatures::sharedFeatures().setSeamlessIFramesEnabled(enabled);
601 void DumpRenderTreeSupportGtk::setShadowDOMEnabled(bool enabled)
603 #if ENABLE(SHADOW_DOM)
604 RuntimeEnabledFeatures::sharedFeatures().setShadowDOMEnabled(enabled);
608 void DumpRenderTreeSupportGtk::deliverAllMutationsIfNecessary()
610 MutationObserver::deliverAllMutations();
613 void DumpRenderTreeSupportGtk::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const char* urlScheme)
615 SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, String::fromUTF8(urlScheme));
618 void DumpRenderTreeSupportGtk::setSerializeHTTPLoads(bool enabled)
620 resourceLoadScheduler()->setSerialLoadingEnabled(enabled);
623 void DumpRenderTreeSupportGtk::setTracksRepaints(WebKitWebFrame* frame, bool tracks)
625 g_return_if_fail(WEBKIT_IS_WEB_FRAME(frame));
627 Frame* coreFrame = core(frame);
628 if (coreFrame && coreFrame->view())
629 coreFrame->view()->setTracksRepaints(tracks);
632 bool DumpRenderTreeSupportGtk::isTrackingRepaints(WebKitWebFrame* frame)
634 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), false);
636 Frame* coreFrame = core(frame);
637 if (coreFrame && coreFrame->view())
638 return coreFrame->view()->isTrackingRepaints();
643 GSList* DumpRenderTreeSupportGtk::trackedRepaintRects(WebKitWebFrame* frame)
645 g_return_val_if_fail(WEBKIT_IS_WEB_FRAME(frame), 0);
647 Frame* coreFrame = core(frame);
648 if (!coreFrame || !coreFrame->view())
652 const Vector<IntRect>& repaintRects = coreFrame->view()->trackedRepaintRects();
653 for (unsigned i = 0; i < repaintRects.size(); i++) {
654 GdkRectangle* rect = g_new0(GdkRectangle, 1);
655 rect->x = repaintRects[i].x();
656 rect->y = repaintRects[i].y();
657 rect->width = repaintRects[i].width();
658 rect->height = repaintRects[i].height();
659 rects = g_slist_append(rects, rect);
665 void DumpRenderTreeSupportGtk::resetTrackedRepaints(WebKitWebFrame* frame)
667 g_return_if_fail(WEBKIT_IS_WEB_FRAME(frame));
669 Frame* coreFrame = core(frame);
670 if (coreFrame && coreFrame->view())
671 coreFrame->view()->resetTrackedRepaints();
674 void DumpRenderTreeSupportGtk::clearMemoryCache()
676 memoryCache()->evictResources();
679 void DumpRenderTreeSupportGtk::clearApplicationCache()
681 cacheStorage().empty();
682 cacheStorage().vacuumDatabaseFile();
685 void DumpRenderTreeSupportGtk::setFrameLoadEventCallback(FrameLoadEventCallback frameLoadEventCallback)
687 s_frameLoadEventCallback = frameLoadEventCallback;
690 void DumpRenderTreeSupportGtk::setAuthenticationCallback(AuthenticationCallback authenticationCallback)
692 s_authenticationCallback = authenticationCallback;
695 void DumpRenderTreeSupportGtk::setPageVisibility(WebKitWebView* webView, WebCore::PageVisibilityState visibilityState, bool isInitialState)
697 #if ENABLE(PAGE_VISIBILITY_API)
698 Page* page = core(webView);
702 page->setVisibilityState(visibilityState, isInitialState);