[EFL][DRT] Implement LayoutTestController::execCommand
[WebKit-https.git] / Source / WebKit / efl / WebCoreSupport / DumpRenderTreeSupportEfl.cpp
1 /*
2     Copyright (C) 2011 ProFUSION embedded systems
3     Copyright (C) 2011 Samsung Electronics
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Library General Public License for more details.
14
15     You should have received a copy of the GNU Library General Public License
16     along with this library; see the file COPYING.LIB.  If not, write to
17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18     Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22 #include "DumpRenderTreeSupportEfl.h"
23
24 #include "FrameLoaderClientEfl.h"
25 #include "ewk_private.h"
26
27 #include <AnimationController.h>
28 #include <CSSComputedStyleDeclaration.h>
29 #include <DocumentLoader.h>
30 #include <EditorClientEfl.h>
31 #include <Eina.h>
32 #include <Evas.h>
33 #include <FindOptions.h>
34 #include <FloatSize.h>
35 #include <FocusController.h>
36 #include <FrameView.h>
37 #include <HTMLInputElement.h>
38 #include <InspectorController.h>
39 #include <IntRect.h>
40 #include <JSCSSStyleDeclaration.h>
41 #include <JSElement.h>
42 #include <PageGroup.h>
43 #include <PrintContext.h>
44 #include <RenderTreeAsText.h>
45 #include <Settings.h>
46 #include <WebKitMutationObserver.h>
47 #include <bindings/js/GCController.h>
48 #include <history/HistoryItem.h>
49 #include <workers/WorkerThread.h>
50 #include <wtf/OwnArrayPtr.h>
51 #include <wtf/text/AtomicString.h>
52
53 unsigned DumpRenderTreeSupportEfl::activeAnimationsCount(const Evas_Object* ewkFrame)
54 {
55     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
56
57     if (!frame)
58         return 0;
59
60     WebCore::AnimationController* animationController = frame->animation();
61
62     if (!animationController)
63         return 0;
64
65     return animationController->numberOfActiveAnimations(frame->document());
66 }
67
68 bool DumpRenderTreeSupportEfl::callShouldCloseOnWebView(Evas_Object* ewkFrame)
69 {
70     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
71
72     if (!frame)
73         return false;
74
75     return frame->loader()->shouldClose();
76 }
77
78 void DumpRenderTreeSupportEfl::clearFrameName(Evas_Object* ewkFrame)
79 {
80     if (WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame))
81         frame->tree()->clearName();
82 }
83
84 void DumpRenderTreeSupportEfl::clearOpener(Evas_Object* ewkFrame)
85 {
86     if (WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame))
87         frame->loader()->setOpener(0);
88 }
89
90 String DumpRenderTreeSupportEfl::counterValueByElementId(const Evas_Object* ewkFrame, const char* elementId)
91 {
92     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
93
94     if (!frame)
95         return String();
96
97     WebCore::Element* element = frame->document()->getElementById(elementId);
98
99     if (!element)
100         return String();
101
102     return WebCore::counterValueForElement(element);
103 }
104
105 bool DumpRenderTreeSupportEfl::elementDoesAutoCompleteForElementWithId(const Evas_Object* ewkFrame, const String& elementId)
106 {
107     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
108
109     if (!frame)
110         return false;
111
112     WebCore::Document* document = frame->document();
113     ASSERT(document);
114
115     WebCore::HTMLInputElement* inputElement = static_cast<WebCore::HTMLInputElement*>(document->getElementById(elementId));
116
117     if (!inputElement)
118         return false;
119
120     return inputElement->isTextField() && !inputElement->isPasswordField() && inputElement->shouldAutocomplete();
121 }
122
123 Eina_List* DumpRenderTreeSupportEfl::frameChildren(const Evas_Object* ewkFrame)
124 {
125     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
126
127     if (!frame)
128         return 0;
129
130     Eina_List* childFrames = 0;
131
132     for (unsigned index = 0; index < frame->tree()->childCount(); index++) {
133         WebCore::Frame *childFrame = frame->tree()->child(index);
134         WebCore::FrameLoaderClientEfl *client = static_cast<WebCore::FrameLoaderClientEfl*>(childFrame->loader()->client());
135
136         if (!client)
137             continue;
138
139         childFrames = eina_list_append(childFrames, client->webFrame());
140     }
141
142     return childFrames;
143 }
144
145 WebCore::Frame* DumpRenderTreeSupportEfl::frameParent(const Evas_Object* ewkFrame)
146 {
147     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
148
149     if (!frame)
150         return 0;
151
152     return frame->tree()->parent();
153 }
154
155 void DumpRenderTreeSupportEfl::layoutFrame(Evas_Object* ewkFrame)
156 {
157     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
158
159     if (!frame)
160         return;
161
162     WebCore::FrameView* frameView = frame->view();
163
164     if (!frameView)
165         return;
166
167     frameView->layout();
168 }
169
170 int DumpRenderTreeSupportEfl::numberOfPages(const Evas_Object* ewkFrame, float pageWidth, float pageHeight)
171 {
172     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
173
174     if (!frame)
175         return 0;
176
177     return WebCore::PrintContext::numberOfPages(frame, WebCore::FloatSize(pageWidth, pageHeight));
178 }
179
180 int DumpRenderTreeSupportEfl::numberOfPagesForElementId(const Evas_Object* ewkFrame, const char* elementId, float pageWidth, float pageHeight)
181 {
182     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
183
184     if (!frame)
185         return 0;
186
187     WebCore::Element *element = frame->document()->getElementById(elementId);
188
189     if (!element)
190         return 0;
191
192     return WebCore::PrintContext::pageNumberForElement(element, WebCore::FloatSize(pageWidth, pageHeight));
193 }
194
195 String DumpRenderTreeSupportEfl::pageSizeAndMarginsInPixels(const Evas_Object* ewkFrame, int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft)
196 {
197     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
198
199     if (!frame)
200         return String();
201
202     return WebCore::PrintContext::pageSizeAndMarginsInPixels(frame, pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft);
203 }
204
205 String DumpRenderTreeSupportEfl::pageProperty(const Evas_Object* ewkFrame, const char* propertyName, int pageNumber)
206 {
207     WebCore::Frame* coreFrame = EWKPrivate::coreFrame(ewkFrame);
208     if (!coreFrame)
209         return String();
210
211     return WebCore::PrintContext::pageProperty(coreFrame, propertyName, pageNumber);
212 }
213
214 bool DumpRenderTreeSupportEfl::pauseAnimation(Evas_Object* ewkFrame, const char* name, const char* elementId, double time)
215 {
216     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
217
218     if (!frame)
219         return false;
220
221     WebCore::Element* element = frame->document()->getElementById(elementId);
222
223     if (!element || !element->renderer())
224         return false;
225
226     return frame->animation()->pauseAnimationAtTime(element->renderer(), name, time);
227 }
228
229 bool DumpRenderTreeSupportEfl::pauseTransition(Evas_Object* ewkFrame, const char* name, const char* elementId, double time)
230 {
231     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
232
233     if (!frame)
234         return false;
235
236     WebCore::Element* element = frame->document()->getElementById(elementId);
237
238     if (!element || !element->renderer())
239         return false;
240
241     return frame->animation()->pauseTransitionAtTime(element->renderer(), name, time);
242 }
243
244 unsigned DumpRenderTreeSupportEfl::pendingUnloadEventCount(const Evas_Object* ewkFrame)
245 {
246     if (WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame))
247         return frame->domWindow()->pendingUnloadEventListeners();
248
249     return 0;
250 }
251
252 String DumpRenderTreeSupportEfl::renderTreeDump(Evas_Object* ewkFrame)
253 {
254     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
255
256     if (!frame)
257         return String();
258
259     WebCore::FrameView *frameView = frame->view();
260
261     if (frameView && frameView->layoutPending())
262         frameView->layout();
263
264     return WebCore::externalRepresentation(frame);
265 }
266
267 String DumpRenderTreeSupportEfl::responseMimeType(const Evas_Object* ewkFrame)
268 {
269     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
270
271     if (!frame)
272         return String();
273
274     WebCore::DocumentLoader *documentLoader = frame->loader()->documentLoader();
275
276     if (!documentLoader)
277         return String();
278
279     return documentLoader->responseMIMEType();
280 }
281
282 void DumpRenderTreeSupportEfl::resumeAnimations(Evas_Object* ewkFrame)
283 {
284     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
285
286     if (!frame)
287         return;
288
289     WebCore::AnimationController *animationController = frame->animation();
290     if (animationController)
291         animationController->resumeAnimations();
292 }
293
294 WebCore::IntRect DumpRenderTreeSupportEfl::selectionRectangle(const Evas_Object* ewkFrame)
295 {
296     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
297
298     if (!frame)
299         return WebCore::IntRect();
300
301     return enclosingIntRect(frame->selection()->bounds());
302 }
303
304 // Compare with "WebKit/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm
305 String DumpRenderTreeSupportEfl::suitableDRTFrameName(const Evas_Object* ewkFrame)
306 {
307     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
308
309     if (!frame)
310         return String();
311
312     const String frameName(ewk_frame_name_get(ewkFrame));
313
314     if (ewkFrame == ewk_view_frame_main_get(ewk_frame_view_get(ewkFrame))) {
315         if (!frameName.isEmpty())
316             return String("main frame \"") + frameName + String("\"");
317
318         return String("main frame");
319     }
320
321     if (!frameName.isEmpty())
322         return String("frame \"") + frameName + String("\"");
323
324     return String("frame (anonymous)");
325 }
326
327 void DumpRenderTreeSupportEfl::suspendAnimations(Evas_Object* ewkFrame)
328 {
329     WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);
330
331     if (!frame)
332         return;
333
334     WebCore::AnimationController *animationController = frame->animation();
335     if (animationController)
336         animationController->suspendAnimations();
337 }
338
339 void DumpRenderTreeSupportEfl::setValueForUser(JSContextRef context, JSValueRef nodeObject, JSStringRef value)
340 {
341     JSC::ExecState* exec = toJS(context);
342     WebCore::Element* element = WebCore::toElement(toJS(exec, nodeObject));
343     if (!element)
344         return;
345     WebCore::HTMLInputElement* inputElement = element->toInputElement();
346     if (!inputElement)
347         return;
348
349     size_t bufferSize = JSStringGetMaximumUTF8CStringSize(value);
350     OwnArrayPtr<char> valueBuffer = adoptArrayPtr(new char[bufferSize]);
351     JSStringGetUTF8CString(value, valueBuffer.get(), bufferSize);
352     inputElement->setValueForUser(String::fromUTF8(valueBuffer.get()));
353 }
354
355 void DumpRenderTreeSupportEfl::setAutofilled(JSContextRef context, JSValueRef nodeObject, bool autofilled)
356 {
357     JSC::ExecState* exec = toJS(context);
358     WebCore::Element* element = WebCore::toElement(toJS(exec, nodeObject));
359     if (!element)
360         return;
361     WebCore::HTMLInputElement* inputElement = element->toInputElement();
362     if (!inputElement)
363         return;
364
365     inputElement->setAutofilled(autofilled);
366 }
367
368 void DumpRenderTreeSupportEfl::setDefersLoading(Evas_Object* ewkView, bool defers)
369 {
370     WebCore::Page* page = EWKPrivate::corePage(ewkView);
371
372     if (!page)
373         return;
374
375     page->setDefersLoading(defers);
376 }
377
378 void DumpRenderTreeSupportEfl::setLoadsSiteIconsIgnoringImageLoadingSetting(Evas_Object* ewkView, bool loadsSiteIconsIgnoringImageLoadingPreferences)
379 {
380     WebCore::Page* page = EWKPrivate::corePage(ewkView);
381     if (!page)
382         return;
383
384     page->settings()->setLoadsSiteIconsIgnoringImageLoadingSetting(loadsSiteIconsIgnoringImageLoadingPreferences);
385 }
386
387 void DumpRenderTreeSupportEfl::addUserStyleSheet(const Evas_Object* ewkView, const char* sourceCode, bool allFrames)
388 {
389     WebCore::Page* page = EWKPrivate::corePage(ewkView);
390     if (!page)
391         return;
392
393     page->group().addUserStyleSheetToWorld(WebCore::mainThreadNormalWorld(), sourceCode, WebCore::KURL(), nullptr, nullptr, allFrames ? WebCore::InjectInAllFrames : WebCore::InjectInTopFrameOnly);
394 }
395
396 void DumpRenderTreeSupportEfl::executeCoreCommandByName(const Evas_Object* ewkView, const char* name, const char* value)
397 {
398     WebCore::Page* page = EWKPrivate::corePage(ewkView);
399     if (!page)
400         return;
401
402     page->focusController()->focusedOrMainFrame()->editor()->command(name).execute(value);
403 }
404
405 bool DumpRenderTreeSupportEfl::findString(const Evas_Object* ewkView, const char* text, WebCore::FindOptions options)
406 {
407     WebCore::Page* page = EWKPrivate::corePage(ewkView);
408
409     if (!page)
410         return false;
411
412     return page->findString(String::fromUTF8(text), options);
413 }
414
415 void DumpRenderTreeSupportEfl::setJavaScriptProfilingEnabled(const Evas_Object* ewkView, bool enabled)
416 {
417 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
418     WebCore::Page* corePage = EWKPrivate::corePage(ewkView);
419     if (!corePage)
420         return;
421
422     WebCore::InspectorController* controller = corePage->inspectorController();
423     if (!controller)
424         return;
425
426     if (enabled)
427         controller->enableProfiler();
428     else
429         controller->disableProfiler();
430 #endif
431 }
432
433 bool DumpRenderTreeSupportEfl::isCommandEnabled(const Evas_Object* ewkView, const char* name)
434 {
435     WebCore::Page* page = EWKPrivate::corePage(ewkView);
436     if (!page)
437         return false;
438
439     return page->focusController()->focusedOrMainFrame()->editor()->command(name).isEnabled();
440 }
441
442 void DumpRenderTreeSupportEfl::setSmartInsertDeleteEnabled(Evas_Object* ewkView, bool enabled)
443 {
444     WebCore::Page* page = EWKPrivate::corePage(ewkView);
445     if (!page)
446         return;
447
448     WebCore::EditorClientEfl* editorClient = static_cast<WebCore::EditorClientEfl*>(page->editorClient());
449     if (!editorClient)
450         return;
451
452     editorClient->setSmartInsertDeleteEnabled(enabled);
453 }
454
455 void DumpRenderTreeSupportEfl::setSelectTrailingWhitespaceEnabled(Evas_Object* ewkView, bool enabled)
456 {
457     WebCore::Page* page = EWKPrivate::corePage(ewkView);
458     if (!page)
459         return;
460
461     WebCore::EditorClientEfl* editorClient = static_cast<WebCore::EditorClientEfl*>(page->editorClient());
462     if (!editorClient)
463         return;
464
465     editorClient->setSelectTrailingWhitespaceEnabled(enabled);
466 }
467
468 void DumpRenderTreeSupportEfl::garbageCollectorCollect()
469 {
470     WebCore::gcController().garbageCollectNow();
471 }
472
473 void DumpRenderTreeSupportEfl::garbageCollectorCollectOnAlternateThread(bool waitUntilDone)
474 {
475     WebCore::gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
476 }
477
478 size_t DumpRenderTreeSupportEfl::javaScriptObjectsCount()
479 {
480     return WebCore::JSDOMWindow::commonJSGlobalData()->heap.objectCount();
481 }
482
483 unsigned DumpRenderTreeSupportEfl::workerThreadCount()
484 {
485 #if ENABLE(WORKERS)
486     return WebCore::WorkerThread::workerThreadCount();
487 #else
488     return 0;
489 #endif
490 }
491
492 HistoryItemChildrenVector DumpRenderTreeSupportEfl::childHistoryItems(const Ewk_History_Item* ewkHistoryItem)
493 {
494     WebCore::HistoryItem* historyItem = EWKPrivate::coreHistoryItem(ewkHistoryItem);
495     HistoryItemChildrenVector kids;
496
497     if (!historyItem)
498         return kids;
499
500     const WebCore::HistoryItemVector& children = historyItem->children();
501     const unsigned size = children.size();
502
503     for (unsigned i = 0; i < size; ++i) {
504         Ewk_History_Item* kid = ewk_history_item_new_from_core(children[i].get());
505         kids.append(kid);
506     }
507
508     return kids;
509 }
510
511 String DumpRenderTreeSupportEfl::historyItemTarget(const Ewk_History_Item* ewkHistoryItem)
512 {
513     WebCore::HistoryItem* historyItem = EWKPrivate::coreHistoryItem(ewkHistoryItem);
514
515     if (!historyItem)
516         return String();
517
518     return historyItem->target();
519 }
520
521 bool DumpRenderTreeSupportEfl::isTargetItem(const Ewk_History_Item* ewkHistoryItem)
522 {
523     WebCore::HistoryItem* historyItem = EWKPrivate::coreHistoryItem(ewkHistoryItem);
524
525     if (!historyItem)
526         return false;
527
528     return historyItem->isTargetItem();
529 }
530
531 void DumpRenderTreeSupportEfl::setMockScrollbarsEnabled(bool enable)
532 {
533     WebCore::Settings::setMockScrollbarsEnabled(enable);
534 }
535
536 void DumpRenderTreeSupportEfl::dumpConfigurationForViewport(Evas_Object* ewkView, int deviceDPI, const WebCore::IntSize& deviceSize, const WebCore::IntSize& availableSize)
537 {
538     WebCore::Page* page = EWKPrivate::corePage(ewkView);
539
540     if (!page)
541         return;
542     WebCore::ViewportArguments arguments = page->mainFrame()->document()->viewportArguments();
543     WebCore::ViewportAttributes attributes = computeViewportAttributes(arguments,
544             /* default layout width for non-mobile pages */ 980,
545             deviceSize.width(), deviceSize.height(),
546             deviceDPI,
547             availableSize);
548     restrictMinimumScaleFactorToViewportSize(attributes, availableSize);
549     restrictScaleFactorToInitialScaleIfNotUserScalable(attributes);
550     fprintf(stdout, "viewport size %dx%d scale %f with limits [%f, %f] and userScalable %f\n", static_cast<int>(attributes.layoutSize.width()), static_cast<int>(attributes.layoutSize.height()), attributes.initialScale, attributes.minimumScale, attributes.maximumScale, attributes.userScalable);
551 }
552
553 void DumpRenderTreeSupportEfl::deliverAllMutationsIfNecessary()
554 {
555 #if ENABLE(MUTATION_OBSERVERS)
556     WebCore::WebKitMutationObserver::deliverAllMutations();
557 #endif
558 }
559
560 void DumpRenderTreeSupportEfl::setEditingBehavior(Evas_Object* ewkView, const char* editingBehavior)
561 {
562     WebCore::EditingBehaviorType coreEditingBehavior;
563
564     if (!strcmp(editingBehavior, "win"))
565         coreEditingBehavior = WebCore::EditingWindowsBehavior;
566     else if (!strcmp(editingBehavior, "mac"))
567         coreEditingBehavior = WebCore::EditingMacBehavior;
568     else if (!strcmp(editingBehavior, "unix"))
569         coreEditingBehavior = WebCore::EditingUnixBehavior;
570     else {
571         ASSERT_NOT_REACHED();
572         return;
573     }
574
575     WebCore::Page* corePage = EWKPrivate::corePage(ewkView);
576     if (!corePage)
577         return;
578
579     corePage->settings()->setEditingBehaviorType(coreEditingBehavior);
580 }
581
582 String DumpRenderTreeSupportEfl::markerTextForListItem(JSContextRef context, JSValueRef nodeObject)
583 {
584     JSC::ExecState* exec = toJS(context);
585     WebCore::Element* element = WebCore::toElement(toJS(exec, nodeObject));
586     if (!element)
587         return String();
588
589     return WebCore::markerTextForListItem(element);
590 }
591
592 void DumpRenderTreeSupportEfl::setInteractiveFormValidationEnabled(Evas_Object* ewkView, bool enabled)
593 {
594     WebCore::Page* corePage = EWKPrivate::corePage(ewkView);
595     if (corePage)
596         corePage->settings()->setInteractiveFormValidationEnabled(enabled);
597 }
598
599 JSValueRef DumpRenderTreeSupportEfl::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef value)
600 {
601     if (!value)
602         return JSValueMakeUndefined(context);
603
604     JSC::ExecState* exec = toJS(context);
605     JSC::JSValue jsValue = toJS(exec, value);
606     if (!jsValue.inherits(&WebCore::JSElement::s_info))
607         return JSValueMakeUndefined(context);
608
609     WebCore::JSElement* jsElement = static_cast<WebCore::JSElement*>(asObject(jsValue));
610     WebCore::Element* element = jsElement->impl();
611     RefPtr<WebCore::CSSComputedStyleDeclaration> style = WebCore::CSSComputedStyleDeclaration::create(element, true);
612     return toRef(exec, toJS(exec, jsElement->globalObject(), style.get()));
613 }
614
615 void DumpRenderTreeSupportEfl::setAuthorAndUserStylesEnabled(Evas_Object* ewkView, bool enabled)
616 {
617     WebCore::Page* corePage = EWKPrivate::corePage(ewkView);
618     if (!corePage)
619         return;
620
621     corePage->settings()->setAuthorAndUserStylesEnabled(enabled);
622 }