1/*
2    Copyright (C) 2011 ProFUSION embedded systems
3    Copyright (C) 2011 Samsung Electronics
4    Copyright (C) 2012 Intel Corporation. All rights reserved.
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public
8    License as published by the Free Software Foundation; either
9    version 2 of the License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public License
17    along with this library; see the file COPYING.LIB.  If not, write to
18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19    Boston, MA 02110-1301, USA.
20*/
21
22#include "config.h"
23#include "DumpRenderTreeSupportEfl.h"
24
25#include "FrameLoaderClientEfl.h"
26#include "ewk_frame_private.h"
27#include "ewk_history_private.h"
28#include "ewk_private.h"
29#include "ewk_view_private.h"
30
31#include <APICast.h>
32#include <AnimationController.h>
33#include <DOMWindow.h>
34#include <DocumentLoader.h>
35#include <Editor.h>
36#include <EditorClientEfl.h>
37#include <Eina.h>
38#include <Evas.h>
39#include <FindOptions.h>
40#include <FloatSize.h>
41#include <FocusController.h>
42#include <FrameLoader.h>
43#include <FrameSelection.h>
44#include <FrameView.h>
45#include <HTMLInputElement.h>
46#include <InspectorController.h>
47#include <IntRect.h>
48#include <JSCSSStyleDeclaration.h>
49#include <JSDOMWindow.h>
50#include <JSElement.h>
51#include <JavaScriptCore/OpaqueJSString.h>
52#include <MemoryCache.h>
53#include <MutationObserver.h>
54#include <PageGroup.h>
55#include <PrintContext.h>
56#include <RenderTreeAsText.h>
57#include <ResourceLoadScheduler.h>
58#include <RuntimeEnabledFeatures.h>
59#include <SchemeRegistry.h>
60#include <ScriptController.h>
61#include <ScriptValue.h>
62#include <Settings.h>
63#include <TextIterator.h>
64#include <bindings/js/GCController.h>
65#include <history/HistoryItem.h>
66#include <wtf/HashMap.h>
67
68#if ENABLE(GEOLOCATION)
69#include <GeolocationClientMock.h>
70#include <GeolocationController.h>
71#include <GeolocationError.h>
72#include <GeolocationPosition.h>
73#include <wtf/CurrentTime.h>
74#endif
75
76#if HAVE(ACCESSIBILITY)
77#include "AXObjectCache.h"
78#include "AccessibilityObject.h"
79#include "WebKitAccessibleWrapperAtk.h"
80#endif
81
82#define DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, ...) \
83    WebCore::Frame* frame = EWKPrivate::coreFrame(ewkFrame);  \
84    if (!frame)                                               \
85        return __VA_ARGS__;
86
87#define DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, ...) \
88    WebCore::Page* page = EWKPrivate::corePage(ewkView);  \
89    if (!page)                                            \
90        return __VA_ARGS__;
91
92bool DumpRenderTreeSupportEfl::s_drtRun = false;
93
94void DumpRenderTreeSupportEfl::setDumpRenderTreeModeEnabled(bool enabled)
95{
96    s_drtRun = enabled;
97}
98
99bool DumpRenderTreeSupportEfl::dumpRenderTreeModeEnabled()
100{
101    return s_drtRun;
102}
103
104bool DumpRenderTreeSupportEfl::callShouldCloseOnWebView(Evas_Object* ewkFrame)
105{
106    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, false);
107
108    return frame->loader()->shouldClose();
109}
110
111void DumpRenderTreeSupportEfl::clearFrameName(Evas_Object* ewkFrame)
112{
113    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame);
114
115    frame->tree()->clearName();
116}
117
118void DumpRenderTreeSupportEfl::clearOpener(Evas_Object* ewkFrame)
119{
120    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame);
121
122    frame->loader()->setOpener(0);
123}
124
125String DumpRenderTreeSupportEfl::layerTreeAsText(const Evas_Object* ewkFrame)
126{
127    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, String());
128
129    return frame->layerTreeAsText();
130}
131
132Eina_List* DumpRenderTreeSupportEfl::frameChildren(const Evas_Object* ewkFrame)
133{
134    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, 0);
135
136    Eina_List* childFrames = 0;
137
138    for (unsigned index = 0; index < frame->tree()->childCount(); index++) {
139        WebCore::Frame *childFrame = frame->tree()->child(index);
140        WebCore::FrameLoaderClientEfl *client = static_cast<WebCore::FrameLoaderClientEfl*>(childFrame->loader()->client());
141
142        if (!client)
143            continue;
144
145        childFrames = eina_list_append(childFrames, client->webFrame());
146    }
147
148    return childFrames;
149}
150
151WebCore::Frame* DumpRenderTreeSupportEfl::frameParent(const Evas_Object* ewkFrame)
152{
153    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, 0);
154
155    return frame->tree()->parent();
156}
157
158void DumpRenderTreeSupportEfl::layoutFrame(Evas_Object* ewkFrame)
159{
160    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame);
161
162    if (!frame->view())
163        return;
164
165    frame->view()->layout();
166}
167
168unsigned DumpRenderTreeSupportEfl::pendingUnloadEventCount(const Evas_Object* ewkFrame)
169{
170    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, 0);
171
172    return frame->document()->domWindow()->pendingUnloadEventListeners();
173}
174
175String DumpRenderTreeSupportEfl::renderTreeDump(Evas_Object* ewkFrame)
176{
177    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, String());
178
179    WebCore::FrameView *frameView = frame->view();
180
181    if (frameView && frameView->layoutPending())
182        frameView->layout();
183
184    return WebCore::externalRepresentation(frame);
185}
186
187String DumpRenderTreeSupportEfl::responseMimeType(const Evas_Object* ewkFrame)
188{
189    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, String());
190
191    WebCore::DocumentLoader *documentLoader = frame->loader()->documentLoader();
192
193    if (!documentLoader)
194        return String();
195
196    return documentLoader->responseMIMEType();
197}
198
199WebCore::IntRect DumpRenderTreeSupportEfl::selectionRectangle(const Evas_Object* ewkFrame)
200{
201    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, WebCore::IntRect());
202
203    return enclosingIntRect(frame->selection()->bounds());
204}
205
206// Compare with "WebKit/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm
207String DumpRenderTreeSupportEfl::suitableDRTFrameName(const Evas_Object* ewkFrame)
208{
209    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, String());
210
211    const String frameName(ewk_frame_name_get(ewkFrame));
212
213    if (ewkFrame == ewk_view_frame_main_get(ewk_frame_view_get(ewkFrame))) {
214        if (!frameName.isEmpty())
215            return String("main frame \"") + frameName + String("\"");
216
217        return String("main frame");
218    }
219
220    if (!frameName.isEmpty())
221        return String("frame \"") + frameName + String("\"");
222
223    return String("frame (anonymous)");
224}
225
226void DumpRenderTreeSupportEfl::setValueForUser(JSContextRef context, JSValueRef nodeObject, const String& value)
227{
228    JSC::ExecState* exec = toJS(context);
229    WebCore::Element* element = WebCore::toElement(toJS(exec, nodeObject));
230    if (!element)
231        return;
232    WebCore::HTMLInputElement* inputElement = element->toInputElement();
233    if (!inputElement)
234        return;
235
236    inputElement->setValueForUser(value);
237}
238
239void DumpRenderTreeSupportEfl::setDefersLoading(Evas_Object* ewkView, bool defers)
240{
241    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
242
243    page->setDefersLoading(defers);
244}
245
246void DumpRenderTreeSupportEfl::setLoadsSiteIconsIgnoringImageLoadingSetting(Evas_Object* ewkView, bool loadsSiteIconsIgnoringImageLoadingPreferences)
247{
248    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
249
250    page->settings()->setLoadsSiteIconsIgnoringImageLoadingSetting(loadsSiteIconsIgnoringImageLoadingPreferences);
251}
252
253void DumpRenderTreeSupportEfl::setMinimumLogicalFontSize(Evas_Object* ewkView, int size)
254{
255    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
256
257    page->settings()->setMinimumLogicalFontSize(size);
258}
259
260void DumpRenderTreeSupportEfl::addUserScript(const Evas_Object* ewkView, const String& sourceCode, bool runAtStart, bool allFrames)
261{
262    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
263
264    page->group().addUserScriptToWorld(WebCore::mainThreadNormalWorld(), sourceCode, WebCore::KURL(),
265                                       Vector<String>(), Vector<String>(), runAtStart ? WebCore::InjectAtDocumentStart : WebCore::InjectAtDocumentEnd,
266                                       allFrames ? WebCore::InjectInAllFrames : WebCore::InjectInTopFrameOnly);
267}
268
269void DumpRenderTreeSupportEfl::clearUserScripts(const Evas_Object* ewkView)
270{
271    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
272
273    page->group().removeUserScriptsFromWorld(WebCore::mainThreadNormalWorld());
274}
275
276void DumpRenderTreeSupportEfl::addUserStyleSheet(const Evas_Object* ewkView, const String& sourceCode, bool allFrames)
277{
278    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
279
280    page->group().addUserStyleSheetToWorld(WebCore::mainThreadNormalWorld(), sourceCode, WebCore::KURL(), Vector<String>(), Vector<String>(), allFrames ? WebCore::InjectInAllFrames : WebCore::InjectInTopFrameOnly);
281}
282
283void DumpRenderTreeSupportEfl::clearUserStyleSheets(const Evas_Object* ewkView)
284{
285    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
286
287    page->group().removeUserStyleSheetsFromWorld(WebCore::mainThreadNormalWorld());
288}
289
290void DumpRenderTreeSupportEfl::executeCoreCommandByName(const Evas_Object* ewkView, const char* name, const char* value)
291{
292    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
293
294    page->focusController()->focusedOrMainFrame()->editor().command(name).execute(value);
295}
296
297bool DumpRenderTreeSupportEfl::findString(const Evas_Object* ewkView, const String& text, WebCore::FindOptions options)
298{
299    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, false);
300
301    return page->findString(text, options);
302}
303
304void DumpRenderTreeSupportEfl::setCSSGridLayoutEnabled(const Evas_Object* ewkView, bool enabled)
305{
306    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
307
308    page->settings()->setCSSGridLayoutEnabled(enabled);
309}
310
311void DumpRenderTreeSupportEfl::setCSSRegionsEnabled(const Evas_Object* ewkView, bool enabled)
312{
313    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
314
315    WebCore::RuntimeEnabledFeatures::setCSSRegionsEnabled(enabled);
316}
317
318void DumpRenderTreeSupportEfl::setSeamlessIFramesEnabled(bool enabled)
319{
320#if ENABLE(IFRAME_SEAMLESS)
321    WebCore::RuntimeEnabledFeatures::setSeamlessIFramesEnabled(enabled);
322#else
323    UNUSED_PARAM(enabled);
324#endif
325}
326
327void DumpRenderTreeSupportEfl::setWebAudioEnabled(Evas_Object* ewkView, bool enabled)
328{
329#if ENABLE(WEB_AUDIO)
330    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
331
332    page->settings()->setWebAudioEnabled(enabled);
333#else
334    UNUSED_PARAM(ewkView);
335    UNUSED_PARAM(enabled);
336#endif
337}
338
339bool DumpRenderTreeSupportEfl::isCommandEnabled(const Evas_Object* ewkView, const char* name)
340{
341    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, false);
342
343    return page->focusController()->focusedOrMainFrame()->editor().command(name).isEnabled();
344}
345
346void DumpRenderTreeSupportEfl::forceLayout(Evas_Object* ewkFrame)
347{
348    ewk_frame_force_layout(ewkFrame);
349}
350
351void DumpRenderTreeSupportEfl::setTracksRepaints(Evas_Object* ewkFrame, bool enabled)
352{
353    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame);
354
355    if (frame->view())
356        frame->view()->setTracksRepaints(enabled);
357}
358
359void DumpRenderTreeSupportEfl::resetTrackedRepaints(Evas_Object* ewkFrame)
360{
361    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame);
362
363    if (frame->view())
364        frame->view()->resetTrackedRepaints();
365}
366
367bool DumpRenderTreeSupportEfl::isTrackingRepaints(const Evas_Object* ewkFrame)
368{
369    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, false);
370
371    if (!frame->view())
372        return false;
373
374    return frame->view()->isTrackingRepaints();
375}
376
377Eina_List* DumpRenderTreeSupportEfl::trackedRepaintRects(const Evas_Object* ewkFrame)
378{
379    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, 0);
380
381    if (!frame->view())
382        return 0;
383
384    const Vector<WebCore::IntRect>& repaintRects = frame->view()->trackedRepaintRects();
385    size_t count = repaintRects.size();
386    Eina_List* rectList = 0;
387
388    for (size_t i = 0; i < count; ++i) {
389        Eina_Rectangle* rect = eina_rectangle_new(repaintRects[i].x(), repaintRects[i].y(), repaintRects[i].width(), repaintRects[i].height());
390        rectList = eina_list_append(rectList, rect);
391    }
392
393    return rectList;
394}
395
396void DumpRenderTreeSupportEfl::garbageCollectorCollect()
397{
398    WebCore::gcController().garbageCollectNow();
399}
400
401void DumpRenderTreeSupportEfl::garbageCollectorCollectOnAlternateThread(bool waitUntilDone)
402{
403    WebCore::gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
404}
405
406size_t DumpRenderTreeSupportEfl::javaScriptObjectsCount()
407{
408    return WebCore::JSDOMWindow::commonVM()->heap.objectCount();
409}
410
411void DumpRenderTreeSupportEfl::setDeadDecodedDataDeletionInterval(double interval)
412{
413    WebCore::memoryCache()->setDeadDecodedDataDeletionInterval(interval);
414}
415
416HistoryItemChildrenVector DumpRenderTreeSupportEfl::childHistoryItems(const Ewk_History_Item* ewkHistoryItem)
417{
418    WebCore::HistoryItem* historyItem = EWKPrivate::coreHistoryItem(ewkHistoryItem);
419    HistoryItemChildrenVector kids;
420
421    if (!historyItem)
422        return kids;
423
424    const WebCore::HistoryItemVector& children = historyItem->children();
425    const unsigned size = children.size();
426
427    for (unsigned i = 0; i < size; ++i) {
428        Ewk_History_Item* kid = ewk_history_item_new_from_core(children[i].get());
429        kids.append(kid);
430    }
431
432    return kids;
433}
434
435String DumpRenderTreeSupportEfl::historyItemTarget(const Ewk_History_Item* ewkHistoryItem)
436{
437    WebCore::HistoryItem* historyItem = EWKPrivate::coreHistoryItem(ewkHistoryItem);
438
439    if (!historyItem)
440        return String();
441
442    return historyItem->target();
443}
444
445bool DumpRenderTreeSupportEfl::isTargetItem(const Ewk_History_Item* ewkHistoryItem)
446{
447    WebCore::HistoryItem* historyItem = EWKPrivate::coreHistoryItem(ewkHistoryItem);
448
449    if (!historyItem)
450        return false;
451
452    return historyItem->isTargetItem();
453}
454
455void DumpRenderTreeSupportEfl::evaluateInWebInspector(const Evas_Object* ewkView, long callId, const String& script)
456{
457#if ENABLE(INSPECTOR)
458    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
459
460    if (page->inspectorController())
461        page->inspectorController()->evaluateForTestInFrontend(callId, script);
462#else
463    UNUSED_PARAM(ewkView);
464    UNUSED_PARAM(callId);
465    UNUSED_PARAM(script);
466#endif
467}
468
469void DumpRenderTreeSupportEfl::evaluateScriptInIsolatedWorld(const Evas_Object* ewkFrame, int worldID, JSObjectRef globalObject, const String& script)
470{
471    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame);
472
473    // Comment from mac: Start off with some guess at a frame and a global object, we'll try to do better...!
474    WebCore::JSDOMWindow* anyWorldGlobalObject = frame->script()->globalObject(WebCore::mainThreadNormalWorld());
475
476    // Comment from mac: The global object is probably a shell object? - if so, we know how to use this!
477    JSC::JSObject* globalObjectObj = toJS(globalObject);
478    if (!strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell"))
479        anyWorldGlobalObject = static_cast<WebCore::JSDOMWindowShell*>(globalObjectObj)->window();
480
481    // Comment from mac: Get the frame from the global object we've settled on.
482    WebCore::Frame* globalFrame = anyWorldGlobalObject->impl()->frame();
483    if (!globalFrame)
484        return;
485
486    WebCore::ScriptController* proxy = globalFrame->script();
487    if (!proxy)
488        return;
489
490    static WTF::HashMap<int, WTF::RefPtr<WebCore::DOMWrapperWorld > > worldMap;
491
492    WTF::RefPtr<WebCore::DOMWrapperWorld> scriptWorld;
493    if (!worldID)
494        scriptWorld = WebCore::ScriptController::createWorld();
495    else {
496        WTF::HashMap<int, RefPtr<WebCore::DOMWrapperWorld > >::const_iterator it = worldMap.find(worldID);
497        if (it != worldMap.end())
498            scriptWorld = (*it).value;
499        else {
500            scriptWorld = WebCore::ScriptController::createWorld();
501            worldMap.set(worldID, scriptWorld);
502        }
503    }
504
505    // The code below is only valid for JSC, V8 specific code is to be added
506    // when V8 will be supported in EFL port. See Qt implemenation.
507    proxy->executeScriptInWorld(scriptWorld.get(), script, true);
508}
509
510JSGlobalContextRef DumpRenderTreeSupportEfl::globalContextRefForFrame(const Evas_Object* ewkFrame)
511{
512    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, 0);
513
514    return toGlobalRef(frame->script()->globalObject(WebCore::mainThreadNormalWorld())->globalExec());
515}
516
517void DumpRenderTreeSupportEfl::setMockScrollbarsEnabled(bool enable)
518{
519    WebCore::Settings::setMockScrollbarsEnabled(enable);
520}
521
522void DumpRenderTreeSupportEfl::deliverAllMutationsIfNecessary()
523{
524    WebCore::MutationObserver::deliverAllMutations();
525}
526
527void DumpRenderTreeSupportEfl::setInteractiveFormValidationEnabled(Evas_Object* ewkView, bool enabled)
528{
529    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
530
531    page->settings()->setInteractiveFormValidationEnabled(enabled);
532}
533
534void DumpRenderTreeSupportEfl::setValidationMessageTimerMagnification(Evas_Object* ewkView, int value)
535{
536    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
537
538    page->settings()->setValidationMessageTimerMagnification(value);
539}
540
541void DumpRenderTreeSupportEfl::setAuthorAndUserStylesEnabled(Evas_Object* ewkView, bool enabled)
542{
543    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
544
545    page->settings()->setAuthorAndUserStylesEnabled(enabled);
546}
547
548void DumpRenderTreeSupportEfl::setSerializeHTTPLoads(bool enabled)
549{
550    WebCore::resourceLoadScheduler()->setSerialLoadingEnabled(enabled);
551}
552
553void DumpRenderTreeSupportEfl::setShouldTrackVisitedLinks(bool shouldTrack)
554{
555    WebCore::PageGroup::setShouldTrackVisitedLinks(shouldTrack);
556}
557
558void DumpRenderTreeSupportEfl::setComposition(Evas_Object* ewkView, const char* text, int start, int length)
559{
560    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
561
562    if (!page->focusController() || !page->focusController()->focusedOrMainFrame())
563        return;
564
565    WebCore::Editor& editor = page->focusController()->focusedOrMainFrame()->editor();
566    if (!editor.canEdit() && !editor.hasComposition())
567        return;
568
569    const String compositionString = String::fromUTF8(text);
570    Vector<WebCore::CompositionUnderline> underlines;
571    underlines.append(WebCore::CompositionUnderline(0, compositionString.length(), WebCore::Color(0, 0, 0), false));
572    editor.setComposition(compositionString, underlines, start, start + length);
573}
574
575bool DumpRenderTreeSupportEfl::hasComposition(const Evas_Object* ewkView)
576{
577    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, false);
578
579    if (!page->focusController() || !page->focusController()->focusedOrMainFrame())
580        return false;
581
582    return page->focusController()->focusedOrMainFrame()->editor().hasComposition();
583}
584
585bool DumpRenderTreeSupportEfl::compositionRange(Evas_Object* ewkView, int* start, int* length)
586{
587    *start = *length = 0;
588
589    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, false);
590
591    if (!page->focusController() || !page->focusController()->focusedOrMainFrame())
592        return false;
593
594    WebCore::Editor& editor = page->focusController()->focusedOrMainFrame()->editor();
595    if (!editor.hasComposition())
596        return false;
597
598    *start = editor.compositionStart();
599    *length = editor.compositionEnd() - *start;
600    return true;
601}
602
603void DumpRenderTreeSupportEfl::confirmComposition(Evas_Object* ewkView, const char* text)
604{
605    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
606
607    if (!page->focusController() || !page->focusController()->focusedOrMainFrame())
608        return;
609
610    WebCore::Editor& editor = page->focusController()->focusedOrMainFrame()->editor();
611
612    if (!editor.hasComposition()) {
613        editor.insertText(String::fromUTF8(text), 0);
614        return;
615    }
616
617    if (text) {
618        editor.confirmComposition(String::fromUTF8(text));
619        return;
620    }
621    editor.confirmComposition();
622}
623
624WebCore::IntRect DumpRenderTreeSupportEfl::firstRectForCharacterRange(Evas_Object* ewkView, int location, int length)
625{
626    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, WebCore::IntRect());
627
628    if (!page->focusController() || !page->focusController()->focusedOrMainFrame())
629        return WebCore::IntRect();
630
631    if ((location + length < location) && (location + length))
632        length = 0;
633
634    WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
635
636    RefPtr<WebCore::Range> range = WebCore::TextIterator::rangeFromLocationAndLength(frame->selection()->rootEditableElementOrDocumentElement(), location, length);
637    if (!range)
638        return WebCore::IntRect();
639
640    return frame->editor().firstRectForRange(range.get());
641}
642
643bool DumpRenderTreeSupportEfl::selectedRange(Evas_Object* ewkView, int* start, int* length)
644{
645    if (!(start && length))
646        return false;
647
648    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, false);
649
650    if (!page->focusController() || !page->focusController()->focusedOrMainFrame())
651        return false;
652
653    WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
654    RefPtr<WebCore::Range> range = frame->selection()->toNormalizedRange().get();
655    if (!range)
656        return false;
657
658    WebCore::Element* selectionRoot = frame->selection()->rootEditableElement();
659    WebCore::Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
660
661    RefPtr<WebCore::Range> testRange = WebCore::Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
662    *start = WebCore::TextIterator::rangeLength(testRange.get());
663
664    WebCore::ExceptionCode ec;
665    testRange->setEnd(range->endContainer(), range->endOffset(), ec);
666    *length = WebCore::TextIterator::rangeLength(testRange.get());
667
668    return true;
669}
670
671void DumpRenderTreeSupportEfl::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const String& scheme)
672{
673    WebCore::SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
674}
675
676void DumpRenderTreeSupportEfl::resetGeolocationClientMock(const Evas_Object* ewkView)
677{
678#if ENABLE(GEOLOCATION)
679    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
680
681    WebCore::GeolocationClientMock* mock = static_cast<WebCore::GeolocationClientMock*>(WebCore::GeolocationController::from(page)->client());
682    mock->reset();
683#else
684    UNUSED_PARAM(ewkView);
685#endif
686}
687
688void DumpRenderTreeSupportEfl::setMockGeolocationPermission(const Evas_Object* ewkView, bool allowed)
689{
690#if ENABLE(GEOLOCATION)
691    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
692
693    WebCore::GeolocationClientMock* mock = static_cast<WebCore::GeolocationClientMock*>(WebCore::GeolocationController::from(page)->client());
694    mock->setPermission(allowed);
695#else
696    UNUSED_PARAM(ewkView);
697    UNUSED_PARAM(allowed);
698#endif
699}
700
701void DumpRenderTreeSupportEfl::setMockGeolocationPosition(const Evas_Object* ewkView, double latitude, double longitude, double accuracy, bool canProvideAltitude, double altitude, bool canProvideAltitudeAccuracy, double altitudeAccuracy, bool canProvideHeading, double heading, bool canProvideSpeed, double speed)
702{
703#if ENABLE(GEOLOCATION)
704    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
705
706    WebCore::GeolocationClientMock* mock = static_cast<WebCore::GeolocationClientMock*>(WebCore::GeolocationController::from(page)->client());
707    mock->setPosition(WebCore::GeolocationPosition::create(currentTime(), latitude, longitude, accuracy, canProvideAltitude, altitude, canProvideAltitudeAccuracy, altitudeAccuracy, canProvideHeading, heading, canProvideSpeed, speed));
708#else
709    UNUSED_PARAM(ewkView);
710    UNUSED_PARAM(latitude);
711    UNUSED_PARAM(longitude);
712    UNUSED_PARAM(accuracy);
713    UNUSED_PARAM(canProvideAltitude);
714    UNUSED_PARAM(altitude);
715    UNUSED_PARAM(canProvideAltitudeAccuracy);
716    UNUSED_PARAM(altitudeAccuracy);
717    UNUSED_PARAM(canProvideHeading);
718    UNUSED_PARAM(heading);
719    UNUSED_PARAM(canProvideSpeed);
720    UNUSED_PARAM(speed);
721#endif
722}
723
724void DumpRenderTreeSupportEfl::setMockGeolocationPositionUnavailableError(const Evas_Object* ewkView, const char* errorMessage)
725{
726#if ENABLE(GEOLOCATION)
727    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page);
728
729    WebCore::GeolocationClientMock* mock = static_cast<WebCore::GeolocationClientMock*>(WebCore::GeolocationController::from(page)->client());
730    mock->setPositionUnavailableError(errorMessage);
731#else
732    UNUSED_PARAM(ewkView);
733    UNUSED_PARAM(errorMessage);
734#endif
735}
736
737int DumpRenderTreeSupportEfl::numberOfPendingGeolocationPermissionRequests(const Evas_Object* ewkView)
738{
739#if ENABLE(GEOLOCATION)
740    DRT_SUPPRT_PAGE_GET_OR_RETURN(ewkView, page, -1);
741
742    WebCore::GeolocationClientMock* mock = static_cast<WebCore::GeolocationClientMock*>(WebCore::GeolocationController::from(page)->client());
743    return mock->numberOfPendingPermissionRequests();
744#else
745    UNUSED_PARAM(ewkView);
746    return 0;
747#endif
748}
749
750#if HAVE(ACCESSIBILITY)
751String DumpRenderTreeSupportEfl::accessibilityHelpText(const AtkObject* axObject)
752{
753    if (!axObject || !WEBKIT_IS_ACCESSIBLE(axObject))
754        return String();
755
756    WebCore::AccessibilityObject* coreObject = webkitAccessibleGetAccessibilityObject(WEBKIT_ACCESSIBLE(axObject));
757    if (!coreObject)
758        return String();
759
760    return coreObject->helpText();
761}
762
763AtkObject* DumpRenderTreeSupportEfl::rootAccessibleElement(const Evas_Object* ewkFrame)
764{
765    DRT_SUPPORT_FRAME_GET_OR_RETURN(ewkFrame, frame, 0);
766
767    if (!WebCore::AXObjectCache::accessibilityEnabled())
768        WebCore::AXObjectCache::enableAccessibility();
769
770    if (!frame->document())
771        return 0;
772
773    AtkObject* wrapper = frame->document()->axObjectCache()->rootObject()->wrapper();
774    if (!wrapper)
775        return 0;
776
777    return wrapper;
778}
779
780AtkObject* DumpRenderTreeSupportEfl::focusedAccessibleElement(const Evas_Object* ewkFrame)
781{
782    AtkObject* wrapper = rootAccessibleElement(ewkFrame);
783    if (!wrapper)
784        return 0;
785
786    return webkitAccessibleGetFocusedElement(WEBKIT_ACCESSIBLE(wrapper));
787}
788#endif
789