diff options
Diffstat (limited to 'Tools/DumpRenderTree/efl')
20 files changed, 3393 insertions, 0 deletions
diff --git a/Tools/DumpRenderTree/efl/CMakeLists.txt b/Tools/DumpRenderTree/efl/CMakeLists.txt new file mode 100644 index 000000000..c929191b2 --- /dev/null +++ b/Tools/DumpRenderTree/efl/CMakeLists.txt @@ -0,0 +1,132 @@ +SET(DumpRenderTree_SOURCES + ${TOOLS_DIR}/DumpRenderTree/CyclicRedundancyCheck.cpp + ${TOOLS_DIR}/DumpRenderTree/GCController.cpp + ${TOOLS_DIR}/DumpRenderTree/LayoutTestController.cpp + ${TOOLS_DIR}/DumpRenderTree/PixelDumpSupport.cpp + ${TOOLS_DIR}/DumpRenderTree/WorkQueue.cpp + ${TOOLS_DIR}/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpHistoryItem.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTree.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTreeChrome.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/DumpRenderTreeView.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/EventSender.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/FontManagement.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/GCControllerEfl.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/JSStringUtils.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/LayoutTestControllerEfl.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/PixelDumpSupportEfl.cpp + ${TOOLS_DIR}/DumpRenderTree/efl/WorkQueueItemEfl.cpp +) + +SET(ImageDiff_SOURCES + ${TOOLS_DIR}/DumpRenderTree/efl/ImageDiff.cpp +) + +SET(DumpRenderTree_LIBRARIES + ${JavaScriptCore_LIBRARY_NAME} + ${WebCore_LIBRARY_NAME} + ${WebKit_LIBRARY_NAME} + ${Cairo_LIBRARIES} + ${ECORE_X_LIBRARIES} + ${EDJE_LIBRARIES} + ${EFLDEPS_LIBRARIES} + ${EVAS_LIBRARIES} + ${LIBXML2_LIBRARIES} + ${LIBXSLT_LIBRARIES} + ${SQLITE_LIBRARIES} +) + +SET(DumpRenderTree_LIBRARIES ${DumpRenderTree_LIBRARIES}) +SET(DumpRenderTree_INCLUDE_DIRECTORIES + "${WEBKIT_DIR}/efl/ewk" + ${WEBKIT_DIR}/efl + ${WEBCORE_DIR} + ${WEBCORE_DIR}/bridge + ${WEBCORE_DIR}/bridge/jsc + ${WEBCORE_DIR}/bindings + ${WEBCORE_DIR}/dom + ${WEBCORE_DIR}/editing + ${WEBCORE_DIR}/css + ${WEBCORE_DIR}/html + ${WEBCORE_DIR}/page + ${WEBCORE_DIR}/page/animation + ${WEBCORE_DIR}/platform + ${WEBCORE_DIR}/platform/animation + ${WEBCORE_DIR}/platform/text + ${WEBCORE_DIR}/platform/graphics + ${WEBCORE_DIR}/platform/graphics/cairo + ${WEBCORE_DIR}/platform/network + ${WEBCORE_DIR}/plugins + ${WEBCORE_DIR}/rendering + ${WEBCORE_DIR}/rendering/style + ${WEBCORE_DIR}/history + ${WEBCORE_DIR}/loader + ${WEBCORE_DIR}/loader/cache + ${WEBCORE_DIR}/loader/icon + ${JAVASCRIPTCORE_DIR} + ${JAVASCRIPTCORE_DIR}/API + ${JAVASCRIPTCORE_DIR}/assembler + ${JAVASCRIPTCORE_DIR}/dfg + ${JAVASCRIPTCORE_DIR}/heap + ${JAVASCRIPTCORE_DIR}/interpreter + ${JAVASCRIPTCORE_DIR}/jit + ${JAVASCRIPTCORE_DIR}/runtime + ${JAVASCRIPTCORE_DIR}/ForwardingHeaders + ${JAVASCRIPTCORE_DIR}/wtf + ${JAVASCRIPTCORE_DIR}/wtf/efl + ${TOOLS_DIR}/DumpRenderTree + ${TOOLS_DIR}/DumpRenderTree/cairo + ${TOOLS_DIR}/DumpRenderTree/efl + ${CMAKE_SOURCE_DIR}/Source + ${CMAKE_BINARY_DIR} + ${DERIVED_SOURCES_WEBCORE_DIR} + ${WEBCORE_DIR}/bindings/js + ${Cairo_INCLUDE_DIRS} + ${EDJE_INCLUDE_DIRS} + ${EFLDEPS_INCLUDE_DIRS} + ${EVAS_INCLUDE_DIRS} +) + +SET(DumpRenderTree_LINK_FLAGS + ${ECORE_X_LDFLAGS} + ${EDJE_LDFLAGS} + ${EFLDEPS_LDFLAGS} + ${EVAS_LDFLAGS} +) + +IF (ENABLE_GLIB_SUPPORT) + LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES "${JAVASCRIPTCORE_DIR}/wtf/gobject") + + LIST(APPEND DumpRenderTree_LIBRARIES + ${Gdk_LIBRARIES} + ${Glib_LIBRARIES} + ${Gthread_LIBRARIES} + ) +ENDIF () + +IF (WTF_USE_SOUP) + LIST(APPEND DumpRenderTree_LIBRARIES ${LIBSOUP24_LIBRARIES}) + LIST(APPEND DumpRenderTree_LINK_FLAGS ${LIBSOUP24_LDFLAGS}) + LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES ${LIBSOUP24_INCLUDE_DIRS} ${WEBCORE_DIR}/platform/network/soup) +ENDIF () + +IF (WTF_USE_CURL) + LIST(APPEND DumpRenderTree_LIBRARIES ${CURL_LIBRARIES}) + LIST(APPEND DumpRenderTree_LINK_FLAGS ${CURL_LDFLAGS}) + LIST(APPEND DumpRenderTree_INCLUDE_DIRECTORIES ${WEBCORE_DIR}/platform/network/curl) +ENDIF () + +ADD_DEFINITIONS(-DFONTS_CONF_DIR="${TOOLS_DIR}/DumpRenderTree/gtk/fonts" + -DDATA_DIR="${THEME_BINARY_DIR}") + +INCLUDE_DIRECTORIES(${DumpRenderTree_INCLUDE_DIRECTORIES}) + +ADD_EXECUTABLE(Programs/DumpRenderTree ${DumpRenderTree_SOURCES}) +TARGET_LINK_LIBRARIES(Programs/DumpRenderTree ${DumpRenderTree_LIBRARIES}) +ADD_TARGET_PROPERTIES(Programs/DumpRenderTree LINK_FLAGS "${DumpRenderTree_LINK_FLAGS}") +SET_TARGET_PROPERTIES(Programs/DumpRenderTree PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") + +ADD_EXECUTABLE(Programs/ImageDiff ${ImageDiff_SOURCES}) +TARGET_LINK_LIBRARIES(Programs/ImageDiff ${DumpRenderTree_LIBRARIES}) +ADD_TARGET_PROPERTIES(Programs/ImageDiff LINK_FLAGS "${DumpRenderTree_LINK_FLAGS}") +SET_TARGET_PROPERTIES(Programs/ImageDiff PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") diff --git a/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp b/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp new file mode 100644 index 000000000..125b12847 --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpHistoryItem.cpp @@ -0,0 +1,134 @@ +/* + * 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 APPLE INC. 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 APPLE INC. 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 "DumpHistoryItem.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <algorithm> +#include <cstdio> +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +Ewk_History_Item* prevTestBFItem = 0; +const unsigned historyItemIndent = 8; + +static bool compareHistoryItemsByTarget(const Ewk_History_Item* item1, const Ewk_History_Item* item2) +{ + return WTF::codePointCompare(DumpRenderTreeSupportEfl::historyItemTarget(item1), + DumpRenderTreeSupportEfl::historyItemTarget(item2)) < 1; +} + +static void dumpHistoryItem(const Ewk_History_Item* item, int indent, bool current) +{ + ASSERT(item); + int start = 0; + if (current) { + printf("curr->"); + start = 6; + } + for (int i = start; i < indent; i++) + putchar(' '); + + // normalize file URLs. + const char* uri = ewk_history_item_uri_get(item); + if (!strncasecmp(uri, "file://", sizeof("file://") - 1)) { + const char* pos = strstr(uri, "/LayoutTests/"); + if (!pos) + return; + + printf("(file test):%s", pos + sizeof("/LayoutTests/") - 1); + } else + printf("%s", uri); + + const String target = DumpRenderTreeSupportEfl::historyItemTarget(item); + if (!target.isEmpty()) + printf(" (in frame \"%s\")", target.utf8().data()); + if (DumpRenderTreeSupportEfl::isTargetItem(item)) + printf(" **nav target**"); + putchar('\n'); + + HistoryItemChildrenVector children = DumpRenderTreeSupportEfl::childHistoryItems(item); + + // Must sort to eliminate arbitrary result ordering which defeats reproducible testing. + std::stable_sort(children.begin(), children.end(), compareHistoryItemsByTarget); + + const size_t size = children.size(); + for (size_t i = 0; i < size; ++i) + dumpHistoryItem(children[i], indent + 4, false); +} + +static void dumpBackForwardListForWebView(Evas_Object* view) +{ + printf("\n============== Back Forward List ==============\n"); + + const Ewk_History* history = ewk_view_history_get(view); + + // Print out all items in the list after prevTestBFItem, which was from the previous test + // Gather items from the end of the list, the print them out from oldest to newest + Eina_List* itemsToPrint = 0; + void* historyItem; + Eina_List* backwardList = ewk_history_back_list_get(history); + EINA_LIST_FREE(backwardList, historyItem) { + if (historyItem == prevTestBFItem) { + eina_list_free(backwardList); + break; + } + itemsToPrint = eina_list_append(itemsToPrint, historyItem); + } + + const Ewk_History_Item* currentItem = ewk_history_history_item_current_get(history); + if (currentItem) + itemsToPrint = eina_list_append(itemsToPrint, currentItem); + + Eina_List* forwardList = ewk_history_forward_list_get(history); + EINA_LIST_FREE(forwardList, historyItem) { + ASSERT(historyItem != prevTestBFItem); + itemsToPrint = eina_list_append(itemsToPrint, historyItem); + } + + EINA_LIST_FREE(itemsToPrint, historyItem) { + dumpHistoryItem(static_cast<Ewk_History_Item*>(historyItem), historyItemIndent, historyItem == currentItem); + ewk_history_item_free(static_cast<Ewk_History_Item*>(historyItem)); + } + + printf("===============================================\n"); +} + +void dumpBackForwardListForWebViews() +{ + // Dump the back forward list of the main WebView first + dumpBackForwardListForWebView(browser->mainView()); + + Vector<Evas_Object*>::const_iterator it = browser->extraViews().begin(); + for (; it != browser->extraViews().end(); ++it) + dumpBackForwardListForWebView(*it); +} diff --git a/Tools/DumpRenderTree/efl/DumpHistoryItem.h b/Tools/DumpRenderTree/efl/DumpHistoryItem.h new file mode 100644 index 000000000..ea8afeaaf --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpHistoryItem.h @@ -0,0 +1,33 @@ +/* + * 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 APPLE INC. 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 APPLE INC. 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. + */ + +#ifndef DumpHistoryItem_h +#define DumpHistoryItem_h + +#include <Evas.h> + +void dumpBackForwardListForWebViews(); + +#endif // DumpHistoryItem_h diff --git a/Tools/DumpRenderTree/efl/DumpRenderTree.cpp b/Tools/DumpRenderTree/efl/DumpRenderTree.cpp new file mode 100644 index 000000000..bb8f7d2d7 --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTree.cpp @@ -0,0 +1,416 @@ +/* + * 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 APPLE INC. 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 APPLE INC. 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 "DumpRenderTree.h" + +#include "DumpHistoryItem.h" +#include "DumpRenderTreeChrome.h" +#include "DumpRenderTreeView.h" +#include "EventSender.h" +#include "FontManagement.h" +#include "LayoutTestController.h" +#include "NotImplemented.h" +#include "PixelDumpSupport.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "WorkQueue.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <Ecore.h> +#include <Ecore_Evas.h> +#include <Ecore_File.h> +#include <Edje.h> +#include <Evas.h> +#include <fontconfig/fontconfig.h> +#include <getopt.h> +#include <stdlib.h> +#include <text/CString.h> +#include <unistd.h> +#include <wtf/OwnPtr.h> + +OwnPtr<DumpRenderTreeChrome> browser; +Evas_Object* topLoadingFrame = 0; +bool waitForPolicy = false; +Ecore_Timer* waitToDumpWatchdog = 0; +extern Ewk_History_Item* prevTestBFItem; + +// From the top-level DumpRenderTree.h +RefPtr<LayoutTestController> gLayoutTestController; +volatile bool done = false; + +static int dumpPixels = false; +static int dumpTree = true; +static int printSeparators = true; +static int useX11Window = false; + +static String dumpFramesAsText(Evas_Object* frame) +{ + String result; + + if (browser->mainFrame() != frame) { + result.append("\n--------\nFrame: '"); + result.append(String::fromUTF8(ewk_frame_name_get(frame))); + result.append("'\n--------\n"); + } + + char* frameContents = ewk_frame_plain_text_get(frame); + result.append(String::fromUTF8(frameContents)); + result.append("\n"); + free(frameContents); + + if (gLayoutTestController->dumpChildFramesAsText()) { + Eina_List* children = DumpRenderTreeSupportEfl::frameChildren(frame); + void* iterator; + + EINA_LIST_FREE(children, iterator) { + Evas_Object* currentFrame = static_cast<Evas_Object*>(iterator); + String tempText(dumpFramesAsText(currentFrame)); + + if (tempText.isEmpty()) + continue; + + result.append(tempText); + } + } + + return result; +} + +static void dumpFrameScrollPosition(Evas_Object*) +{ + notImplemented(); +} + +static bool shouldLogFrameLoadDelegates(const String& pathOrURL) +{ + return pathOrURL.contains("loading/"); +} + +static bool shouldDumpAsText(const String& pathOrURL) +{ + return pathOrURL.contains("dumpAsText/"); +} + +static void sendPixelResultsEOF() +{ + puts("#EOF"); + fflush(stdout); + fflush(stderr); +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (waitToDumpWatchdog) { + ecore_timer_del(waitToDumpWatchdog); + waitToDumpWatchdog = 0; + } + waitForPolicy = false; +} + +static void onEcoreEvasResize(Ecore_Evas* ecoreEvas) +{ + int width, height; + + ecore_evas_geometry_get(ecoreEvas, 0, 0, &width, &height); + evas_object_move(browser->mainView(), 0, 0); + evas_object_resize(browser->mainView(), width, height); +} + +static void onCloseWindow(Ecore_Evas*) +{ + notImplemented(); +} + +static Eina_Bool useLongRunningServerMode(int argc, char** argv) +{ + return (argc == optind + 1 && !strcmp(argv[optind], "-")); +} + +static bool parseCommandLineOptions(int argc, char** argv) +{ + static const option options[] = { + {"notree", no_argument, &dumpTree, false}, + {"pixel-tests", no_argument, &dumpPixels, true}, + {"tree", no_argument, &dumpTree, true}, + {"gui", no_argument, &useX11Window, true}, + {0, 0, 0, 0} + }; + + int option; + while ((option = getopt_long(argc, (char* const*)argv, "", options, 0)) != -1) { + switch (option) { + case '?': + case ':': + return false; + } + } + + return true; +} + +static String getFinalTestURL(const String& testURL) +{ + const size_t hashSeparatorPos = testURL.find("'"); + if (hashSeparatorPos != notFound) + return getFinalTestURL(testURL.left(hashSeparatorPos)); + + // Convert the path into a full file URL if it does not look + // like an HTTP/S URL (doesn't start with http:// or https://). + if (!testURL.startsWith("http://") && !testURL.startsWith("https://")) { + char* cFilePath = ecore_file_realpath(testURL.utf8().data()); + const String filePath = String::fromUTF8(cFilePath); + free(cFilePath); + + if (ecore_file_exists(filePath.utf8().data())) + return String("file://") + filePath; + } + + return testURL; +} + +static String getExpectedPixelHash(const String& testURL) +{ + const size_t hashSeparatorPos = testURL.find("'"); + return (hashSeparatorPos != notFound) ? testURL.substring(hashSeparatorPos + 1) : String(); +} + +static void createLayoutTestController(const String& testURL, const String& expectedPixelHash) +{ + gLayoutTestController = + LayoutTestController::create(std::string(testURL.utf8().data()), + std::string(expectedPixelHash.utf8().data())); + + topLoadingFrame = 0; + done = false; + + gLayoutTestController->setIconDatabaseEnabled(false); + + if (shouldLogFrameLoadDelegates(testURL)) + gLayoutTestController->setDumpFrameLoadCallbacks(true); + + gLayoutTestController->setDeveloperExtrasEnabled(true); + + if (shouldDumpAsText(testURL)) { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } +} + +static void runTest(const char* cTestPathOrURL) +{ + const String testPathOrURL = String::fromUTF8(cTestPathOrURL); + ASSERT(!testPathOrURL.isEmpty()); + + const String testURL = getFinalTestURL(testPathOrURL); + const String expectedPixelHash = getExpectedPixelHash(testPathOrURL); + + browser->resetDefaultsToConsistentValues(); + createLayoutTestController(testURL, expectedPixelHash); + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + const bool isSVGW3CTest = testURL.contains("svg/W3C-SVG-1.1"); + const int width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth; + const int height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight; + evas_object_resize(browser->mainView(), width, height); + + if (prevTestBFItem) + ewk_history_item_free(prevTestBFItem); + const Ewk_History* history = ewk_view_history_get(browser->mainView()); + prevTestBFItem = ewk_history_history_item_current_get(history); + + evas_object_focus_set(browser->mainView(), EINA_TRUE); + ewk_view_uri_set(browser->mainView(), testURL.utf8().data()); + + ecore_main_loop_begin(); + + gLayoutTestController->closeWebInspector(); + gLayoutTestController->setDeveloperExtrasEnabled(false); + + ewk_view_uri_set(browser->mainView(), "about:blank"); + + gLayoutTestController.clear(); + sendPixelResultsEOF(); +} + +static void runTestingServerLoop() +{ + char filename[PATH_MAX]; + + while (fgets(filename, sizeof(filename), stdin)) { + char* newLine = strrchr(filename, '\n'); + if (newLine) + *newLine = '\0'; + + if (filename[0] != '\0') + runTest(filename); + } +} + +static void adjustOutputTypeByMimeType(const Evas_Object* frame) +{ + const String responseMimeType(DumpRenderTreeSupportEfl::responseMimeType(frame)); + if (responseMimeType == "text/plain") { + gLayoutTestController->setDumpAsText(true); + gLayoutTestController->setGeneratePixelResults(false); + } +} + +static void dumpFrameContentsAsText(Evas_Object* frame) +{ + String result; + if (gLayoutTestController->dumpAsText()) + result = dumpFramesAsText(frame); + else + result = DumpRenderTreeSupportEfl::renderTreeDump(frame); + + printf("%s", result.utf8().data()); +} + +static bool shouldDumpFrameScrollPosition() +{ + return gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive(); +} + +static bool shouldDumpPixelsAndCompareWithExpected() +{ + return dumpPixels && gLayoutTestController->generatePixelResults() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive(); +} + +static bool shouldDumpBackForwardList() +{ + return gLayoutTestController->dumpBackForwardList(); +} + +static bool initEfl() +{ + if (!ecore_evas_init()) + return false; + if (!ecore_file_init()) { + ecore_evas_shutdown(); + return false; + } + if (!edje_init()) { + ecore_file_shutdown(); + ecore_evas_shutdown(); + return false; + } + if (!ewk_init()) { + edje_shutdown(); + ecore_file_shutdown(); + ecore_evas_shutdown(); + return false; + } + + return true; +} + +static void shutdownEfl() +{ + ewk_shutdown(); + edje_shutdown(); + ecore_file_shutdown(); + ecore_evas_shutdown(); +} + +void displayWebView() +{ + notImplemented(); +} + +void dump() +{ + Evas_Object* frame = browser->mainFrame(); + + invalidateAnyPreviousWaitToDumpWatchdog(); + + if (dumpTree) { + adjustOutputTypeByMimeType(frame); + dumpFrameContentsAsText(frame); + + if (shouldDumpFrameScrollPosition()) + dumpFrameScrollPosition(frame); + + if (shouldDumpBackForwardList()) + dumpBackForwardListForWebViews(); + + if (printSeparators) { + puts("#EOF"); + fputs("#EOF\n", stderr); + fflush(stdout); + fflush(stderr); + } + } + + if (shouldDumpPixelsAndCompareWithExpected()) + dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash()); + + done = true; + ecore_main_loop_quit(); +} + +static Ecore_Evas* initEcoreEvas() +{ + Ecore_Evas* ecoreEvas = useX11Window ? ecore_evas_new(0, 0, 0, 800, 600, 0) : ecore_evas_buffer_new(800, 600); + if (!ecoreEvas) { + shutdownEfl(); + exit(EXIT_FAILURE); + } + + ecore_evas_title_set(ecoreEvas, "EFL DumpRenderTree"); + ecore_evas_callback_resize_set(ecoreEvas, onEcoreEvasResize); + ecore_evas_callback_delete_request_set(ecoreEvas, onCloseWindow); + ecore_evas_show(ecoreEvas); + + return ecoreEvas; +} + +int main(int argc, char** argv) +{ + if (!parseCommandLineOptions(argc, argv)) + return EXIT_FAILURE; + + if (!initEfl()) + return EXIT_FAILURE; + + OwnPtr<Ecore_Evas> ecoreEvas = adoptPtr(initEcoreEvas()); + browser = DumpRenderTreeChrome::create(ecore_evas_get(ecoreEvas.get())); + addFontsToEnvironment(); + + if (useLongRunningServerMode(argc, argv)) { + printSeparators = true; + runTestingServerLoop(); + } else { + printSeparators = (optind < argc - 1 || (dumpPixels && dumpTree)); + for (int i = optind; i != argc; ++i) + runTest(argv[i]); + } + + ecoreEvas.clear(); + + shutdownEfl(); + return EXIT_SUCCESS; +} diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp new file mode 100644 index 000000000..ce7a00d9f --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.cpp @@ -0,0 +1,282 @@ +/* + * 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 "WorkQueue.h" +#include "ewk_private.h" // FIXME: create some WebCoreSupport/DumpRenderTree.cpp instead + +#include <EWebKit.h> +#include <Ecore.h> +#include <Eina.h> +#include <Evas.h> +#include <cstdio> +#include <wtf/NotFound.h> + +PassOwnPtr<DumpRenderTreeChrome> DumpRenderTreeChrome::create(Evas* evas) +{ + OwnPtr<DumpRenderTreeChrome> 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, "load,finished", onLoadFinished, 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); + + 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<Evas_Object*> 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<Evas_Object*>::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_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()); +} + +// Smart Callbacks +// --------------- + +void DumpRenderTreeChrome::onWindowObjectCleared(void* userData, Evas_Object*, void* eventInfo) +{ + Ewk_Window_Object_Cleared_Event* objectClearedInfo = static_cast<Ewk_Window_Object_Cleared_Event*>(eventInfo); + JSValueRef exception = 0; + ASSERT(gLayoutTestController); + + GCController* gcController = static_cast<GCController*>(userData); + ASSERT(gcController); + + gLayoutTestController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception); + ASSERT(!exception); + + gcController->makeWindowObject(objectClearedInfo->context, objectClearedInfo->windowObject, &exception); + ASSERT(!exception); + + JSRetainPtr<JSStringRef> controllerName(JSStringCreateWithUTF8CString("eventSender")); + JSObjectSetProperty(objectClearedInfo->context, objectClearedInfo->windowObject, + controllerName.get(), + makeEventSender(objectClearedInfo->context, !DumpRenderTreeSupportEfl::frameParent(objectClearedInfo->frame)), + kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); +} + +void DumpRenderTreeChrome::onLoadStarted(void*, Evas_Object* view, void*) +{ + // FIXME: we actually need the frame related to this event + Evas_Object* frame = ewk_view_frame_main_get(view); + + // 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* data) +{ + Evas_Object* frame = static_cast<Evas_Object*>(data); + + if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump()) + dump(); + + return ECORE_CALLBACK_CANCEL; +} + +void DumpRenderTreeChrome::onLoadFinished(void*, Evas_Object* view, void*) +{ + // FIXME: we actually need the frame related to this event + Evas_Object* frame = ewk_view_frame_main_get(view); + + if (topLoadingFrame != frame) + return; + + topLoadingFrame = 0; + + WorkQueue::shared()->setFrozen(true); + if (gLayoutTestController->waitToDump()) + return; + + if (WorkQueue::shared()->count()) + ecore_idler_add(processWork, frame); + else + dump(); +} + +void DumpRenderTreeChrome::onStatusbarTextSet(void*, Evas_Object*, void* eventInfo) +{ + if (!gLayoutTestController->dumpStatusCallbacks()) + return; + + const char* statusbarText = static_cast<const char*>(eventInfo); + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", statusbarText); +} + +void DumpRenderTreeChrome::onTitleChanged(void*, Evas_Object*, void*) +{ + notImplemented(); +} + +void DumpRenderTreeChrome::onDocumentLoadFinished(void*, Evas_Object*, void* eventInfo) +{ + const Evas_Object* frame = static_cast<Evas_Object*>(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); + } +} diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h new file mode 100644 index 000000000..4ea991806 --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeChrome.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#ifndef DumpRenderTreeChrome_h +#define DumpRenderTreeChrome_h + +#include "GCController.h" + +#include <Eina.h> +#include <Evas.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +class DumpRenderTreeChrome { +public: + ~DumpRenderTreeChrome(); + + static PassOwnPtr<DumpRenderTreeChrome> create(Evas*); + + Evas_Object* createNewWindow(); + void removeWindow(Evas_Object*); + + Vector<Evas_Object*> extraViews() const; + Evas_Object* mainFrame() const; + Evas_Object* mainView() const; + + void resetDefaultsToConsistentValues(); + +private: + DumpRenderTreeChrome(Evas*); + + Evas_Object* createView() const; + bool initialize(); + + Evas_Object* m_mainFrame; + Evas_Object* m_mainView; + Evas* m_evas; + OwnPtr<GCController> m_gcController; + Vector<Evas_Object*> m_extraViews; + + // Smart callbacks + static void onWindowObjectCleared(void*, Evas_Object*, void*); + static void onLoadStarted(void*, Evas_Object*, void*); + + static Eina_Bool processWork(void*); + + static void onLoadFinished(void*, Evas_Object*, void*); + + static void onStatusbarTextSet(void*, Evas_Object*, void*); + + static void onTitleChanged(void*, Evas_Object*, void*); + + static void onDocumentLoadFinished(void*, Evas_Object*, void*); +}; + +#endif // DumpRenderTreeChrome_h diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h b/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h new file mode 100644 index 000000000..43812b19b --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeEfl.h @@ -0,0 +1,41 @@ +/* + * 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. Red istributions 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. + */ + +#ifndef DumpRenderTreeEfl_h +#define DumpRenderTreeEfl_h + +#include <Ecore.h> +#include <Evas.h> +#include <wtf/OwnPtr.h> + +class DumpRenderTreeChrome; + +extern OwnPtr<DumpRenderTreeChrome> browser; +extern Evas_Object* topLoadingFrame; +extern bool waitForPolicy; +extern Ecore_Timer* waitToDumpWatchdog; + +#endif /* DumpRenderTreeEfl_h */ diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp b/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp new file mode 100644 index 000000000..938c3fbdb --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeView.cpp @@ -0,0 +1,113 @@ +/* + * 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. Red istributions 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 APPLE INC. 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 APPLE INC. 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 "DumpRenderTreeView.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "LayoutTestController.h" +#include <EWebKit.h> +#include <Ecore.h> +#include <Eina.h> +#include <Evas.h> +#include <cstdio> +#include <cstdlib> + +using namespace std; + +static Ewk_View_Smart_Class gParentSmartClass = EWK_VIEW_SMART_CLASS_INIT_NULL; + +static void onConsoleMessage(Ewk_View_Smart_Data*, const char* message, unsigned int lineNumber, const char*) +{ + printf("CONSOLE MESSAGE: line %u: %s\n", lineNumber, message); +} + +static void onJavaScriptAlert(Ewk_View_Smart_Data*, Evas_Object*, const char* message) +{ + printf("ALERT: %s\n", message); +} + +static Eina_Bool onJavaScriptConfirm(Ewk_View_Smart_Data*, Evas_Object*, const char* message) +{ + printf("CONFIRM: %s\n", message); + return EINA_TRUE; +} + +static Eina_Bool onJavaScriptPrompt(Ewk_View_Smart_Data*, Evas_Object*, const char* message, const char* defaultValue, char** value) +{ + printf("PROMPT: %s, default text: %s\n", message, defaultValue); + *value = strdup(defaultValue); + return EINA_TRUE; +} + +static Evas_Object* onWindowCreate(Ewk_View_Smart_Data*, Eina_Bool, const Ewk_Window_Features*) +{ + return gLayoutTestController->canOpenWindows() ? browser->createNewWindow() : 0; +} + +static Eina_Bool onWindowCloseDelayed(void* data) +{ + Evas_Object* view = static_cast<Evas_Object*>(data); + browser->removeWindow(view); + return EINA_FALSE; +} + +static void onWindowClose(Ewk_View_Smart_Data* smartData) +{ + Evas_Object* view = smartData->self; + ecore_idler_add(onWindowCloseDelayed, view); +} + +static bool shouldUseSingleBackingStore() +{ + const char* useSingleBackingStore = getenv("DRT_USE_SINGLE_BACKING_STORE"); + return useSingleBackingStore && *useSingleBackingStore == '1'; +} + +static bool chooseAndInitializeAppropriateSmartClass(Ewk_View_Smart_Class* api) +{ + return shouldUseSingleBackingStore() ? ewk_view_single_smart_set(api) : ewk_view_tiled_smart_set(api); +} + +Evas_Object* drtViewAdd(Evas* evas) +{ + static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("DRT_View"); + + if (!chooseAndInitializeAppropriateSmartClass(&api)) + return 0; + + if (EINA_UNLIKELY(!gParentSmartClass.sc.add)) + ewk_view_base_smart_set(&gParentSmartClass); + + api.add_console_message = onConsoleMessage; + api.run_javascript_alert = onJavaScriptAlert; + api.run_javascript_confirm = onJavaScriptConfirm; + api.run_javascript_prompt = onJavaScriptPrompt; + api.window_create = onWindowCreate; + api.window_close = onWindowClose; + + return evas_object_smart_add(evas, evas_smart_class_new(&api.sc)); +} diff --git a/Tools/DumpRenderTree/efl/DumpRenderTreeView.h b/Tools/DumpRenderTree/efl/DumpRenderTreeView.h new file mode 100644 index 000000000..72ddab56d --- /dev/null +++ b/Tools/DumpRenderTree/efl/DumpRenderTreeView.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 ProFUSION Embedded Systems. All rights reserved. + * + * 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. Red istributions 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 APPLE INC. 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 APPLE INC. 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. + */ + +#ifndef DumpRenderTreeView_h +#define DumpRenderTreeView_h + +#include <Evas.h> + +Evas_Object* drtViewAdd(Evas*); + +#endif // DumpRenderTreeView_h diff --git a/Tools/DumpRenderTree/efl/EventSender.cpp b/Tools/DumpRenderTree/efl/EventSender.cpp new file mode 100644 index 000000000..89130f00a --- /dev/null +++ b/Tools/DumpRenderTree/efl/EventSender.cpp @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2009 Holger Hans Peter Freyther + * Copyright (C) 2010 Igalia S.L. + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 APPLE 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 "EventSender.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "JSStringUtils.h" +#include "NotImplemented.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/OpaqueJSString.h> +#include <wtf/ASCIICType.h> +#include <wtf/Platform.h> +#include <wtf/text/CString.h> + +static bool gDragMode; +static int gTimeOffset = 0; + +static int gLastMousePositionX; +static int gLastMousePositionY; +static int gLastClickPositionX; +static int gLastClickPositionY; +static int gLastClickTimeOffset; +static int gLastClickButton; +static int gButtonCurrentlyDown; +static int gClickCount; + +static const float zoomMultiplierRatio = 1.2f; + +// Key event location code defined in DOM Level 3. +enum KeyLocationCode { + DomKeyLocationStandard, + DomKeyLocationLeft, + DomKeyLocationRight, + DomKeyLocationNumpad +}; + +enum EvasKeyModifier { + EvasKeyModifierNone = 0, + EvasKeyModifierControl = 1 << 0, + EvasKeyModifierShift = 1 << 1, + EvasKeyModifierAlt = 1 << 2, + EvasKeyModifierMeta = 1 << 3 +}; + +enum EvasMouseButton { + EvasMouseButtonNone, + EvasMouseButtonLeft, + EvasMouseButtonMiddle, + EvasMouseButtonRight +}; + +enum EvasMouseEvent { + EvasMouseEventNone = 0, + EvasMouseEventDown = 1 << 0, + EvasMouseEventUp = 1 << 1, + EvasMouseEventMove = 1 << 2, + EvasMouseEventScrollUp = 1 << 3, + EvasMouseEventScrollDown = 1 << 4, + EvasMouseEventScrollLeft = 1 << 5, + EvasMouseEventScrollRight = 1 << 6, + EvasMouseEventClick = EvasMouseEventMove | EvasMouseEventDown | EvasMouseEventUp, +}; + +static void setEvasModifiers(Evas* evas, EvasKeyModifier modifiers) +{ + static const char* modifierNames[] = { "Control", "Shift", "Alt", "Super" }; + for (unsigned modifier = 0; modifier < 4; ++modifier) { + if (modifiers & (1 << modifier)) + evas_key_modifier_on(evas, modifierNames[modifier]); + else + evas_key_modifier_off(evas, modifierNames[modifier]); + } +} + +static EvasMouseButton translateMouseButtonNumber(int eventSenderButtonNumber) +{ + static const EvasMouseButton translationTable[] = { + EvasMouseButtonLeft, + EvasMouseButtonMiddle, + EvasMouseButtonRight, + EvasMouseButtonMiddle // fast/events/mouse-click-events expects the 4th button to be treated as the middle button + }; + static const unsigned translationTableSize = sizeof(translationTable) / sizeof(translationTable[0]); + + if (eventSenderButtonNumber < translationTableSize) + return translationTable[eventSenderButtonNumber]; + + return EvasMouseButtonLeft; +} + +static bool sendMouseEvent(Evas* evas, EvasMouseEvent event, int buttonNumber, EvasKeyModifier modifiers) +{ + unsigned timeStamp = 0; + + DumpRenderTreeSupportEfl::layoutFrame(browser->mainFrame()); + + setEvasModifiers(evas, modifiers); + if (event & EvasMouseEventMove) + evas_event_feed_mouse_move(evas, gLastMousePositionX, gLastMousePositionY, timeStamp++, 0); + if (event & EvasMouseEventDown) + evas_event_feed_mouse_down(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0); + if (event & EvasMouseEventUp) + evas_event_feed_mouse_up(evas, buttonNumber, EVAS_BUTTON_NONE, timeStamp++, 0); + + const bool horizontal = !!(event & EvasMouseEventScrollLeft | event & EvasMouseEventScrollRight); + const bool vertical = !!(event & EvasMouseEventScrollUp | event & EvasMouseEventScrollDown); + if (vertical && horizontal) { + evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0); + evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0); + } else if (vertical) + evas_event_feed_mouse_wheel(evas, 0, (event & EvasMouseEventScrollUp) ? 10 : -10, timeStamp, 0); + else if (horizontal) + evas_event_feed_mouse_wheel(evas, 1, (event & EvasMouseEventScrollLeft) ? 10 : -10, timeStamp, 0); + + setEvasModifiers(evas, EvasKeyModifierNone); + + return true; +} + +static Eina_Bool sendClick(void*) +{ + return !!sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventClick, EvasMouseButtonLeft, EvasKeyModifierNone); +} + +static JSValueRef scheduleAsynchronousClickCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + ecore_idler_add(sendClick, 0); + return JSValueMakeUndefined(context); +} + +static void updateClickCount(int button) +{ + if (gLastClickPositionX != gLastMousePositionX + || gLastClickPositionY != gLastMousePositionY + || gLastClickButton != button + || gTimeOffset - gLastClickTimeOffset >= 1) + gClickCount = 1; + else + gClickCount++; +} + +static EvasKeyModifier modifierFromJSValue(JSContextRef context, const JSValueRef value) +{ + JSRetainPtr<JSStringRef> jsKeyValue(Adopt, JSValueToStringCopy(context, value, 0)); + + if (equals(jsKeyValue, "ctrlKey") || equals(jsKeyValue, "addSelectionKey")) + return EvasKeyModifierControl; + if (equals(jsKeyValue, "shiftKey") || equals(jsKeyValue, "rangeSelectionKey")) + return EvasKeyModifierShift; + if (equals(jsKeyValue, "altKey")) + return EvasKeyModifierAlt; + if (equals(jsKeyValue, "metaKey")) + return EvasKeyModifierMeta; + + return EvasKeyModifierNone; +} + +static EvasKeyModifier modifiersFromJSValue(JSContextRef context, const JSValueRef modifiers) +{ + // The value may either be a string with a single modifier or an array of modifiers. + if (JSValueIsString(context, modifiers)) + return modifierFromJSValue(context, modifiers); + + JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0); + if (!modifiersArray) + return EvasKeyModifierNone; + + unsigned modifier = 0; + int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0); + for (int i = 0; i < modifiersCount; ++i) + modifier |= static_cast<unsigned>(modifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0))); + return static_cast<EvasKeyModifier>(modifier); +} + +static JSValueRef mouseDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int button = 0; + if (argumentCount == 1) { + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + + if (exception && *exception) + return JSValueMakeUndefined(context); + } + + button = translateMouseButtonNumber(button); + // If the same mouse button is already in the down position don't send another event as it may confuse Xvfb. + if (gButtonCurrentlyDown == button) + return JSValueMakeUndefined(context); + + updateClickCount(button); + + EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone; + if (!sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventDown, button, modifiers)) + return JSValueMakeUndefined(context); + + gButtonCurrentlyDown = button; + return JSValueMakeUndefined(context); +} + +static JSValueRef mouseUpCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + int button = 0; + if (argumentCount == 1) { + button = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + } + + gLastClickPositionX = gLastMousePositionX; + gLastClickPositionY = gLastMousePositionY; + gLastClickButton = gButtonCurrentlyDown; + gLastClickTimeOffset = gTimeOffset; + gButtonCurrentlyDown = 0; + + EvasKeyModifier modifiers = argumentCount >= 2 ? modifiersFromJSValue(context, arguments[1]) : EvasKeyModifierNone; + sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventUp, translateMouseButtonNumber(button), modifiers); + return JSValueMakeUndefined(context); +} + +static JSValueRef mouseMoveToCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + gLastMousePositionX = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + gLastMousePositionY = static_cast<int>(JSValueToNumber(context, arguments[1], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + + sendMouseEvent(evas_object_evas_get(browser->mainFrame()), EvasMouseEventMove, EvasMouseButtonNone, EvasKeyModifierNone); + return JSValueMakeUndefined(context); +} + +static EvasMouseEvent evasMouseEventFromHorizontalAndVerticalOffsets(int horizontalOffset, int verticalOffset) +{ + unsigned mouseEvent = 0; + + if (verticalOffset > 0) + mouseEvent |= EvasMouseEventScrollUp; + else if (verticalOffset < 0) + mouseEvent |= EvasMouseEventScrollDown; + + if (horizontalOffset > 0) + mouseEvent |= EvasMouseEventScrollRight; + else if (horizontalOffset < 0) + mouseEvent |= EvasMouseEventScrollLeft; + + return static_cast<EvasMouseEvent>(mouseEvent); +} + +static JSValueRef mouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 2) + return JSValueMakeUndefined(context); + + const int horizontal = static_cast<int>(JSValueToNumber(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + const int vertical = static_cast<int>(JSValueToNumber(context, arguments[1], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + + sendMouseEvent(evas_object_evas_get(browser->mainFrame()), evasMouseEventFromHorizontalAndVerticalOffsets(horizontal, vertical), EvasMouseButtonNone, EvasKeyModifierNone); + return JSValueMakeUndefined(context); +} + +static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + return JSValueMakeUndefined(context); +} + +static const char* keyPadNameFromJSValue(JSStringRef character) +{ + if (equals(character, "leftArrow")) + return "KP_Left"; + if (equals(character, "rightArrow")) + return "KP_Right"; + if (equals(character, "upArrow")) + return "KP_Up"; + if (equals(character, "downArrow")) + return "KP_Down"; + if (equals(character, "pageUp")) + return "KP_Prior"; + if (equals(character, "pageDown")) + return "KP_Next"; + if (equals(character, "home")) + return "KP_Home"; + if (equals(character, "end")) + return "KP_End"; + if (equals(character, "insert")) + return "KP_Insert"; + if (equals(character, "delete")) + return "KP_Delete"; + + return 0; +} + +static const char* keyNameFromJSValue(JSStringRef character) +{ + if (equals(character, "leftArrow")) + return "Left"; + if (equals(character, "rightArrow")) + return "Right"; + if (equals(character, "upArrow")) + return "Up"; + if (equals(character, "downArrow")) + return "Down"; + if (equals(character, "pageUp")) + return "Prior"; + if (equals(character, "pageDown")) + return "Next"; + if (equals(character, "home")) + return "Home"; + if (equals(character, "end")) + return "End"; + if (equals(character, "insert")) + return "Insert"; + if (equals(character, "delete")) + return "Delete"; + if (equals(character, "printScreen")) + return "Print"; + if (equals(character, "menu")) + return "Menu"; + if (equals(character, "F1")) + return "F1"; + if (equals(character, "F2")) + return "F2"; + if (equals(character, "F3")) + return "F3"; + if (equals(character, "F4")) + return "F4"; + if (equals(character, "F5")) + return "F5"; + if (equals(character, "F6")) + return "F6"; + if (equals(character, "F7")) + return "F7"; + if (equals(character, "F8")) + return "F8"; + if (equals(character, "F9")) + return "F9"; + if (equals(character, "F10")) + return "F10"; + if (equals(character, "F11")) + return "F11"; + if (equals(character, "F12")) + return "F12"; + + int charCode = JSStringGetCharactersPtr(character)[0]; + if (charCode == '\n' || charCode == '\r') + return "Return"; + if (charCode == '\t') + return "Tab"; + if (charCode == '\x8') + return "BackSpace"; + + return 0; +} + +static JSValueRef keyDownCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + Evas_Object* view = ewk_frame_view_get(browser->mainFrame()); + if (!view) + return JSValueMakeUndefined(context); + + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + // handle location argument. + int location = DomKeyLocationStandard; + if (argumentCount > 2) + location = static_cast<int>(JSValueToNumber(context, arguments[2], exception)); + + JSRetainPtr<JSStringRef> character(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + if (exception && *exception) + return JSValueMakeUndefined(context); + + // send the event + Evas* evas = evas_object_evas_get(view); + if (argumentCount >= 2) + setEvasModifiers(evas, modifiersFromJSValue(context, arguments[1])); + + const CString cCharacter = character.get()->ustring().utf8(); + const char* keyName = (location == DomKeyLocationNumpad) ? keyPadNameFromJSValue(character.get()) : keyNameFromJSValue(character.get()); + + if (!keyName) + keyName = cCharacter.data(); + + DumpRenderTreeSupportEfl::layoutFrame(browser->mainFrame()); + evas_event_feed_key_down(evas, keyName, keyName, keyName, 0, 0, 0); + evas_event_feed_key_up(evas, keyName, keyName, keyName, 0, 1, 0); + + setEvasModifiers(evas, EvasKeyModifierNone); + + return JSValueMakeUndefined(context); +} + +static JSValueRef scalePageByCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 3) + return JSValueMakeUndefined(context); + + Evas_Object* view = ewk_frame_view_get(browser->mainFrame()); + if (!view) + return JSValueMakeUndefined(context); + + float scaleFactor = JSValueToNumber(context, arguments[0], exception); + float x = JSValueToNumber(context, arguments[1], exception); + float y = JSValueToNumber(context, arguments[2], exception); + ewk_view_scale_set(view, scaleFactor, x, y); + + return JSValueMakeUndefined(context); +} + +static JSStaticFunction staticFunctions[] = { + { "mouseScrollBy", mouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "continuousMouseScrollBy", continuousMouseScrollByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseDown", mouseDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseUp", mouseUpCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "mouseMoveTo", mouseMoveToCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "keyDown", keyDownCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "scheduleAsynchronousClick", scheduleAsynchronousClickCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "scalePageBy", scalePageByCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } +}; + +static JSStaticValue staticValues[] = { + { 0, 0, 0, 0 } +}; + +static JSClassRef getClass(JSContextRef context) +{ + static JSClassRef eventSenderClass = 0; + + if (!eventSenderClass) { + JSClassDefinition classDefinition = { + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + classDefinition.staticFunctions = staticFunctions; + classDefinition.staticValues = staticValues; + + eventSenderClass = JSClassCreate(&classDefinition); + } + + return eventSenderClass; +} + +JSObjectRef makeEventSender(JSContextRef context, bool isTopFrame) +{ + if (isTopFrame) { + gDragMode = true; + + // Fly forward in time one second when the main frame loads. This will + // ensure that when a test begins clicking in the same location as + // a previous test, those clicks won't be interpreted as continuations + // of the previous test's click sequences. + gTimeOffset += 1000; + + gLastMousePositionX = gLastMousePositionY = 0; + gLastClickPositionX = gLastClickPositionY = 0; + gLastClickTimeOffset = 0; + gLastClickButton = 0; + gButtonCurrentlyDown = 0; + gClickCount = 0; + } + + return JSObjectMake(context, getClass(context), 0); +} diff --git a/Tools/DumpRenderTree/efl/EventSender.h b/Tools/DumpRenderTree/efl/EventSender.h new file mode 100644 index 000000000..bded6552d --- /dev/null +++ b/Tools/DumpRenderTree/efl/EventSender.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Holger Hans Peter Freyther + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 APPLE 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. + */ + +#ifndef EventSender_h +#define EventSender_h + +typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSValue* JSObjectRef; + +// The boolean parameter refers to whether this is being called from a top-level frame. +JSObjectRef makeEventSender(JSContextRef, bool); + +#endif // EventSender_h diff --git a/Tools/DumpRenderTree/efl/FontManagement.cpp b/Tools/DumpRenderTree/efl/FontManagement.cpp new file mode 100644 index 000000000..4cf2fb69b --- /dev/null +++ b/Tools/DumpRenderTree/efl/FontManagement.cpp @@ -0,0 +1,132 @@ +/* + * 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 APPLE INC. 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 APPLE INC. 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 "FontManagement.h" + +#include <Ecore_File.h> +#include <cstdio> +#include <fontconfig/fontconfig.h> +#include <wtf/Vector.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +static Vector<String> getFontDirectories() +{ + Vector<String> fontDirPaths; + + fontDirPaths.append(String("/usr/share/fonts/TTF/")); + fontDirPaths.append(String("/usr/share/fonts/truetype/ttf-liberation/")); + fontDirPaths.append(String("/usr/share/fonts/liberation/")); + fontDirPaths.append(String("/usr/share/fonts/truetype/ttf-dejavu/")); + fontDirPaths.append(String("/usr/share/fonts/dejavu/")); + fontDirPaths.append(String("/usr/share/fonts/OTF/")); // MathML + fontDirPaths.append(String("/usr/share/fonts/opentype/stix/")); // MathML + fontDirPaths.append(String("/usr/share/fonts/stix/")); // MathML + + return fontDirPaths; +} + +static Vector<String> getFontFiles() +{ + Vector<String> fontFilePaths; + + // Ahem is used by many layout tests. + fontFilePaths.append(String(FONTS_CONF_DIR "/AHEM____.TTF")); + // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452 + fontFilePaths.append(String(FONTS_CONF_DIR "/FontWithNoValidEncoding.fon")); + + for (int i = 1; i <= 9; i++) { + char fontPath[PATH_MAX]; + snprintf(fontPath, PATH_MAX - 1, + FONTS_CONF_DIR "/../../fonts/WebKitWeightWatcher%i00.ttf", i); + + fontFilePaths.append(String(fontPath)); + } + + return fontFilePaths; +} + +static size_t addFontDirectories(const Vector<String>& fontDirectories, FcConfig* config) +{ + size_t addedDirectories = 0; + + for (Vector<String>::const_iterator it = fontDirectories.begin(); + it != fontDirectories.end(); ++it) { + const CString currentDirectory = (*it).utf8(); + const char* path = currentDirectory.data(); + + if (ecore_file_is_dir(path)) { + if (!FcConfigAppFontAddDir(config, reinterpret_cast<const FcChar8*>(path))) { + fprintf(stderr, "Could not load font at %s!\n", path); + continue; + } + + ++addedDirectories; + } + } + + return addedDirectories; +} + +static void addFontFiles(const Vector<String>& fontFiles, FcConfig* config) +{ + for (Vector<String>::const_iterator it = fontFiles.begin(); it != fontFiles.end(); ++it) { + const CString currentFile = (*it).utf8(); + const char* path = currentFile.data(); + + if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(path))) + fprintf(stderr, "Could not load font at %s!\n", path); + } +} + +void addFontsToEnvironment() +{ + FcInit(); + + // Load our configuration file, which sets up proper aliases for family + // names like sans, serif and monospace. + FcConfig* config = FcConfigCreate(); + const char* fontConfigFilename = FONTS_CONF_DIR "/fonts.conf"; + if (!FcConfigParseAndLoad(config, reinterpret_cast<const FcChar8*>(fontConfigFilename), true)) { + fprintf(stderr, "Couldn't load font configuration file from: %s\n", fontConfigFilename); + exit(1); + } + + if (!addFontDirectories(getFontDirectories(), config)) { + fprintf(stderr, "None of the font directories could be added. Either install them " + "or file a bug at http://bugs.webkit.org if they are installed in " + "another location.\n"); + exit(1); + } + + addFontFiles(getFontFiles(), config); + + if (!FcConfigSetCurrent(config)) { + fprintf(stderr, "Could not set the current font configuration!\n"); + exit(1); + } +} + diff --git a/Tools/DumpRenderTree/efl/FontManagement.h b/Tools/DumpRenderTree/efl/FontManagement.h new file mode 100644 index 000000000..d497513ae --- /dev/null +++ b/Tools/DumpRenderTree/efl/FontManagement.h @@ -0,0 +1,31 @@ +/* + * 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 APPLE INC. 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 APPLE INC. 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. + */ + +#ifndef FontManagement_h +#define FontManagement_h + +void addFontsToEnvironment(); + +#endif // FontManagement_h diff --git a/Tools/DumpRenderTree/efl/GCControllerEfl.cpp b/Tools/DumpRenderTree/efl/GCControllerEfl.cpp new file mode 100644 index 000000000..1f55a5ce6 --- /dev/null +++ b/Tools/DumpRenderTree/efl/GCControllerEfl.cpp @@ -0,0 +1,49 @@ +/* + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 APPLE 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 "GCController.h" + +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" + +void GCController::collect() const +{ + DumpRenderTreeSupportEfl::garbageCollectorCollect(); +} + +void GCController::collectOnAlternateThread(bool waitUntilDone) const +{ + DumpRenderTreeSupportEfl::garbageCollectorCollectOnAlternateThread(waitUntilDone); +} + +size_t GCController::getJSObjectCount() const +{ + return DumpRenderTreeSupportEfl::javaScriptObjectsCount(); +} diff --git a/Tools/DumpRenderTree/efl/ImageDiff.cpp b/Tools/DumpRenderTree/efl/ImageDiff.cpp new file mode 100644 index 000000000..754ecb22a --- /dev/null +++ b/Tools/DumpRenderTree/efl/ImageDiff.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2010 Igalia S.L. + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 APPLE 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 <Ecore.h> +#include <Ecore_Evas.h> +#include <Evas.h> +#include <algorithm> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <getopt.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <wtf/OwnArrayPtr.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> + +enum PixelComponent { + Red, + Green, + Blue, + Alpha +}; + +static OwnPtr<Ecore_Evas> gEcoreEvas; +static double gTolerance = 0; + +static void abortWithErrorMessage(const char* errorMessage); + +static unsigned char* pixelFromImageData(unsigned char* imageData, int rowStride, int x, int y) +{ + return imageData + (y * rowStride) + (x << 2); +} + +static Evas_Object* differenceImageFromDifferenceBuffer(Evas* evas, unsigned char* buffer, int width, int height) +{ + Evas_Object* image = evas_object_image_filled_add(evas); + if (!image) + abortWithErrorMessage("could not create difference image"); + + evas_object_image_size_set(image, width, height); + evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); + + unsigned char* diffPixels = static_cast<unsigned char*>(evas_object_image_data_get(image, EINA_TRUE)); + const int rowStride = evas_object_image_stride_get(image); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + unsigned char* diffPixel = pixelFromImageData(diffPixels, rowStride, x, y); + diffPixel[Red] = diffPixel[Green] = diffPixel[Blue] = *buffer++; + diffPixel[Alpha] = 0xff; + } + } + + evas_object_image_data_set(image, diffPixels); + + return image; +} + +static float computeDistanceBetweenPixelComponents(unsigned char actualComponent, unsigned char baseComponent) +{ + return (actualComponent - baseComponent) / std::max<float>(255 - baseComponent, baseComponent); +} + +static float computeDistanceBetweenPixelComponents(unsigned char* actualPixel, unsigned char* basePixel, PixelComponent component) +{ + return computeDistanceBetweenPixelComponents(actualPixel[component], basePixel[component]); +} + +static float calculatePixelDifference(unsigned char* basePixel, unsigned char* actualPixel) +{ + const float red = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Red); + const float green = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Green); + const float blue = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Blue); + const float alpha = computeDistanceBetweenPixelComponents(actualPixel, basePixel, Alpha); + return sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f; +} + +static float calculateDifference(Evas_Object* baselineImage, Evas_Object* actualImage, OwnPtr<Evas_Object>& differenceImage) +{ + int width, height, baselineWidth, baselineHeight; + evas_object_image_size_get(actualImage, &width, &height); + evas_object_image_size_get(baselineImage, &baselineWidth, &baselineHeight); + + if (width != baselineWidth || height != baselineHeight) { + printf("Error, test and reference image have different sizes.\n"); + return 100; // Completely different. + } + + OwnArrayPtr<unsigned char> diffBuffer = adoptArrayPtr(new unsigned char[width * height]); + if (!diffBuffer) + abortWithErrorMessage("could not create difference buffer"); + + const int actualRowStride = evas_object_image_stride_get(actualImage); + const int baseRowStride = evas_object_image_stride_get(baselineImage); + unsigned numberOfDifferentPixels = 0; + float totalDistance = 0; + float maxDistance = 0; + unsigned char* actualPixels = static_cast<unsigned char*>(evas_object_image_data_get(actualImage, EINA_FALSE)); + unsigned char* basePixels = static_cast<unsigned char*>(evas_object_image_data_get(baselineImage, EINA_FALSE)); + unsigned char* currentDiffPixel = diffBuffer.get(); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + unsigned char* actualPixel = pixelFromImageData(actualPixels, actualRowStride, x, y); + unsigned char* basePixel = pixelFromImageData(basePixels, baseRowStride, x, y); + + const float distance = calculatePixelDifference(basePixel, actualPixel); + *currentDiffPixel++ = static_cast<unsigned char>(distance * 255.0f); + + if (distance >= 1.0f / 255.0f) { + ++numberOfDifferentPixels; + totalDistance += distance; + maxDistance = std::max<float>(maxDistance, distance); + } + } + } + + // When using evas_object_image_data_get(), a complementary evas_object_data_set() must be + // issued to balance the reference count, even if the image hasn't been changed. + evas_object_image_data_set(baselineImage, basePixels); + evas_object_image_data_set(actualImage, actualPixels); + + // Compute the difference as a percentage combining both the number of + // different pixels and their difference amount i.e. the average distance + // over the entire image + float difference = 0; + if (numberOfDifferentPixels) + difference = 100.0f * totalDistance / (height * width); + if (difference <= gTolerance) + difference = 0; + else { + difference = roundf(difference * 100.0f) / 100.0f; + difference = std::max(difference, 0.01f); // round to 2 decimal places + + differenceImage = adoptPtr(differenceImageFromDifferenceBuffer(evas_object_evas_get(baselineImage), diffBuffer.get(), width, height)); + } + + return difference; +} + +static int getTemporaryFile(char *fileName, size_t fileNameLength) +{ + char* tempDirectory = getenv("TMPDIR"); + if (!tempDirectory) + tempDirectory = getenv("TEMP"); + + if (tempDirectory) + snprintf(fileName, fileNameLength, "%s/ImageDiffXXXXXX.png", tempDirectory); + else { +#if __linux__ + strcpy(fileName, "/dev/shm/ImageDiffXXXXXX.png"); + const int fileDescriptor = mkstemps(fileName, sizeof(".png") - 1); + if (fileDescriptor >= 0) + return fileDescriptor; +#endif // __linux__ + + strcpy(fileName, "ImageDiffXXXXXX.png"); + } + + return mkstemps(fileName, sizeof(".png") - 1); +} + +static void printImage(Evas_Object* image) +{ + char fileName[PATH_MAX]; + + const int tempImageFd = getTemporaryFile(fileName, PATH_MAX); + if (tempImageFd == -1) + abortWithErrorMessage("could not create temporary file"); + + evas_render(evas_object_evas_get(image)); + + if (evas_object_image_save(image, fileName, 0, 0)) { + struct stat fileInfo; + if (!stat(fileName, &fileInfo)) { + printf("Content-Length: %ld\n", fileInfo.st_size); + fflush(stdout); + + unsigned char buffer[2048]; + ssize_t bytesRead; + while ((bytesRead = read(tempImageFd, buffer, sizeof(buffer))) > 0) + write(1, buffer, bytesRead); + } + } + close(tempImageFd); + unlink(fileName); +} + +static void printImageDifferences(Evas_Object* baselineImage, Evas_Object* actualImage) +{ + OwnPtr<Evas_Object> differenceImage; + const float difference = calculateDifference(baselineImage, actualImage, differenceImage); + + if (difference > 0.0f) { + if (differenceImage) + printImage(differenceImage.get()); + + printf("diff: %01.2f%% failed\n", difference); + } else + printf("diff: %01.2f%% passed\n", difference); +} + +static void resizeEcoreEvasIfNeeded(Evas_Object* image) +{ + int newWidth, newHeight; + evas_object_image_size_get(image, &newWidth, &newHeight); + + int currentWidth, currentHeight; + ecore_evas_screen_geometry_get(gEcoreEvas.get(), 0, 0, ¤tWidth, ¤tHeight); + + if (newWidth > currentWidth) + currentWidth = newWidth; + if (newHeight > currentHeight) + currentHeight = newHeight; + + ecore_evas_resize(gEcoreEvas.get(), currentWidth, currentHeight); +} + +static PassOwnPtr<Evas_Object> readImageFromStdin(Evas* evas, long imageSize) +{ + OwnArrayPtr<unsigned char> imageBuffer = adoptArrayPtr(new unsigned char[imageSize]); + if (!imageBuffer) + abortWithErrorMessage("cannot allocate image"); + + const size_t bytesRead = fread(imageBuffer.get(), 1, imageSize, stdin); + if (!bytesRead) + return PassOwnPtr<Evas_Object>(); + + Evas_Object* image = evas_object_image_filled_add(evas); + evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); + evas_object_image_memfile_set(image, imageBuffer.get(), bytesRead, 0, 0); + + resizeEcoreEvasIfNeeded(image); + + return adoptPtr(image); +} + +static bool parseCommandLineOptions(int argc, char** argv) +{ + static const option options[] = { + { "tolerance", required_argument, 0, 't' }, + { 0, 0, 0, 0 } + }; + int option; + + while ((option = getopt_long(argc, (char* const*)argv, "t:", options, 0)) != -1) { + switch (option) { + case 't': + gTolerance = atof(optarg); + break; + case '?': + case ':': + return false; + } + } + + return true; +} + +static void shutdownEfl() +{ + ecore_evas_shutdown(); + ecore_shutdown(); + evas_shutdown(); +} + +static void abortWithErrorMessage(const char* errorMessage) +{ + shutdownEfl(); + + printf("Error, %s.\n", errorMessage); + exit(EXIT_FAILURE); +} + +static Evas* initEfl() +{ + evas_init(); + ecore_init(); + ecore_evas_init(); + + gEcoreEvas = adoptPtr(ecore_evas_buffer_new(1, 1)); + Evas* evas = ecore_evas_get(gEcoreEvas.get()); + if (!evas) + abortWithErrorMessage("could not create Ecore_Evas buffer"); + + return evas; +} + +int main(int argc, char* argv[]) +{ + if (!parseCommandLineOptions(argc, argv)) + return EXIT_FAILURE; + + Evas* evas = initEfl(); + + OwnPtr<Evas_Object> actualImage; + OwnPtr<Evas_Object> baselineImage; + + char buffer[2048]; + while (fgets(buffer, sizeof(buffer), stdin)) { + char* contentLengthStart = strstr(buffer, "Content-Length: "); + if (!contentLengthStart) + continue; + long imageSize; + if (sscanf(contentLengthStart, "Content-Length: %ld", &imageSize) == 1) { + if (imageSize <= 0) + abortWithErrorMessage("image size must be specified"); + + if (!actualImage) + actualImage = readImageFromStdin(evas, imageSize); + else if (!baselineImage) { + baselineImage = readImageFromStdin(evas, imageSize); + + printImageDifferences(baselineImage.get(), actualImage.get()); + + actualImage.clear(); + baselineImage.clear(); + } + } + + fflush(stdout); + } + + gEcoreEvas.clear(); // Make sure ecore_evas_free is called before the EFL are shut down + + shutdownEfl(); + return EXIT_SUCCESS; +} diff --git a/Tools/DumpRenderTree/efl/JSStringUtils.cpp b/Tools/DumpRenderTree/efl/JSStringUtils.cpp new file mode 100644 index 000000000..19ca55736 --- /dev/null +++ b/Tools/DumpRenderTree/efl/JSStringUtils.cpp @@ -0,0 +1,38 @@ +/* + * 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 "JSStringUtils.h" + +bool equals(JSStringRef jsString, const char* cString) +{ + return JSStringIsEqualToUTF8CString(jsString, cString); +} + +bool equals(JSRetainPtr<JSStringRef> jsString, const char* cString) +{ + return equals(jsString.get(), cString); +} diff --git a/Tools/DumpRenderTree/efl/JSStringUtils.h b/Tools/DumpRenderTree/efl/JSStringUtils.h new file mode 100644 index 000000000..04d7e0812 --- /dev/null +++ b/Tools/DumpRenderTree/efl/JSStringUtils.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + + +#ifndef JSStringUtils_h +#define JSStringUtils_h + +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> + +bool equals(JSStringRef, const char*); +bool equals(JSRetainPtr<JSStringRef>, const char*); + +#endif // JSStringUtils_h + diff --git a/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp b/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp new file mode 100644 index 000000000..8dd0a37ca --- /dev/null +++ b/Tools/DumpRenderTree/efl/LayoutTestControllerEfl.cpp @@ -0,0 +1,785 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2009 Jan Michael Alonzo <jmalonzo@gmail.com> + * Copyright (C) 2009,2011 Collabora Ltd. + * Copyright (C) 2010 Joone Hur <joone@kldp.org> + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 APPLE 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 "LayoutTestController.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "JSStringUtils.h" +#include "NotImplemented.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" +#include "ewk_private.h" +#include <EWebKit.h> +#include <Ecore_File.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/OpaqueJSString.h> +#include <JavaScriptCore/wtf/text/WTFString.h> +#include <KURL.h> +#include <editing/FindOptions.h> +#include <stdio.h> + +LayoutTestController::~LayoutTestController() +{ +} + +void LayoutTestController::addDisallowedURL(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::clearBackForwardList() +{ + notImplemented(); +} + +JSStringRef LayoutTestController::copyDecodedHostName(JSStringRef) +{ + notImplemented(); + return 0; +} + +JSStringRef LayoutTestController::copyEncodedHostName(JSStringRef) +{ + notImplemented(); + return 0; +} + +void LayoutTestController::dispatchPendingLoadRequests() +{ + // FIXME: Implement for testing fix for 6727495 + notImplemented(); +} + +void LayoutTestController::display() +{ + displayWebView(); +} + +JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef id) +{ + const Evas_Object* mainFrame = browser->mainFrame(); + const String counterValue(DumpRenderTreeSupportEfl::counterValueByElementId(mainFrame, id->ustring().utf8().data())); + return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(counterValue.utf8().data())); +} + +void LayoutTestController::keepWebHistory() +{ + notImplemented(); +} + +JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSContextRef context, JSValueRef) +{ + notImplemented(); + return JSValueMakeUndefined(context); +} + +JSValueRef LayoutTestController::nodesFromRect(JSContextRef context, JSValueRef, int, int, unsigned, unsigned, unsigned, unsigned, bool) +{ + notImplemented(); + return JSValueMakeUndefined(context); +} + +JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const +{ + notImplemented(); + return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString("")); +} + +int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidth, float pageHeight) +{ + return DumpRenderTreeSupportEfl::numberOfPagesForElementId(browser->mainFrame(), id->ustring().utf8().data(), pageWidth, pageHeight); +} + +int LayoutTestController::numberOfPages(float pageWidth, float pageHeight) +{ + return DumpRenderTreeSupportEfl::numberOfPages(browser->mainFrame(), pageWidth, pageHeight); +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageProperty(const char*, int) const +{ + notImplemented(); + return 0; +} + +bool LayoutTestController::isPageBoxVisible(int) const +{ + notImplemented(); + return false; +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int, int, int, int, int, int, int) const +{ + notImplemented(); + return 0; +} + +size_t LayoutTestController::webHistoryItemCount() +{ + const Ewk_History* history = ewk_view_history_get(browser->mainView()); + if (!history) + return -1; + + return ewk_history_back_list_length(history) + ewk_history_forward_list_length(history); +} + +unsigned LayoutTestController::workerThreadCount() const +{ + return DumpRenderTreeSupportEfl::workerThreadCount(); +} + +void LayoutTestController::notifyDone() +{ + if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count()) + dump(); + m_waitToDump = false; + waitForPolicy = false; +} + +JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url) +{ + // Function introduced in r28690. This may need special-casing on Windows. + return JSStringRetain(url); // Do nothing on Unix. +} + +void LayoutTestController::queueLoad(JSStringRef url, JSStringRef target) +{ + WebCore::KURL baseURL(WebCore::KURL(), String::fromUTF8(ewk_frame_uri_get(browser->mainFrame()))); + WebCore::KURL absoluteURL(baseURL, WTF::String(url->characters(), url->length())); + + JSRetainPtr<JSStringRef> jsAbsoluteURL( + Adopt, JSStringCreateWithUTF8CString(absoluteURL.string().utf8().data())); + + WorkQueue::shared()->queue(new LoadItem(jsAbsoluteURL.get(), target)); +} + +void LayoutTestController::setAcceptsEditing(bool acceptsEditing) +{ + ewk_view_editable_set(browser->mainView(), acceptsEditing); +} + +void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) +{ + ewk_cookies_policy_set(alwaysAcceptCookies ? EWK_COOKIE_JAR_ACCEPT_ALWAYS : EWK_COOKIE_JAR_ACCEPT_NEVER); +} + +void LayoutTestController::setCustomPolicyDelegate(bool, bool) +{ + notImplemented(); +} + +void LayoutTestController::waitForPolicyDelegate() +{ + waitForPolicy = true; + setWaitToDump(true); +} + +void LayoutTestController::setScrollbarPolicy(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::addOriginAccessWhitelistEntry(JSStringRef, JSStringRef, JSStringRef, bool) +{ + notImplemented(); +} + +void LayoutTestController::removeOriginAccessWhitelistEntry(JSStringRef, JSStringRef, JSStringRef, bool) +{ + notImplemented(); +} + +void LayoutTestController::setMainFrameIsFirstResponder(bool) +{ + notImplemented(); +} + +void LayoutTestController::setTabKeyCyclesThroughElements(bool) +{ + notImplemented(); +} + +void LayoutTestController::setUseDashboardCompatibilityMode(bool) +{ + notImplemented(); +} + +static CString gUserStyleSheet; +static bool gUserStyleSheetEnabled = true; + +void LayoutTestController::setUserStyleSheetEnabled(bool flag) +{ + gUserStyleSheetEnabled = flag; + ewk_view_setting_user_stylesheet_set(browser->mainView(), flag ? gUserStyleSheet.data() : 0); +} + +void LayoutTestController::setUserStyleSheetLocation(JSStringRef path) +{ + gUserStyleSheet = path->ustring().utf8(); + + if (gUserStyleSheetEnabled) + setUserStyleSheetEnabled(true); +} + +void LayoutTestController::setValueForUser(JSContextRef, JSValueRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::setViewModeMediaFeature(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::setWindowIsKey(bool) +{ + notImplemented(); +} + +void LayoutTestController::setSmartInsertDeleteEnabled(bool) +{ + notImplemented(); +} + +static Eina_Bool waitToDumpWatchdogFired(void*) +{ + waitToDumpWatchdog = 0; + gLayoutTestController->waitToDumpWatchdogTimerFired(); + return ECORE_CALLBACK_CANCEL; +} + +void LayoutTestController::setWaitToDump(bool waitUntilDone) +{ + static const double timeoutSeconds = 30; + + m_waitToDump = waitUntilDone; + if (m_waitToDump && !waitToDumpWatchdog) + waitToDumpWatchdog = ecore_timer_add(timeoutSeconds, waitToDumpWatchdogFired, 0); +} + +int LayoutTestController::windowCount() +{ + return browser->extraViews().size() + 1; // + 1 for the main view. +} + +void LayoutTestController::setPrivateBrowsingEnabled(bool flag) +{ + ewk_view_setting_private_browsing_set(browser->mainView(), flag); +} + +void LayoutTestController::setJavaScriptCanAccessClipboard(bool) +{ + notImplemented(); +} + +void LayoutTestController::setXSSAuditorEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setFrameFlatteningEnabled(bool flag) +{ + ewk_view_setting_enable_frame_flattening_set(browser->mainView(), flag); +} + +void LayoutTestController::setSpatialNavigationEnabled(bool flag) +{ + ewk_view_setting_spatial_navigation_set(browser->mainView(), flag); +} + +void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool) +{ + notImplemented(); +} + +void LayoutTestController::setAllowFileAccessFromFileURLs(bool) +{ + notImplemented(); +} + +void LayoutTestController::setAuthorAndUserStylesEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setAutofilled(JSContextRef, JSValueRef, bool) +{ + notImplemented(); +} + +void LayoutTestController::disableImageLoading() +{ + // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27896 + // Also need to make sure image loading is re-enabled for each new test. + notImplemented(); +} + +void LayoutTestController::setMockDeviceOrientation(bool, double, bool, double, bool, double) +{ + // FIXME: Implement for DeviceOrientation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=30335. + notImplemented(); +} + +void LayoutTestController::setMockGeolocationPosition(double, double, double) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. + notImplemented(); +} + +void LayoutTestController::setMockGeolocationError(int, JSStringRef) +{ + // FIXME: Implement for Geolocation layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=28264. + notImplemented(); +} + +void LayoutTestController::setGeolocationPermission(bool allow) +{ + // FIXME: Implement for Geolocation layout tests. + setGeolocationPermissionCommon(allow); +} + +int LayoutTestController::numberOfPendingGeolocationPermissionRequests() +{ + // FIXME: Implement for Geolocation layout tests. + return -1; +} + +void LayoutTestController::addMockSpeechInputResult(JSStringRef, double, JSStringRef) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. + notImplemented(); +} + +void LayoutTestController::startSpeechInput(JSContextRef inputElement) +{ + // FIXME: Implement for speech input layout tests. + // See https://bugs.webkit.org/show_bug.cgi?id=39485. + notImplemented(); +} + +void LayoutTestController::setIconDatabaseEnabled(bool enabled) +{ + ewk_settings_icon_database_path_set(0); + + if (!enabled) + return; + + String databasePath; + const char* tempDir = getenv("TMPDIR"); + + if (tempDir) + databasePath = String::fromUTF8(tempDir); + else if (tempDir = getenv("TEMP")) + databasePath = String::fromUTF8(tempDir); + else + databasePath = String::fromUTF8("/tmp"); + + databasePath.append("/DumpRenderTree/IconDatabase"); + + if (ecore_file_mkpath(databasePath.utf8().data())) + ewk_settings_icon_database_path_set(databasePath.utf8().data()); +} + +void LayoutTestController::setJavaScriptProfilingEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setPopupBlockingEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::setPluginsEnabled(bool flag) +{ + ewk_view_setting_enable_plugins_set(browser->mainView(), flag); +} + +bool LayoutTestController::elementDoesAutoCompleteForElementWithId(JSStringRef) +{ + notImplemented(); + return false; +} + +void LayoutTestController::execCommand(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray) +{ + JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length")); + JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0); + if (!JSValueIsNumber(context, lengthValue)) + return false; + + WebCore::FindOptions options = 0; + + const size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0)); + for (size_t i = 0; i < length; ++i) { + JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0); + if (!JSValueIsString(context, value)) + continue; + + JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0)); + + if (equals(optionName, "CaseInsensitive")) + options |= WebCore::CaseInsensitive; + else if (equals(optionName, "AtWordStarts")) + options |= WebCore::AtWordStarts; + else if (equals(optionName, "TreatMedialCapitalAsWordStart")) + options |= WebCore::TreatMedialCapitalAsWordStart; + else if (equals(optionName, "Backwards")) + options |= WebCore::Backwards; + else if (equals(optionName, "WrapAround")) + options |= WebCore::WrapAround; + else if (equals(optionName, "StartInSelection")) + options |= WebCore::StartInSelection; + } + + return DumpRenderTreeSupportEfl::findString(browser->mainView(), target->ustring().utf8().data(), options); +} + +bool LayoutTestController::isCommandEnabled(JSStringRef name) +{ + return false; +} + +void LayoutTestController::setCacheModel(int) +{ + notImplemented(); +} + +void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::clearPersistentUserStyleSheet() +{ + notImplemented(); +} + +void LayoutTestController::clearAllApplicationCaches() +{ + ewk_settings_application_cache_clear(); +} + +void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long) +{ + // FIXME: Implement to support application cache quotas. + notImplemented(); +} + +void LayoutTestController::clearApplicationCacheForOrigin(OpaqueJSString*) +{ + // FIXME: Implement to support deleting all application caches for an origin. + notImplemented(); +} + +long long LayoutTestController::localStorageDiskUsageForOrigin(JSStringRef) +{ + // FIXME: Implement to support getting disk usage in bytes for an origin. + notImplemented(); + return 0; +} + +JSValueRef LayoutTestController::originsWithApplicationCache(JSContextRef context) +{ + // FIXME: Implement to get origins that contain application caches. + notImplemented(); + return JSValueMakeUndefined(context); +} + +long long LayoutTestController::applicationCacheDiskUsageForOrigin(JSStringRef) +{ + notImplemented(); + return 0; +} + +void LayoutTestController::clearAllDatabases() +{ + ewk_settings_web_database_clear(); +} + +void LayoutTestController::setDatabaseQuota(unsigned long long quota) +{ + ewk_settings_web_database_default_quota_set(quota); +} + +JSValueRef LayoutTestController::originsWithLocalStorage(JSContextRef context) +{ + notImplemented(); + return JSValueMakeUndefined(context); +} + +void LayoutTestController::deleteAllLocalStorage() +{ + notImplemented(); +} + +void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::observeStorageTrackerNotifications(unsigned) +{ + notImplemented(); +} + +void LayoutTestController::syncLocalStorage() +{ + notImplemented(); +} + +void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::goBack() +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html + notImplemented(); +} + +void LayoutTestController::setDefersLoading(bool) +{ + // FIXME: implement to enable loader/navigation-while-deferring-loads.html + notImplemented(); +} + +void LayoutTestController::setAppCacheMaximumSize(unsigned long long size) +{ + ewk_settings_application_cache_max_quota_set(size); +} + +bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId) +{ + return DumpRenderTreeSupportEfl::pauseAnimation(browser->mainFrame(), animationName->ustring().utf8().data(), elementId->ustring().utf8().data(), time); +} + +bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId) +{ + return DumpRenderTreeSupportEfl::pauseTransition(browser->mainFrame(), propertyName->ustring().utf8().data(), elementId->ustring().utf8().data(), time); +} + +bool LayoutTestController::sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId) +{ + return DumpRenderTreeSupportEfl::pauseSVGAnimation(browser->mainFrame(), animationId->ustring().utf8().data(), elementId->ustring().utf8().data(), time); +} + +unsigned LayoutTestController::numberOfActiveAnimations() const +{ + return DumpRenderTreeSupportEfl::activeAnimationsCount(browser->mainFrame()); +} + +void LayoutTestController::suspendAnimations() const +{ + DumpRenderTreeSupportEfl::suspendAnimations(browser->mainFrame()); +} + +void LayoutTestController::resumeAnimations() const +{ + DumpRenderTreeSupportEfl::resumeAnimations(browser->mainFrame()); +} + +void LayoutTestController::overridePreference(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::addUserScript(JSStringRef, bool, bool) +{ + notImplemented(); +} + +void LayoutTestController::addUserStyleSheet(JSStringRef, bool) +{ + // FIXME: needs more investigation why userscripts/user-style-top-frame-only.html fails when allFrames is false. + notImplemented(); +} + +void LayoutTestController::setDeveloperExtrasEnabled(bool enabled) +{ + ewk_view_setting_enable_developer_extras_set(browser->mainView(), enabled); +} + +void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool) +{ + notImplemented(); +} + +void LayoutTestController::showWebInspector() +{ + notImplemented(); +} + +void LayoutTestController::closeWebInspector() +{ + notImplemented(); +} + +void LayoutTestController::evaluateInWebInspector(long, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned, JSObjectRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::removeAllVisitedLinks() +{ + notImplemented(); +} + +bool LayoutTestController::callShouldCloseOnWebView() +{ + notImplemented(); + return false; +} + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::apiTestGoToCurrentBackForwardItem() +{ + notImplemented(); +} + +void LayoutTestController::setWebViewEditable(bool) +{ + ewk_frame_editable_set(browser->mainFrame(), EINA_TRUE); +} + +JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSContextRef, JSValueRef) const +{ + notImplemented(); + return 0; +} + +void LayoutTestController::authenticateSession(JSStringRef, JSStringRef, JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::setEditingBehavior(const char*) +{ + notImplemented(); +} + +void LayoutTestController::abortModal() +{ + notImplemented(); +} + +bool LayoutTestController::hasSpellingMarker(int, int) +{ + notImplemented(); + return false; +} + +bool LayoutTestController::hasGrammarMarker(int, int) +{ + notImplemented(); + return false; +} + +void LayoutTestController::dumpConfigurationForViewport(int, int, int, int, int) +{ + notImplemented(); +} + +void LayoutTestController::setSerializeHTTPLoads(bool) +{ + // FIXME: Implement if needed for https://bugs.webkit.org/show_bug.cgi?id=50758. + notImplemented(); +} + +void LayoutTestController::setMinimumTimerInterval(double) +{ + notImplemented(); +} + +void LayoutTestController::setTextDirection(JSStringRef) +{ + notImplemented(); +} + +void LayoutTestController::allowRoundingHacks() +{ + notImplemented(); +} + +void LayoutTestController::addChromeInputField() +{ + notImplemented(); +} + +void LayoutTestController::removeChromeInputField() +{ + notImplemented(); +} + +void LayoutTestController::focusWebView() +{ + notImplemented(); +} + +void LayoutTestController::setBackingScaleFactor(double) +{ + notImplemented(); +} + +void LayoutTestController::simulateDesktopNotificationClick(JSStringRef title) +{ +} diff --git a/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp b/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp new file mode 100644 index 000000000..109374ec9 --- /dev/null +++ b/Tools/DumpRenderTree/efl/PixelDumpSupportEfl.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009 Zan Dobersek <zandobersek@gmail.com> + * Copyright (C) 2010 Igalia S.L. + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 APPLE 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 "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" +#include "IntRect.h" +#include "PixelDumpSupportCairo.h" +#include "RefPtrCairo.h" +#include "WebCoreSupport/DumpRenderTreeSupportEfl.h" +#include "ewk_private.h" + +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect) +{ + Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(browser->mainView())); + Ewk_View_Private_Data* privateData = static_cast<Ewk_View_Private_Data*>(smartData->_priv); + const Evas_Object* mainFrame = browser->mainFrame(); + + int x, y, width, height; + if (!ewk_frame_visible_content_geometry_get(mainFrame, EINA_TRUE, &x, &y, &width, &height)) + return 0; + + RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)); + RefPtr<cairo_t> context = adoptRef(cairo_create(surface.get())); + + const Eina_Rectangle rect = { x, y, width, height }; + if (!ewk_view_paint(privateData, context.get(), &rect)) + return 0; + + if (drawSelectionRect) { + const WebCore::IntRect selectionRect = DumpRenderTreeSupportEfl::selectionRectangle(mainFrame); + + if (!selectionRect.isEmpty()) { + cairo_set_line_width(context.get(), 1.0); + cairo_rectangle(context.get(), selectionRect.x(), selectionRect.y(), selectionRect.width(), selectionRect.height()); + cairo_set_source_rgba(context.get(), 1.0, 0.0, 0.0, 1.0); + cairo_stroke(context.get()); + } + } + + return BitmapContext::createByAdoptingBitmapAndContext(0, context.release().leakRef()); +} diff --git a/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp b/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp new file mode 100644 index 000000000..356a6553c --- /dev/null +++ b/Tools/DumpRenderTree/efl/WorkQueueItemEfl.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2011 ProFUSION Embedded Systems + * Copyright (C) 2011 Samsung Electronics + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WorkQueueItem.h" + +#include "DumpRenderTree.h" +#include "DumpRenderTreeChrome.h" + +#include <EWebKit.h> +#include <JavaScriptCore/JSStringRef.h> +#include <JavaScriptCore/OpaqueJSString.h> +#include <JavaScriptCore/runtime/UString.h> +#include <JavaScriptCore/wtf/text/CString.h> + +bool LoadItem::invoke() const +{ + Evas_Object* targetFrame; + + if (!m_target->length()) + targetFrame = browser->mainFrame(); + else + targetFrame = ewk_frame_child_find(browser->mainFrame(), m_target->ustring().utf8().data()); + + ewk_frame_uri_set(targetFrame, m_url->ustring().utf8().data()); + + return true; +} + +bool LoadHTMLStringItem::invoke() const +{ + if (!m_unreachableURL->length()) + ewk_frame_contents_set(browser->mainFrame(), m_content->ustring().utf8().data(), 0, 0, 0, m_baseURL->ustring().utf8().data()); + else + ewk_frame_contents_alternate_set(browser->mainFrame(), m_content->ustring().utf8().data(), 0, 0, 0, m_baseURL->ustring().utf8().data(), m_unreachableURL->ustring().utf8().data()); + + return true; +} + +bool ReloadItem::invoke() const +{ + ewk_view_reload(browser->mainView()); + return true; +} + +bool ScriptItem::invoke() const +{ + return ewk_frame_script_execute(browser->mainFrame(), m_script->ustring().utf8().data()); +} + +bool BackForwardItem::invoke() const +{ + if (m_howFar == 1) + ewk_view_forward(browser->mainView()); + else if (m_howFar == -1) + ewk_view_back(browser->mainView()); + else + ewk_view_navigate(browser->mainView(), m_howFar); + + return true; +} |
