/* * Copyright (C) 2011 ProFUSION Embedded Systems * Copyright (C) 2011 Samsung Electronics * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ITS CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "DumpRenderTreeChrome.h" #include "DumpRenderTree.h" #include "DumpRenderTreeView.h" #include "EventSender.h" #include "GCController.h" #include "LayoutTestController.h" #include "NotImplemented.h" #include "WebCoreSupport/DumpRenderTreeSupportEfl.h" #include "WebCoreTestSupport.h" #include "WorkQueue.h" #include "ewk_private.h" // FIXME: create some WebCoreSupport/DumpRenderTree.cpp instead #include #include #include #include #include #include using namespace WebCore; PassOwnPtr DumpRenderTreeChrome::create(Evas* evas) { OwnPtr chrome = adoptPtr(new DumpRenderTreeChrome(evas)); if (!chrome->initialize()) return nullptr; return chrome.release(); } DumpRenderTreeChrome::DumpRenderTreeChrome(Evas* evas) : m_mainView(0) , m_mainFrame(0) , m_evas(evas) , m_gcController(adoptPtr(new GCController)) { } DumpRenderTreeChrome::~DumpRenderTreeChrome() { } Evas_Object* DumpRenderTreeChrome::createNewWindow() { Evas_Object* newView = createView(); ewk_view_setting_scripts_can_open_windows_set(newView, EINA_TRUE); ewk_view_setting_scripts_can_close_windows_set(newView, EINA_TRUE); m_extraViews.append(newView); return newView; } Evas_Object* DumpRenderTreeChrome::createView() const { Evas_Object* view = drtViewAdd(m_evas); if (!view) return 0; ewk_view_theme_set(view, DATA_DIR"/default.edj"); evas_object_smart_callback_add(view, "load,started", onLoadStarted, 0); evas_object_smart_callback_add(view, "title,changed", onTitleChanged, 0); evas_object_smart_callback_add(view, "window,object,cleared", onWindowObjectCleared, m_gcController.get()); evas_object_smart_callback_add(view, "statusbar,text,set", onStatusbarTextSet, 0); evas_object_smart_callback_add(view, "load,document,finished", onDocumentLoadFinished, 0); evas_object_smart_callback_add(view, "resource,request,willsend", onWillSendRequest, 0); evas_object_smart_callback_add(view, "onload,event", onWebViewOnloadEvent, 0); evas_object_smart_callback_add(view, "mixedcontent,run", onInsecureContentRun, 0); evas_object_smart_callback_add(view, "mixedcontent,displayed", onInsecureContentDisplayed, 0); evas_object_smart_callback_add(view, "frame,created", onFrameCreated, 0); Evas_Object* mainFrame = ewk_view_frame_main_get(view); evas_object_smart_callback_add(mainFrame, "load,provisional", onFrameProvisionalLoad, 0); evas_object_smart_callback_add(mainFrame, "load,committed", onFrameLoadCommitted, 0); evas_object_smart_callback_add(mainFrame, "load,finished", onFrameLoadFinished, 0); evas_object_smart_callback_add(mainFrame, "load,error", onFrameLoadError, 0); evas_object_smart_callback_add(mainFrame, "xss,detected", onDidDetectXSS, 0); return view; } void DumpRenderTreeChrome::removeWindow(Evas_Object* view) { const size_t pos = m_extraViews.find(view); if (pos == notFound) return; m_extraViews.remove(pos); evas_object_del(view); } bool DumpRenderTreeChrome::initialize() { DumpRenderTreeSupportEfl::setMockScrollbarsEnabled(true); m_mainView = createView(); if (!m_mainView) return false; ewk_view_theme_set(m_mainView, DATA_DIR"/default.edj"); evas_object_name_set(m_mainView, "m_mainView"); evas_object_move(m_mainView, 0, 0); evas_object_resize(m_mainView, 800, 600); evas_object_layer_set(m_mainView, EVAS_LAYER_MAX); evas_object_show(m_mainView); evas_object_focus_set(m_mainView, EINA_TRUE); m_mainFrame = ewk_view_frame_main_get(m_mainView); return true; } Vector DumpRenderTreeChrome::extraViews() const { return m_extraViews; } Evas_Object* DumpRenderTreeChrome::mainFrame() const { return m_mainFrame; } Evas_Object* DumpRenderTreeChrome::mainView() const { return m_mainView; } void DumpRenderTreeChrome::resetDefaultsToConsistentValues() { Vector::iterator it = m_extraViews.begin(); for (; it != m_extraViews.end(); ++it) evas_object_del(*it); m_extraViews.clear(); ewk_settings_icon_database_clear(); ewk_settings_icon_database_path_set(0); ewk_view_setting_private_browsing_set(mainView(), EINA_FALSE); ewk_view_setting_spatial_navigation_set(mainView(), EINA_FALSE); ewk_view_setting_enable_frame_flattening_set(mainView(), EINA_FALSE); ewk_view_setting_application_cache_set(mainView(), EINA_TRUE); ewk_view_setting_enable_scripts_set(mainView(), EINA_TRUE); ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_STANDARD, "Times"); ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_MONOSPACE, "Courier"); ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_SERIF, "Times"); ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_SANS_SERIF, "Helvetica"); ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_CURSIVE, "cursive"); ewk_view_font_family_name_set(mainView(), EWK_FONT_FAMILY_FANTASY, "fantasy"); ewk_view_setting_font_default_size_set(mainView(), 16); ewk_view_setting_font_monospace_size_set(mainView(), 13); ewk_view_setting_font_minimum_size_set(mainView(), 0); ewk_view_setting_caret_browsing_set(mainView(), EINA_FALSE); ewk_view_setting_page_cache_set(mainView(), EINA_FALSE); ewk_view_setting_enable_auto_resize_window_set(mainView(), EINA_TRUE); ewk_view_setting_enable_plugins_set(mainView(), EINA_TRUE); ewk_view_setting_scripts_can_open_windows_set(mainView(), EINA_TRUE); ewk_view_setting_scripts_can_close_windows_set(mainView(), EINA_TRUE); ewk_view_setting_auto_load_images_set(mainView(), EINA_TRUE); ewk_view_zoom_set(mainView(), 1.0, 0, 0); ewk_view_scale_set(mainView(), 1.0, 0, 0); ewk_history_clear(ewk_view_history_get(mainView())); ewk_cookies_clear(); ewk_cookies_policy_set(EWK_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY); DumpRenderTreeSupportEfl::clearFrameName(mainFrame()); DumpRenderTreeSupportEfl::clearOpener(mainFrame()); DumpRenderTreeSupportEfl::setInteractiveFormValidationEnabled(mainView(), true); } // Smart Callbacks // --------------- void DumpRenderTreeChrome::onWindowObjectCleared(void* userData, Evas_Object*, void* eventInfo) { Ewk_Window_Object_Cleared_Event* objectClearedInfo = static_cast(eventInfo); JSValueRef exception = 0; ASSERT(gLayoutTestController); GCController* gcController = static_cast(userData); ASSERT(gcController); gLayoutTestController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception); ASSERT(!exception); gcController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception); ASSERT(!exception); JSRetainPtr controllerName(JSStringCreateWithUTF8CString("eventSender")); JSObjectSetProperty(objectClearedInfo->context, objectClearedInfo->windowObject, controllerName.get(), makeEventSender(objectClearedInfo->context, !DumpRenderTreeSupportEfl::frameParent(objectClearedInfo->frame)), kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); WebCoreTestSupport::injectInternalsObject(objectClearedInfo->context); } void DumpRenderTreeChrome::onLoadStarted(void*, Evas_Object* view, void* eventInfo) { Evas_Object* frame = static_cast(eventInfo); // Make sure we only set this once per test. If it gets cleared, and then set again, we might // end up doing two dumps for one test. if (!topLoadingFrame && !done) topLoadingFrame = frame; } Eina_Bool DumpRenderTreeChrome::processWork(void*) { if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) dump(); return ECORE_CALLBACK_CANCEL; } void DumpRenderTreeChrome::topLoadingFrameLoadFinished() { topLoadingFrame = 0; WorkQueue::shared()->setFrozen(true); if (gLayoutTestController->waitToDump()) return; if (WorkQueue::shared()->count()) ecore_idler_add(processWork, 0 /*frame*/); else dump(); } void DumpRenderTreeChrome::onStatusbarTextSet(void*, Evas_Object*, void* eventInfo) { if (!gLayoutTestController->dumpStatusCallbacks()) return; const char* statusbarText = static_cast(eventInfo); printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", statusbarText); } void DumpRenderTreeChrome::onTitleChanged(void*, Evas_Object*, void* eventInfo) { if (!gLayoutTestController->dumpTitleChanges()) return; const char* titleText = static_cast(eventInfo); printf("TITLE CHANGED: %s\n", titleText); } void DumpRenderTreeChrome::onDocumentLoadFinished(void*, Evas_Object*, void* eventInfo) { const Evas_Object* frame = static_cast(eventInfo); const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame)); if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) printf("%s - didFinishDocumentLoadForFrame\n", frameName.utf8().data()); else if (!done) { const unsigned pendingFrameUnloadEvents = DumpRenderTreeSupportEfl::pendingUnloadEventCount(frame); if (pendingFrameUnloadEvents) printf("%s - has %u onunload handler(s)\n", frameName.utf8().data(), pendingFrameUnloadEvents); } } void DumpRenderTreeChrome::onWillSendRequest(void*, Evas_Object*, void* eventInfo) { Ewk_Frame_Resource_Request* request = static_cast(eventInfo); if (!done && gLayoutTestController->willSendRequestReturnsNull()) { // As requested by the LayoutTestController, don't perform the request. request->url = 0; return; } KURL url = KURL(ParsedURLString, request->url); if (url.isValid() && url.protocolIsInHTTPFamily() && url.host() != "127.0.0.1" && url.host() != "255.255.255.255" && url.host().lower() != "localhost") { printf("Blocked access to external URL %s\n", request->url); request->url = 0; } } void DumpRenderTreeChrome::onWebViewOnloadEvent(void*, Evas_Object*, void* eventInfo) { const Evas_Object* frame = static_cast(eventInfo); if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame)); printf("%s - didHandleOnloadEventsForFrame\n", frameName.utf8().data()); } } void DumpRenderTreeChrome::onInsecureContentRun(void*, Evas_Object*, void*) { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) printf("didRunInsecureContent\n"); } void DumpRenderTreeChrome::onInsecureContentDisplayed(void*, Evas_Object*, void*) { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) printf("didDisplayInsecureContent\n"); } void DumpRenderTreeChrome::onFrameCreated(void*, Evas_Object*, void* eventInfo) { Evas_Object* frame = static_cast(eventInfo); evas_object_smart_callback_add(frame, "load,provisional", onFrameProvisionalLoad, 0); evas_object_smart_callback_add(frame, "load,committed", onFrameLoadCommitted, 0); evas_object_smart_callback_add(frame, "load,finished", onFrameLoadFinished, 0); evas_object_smart_callback_add(frame, "load,error", onFrameLoadError, 0); evas_object_smart_callback_add(frame, "xss,detected", onDidDetectXSS, 0); } void DumpRenderTreeChrome::onFrameProvisionalLoad(void*, Evas_Object* frame, void*) { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame)); printf("%s - didStartProvisionalLoadForFrame\n", frameName.utf8().data()); } } void DumpRenderTreeChrome::onFrameLoadCommitted(void*, Evas_Object* frame, void*) { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame)); printf("%s - didCommitLoadForFrame\n", frameName.utf8().data()); } } void DumpRenderTreeChrome::onFrameLoadFinished(void*, Evas_Object* frame, void* eventInfo) { const Ewk_Frame_Load_Error* error = static_cast(eventInfo); // EFL port emits both "load,finished" and "load,error" signals in error case. // Error case is therefore already handled in onFrameLoadError() and we don't need // to handle it here. if (error) return; if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame)); printf("%s - didFinishLoadForFrame\n", frameName.utf8().data()); } if (frame == topLoadingFrame) topLoadingFrameLoadFinished(); } void DumpRenderTreeChrome::onFrameLoadError(void*, Evas_Object* frame, void*) { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) { const String frameName(DumpRenderTreeSupportEfl::suitableDRTFrameName(frame)); printf("%s - didFailLoadWithError\n", frameName.utf8().data()); } if (frame == topLoadingFrame) topLoadingFrameLoadFinished(); } void DumpRenderTreeChrome::onDidDetectXSS(void*, Evas_Object* view, void*) { if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) printf("didDetectXSS\n"); }