Unreviewed, rolling out r212514.
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Feb 2017 02:15:35 +0000 (02:15 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 17 Feb 2017 02:15:35 +0000 (02:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=168489

broke test runner (Requested by alexchristensen on #webkit).

Reverted changeset:

"Remove EFL-specific files in Tools."
http://trac.webkit.org/changeset/212514

Patch by Commit Queue <commit-queue@webkit.org> on 2017-02-16

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212517 268f45cc-cd09-0410-ab3c-d52691b4dbfc

36 files changed:
Tools/ChangeLog
Tools/ImageDiff/efl/ImageDiff.cpp [new file with mode: 0644]
Tools/MiniBrowser/efl/CMakeLists.txt [new file with mode: 0644]
Tools/MiniBrowser/efl/main.c [new file with mode: 0644]
Tools/Scripts/run-efl-tests [new file with mode: 0755]
Tools/Scripts/update-webkitefl-libs [new file with mode: 0755]
Tools/Scripts/webkitpy/port/efl.py [new file with mode: 0644]
Tools/Scripts/webkitpy/port/efl_unittest.py [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewClientWebProcessCallbacks.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewClientWebProcessCallbacks_Bundle.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewScrollTo.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKit2/efl/scrollTo.html [new file with mode: 0644]
Tools/TestWebKitAPI/efl/InjectedBundleController.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/efl/PlatformUtilities.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/efl/PlatformWebView.cpp [new file with mode: 0644]
Tools/TestWebKitAPI/efl/main.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/InjectedBundle/efl/ActivateFontsEfl.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/InjectedBundle/efl/FontManagement.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/InjectedBundle/efl/FontManagement.h [new file with mode: 0644]
Tools/WebKitTestRunner/InjectedBundle/efl/InjectedBundleEfl.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/InjectedBundle/efl/TestRunnerEfl.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/efl/EventSenderProxyEfl.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/efl/PlatformWebViewEfl.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/efl/TestControllerEfl.cpp [new file with mode: 0644]
Tools/WebKitTestRunner/efl/main.cpp [new file with mode: 0644]
Tools/efl/install-dependencies [new file with mode: 0755]
Tools/efl/jhbuild-optional.modules [new file with mode: 0644]
Tools/efl/jhbuild.modules [new file with mode: 0644]
Tools/efl/jhbuildrc [new file with mode: 0644]
Tools/efl/patches/evas-fix-build-with-giflib5.patch [new file with mode: 0644]
Tools/efl/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch [new file with mode: 0644]
Tools/efl/patches/gst-libav.patch [new file with mode: 0644]
Tools/efl/patches/gst-plugins-base-rtp-rtcpbuffer-fix-typo-in-enum.patch [new file with mode: 0644]
Tools/efl/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch [new file with mode: 0644]
Tools/efl/patches/gst-plugins-good-use-the-tfdt-decode-time.patch [new file with mode: 0644]
Tools/efl/patches/openwebrtc-gst-plugins-clang-warning-fix.patch [new file with mode: 0644]

index f263478..dcbd4b3 100644 (file)
@@ -1,3 +1,15 @@
+2017-02-16  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r212514.
+        https://bugs.webkit.org/show_bug.cgi?id=168489
+
+        broke test runner (Requested by alexchristensen on #webkit).
+
+        Reverted changeset:
+
+        "Remove EFL-specific files in Tools."
+        http://trac.webkit.org/changeset/212514
+
 2017-02-16  Alex Christensen  <achristensen@webkit.org>
 
         Remove EFL-specific files in Tools.
diff --git a/Tools/ImageDiff/efl/ImageDiff.cpp b/Tools/ImageDiff/efl/ImageDiff.cpp
new file mode 100644 (file)
index 0000000..f57b97b
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * 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 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/StdLibExtras.h>
+#include <wtf/efl/UniquePtrEfl.h>
+
+enum PixelComponent {
+    Red,
+    Green,
+    Blue,
+    Alpha
+};
+
+static EflUniquePtr<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, EflUniquePtr<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.
+    }
+
+    auto diffBuffer = std::make_unique<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 = EflUniquePtr<Evas_Object>(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) {
+                ssize_t bytesWritten = 0;
+                ssize_t count;
+                do {
+                    if ((count = write(1, buffer + bytesWritten, bytesRead - bytesWritten)) <= 0)
+                        break;
+                    bytesWritten += count;
+                } while (bytesWritten < bytesRead);
+            }
+        }
+    }
+    close(tempImageFd);
+    unlink(fileName);
+}
+
+static void printImageDifferences(Evas_Object* baselineImage, Evas_Object* actualImage)
+{
+    EflUniquePtr<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, &currentWidth, &currentHeight);
+
+    if (newWidth > currentWidth)
+        currentWidth = newWidth;
+    if (newHeight > currentHeight)
+        currentHeight = newHeight;
+
+    ecore_evas_resize(gEcoreEvas.get(), currentWidth, currentHeight);
+}
+
+static EflUniquePtr<Evas_Object> readImageFromStdin(Evas* evas, long imageSize)
+{
+    auto imageBuffer = std::make_unique<unsigned char[]>(imageSize);
+    if (!imageBuffer)
+        abortWithErrorMessage("cannot allocate image");
+
+    const size_t bytesRead = fread(imageBuffer.get(), 1, imageSize, stdin);
+    if (!bytesRead)
+        return nullptr;
+
+    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 EflUniquePtr<Evas_Object>(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 = EflUniquePtr<Ecore_Evas>(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();
+
+    EflUniquePtr<Evas_Object> actualImage;
+    EflUniquePtr<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.reset();
+                baselineImage.reset();
+            }
+        }
+
+        fflush(stdout);
+    }
+
+    gEcoreEvas = nullptr; // Make sure ecore_evas_free is called before the EFL are shut down
+
+    shutdownEfl();
+    return EXIT_SUCCESS;
+}
diff --git a/Tools/MiniBrowser/efl/CMakeLists.txt b/Tools/MiniBrowser/efl/CMakeLists.txt
new file mode 100644 (file)
index 0000000..82d72c7
--- /dev/null
@@ -0,0 +1,70 @@
+set(MiniBrowser_DIR "${TOOLS_DIR}/MiniBrowser/efl")
+
+# Elementary is needed to build MiniBrowser
+find_package(Eldbus ${EFL_REQUIRED_VERSION} ${EFL_CONFIG_MODE})
+find_package(Elementary ${EFL_REQUIRED_VERSION} ${EFL_CONFIG_MODE})
+find_package(Ethumb ${EFL_REQUIRED_VERSION} ${EFL_CONFIG_MODE})
+find_package(EthumbClient ${EFL_REQUIRED_VERSION} ${EFL_CONFIG_MODE})
+
+set(MiniBrowser_SOURCES
+    ${MiniBrowser_DIR}/main.c
+)
+
+set(MiniBrowser_INCLUDE_DIRECTORIES
+    ${DERIVED_SOURCES_WEBKIT2_DIR}/include
+    ${WEBKIT2_DIR}/UIProcess/API/efl
+    ${WEBKIT2_DIR}
+    ${CMAKE_SOURCE_DIR}/Source
+)
+
+set(MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES
+    ${CAIRO_INCLUDE_DIRS}
+    ${ECORE_INCLUDE_DIRS}
+    ${ECORE_EVAS_INCLUDE_DIRS}
+    ${ECORE_CON_INCLUDE_DIRS}
+    ${ECORE_FILE_INCLUDE_DIRS}
+    ${ECORE_IMF_INCLUDE_DIRS}
+    ${ECORE_INPUT_INCLUDE_DIRS}
+    ${EDJE_INCLUDE_DIRS}
+    ${EET_INCLUDE_DIRS}
+    ${EO_INCLUDE_DIRS}
+    ${DBUS_INCLUDE_DIRS}
+    ${EFREET_INCLUDE_DIRS}
+    ${EINA_INCLUDE_DIRS}
+    ${ELDBUS_INCLUDE_DIRS}
+    ${ELEMENTARY_INCLUDE_DIRS}
+    ${ETHUMB_INCLUDE_DIRS}
+    ${ETHUMB_CLIENT_INCLUDE_DIRS}
+    ${EVAS_INCLUDE_DIRS}
+)
+
+set(MiniBrowser_LIBRARIES
+    JavaScriptCore
+    WebCore
+    WebKit2
+    ${CAIRO_LIBRARIES}
+    ${ECORE_LIBRARIES}
+    ${ECORE_EVAS_LIBRARIES}
+    ${ECORE_FILE_LIBRARIES}
+    ${EDJE_LIBRARIES}
+    ${EET_LIBRARIES}
+    ${EINA_LIBRARIES}
+    ${ELEMENTARY_LIBRARIES}
+    ${EO_LIBRARIES}
+    ${EVAS_LIBRARIES}
+    ${FONTCONFIG_LIBRARIES}
+    ${GLIB_LIBRARIES}
+    ${GLIB_GTHREAD_LIBRARIES}
+    ${LIBSOUP_LIBRARIES}
+    ${LIBXML2_LIBRARIES}
+    ${LIBXSLT_LIBRARIES} -lm
+    ${OPENGL_LIBRARIES}
+    ${SQLITE_LIBRARIES}
+)
+
+if (ELEMENTARY_FOUND)
+    include_directories(${MiniBrowser_INCLUDE_DIRECTORIES})
+    include_directories(SYSTEM ${MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES})
+    add_executable(MiniBrowser ${MiniBrowser_SOURCES})
+    target_link_libraries(MiniBrowser ${MiniBrowser_LIBRARIES})
+endif ()
diff --git a/Tools/MiniBrowser/efl/main.c b/Tools/MiniBrowser/efl/main.c
new file mode 100644 (file)
index 0000000..e3825ee
--- /dev/null
@@ -0,0 +1,2536 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "EWebKit2.h"
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Ecore_Getopt.h>
+#include <Eet.h>
+#include <Eina.h>
+#include <Elementary.h>
+#include <Evas.h>
+
+extern int efreet_cache_update;
+
+static const char DEFAULT_URL[] = "http://www.ewebkit.org/";
+static const char APP_NAME[] = "EFL MiniBrowser";
+static const char JAVASCRIPT_SCHEME[] = "javascript:";
+static const char FILE_SCHEME[] = "file://";
+static const char HTTP_SCHEME[] = "http://";
+static const int TOOL_BAR_ICON_SIZE = 24;
+static const int TOOL_BAR_BUTTON_SIZE = 32;
+static const int SEARCH_FIELD_SIZE = 200;
+static const int SEARCH_BUTTON_SIZE = 30;
+static const int MAX_SEARCH_COUNT = 1000;
+static const double TOOLTIP_DELAY_SECONDS = 1.0;
+static const double LONGPRESS_INTERVAL_SECONDS = 1.5;
+static const double LIST_ITEM_HEIGHT = 24.35;
+
+static Eina_List *windows = NULL;
+static char *evas_engine_name = NULL;
+static char *user_agent_string = NULL;
+static char *extensions_path = NULL;
+static char *background_color_string = NULL;
+static Eina_Bool encoding_detector_enabled = EINA_FALSE;
+static Eina_Bool frame_flattening_enabled = EINA_FALSE;
+static Eina_Bool local_storage_enabled = EINA_TRUE;
+static Eina_Bool offline_web_application_cache_enabled = EINA_TRUE;
+static Eina_Bool fullscreen_enabled = EINA_FALSE;
+static Eina_Bool spell_checking_enabled = EINA_FALSE;
+static Eina_Bool web_security_enabled = EINA_TRUE;
+static Eina_Bool touch_events_enabled = EINA_FALSE;
+static Eina_Bool fixed_layout_enabled = EINA_TRUE;
+static Eina_Bool separated_process_enabled = EINA_FALSE;
+static Eina_Bool longpress_enabled = EINA_FALSE;
+static int window_width = 1000;
+static int window_height = 800;
+static int color_picker_width = 350;
+static int color_picker_height = 500;
+static int search_flags = EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_WRAP_AROUND | EWK_FIND_OPTIONS_CASE_INSENSITIVE;
+/* Default value of device_pixel_ratio is '0' so that we don't set custom device
+ * scale factor unless it's required by the User. */
+static double device_pixel_ratio = 0;
+static Eina_Bool legacy_behavior_enabled = EINA_FALSE;
+
+#define DEFAULT_ZOOM_LEVEL 5 // Set default zoom level to 1.0 (index 5 on zoomLevels).
+// The zoom values are chosen to be like in Mozilla Firefox 3.
+const static float zoomLevels[] = {0.3, 0.5, 0.67, 0.8, 0.9, 1.0, 1.1, 1.2, 1.33, 1.5, 1.7, 2.0, 2.4, 3.0};
+static int _log_domain_id = -1;
+
+#define INFO(...) EINA_LOG_DOM_INFO(_log_domain_id, __VA_ARGS__)
+#define ERROR(...) EINA_LOG_DOM_ERR(_log_domain_id, __VA_ARGS__)
+
+static Eina_Bool
+zoom_level_set(Evas_Object *webview, int level)
+{
+   if (level < 0  || level >= sizeof(zoomLevels) / sizeof(float))
+     return EINA_FALSE;
+
+   return ewk_view_page_zoom_set(webview, zoomLevels[level]);
+}
+
+static Ewk_View_Smart_Class *miniBrowserViewSmartClass()
+{
+   static Ewk_View_Smart_Class ewkViewClass = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("MiniBrowser_View");
+   return &ewkViewClass;
+}
+
+typedef struct _Tooltip_Information {
+   Ecore_Timer *show_timer;
+   Eina_Bool activated;
+   Eina_Bool text_set;
+   Eina_Bool shown;
+} Tooltip_Information;
+
+typedef struct _Color_Selector {
+   Ewk_Color_Picker *ewk_picker;
+   Evas_Object *elm_selector;
+   Evas_Object *elm_selector_window;
+} Color_Selector;
+
+typedef struct _Browser_Window {
+   Evas_Object *elm_window;
+   Evas_Object *ewk_view;
+   Evas_Object *horizontal_layout;
+   Evas_Object *vertical_layout;
+   Evas_Object *url_bar;
+   Evas_Object *back_button;
+   Evas_Object *forward_button;
+   struct {
+     Evas_Object *elm_menu;
+     Ewk_Popup_Menu *ewk_menu;
+    } popup;
+   struct {
+     Evas_Object *search_bar;
+     Evas_Object *search_field;
+     Evas_Object *search_field_count;
+     Evas_Object *backward_button;
+     Evas_Object *forward_button;
+     Evas_Object *search_case_check_box;
+     Evas_Object *search_word_start_check_box;
+     Evas_Object *close_button;
+   } search;
+   struct {
+     Evas_Object *history_box;
+     Evas_Object *history_list;
+     Eina_List *history_list_items;
+   } history;
+   int current_zoom_level;
+   Tooltip_Information tooltip;
+   Color_Selector color_selector;
+   struct {
+     Evas_Object *elm_menu;
+     Ewk_Context_Menu *ewk_menu;
+   } context_menu;
+} Browser_Window;
+
+typedef struct _File_Selector_Data {
+   Browser_Window* parent;
+   Evas_Object *elm_window;
+   Ewk_File_Chooser_Request *request;
+} File_Selector_Data;
+
+typedef struct _Auth_Data {
+   Evas_Object *popup;
+   Ewk_Auth_Request *request;
+   Evas_Object *username_entry;
+   Evas_Object *password_entry;
+} Auth_Data;
+
+static const Ecore_Getopt options = {
+   "MiniBrowser",
+   "%prog [options] [url]",
+   "0.0.1",
+   "(C)2012 Samsung Electronics\n (C)2012 Intel Corporation\n",
+   "",
+   "Test Web Browser using the Enlightenment Foundation Libraries (EFL) port of WebKit2",
+   EINA_TRUE, {
+     ECORE_GETOPT_STORE_STR
+         ('e', "engine", "Ecore-evas engine to use."),
+     ECORE_GETOPT_STORE_STR
+         ('s', "window-size", "Window size in following format (width)x(height)."),
+     ECORE_GETOPT_STORE_STR
+         ('u', "user-agent", "User agent to set."),
+     ECORE_GETOPT_STORE_STR
+         ('x', "extensions-path", "The path which extensions are stored."),
+     ECORE_GETOPT_STORE_DOUBLE
+         ('r', "device-pixel-ratio", "Ratio between the CSS units and device pixels."),
+     ECORE_GETOPT_CALLBACK_NOARGS
+         ('E', "list-engines", "List ecore-evas engines.",
+          ecore_getopt_callback_ecore_evas_list_engines, NULL),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('c', "encoding-detector", "Enable/disable encoding detector.", EINA_FALSE),
+     ECORE_GETOPT_STORE_STR
+         ('C', "background-color", "Background color of page. ex) -C=255:255:255:255"),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('f', "flattening", "Enable/disable frame flattening.", EINA_FALSE),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('l', "local-storage", "Enable/disable HTML5 local storage.", EINA_TRUE),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('o', "offline-web-application-cache", "Enable/disable offline web application cache.", EINA_TRUE),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('F', "full-screen", "Start in full-screen.", EINA_FALSE),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('t', "text-checking", "Enable/disable text spell checking.", EINA_FALSE),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('T', "touch-events", "Enable/disable touch events.", EINA_FALSE),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('L', "fixed-layout", "Enable/disable fixed layout.", EINA_TRUE),
+     ECORE_GETOPT_STORE_DEF_STR
+         ('p', "policy-cookies", "Cookies policy:\n  always - always accept,\n  never - never accept,\n  no-third-party - don't accept third-party cookies.", "no-third-party"),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('w', "web-security", "enable/disable web security.", EINA_TRUE),
+     ECORE_GETOPT_STORE_DEF_BOOL
+         ('S', "separate-process", "Create new window in separated web process.", EINA_FALSE),
+     ECORE_GETOPT_VERSION
+         ('V', "version"),
+     ECORE_GETOPT_COPYRIGHT
+         ('R', "copyright"),
+     ECORE_GETOPT_HELP
+         ('h', "help"),
+     ECORE_GETOPT_SENTINEL
+   }
+};
+
+static Eina_Stringshare *_file_entry_dialog_show(Browser_Window *window, const char *label_tag, const char *default_text);
+static Browser_Window *window_create(Ewk_View_Configuration* configuration, int width, int height);
+static Ewk_View_Configuration* configuration();
+
+static Browser_Window *window_find_with_ewk_view(Evas_Object *ewk_view)
+{
+   Eina_List *l;
+   void *data;
+
+   if (!ewk_view)
+     return NULL;
+
+   EINA_LIST_FOREACH(windows, l, data) {
+     Browser_Window *window = (Browser_Window *)data;
+     if (window->ewk_view == ewk_view)
+       return window;
+   }
+   return NULL;
+}
+
+static Eina_Bool
+_tooltip_show(void *user_data)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   window->tooltip.show_timer = NULL;
+   elm_object_tooltip_show(window->elm_window);
+   window->tooltip.shown = EINA_TRUE;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+window_tooltip_hide(Browser_Window *window)
+{
+   if (window->tooltip.show_timer) {
+     ecore_timer_del(window->tooltip.show_timer);
+     window->tooltip.show_timer = NULL;
+   }
+
+   if (window->tooltip.shown) {
+     elm_object_tooltip_hide(window->elm_window);
+     window->tooltip.shown = EINA_FALSE;
+   }
+}
+
+static void
+window_tooltip_update(Browser_Window *window)
+{
+   window_tooltip_hide(window);
+
+   if (window->tooltip.activated && window->tooltip.text_set)
+     window->tooltip.show_timer = ecore_timer_add(TOOLTIP_DELAY_SECONDS, _tooltip_show, window);
+}
+
+static void
+_mouse_in_cb(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   window->tooltip.activated = EINA_TRUE;
+   window_tooltip_update(window);
+}
+
+static void
+_mouse_move_cb(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
+{
+   window_tooltip_update((Browser_Window *)user_data);
+}
+
+static void
+_mouse_out_cb(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   window->tooltip.activated = EINA_FALSE;
+   window_tooltip_update(window);
+}
+
+static void
+_mouse_wheel_cb(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   const Evas_Modifier *mod = evas_key_modifier_get(e);
+   Evas_Event_Mouse_Wheel *ev = (Evas_Event_Mouse_Wheel *)event_info;
+   Eina_Bool shiftPressed = evas_key_modifier_is_set(mod, "Shift");
+   Eina_Bool ctrlPressed = evas_key_modifier_is_set(mod, "Control");
+
+   if (!shiftPressed && !ctrlPressed)
+     return;
+
+   /* navigate history or zoom web page based on mouse wheel scroll action with shift or control key */
+   if (shiftPressed) {
+     if (ev->z == -1 && ewk_view_forward_possible(ewk_view)) {
+       ewk_view_forward(ewk_view);
+       elm_object_disabled_set(window->forward_button, !ewk_view_forward_possible(ewk_view));
+     } else if (ev->z == 1 && ewk_view_back_possible(ewk_view)) {
+       ewk_view_back(ewk_view);
+       elm_object_disabled_set(window->back_button, !ewk_view_back_possible(ewk_view));
+     }
+   } else if (ctrlPressed) {
+     if (ev->z == -1 && zoom_level_set(ewk_view, window->current_zoom_level + 1)) {
+       window->current_zoom_level++;
+       INFO("Zoom in (Ctrl + 'scroll up') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
+     } else if (ev->z == 1 && zoom_level_set(ewk_view, window->current_zoom_level - 1)) {
+       window->current_zoom_level--;
+       INFO("Zoom out (Ctrl + 'scroll down') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
+     }
+   }
+}
+
+static void
+_window_resize_cb(void *user_data, Evas *e, Evas_Object *elm_window, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   if (!window) {
+     ERROR("Window is NULL.");
+     return;
+   }
+
+   if (window->context_menu.ewk_menu)
+     ewk_context_menu_hide(window->context_menu.ewk_menu);
+   if (window->popup.ewk_menu)
+     ewk_popup_menu_close(window->popup.ewk_menu);
+   if (window->popup.elm_menu)
+     elm_menu_close(window->popup.elm_menu);
+}
+
+static void
+update_view_favicon(Browser_Window *window, Evas_Object *icon)
+{
+   /* Remove previous icon from URL bar */
+   Evas_Object *old_icon = elm_object_part_content_unset(window->url_bar, "icon");
+   if (old_icon) {
+     evas_object_unref(old_icon);
+     evas_object_del(old_icon);
+   }
+
+   /* Show new icon in URL bar */
+   if (icon) {
+     evas_object_size_hint_min_set(icon, 32, 32);
+     elm_object_part_content_set(window->url_bar, "icon", icon);
+     evas_object_ref(icon);
+   }
+}
+
+static void
+_icon_changed_cb(Ewk_Favicon_Database *database, const char *url, void *user_data)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   Evas_Object *ewk_view = window->ewk_view;
+
+   if (strcmp(url, ewk_view_url_get(ewk_view)))
+     return;
+
+   Evas_Object *favicon = ewk_favicon_database_icon_get(database, url, evas_object_evas_get(ewk_view));
+   update_view_favicon(window, favicon);
+
+   if (favicon)
+     evas_object_unref(favicon);
+}
+
+static void window_free(Browser_Window *window)
+{
+   evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_IN, _mouse_in_cb);
+   evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_OUT, _mouse_out_cb);
+   evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb);
+   evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb);
+
+   evas_object_event_callback_del(window->elm_window, EVAS_CALLBACK_RESIZE, _window_resize_cb);
+
+   ewk_favicon_database_icon_change_callback_del(ewk_context_favicon_database_get(ewk_view_context_get(window->ewk_view)), _icon_changed_cb);
+
+   evas_object_del(window->ewk_view);
+   /* The elm_win will take care of freeing its children */
+   evas_object_del(window->elm_window);
+
+   if (window->tooltip.show_timer)
+     ecore_timer_del(window->tooltip.show_timer);
+
+   if (window->color_selector.elm_selector_window)
+     evas_object_del(window->color_selector.elm_selector_window);
+
+   free(window);
+}
+
+static void window_close(Browser_Window *window)
+{
+   windows = eina_list_remove(windows, window);
+   window_free(window);
+
+   if (!windows)
+     elm_exit();
+}
+
+static void
+search_icon_show(Browser_Window *window)
+{
+   Evas_Object *icon = elm_icon_add(window->elm_window);
+   elm_icon_standard_set(icon, "edit-find");
+   elm_object_part_content_set(window->search.search_field, "icon", icon);
+   evas_object_size_hint_min_set(icon, 20, 20);
+   evas_object_size_hint_max_set(icon, 20, 20);
+   elm_entry_icon_visible_set(window->search.search_field, EINA_TRUE);
+   evas_object_show(icon);
+}
+
+static void
+search_box_show(Browser_Window *window)
+{
+   evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
+
+   search_icon_show(window);
+   evas_object_show(window->search.search_bar);
+   evas_object_show(window->search.search_field);
+   evas_object_show(window->search.search_field_count);
+   evas_object_show(window->search.backward_button);
+   evas_object_show(window->search.forward_button);
+   evas_object_show(window->search.search_case_check_box);
+   evas_object_show(window->search.search_word_start_check_box);
+   evas_object_show(window->search.close_button);
+
+   /* Grab focus from the view */
+   evas_object_focus_set(window->ewk_view, EINA_FALSE);
+   elm_object_focus_set(window->search.search_field, EINA_TRUE);
+}
+
+static void
+search_box_hide(Browser_Window *window)
+{
+   ewk_view_text_find_highlight_clear(window->ewk_view);
+
+   evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, 0);
+   evas_object_hide(window->search.search_bar);
+   evas_object_hide(window->search.search_field);
+   evas_object_hide(window->search.search_field_count);
+   evas_object_hide(window->search.backward_button);
+   evas_object_hide(window->search.forward_button);
+   evas_object_hide(window->search.search_case_check_box);
+   evas_object_hide(window->search.search_word_start_check_box);
+   evas_object_hide(window->search.close_button);
+
+   /* Give focus back to the view */
+   elm_object_focus_set(window->search.search_field, EINA_FALSE);
+   evas_object_focus_set(window->ewk_view, EINA_TRUE);
+}
+
+static void
+history_list_hide(Browser_Window *window)
+{
+   /* Hide history list */
+   evas_object_hide(window->history.history_box);
+   evas_object_hide(window->history.history_list);
+
+   /* Dereference the list items and clear the history list */
+   void *data;
+   EINA_LIST_FREE(window->history.history_list_items, data) {
+       ewk_object_unref(data);
+   }
+
+   elm_genlist_clear(window->history.history_list);
+
+   /* Give focus back to the view */
+   elm_object_focus_set(window->history.history_box, EINA_FALSE);
+   elm_object_focus_set(window->history.history_list, EINA_FALSE);
+   evas_object_focus_set(window->ewk_view, EINA_TRUE);
+
+   /* Reset flags */
+   longpress_enabled = EINA_FALSE;
+}
+
+static void save_page_contents_callback(Ewk_Page_Contents_Type type, const char *data, void *user_data)
+{
+   Eet_File *ef;
+   Eina_Stringshare *fileName = (Eina_Stringshare *)user_data;
+
+   if (!eina_str_has_extension(fileName, ".mht")) {
+     Eina_Strbuf *fileNameWithMht = eina_strbuf_new();
+     eina_strbuf_append_printf(fileNameWithMht, "%s.mht", fileName);
+     ef = eet_open(eina_strbuf_string_get(fileNameWithMht), EET_FILE_MODE_WRITE);
+     INFO("Saving file to: %s", eina_strbuf_string_get(fileNameWithMht));
+     eina_strbuf_free(fileNameWithMht);
+   } else {
+     ef = eet_open(fileName, EET_FILE_MODE_WRITE);
+     INFO("Saving file to: %s", fileName);
+   }
+
+   if (!ef) {
+     ERROR("Could not create File");
+     return;
+   }
+
+   eet_write(ef, "MHTML data", data, strlen(data), 0 /* compress */);
+   eet_close(ef);
+   INFO("SUCCESS: saved.");
+
+   eina_stringshare_del(fileName);
+}
+
+static void
+script_execute_callback(Evas_Object *ewk_view, const char *return_value, void *user_data)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   Eina_Strbuf *text_buffer = eina_strbuf_new();
+
+   if (return_value) {
+     eina_strbuf_append(text_buffer, return_value);
+     INFO("selected text is: %s", eina_strbuf_string_get(text_buffer));
+     elm_entry_entry_set(window->search.search_field, eina_strbuf_string_get(text_buffer));
+   }
+   eina_strbuf_free(text_buffer);
+   search_box_show(window);
+}
+
+static void
+toggle_window_fullscreen(Browser_Window *window, Eina_Bool isFullScreen)
+{
+   if (isFullScreen) {
+     evas_object_hide(window->horizontal_layout);
+     elm_box_unpack(window->vertical_layout, window->horizontal_layout);
+     elm_win_fullscreen_set(window->elm_window, EINA_TRUE);
+   } else {
+     elm_win_fullscreen_set(window->elm_window, EINA_FALSE);
+     elm_box_pack_start(window->vertical_layout, window->horizontal_layout);
+      evas_object_show(window->horizontal_layout);
+   }
+}
+
+static void
+_key_down_cb(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
+
+   static const char *encodings[] = {
+     "ISO-8859-1",
+     "UTF-8",
+     NULL
+   };
+   static int currentEncoding = -1;
+   const Evas_Modifier *mod = evas_key_modifier_get(e);
+   Eina_Bool ctrlPressed = evas_key_modifier_is_set(mod, "Control");
+   Eina_Bool altPressed = evas_key_modifier_is_set(mod, "Alt");
+   Eina_Bool shiftPressed = evas_key_modifier_is_set(mod, "Shift");
+
+   if (!strcmp(ev->key, "Left") && altPressed) {
+     INFO("Back (Alt+Left) was pressed");
+     if (!ewk_view_back(ewk_view))
+       INFO("Back ignored: No back history");
+   } else if (!strcmp(ev->key, "Right") && altPressed) {
+     INFO("Forward (Alt+Right) was pressed");
+     if (!ewk_view_forward(ewk_view))
+       INFO("Forward ignored: No forward history");
+   } else if (!strcmp(ev->key, "Home") && altPressed) {
+     INFO("Home (Alt+Home) was pressed");
+     ewk_view_url_set(window->ewk_view, DEFAULT_URL);
+   } else if (!strcmp(ev->key, "F3")) {
+     currentEncoding = (currentEncoding + 1) % (sizeof(encodings) / sizeof(encodings[0]));
+     INFO("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
+     ewk_view_custom_encoding_set(ewk_view, encodings[currentEncoding]);
+   } else if ((!strcmp(ev->key, "F5") && ctrlPressed) || (!strcmp(ev->key, "r") && (shiftPressed & ctrlPressed))) {
+     INFO("Reload ignoring cache (Ctrl+F5 or Ctrl+Shift+r) was pressed, reloading and bypassing cache...");
+     ewk_view_reload_bypass_cache(ewk_view);
+   } else if (!strcmp(ev->key, "F5") || (!strcmp(ev->key, "r") && ctrlPressed)) {
+     INFO("Reload (F5 or Ctrl+r) was pressed, reloading...");
+     ewk_view_reload(ewk_view);
+   } else if (!strcmp(ev->key, "F6")) {
+     INFO("Stop (F6) was pressed, stop loading.");
+     ewk_view_stop(ewk_view);
+   } else if (!strcmp(ev->key, "F7")) {
+     Ewk_Pagination_Mode mode =  ewk_view_pagination_mode_get(ewk_view);
+     mode = (mode + 1) % (EWK_PAGINATION_MODE_BOTTOM_TO_TOP + 1);
+     if (ewk_view_pagination_mode_set(ewk_view, mode))
+       INFO("Change Pagination Mode (F7) was pressed, changed to: %d", mode);
+     else
+       INFO("Change Pagination Mode (F7) was pressed, but NOT changed!");
+   } else if (!strcmp(ev->key, "F11")) {
+     INFO("Fullscreen (F11) was pressed, toggling window/fullscreen.");
+     toggle_window_fullscreen(window, !elm_win_fullscreen_get(window->elm_window));
+   } else if (!strcmp(ev->key, "n") && ctrlPressed) {
+     INFO("Create new window (Ctrl+n) was pressed.");
+     Browser_Window *window = window_create(configuration(), 0, 0);
+     ewk_view_url_set(window->ewk_view, DEFAULT_URL);
+     // 0 equals default width and height.
+     windows = eina_list_append(windows, window);
+   } else if (!strcmp(ev->key, "i") && ctrlPressed) {
+     INFO("Show Inspector (Ctrl+i) was pressed.");
+     ewk_view_inspector_show(ewk_view);
+   } else if (!strcmp(ev->key, "f") && ctrlPressed) {
+     INFO("Show Search Box (Ctrl+f) was pressed.");
+     const char get_data_script[] = "window.getSelection().toString();";
+     ewk_view_script_execute(ewk_view, get_data_script, script_execute_callback, (void*)(window));
+   } else if (!strcmp(ev->key, "Escape")) {
+     if (evas_object_visible_get(window->search.search_bar))
+       search_box_hide(window);
+     else if (evas_object_visible_get(window->history.history_box))
+       history_list_hide(window);
+     else if (elm_win_fullscreen_get(window->elm_window))
+       ewk_view_fullscreen_exit(ewk_view);
+     else
+       ewk_view_stop(ewk_view);
+   } else if (ctrlPressed && (!strcmp(ev->key, "minus") || !strcmp(ev->key, "KP_Subtract"))) {
+     if (zoom_level_set(ewk_view, window->current_zoom_level - 1))
+       window->current_zoom_level--;
+     INFO("Zoom out (Ctrl + '-') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
+   } else if (ctrlPressed && (!strcmp(ev->key, "equal") || !strcmp(ev->key, "KP_Add"))) {
+     if (zoom_level_set(ewk_view, window->current_zoom_level + 1))
+       window->current_zoom_level++;
+     INFO("Zoom in (Ctrl + '+') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
+   } else if (ctrlPressed && !strcmp(ev->key, "0")) {
+     if (zoom_level_set(ewk_view, DEFAULT_ZOOM_LEVEL))
+       window->current_zoom_level = DEFAULT_ZOOM_LEVEL;
+     INFO("Zoom to default (Ctrl + '0') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
+   } else if (ctrlPressed && !strcmp(ev->key, "s")) {
+     Eina_Strbuf *default_file = eina_strbuf_new();
+     const char *home_path = getenv("HOME");
+     const char *title = ewk_view_title_get(window->ewk_view);
+     eina_strbuf_append_printf(default_file, "%s/%s.mht", home_path ? home_path : "/home", title ? title : "title");
+     INFO("Pressed (CTRL + S) : Saving Current Page.");
+     Eina_Stringshare *save_file_name = _file_entry_dialog_show(window, "SAVE", eina_strbuf_string_get(default_file));
+     if (!save_file_name)
+       return;
+     ewk_view_page_contents_get(ewk_view, EWK_PAGE_CONTENTS_TYPE_MHTML, save_page_contents_callback, (void *)save_file_name);
+     eina_strbuf_free(default_file);
+   } else if (ctrlPressed && !strcmp(ev->key, "l")) {
+     const char *home_path =  getenv("HOME");
+     Eina_Stringshare *open_file_name = _file_entry_dialog_show(window, "LOAD", home_path ? home_path : "/home");
+     if (!open_file_name)
+       return;
+     Eina_Strbuf *uri_path = eina_strbuf_new();
+     eina_strbuf_append_printf(uri_path, "%s%s", FILE_SCHEME, open_file_name);
+     INFO("pressed (CTRL + L) : Loading Page %s", eina_strbuf_string_get(uri_path));
+     ewk_view_url_set(ewk_view, eina_strbuf_string_get(uri_path));
+     eina_strbuf_free(uri_path);
+     eina_stringshare_del(open_file_name);
+   }
+}
+
+static void
+view_focus_set(Browser_Window *window, Eina_Bool focus)
+{
+   /* We steal focus away from elm's focus model and start to do things
+    * manually here, so elm now has no clue what's up. Tell elm that its
+    * toplevel widget is to be unfocused so elm gives up the focus */
+   elm_object_focus_set(elm_object_top_widget_get(window->elm_window), EINA_FALSE);
+   evas_object_focus_set(window->ewk_view, focus);
+}
+
+static void
+_mouse_down_cb(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
+
+   /* Clear selection from the URL bar */
+   elm_entry_select_none(window->url_bar);
+
+   if (longpress_enabled)
+     history_list_hide(window);
+   if (ev->button == 1)
+     view_focus_set(window, EINA_TRUE);
+   else if (ev->button == 2)
+     view_focus_set(window, !evas_object_focus_get(ewk_view));
+}
+
+static void
+title_set(Evas_Object *elm_window, const char *title, int progress)
+{
+   Eina_Strbuf *buffer;
+
+   if (!title || !*title) {
+     elm_win_title_set(elm_window, APP_NAME);
+     return;
+   }
+
+   buffer = eina_strbuf_new();
+   if (progress < 100)
+     eina_strbuf_append_printf(buffer, "%s (%d%%) - %s", title, progress, APP_NAME);
+   else
+     eina_strbuf_append_printf(buffer, "%s - %s", title, APP_NAME);
+
+   elm_win_title_set(elm_window, eina_strbuf_string_get(buffer));
+   eina_strbuf_free(buffer);
+}
+
+static void
+_title_changed_cb(void *user_data, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   const char *title = (const char *)event_info;
+
+   title_set(window->elm_window, title, 100);
+}
+
+static void
+_url_changed_cb(void *user_data, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   const char *url = ewk_view_url_get(window->ewk_view);
+   char *converted_url = elm_entry_utf8_to_markup(url);
+   elm_entry_entry_set(window->url_bar, converted_url);
+
+   _icon_changed_cb(ewk_context_favicon_database_get(ewk_view_context_get(ewk_view)), url, user_data);
+
+   free(converted_url);
+
+   search_box_hide(window);
+}
+
+static void
+_back_forward_list_changed_cb(void *user_data, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   /* Update navigation buttons state */
+   elm_object_disabled_set(window->back_button, !ewk_view_back_possible(ewk_view));
+   elm_object_disabled_set(window->forward_button, !ewk_view_forward_possible(ewk_view));
+}
+
+static void
+_progress_cb(void *user_data, Evas_Object *ewk_view, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   double progress = *(double *)event_info;
+
+   title_set(window->elm_window, ewk_view_title_get(window->ewk_view), progress * 100);
+}
+
+static void
+_error_cb(void *user_data, Evas_Object *ewk_view, void *event_info)
+{
+   Eina_Strbuf *buffer;
+   const Ewk_Error *error = (const Ewk_Error *)event_info;
+
+   /* This is a cancellation, do not display the error page */
+   if (ewk_error_cancellation_get(error))
+     return;
+
+   buffer = eina_strbuf_new();
+   eina_strbuf_append_printf(buffer,
+     "<html><body><div style=\"color:#ff0000\">ERROR!</div><br><div>Code: %d<br>Description: %s<br>URL: %s</div></body</html>",
+     ewk_error_code_get(error), ewk_error_description_get(error), ewk_error_url_get(error));
+
+   ewk_view_html_string_load(ewk_view, eina_strbuf_string_get(buffer), 0, ewk_error_url_get(error));
+   eina_strbuf_free(buffer);
+}
+
+static void
+_download_request_cb(Ewk_Download_Job *download, void *user_data)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   Eina_Strbuf *destination_path = eina_strbuf_new();
+
+   const char *home_path = getenv("HOME");
+   Eina_Stringshare *save_file_path = _file_entry_dialog_show(window, "DOWNLOAD", home_path ? home_path : "/tmp");
+
+   if (save_file_path)
+     eina_strbuf_append_printf(destination_path, "%s", save_file_path);
+   else
+     eina_strbuf_append(destination_path, "/tmp");
+
+   const char *suggested_name = ewk_download_job_suggested_filename_get(download);
+   if (suggested_name && *suggested_name)
+     eina_strbuf_append_printf(destination_path, "/%s", suggested_name);
+   else {
+     // Generate a unique file name since no name was suggested.
+     eina_strbuf_append(destination_path, "/downloaded-file.XXXXXX");
+     char *url = NULL;
+     url = eina_strbuf_string_steal(destination_path);
+     if (mkstemp(url) == -1) {
+       ERROR("Could not generate a unique file name.");
+       return;
+     }
+     eina_strbuf_append(destination_path, url);
+   }
+
+   ewk_download_job_destination_set(download, eina_strbuf_string_get(destination_path));
+   INFO("Downloading: %s", eina_strbuf_string_get(destination_path));
+   eina_strbuf_free(destination_path);
+   eina_stringshare_del(save_file_path);
+}
+
+static void _filepicker_parent_deletion_cb(void *user_data, Evas *evas, Evas_Object *elm_window, void *event);
+
+static void close_file_picker(File_Selector_Data *fs_data)
+{
+   evas_object_event_callback_del(fs_data->parent->elm_window, EVAS_CALLBACK_DEL, _filepicker_parent_deletion_cb);
+   evas_object_del(fs_data->elm_window);
+   ewk_object_unref(fs_data->request);
+   free(fs_data);
+}
+
+static void
+_filepicker_parent_deletion_cb(void *user_data, Evas *evas, Evas_Object *elm_window, void *event)
+{
+   close_file_picker((File_Selector_Data *)user_data);
+}
+
+static void
+_filepicker_deletion_cb(void *user_data, Evas_Object *elm_window, void *event_info)
+{
+   close_file_picker((File_Selector_Data *)user_data);
+}
+
+static void
+_fileselector_done_cb(void *user_data, Evas_Object *file_selector, void *event_info)
+{
+   File_Selector_Data *fs_data = (File_Selector_Data *)user_data;
+
+   const char *selected = (const char *)event_info;
+   if (selected && *selected)
+     ewk_file_chooser_request_file_choose(fs_data->request, selected);
+
+   close_file_picker(fs_data);
+}
+
+static void
+_file_chooser_request_cb(void *user_data, Evas_Object *ewk_view, void *event_info)
+{
+   Evas_Object *bg;
+   Browser_Window *window = (Browser_Window *)user_data;
+   Ewk_File_Chooser_Request *request = (Ewk_File_Chooser_Request *)event_info;
+
+   // Show basic file picker which does not currently support multiple files
+   // or MIME type filtering.
+   Evas_Object *elm_window = elm_win_add(window->elm_window, "file-picker-window", ELM_WIN_DIALOG_BASIC);
+   elm_win_title_set(elm_window, "File picker");
+   elm_win_modal_set(elm_window, EINA_TRUE);
+
+   bg = elm_bg_add(elm_window);
+   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(elm_window, bg);
+   evas_object_show(bg);
+
+   File_Selector_Data *fs_data = (File_Selector_Data *)malloc(sizeof(File_Selector_Data));
+   fs_data->parent = window;
+   fs_data->elm_window = elm_window;
+   fs_data->request = ewk_object_ref(request);
+   evas_object_smart_callback_add(elm_window, "delete,request", _filepicker_deletion_cb, fs_data);
+   evas_object_event_callback_add(window->elm_window, EVAS_CALLBACK_DEL, _filepicker_parent_deletion_cb, fs_data);
+
+   Evas_Object *file_selector = elm_fileselector_add(elm_window);
+   const char *home_path = getenv("HOME");
+   elm_fileselector_path_set(file_selector, home_path ? home_path : "/home");
+   evas_object_size_hint_weight_set(file_selector, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(elm_window, file_selector);
+   evas_object_show(file_selector);
+
+   evas_object_smart_callback_add(file_selector, "done", _fileselector_done_cb, fs_data);
+
+   int x, y, width, height;
+   evas_object_geometry_get(window->elm_window, &x, &y, &width, &height);
+
+   int picker_x = x + width / 2 - color_picker_width / 2;
+   int picker_y = y + height / 2 - color_picker_height / 2;
+   evas_object_geometry_set(window->color_selector.elm_selector_window, picker_x, picker_y,
+     color_picker_width, color_picker_height);
+}
+
+static void
+_download_finished_cb(Ewk_Download_Job *download, void *user_data)
+{
+   INFO("Download finished: %s",  ewk_download_job_destination_get(download));
+}
+
+static void
+_download_failed_cb(Ewk_Download_Job_Error *download_error, void *user_data)
+{
+   Ewk_Error *error = download_error->error;
+
+   INFO("Download failed! Error code: %d, Error description: %s, Error URL: %s", ewk_error_code_get(error), ewk_error_description_get(error), ewk_error_url_get(error));
+}
+
+static void
+_color_changed_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   int r, g, b, a;
+
+   elm_colorselector_color_get(obj, &r, &g, &b, &a);
+   evas_object_color_set(data, r, g, b, a);
+}
+
+static void
+_color_item_selected_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   int r, g, b, a;
+   Elm_Object_Item *color_item = (Elm_Object_Item *)event_info;
+
+   elm_colorselector_palette_item_color_get(color_item, &r, &g, &b, &a);
+   evas_object_color_set(data, r, g, b, a);
+}
+
+static void
+_color_picker_ok_clicked_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   int r, g, b, a;
+   Color_Selector *color_selector = (Color_Selector *)data;
+
+   elm_colorselector_color_get(color_selector->elm_selector, &r, &g, &b, &a);
+   ewk_color_picker_color_set(color_selector->ewk_picker, r, g, b, a);
+}
+
+static void
+_color_picker_cancel_clicked_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   int r, g, b, a;
+
+   ewk_color_picker_color_get(data, &r, &g, &b, &a);
+   ewk_color_picker_color_set(data, r, g, b, a);
+}
+
+static Eina_Bool
+_color_picker_dismiss_cb(Ewk_View_Smart_Data *sd)
+{
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+
+   evas_object_del(window->color_selector.elm_selector_window);
+   window->color_selector.elm_selector_window = NULL;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_color_picker_request_cb(Ewk_View_Smart_Data *sd, Ewk_Color_Picker *color_picker)
+{
+   int r, g, b, a;
+   Evas_Object *background, *rect, *box, *button_box, *rect_frame, *cs_frame, *ok_button, *cancel_button;
+
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+   window->color_selector.elm_selector_window = elm_win_add(window->elm_window, "color selector", ELM_WIN_BASIC);
+   window->color_selector.ewk_picker = color_picker;
+
+   elm_win_title_set(window->color_selector.elm_selector_window, "Color selector");
+
+   /* Show color view */
+   background = elm_bg_add(window->color_selector.elm_selector_window);
+   evas_object_size_hint_weight_set(background, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(window->color_selector.elm_selector_window, background);
+   evas_object_show(background);
+
+   box = elm_box_add(window->color_selector.elm_selector_window);
+   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(window->color_selector.elm_selector_window, box);
+   evas_object_show(box);
+
+   rect_frame = elm_frame_add(window->color_selector.elm_selector_window);
+   evas_object_size_hint_weight_set(rect_frame, EVAS_HINT_EXPAND, 0.3);
+   evas_object_size_hint_align_set(rect_frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_object_text_set(rect_frame, "Color View");
+   elm_box_pack_end(box, rect_frame);
+   evas_object_show(rect_frame);
+
+   rect = evas_object_rectangle_add(evas_object_evas_get(window->color_selector.elm_selector_window));
+   elm_object_content_set(rect_frame, rect);
+   ewk_color_picker_color_get(window->color_selector.ewk_picker, &r, &g, &b, &a);
+   evas_object_color_set(rect, r, g, b, a);
+   evas_object_show(rect);
+
+   /* Show color selector */
+   cs_frame = elm_frame_add(window->color_selector.elm_selector_window);
+   evas_object_size_hint_weight_set(cs_frame, EVAS_HINT_EXPAND, 0.7);
+   evas_object_size_hint_align_set(cs_frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_object_text_set(cs_frame, "Color Selector");
+   elm_box_pack_end(box, cs_frame);
+   evas_object_show(cs_frame);
+
+   window->color_selector.elm_selector = elm_colorselector_add(window->color_selector.elm_selector_window);
+   elm_object_content_set(cs_frame, window->color_selector.elm_selector);
+   evas_object_show(window->color_selector.elm_selector);
+
+   /* OK, Cancel Buttons */
+   button_box = elm_box_add(window->color_selector.elm_selector_window);
+   elm_box_horizontal_set(button_box, EINA_TRUE);
+   evas_object_size_hint_min_set(button_box, 200, 50);
+   elm_box_pack_end(box, button_box);
+   evas_object_show(button_box);
+
+   ok_button = elm_button_add(window->color_selector.elm_selector_window);
+   elm_object_text_set(ok_button, "OK");
+   elm_box_pack_end(button_box, ok_button);
+   evas_object_show(ok_button);
+
+   cancel_button = elm_button_add(window->color_selector.elm_selector_window);
+   elm_object_text_set(cancel_button, "Cancel");
+   elm_box_pack_end(button_box, cancel_button);
+   evas_object_show(cancel_button);
+
+   evas_object_smart_callback_add(ok_button, "clicked", _color_picker_ok_clicked_cb, &(window->color_selector));
+   evas_object_smart_callback_add(cancel_button, "clicked", _color_picker_cancel_clicked_cb,
+     window->color_selector.ewk_picker);
+   evas_object_smart_callback_add(window->color_selector.elm_selector_window, "delete,request",
+     _color_picker_cancel_clicked_cb, window->color_selector.ewk_picker);
+   evas_object_smart_callback_add(window->color_selector.elm_selector, "changed", _color_changed_cb, rect);
+   evas_object_smart_callback_add(window->color_selector.elm_selector, "color,item,selected", _color_item_selected_cb,
+     rect);
+
+   int x, y, width, height;
+   evas_object_geometry_get(window->elm_window, &x, &y, &width, &height);
+
+   elm_win_center(window->color_selector.elm_selector_window, EINA_TRUE, EINA_TRUE);
+   evas_object_resize(window->color_selector.elm_selector_window, 350, 500);
+   evas_object_show(window->color_selector.elm_selector_window);
+
+   return EINA_TRUE;
+}
+
+static int
+quit(Eina_Bool success, const char *msg)
+{
+   if (msg)
+     success ? INFO("%s", msg) : ERROR("%s", msg);
+
+   ewk_object_unref(configuration());
+   ewk_shutdown();
+   elm_shutdown();
+   eina_log_domain_unregister(_log_domain_id);
+
+   if (!success)
+     return EXIT_FAILURE;
+
+   return EXIT_SUCCESS;
+}
+
+static Eina_Bool
+has_scheme(const char *url)
+{
+   return !!strstr(url, "://");
+}
+
+static char *
+url_from_user_input(const char *arg)
+{
+   /* If it is already a URL, return the argument as is. */
+   if (has_scheme(arg) || eina_str_has_prefix(arg, JAVASCRIPT_SCHEME) || !strcasecmp(arg, "about:blank"))
+     return strdup(arg);
+
+   Eina_Strbuf *buf = eina_strbuf_manage_new(eina_file_path_sanitize(arg));
+
+   /* Check if the path exists. */
+   if (ecore_file_exists(eina_strbuf_string_get(buf))) {
+     /* File exists, convert local path to a URL. */
+     eina_strbuf_prepend(buf, FILE_SCHEME);
+   } else {
+     /* The path does not exist, convert it to a URL by
+        prepending http:// scheme:
+        www.google.com -> http://www.google.com */
+     eina_strbuf_string_free(buf);
+     eina_strbuf_append_printf(buf, "%s%s", HTTP_SCHEME, arg);
+   }
+   char *url = eina_strbuf_string_steal(buf);
+   eina_strbuf_free(buf);
+
+   return url;
+}
+
+static Eina_Bool
+url_load_from_user_input(Evas_Object *ewk_view, const char *url)
+{
+   if (!ewk_view || !url)
+     return EINA_FALSE;
+
+   if (eina_str_has_prefix(url, JAVASCRIPT_SCHEME))
+     return ewk_view_script_execute(ewk_view, strstr(url, JAVASCRIPT_SCHEME), 0, 0);
+
+   return ewk_view_url_set(ewk_view, url);
+}
+
+static void
+_url_bar_activated_cb(void *user_data, Evas_Object *url_bar, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   const char *markup_url = elm_entry_entry_get(url_bar);
+   char *user_url = elm_entry_markup_to_utf8(markup_url);
+   char *url = url_from_user_input(user_url);
+   url_load_from_user_input(window->ewk_view, url);
+
+   free(user_url);
+   free(url);
+
+   /* Give focus back to the view */
+   view_focus_set(window, EINA_TRUE);
+}
+
+static void
+_url_bar_clicked_cb(void *user_data, Evas_Object *url_bar, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   /* Grab focus from the view */
+   evas_object_focus_set(window->ewk_view, EINA_FALSE);
+   elm_object_focus_set(url_bar, EINA_TRUE);
+}
+
+static void
+_search_field_aborted_cb(void *user_data, Evas_Object *search_field, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   search_box_hide(window);
+
+   /* Give focus back to the view */
+   view_focus_set(window, EINA_TRUE);
+}
+
+static void
+_search_field_activated_cb(void *user_data, Evas_Object *search_field, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   const char *markup_text = elm_entry_entry_get(search_field);
+   char *text = elm_entry_markup_to_utf8(markup_text);
+   ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
+   free(text);
+
+   /* Grab focus from the view */
+   evas_object_focus_set(window->ewk_view, EINA_FALSE);
+   elm_object_focus_set(search_field, EINA_TRUE);
+}
+
+static void
+_search_field_clicked_cb(void *user_data, Evas_Object *search_field, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   /* Grab focus from the view */
+   evas_object_focus_set(window->ewk_view, EINA_FALSE);
+   elm_object_focus_set(search_field, EINA_TRUE);
+}
+
+static void
+_back_button_clicked_cb(void *user_data, Evas_Object *back_button, void *event_info)
+{
+   if (longpress_enabled)
+     return;
+
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   ewk_view_back(window->ewk_view);
+   /* Update back button state */
+   elm_object_disabled_set(back_button, !ewk_view_back_possible(window->ewk_view));
+}
+
+static void
+_forward_button_clicked_cb(void *user_data, Evas_Object *forward_button, void *event_info)
+{
+   if (longpress_enabled)
+     return;
+
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   ewk_view_forward(window->ewk_view);
+   /* Update forward button state */
+   elm_object_disabled_set(forward_button, !ewk_view_forward_possible(window->ewk_view));
+}
+
+static void
+_search_backward_button_clicked_cb(void *user_data, Evas_Object *search_backward_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
+   ewk_view_text_find(window->ewk_view, text, search_flags | EWK_FIND_OPTIONS_BACKWARDS, MAX_SEARCH_COUNT);
+   free(text);
+}
+
+static void
+_search_forward_button_clicked_cb(void *user_data, Evas_Object *search_forward_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
+   ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
+   free(text);
+}
+
+static void
+_search_case_option_changed(void *user_data, Evas_Object *search_case_check_box, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
+
+   /* Bit toggle the case sensitive flag */
+   search_flags = search_flags ^ EWK_FIND_OPTIONS_CASE_INSENSITIVE;
+
+   ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
+   free(text);
+}
+
+static void
+_search_word_start_option_changed_cb(void *user_data, Evas_Object *search_word_start_check_box, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
+
+   /* Bit toggle the word start flag */
+   search_flags = search_flags ^ EWK_FIND_OPTIONS_AT_WORD_STARTS;
+
+   ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
+   free(text);
+}
+
+static void
+_search_close_button_clicked_cb(void *user_data, Evas_Object *search_close_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   search_box_hide(window);
+}
+
+static void
+_refresh_button_clicked_cb(void *user_data, Evas_Object *refresh_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   Evas *evas = evas_object_evas_get(refresh_button);
+   Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(evas), "Control");
+   if (ctrlPressed) {
+     INFO("Reloading and bypassing cache...");
+     ewk_view_reload_bypass_cache(window->ewk_view);
+   } else {
+     INFO("Reloading...");
+     ewk_view_reload(window->ewk_view);
+   }
+}
+
+static void
+_stop_button_clicked_cb(void *user_data, Evas_Object *stop_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   INFO("Stop was Pressed. Aborting load...");
+   ewk_view_stop(window->ewk_view);
+}
+
+static char *
+list_item_label_get(void *data, Evas_Object *obj, const char *part)
+{
+   int len = strlen((char *)data);
+   char *buf = (char *)malloc(sizeof(char) * (len + 1));
+   snprintf(buf, len + 1, "%s", (char *)data);
+   return buf;
+}
+
+static void
+_list_item_select_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Browser_Window *window = evas_object_data_get(obj, "Browser_Window");
+   ewk_view_navigate_to(window->ewk_view, user_data);
+   history_list_hide(window);
+   evas_object_data_del(obj, "Browser_Window");
+}
+
+static void
+navigation_button_longpress_process(void *user_data, Eina_Bool forward_navigation_enabled)
+{
+   if (longpress_enabled)
+     return;
+
+   longpress_enabled = EINA_TRUE;
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   Ewk_Back_Forward_List *list = ewk_view_back_forward_list_get(window->ewk_view);
+   const Eina_List *l;
+   void *data;
+   static Elm_Genlist_Item_Class *list_item = NULL;
+   const char *title = NULL;
+   int item_count;
+   int x;
+   int y;
+   int width;
+   int height;
+   size_t index;
+
+   evas_object_data_set(window->history.history_list, "Browser_Window", window);
+
+   if (forward_navigation_enabled)
+     window->history.history_list_items = ewk_back_forward_list_forward_items_copy(list);
+   else
+     window->history.history_list_items = ewk_back_forward_list_back_items_copy(list);
+
+   if (!list_item) {
+     list_item = elm_genlist_item_class_new();
+     list_item->item_style = "default";
+     list_item->func.text_get = list_item_label_get;
+     list_item->func.content_get = NULL;
+     list_item->func.state_get = NULL;
+     list_item->func.del = NULL;
+   }
+
+   item_count = eina_list_count(window->history.history_list_items);
+   INFO("navigation_button_longpress_process : Item count = %d forward_navigation_enabled = %d", item_count, forward_navigation_enabled);
+
+   EINA_LIST_FOREACH(window->history.history_list_items, l, data) {
+     title = ewk_back_forward_list_item_title_get(data);
+     INFO(" title = %s", title);
+     elm_genlist_item_append(window->history.history_list, list_item, (void *)(title), NULL, ELM_GENLIST_ITEM_NONE, _list_item_select_cb, data);
+   }
+
+   if (item_count > 0) {
+     evas_object_geometry_get(window->elm_window, &x, &y, &width, &height);
+     elm_list_go(window->history.history_list);
+     evas_object_resize(window->history.history_box , width / 3 , LIST_ITEM_HEIGHT * item_count);
+
+     if (forward_navigation_enabled) {
+       evas_object_move(window->history.history_box , x + TOOL_BAR_BUTTON_SIZE + 1, y + TOOL_BAR_BUTTON_SIZE);
+       evas_object_move(window->history.history_list , x + TOOL_BAR_BUTTON_SIZE + 1, y + TOOL_BAR_BUTTON_SIZE);
+     } else {
+       evas_object_move(window->history.history_box , x, y + TOOL_BAR_BUTTON_SIZE);
+       evas_object_move(window->history.history_list , x, y + TOOL_BAR_BUTTON_SIZE);
+     }
+
+     elm_genlist_mode_set(window->history.history_list, ELM_LIST_COMPRESS);
+     evas_object_show(window->history.history_box);
+     evas_object_show(window->history.history_list);
+     evas_object_focus_set(window->ewk_view, EINA_FALSE);
+     elm_object_focus_set(window->history.history_list, EINA_TRUE);
+   } else
+     longpress_enabled = EINA_FALSE;
+}
+
+static void
+_forward_button_longpress_cb(void *user_data, Evas_Object *forward_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   navigation_button_longpress_process(user_data, EINA_TRUE);
+   elm_object_disabled_set(forward_button, !ewk_view_back_possible(window->ewk_view));
+}
+
+static void
+_back_button_longpress_cb(void *user_data, Evas_Object *back_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   navigation_button_longpress_process(user_data, EINA_FALSE);
+   elm_object_disabled_set(back_button, !ewk_view_back_possible(window->ewk_view));
+}
+
+static void
+_ok_clicked_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Eina_Bool *confirmed = (Eina_Bool *)user_data;
+   *confirmed = EINA_TRUE;
+}
+
+static Eina_Stringshare *
+_file_entry_dialog_show(Browser_Window *window, const char *label_tag, const char *default_text)
+{
+   Evas_Object *file_popup = elm_popup_add(window->elm_window);
+   evas_object_size_hint_weight_set(file_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_show(file_popup);
+
+   Evas_Object *vbox = elm_box_add(file_popup);
+   evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_object_content_set(file_popup, vbox);
+   evas_object_show(vbox);
+
+   Evas_Object *label = elm_label_add(window->elm_window);
+   elm_object_text_set(label, label_tag);
+   evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(label, EVAS_HINT_FILL, 0.5);
+   evas_object_color_set(label, 23, 45, 67, 142);
+   elm_box_pack_end(vbox, label);
+   evas_object_show(label);
+
+   Evas_Object *fs_entry = elm_fileselector_entry_add(file_popup);
+   elm_fileselector_is_save_set(fs_entry, EINA_TRUE);
+   evas_object_size_hint_align_set(fs_entry, EVAS_HINT_FILL, 0);
+   elm_fileselector_path_set(fs_entry, default_text);
+   elm_object_text_set(fs_entry, "FileChooser");
+   elm_box_pack_end(vbox, fs_entry);
+   evas_object_show(fs_entry);
+
+   Evas_Object *hbox = elm_box_add(file_popup);
+   evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_box_horizontal_set(hbox, EINA_TRUE);
+   evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(vbox, hbox);
+   evas_object_show(hbox);
+
+   Eina_Bool ok = EINA_FALSE;
+   Evas_Object *ok_button = elm_button_add(file_popup);
+   elm_object_text_set(ok_button, "OK");
+   evas_object_smart_callback_add(ok_button, "clicked", _ok_clicked_cb, &ok);
+   elm_box_pack_end(hbox, ok_button);
+   evas_object_show(ok_button);
+
+   Eina_Bool cancel = EINA_FALSE;
+   Evas_Object *cancel_button = elm_button_add(file_popup);
+   elm_object_text_set(cancel_button, "Cancel");
+   evas_object_smart_callback_add(cancel_button, "clicked", _ok_clicked_cb, &cancel);
+   elm_box_pack_end(hbox, cancel_button);
+   evas_object_show(cancel_button);
+
+   while (ok != EINA_TRUE && cancel != EINA_TRUE)
+    ecore_main_loop_iterate();
+
+   Eina_Stringshare *file_path = ok ? eina_stringshare_add(elm_fileselector_path_get(fs_entry)) : NULL;
+   evas_object_del(file_popup);
+   return file_path;
+}
+
+static void
+_javascript_alert_cb(Ewk_View_Smart_Data *smartData, const char *message)
+{
+   Browser_Window *window = window_find_with_ewk_view(smartData->self);
+
+   Evas_Object *alert_popup = elm_popup_add(window->elm_window);
+   evas_object_size_hint_weight_set(alert_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_object_text_set(alert_popup, message);
+   elm_object_part_text_set(alert_popup, "title,text", "Alert");
+
+   /* Popup buttons */
+   Eina_Bool ok = EINA_FALSE;
+   Evas_Object *button = elm_button_add(alert_popup);
+   elm_object_text_set(button, "OK");
+   elm_object_part_content_set(alert_popup, "button1", button);
+   evas_object_smart_callback_add(button, "clicked", _ok_clicked_cb, &ok);
+   elm_object_focus_set(button, EINA_TRUE);
+   evas_object_show(alert_popup);
+
+   while (ok != EINA_TRUE)
+      ecore_main_loop_iterate();
+
+   evas_object_del(alert_popup);
+}
+
+static Eina_Bool
+_javascript_confirm_cb(Ewk_View_Smart_Data *smartData, const char *message)
+{
+   Browser_Window *window = window_find_with_ewk_view(smartData->self);
+
+   Evas_Object *confirm_popup = elm_popup_add(window->elm_window);
+   evas_object_size_hint_weight_set(confirm_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_object_text_set(confirm_popup, message);
+   elm_object_part_text_set(confirm_popup, "title,text", "Confirmation");
+
+   /* Popup buttons */
+   Eina_Bool cancel = EINA_FALSE;
+   Evas_Object *cancel_button = elm_button_add(confirm_popup);
+   elm_object_text_set(cancel_button, "Cancel");
+   elm_object_part_content_set(confirm_popup, "button1", cancel_button);
+   evas_object_smart_callback_add(cancel_button, "clicked", _ok_clicked_cb, &cancel);
+   Evas_Object *ok_button = elm_button_add(confirm_popup);
+   Eina_Bool ok = EINA_FALSE;
+   elm_object_text_set(ok_button, "OK");
+   elm_object_part_content_set(confirm_popup, "button2", ok_button);
+   evas_object_smart_callback_add(ok_button, "clicked", _ok_clicked_cb, &ok);
+   elm_object_focus_set(ok_button, EINA_TRUE);
+   evas_object_show(confirm_popup);
+
+   while (cancel != EINA_TRUE && ok != EINA_TRUE)
+      ecore_main_loop_iterate();
+
+   evas_object_del(confirm_popup);
+
+   return ok;
+}
+
+static const char *
+_javascript_prompt_cb(Ewk_View_Smart_Data *smartData, const char *message, const char *default_value)
+{
+   Browser_Window *window = window_find_with_ewk_view(smartData->self);
+
+   Evas_Object *prompt_popup = elm_popup_add(window->elm_window);
+   evas_object_size_hint_weight_set(prompt_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_object_part_text_set(prompt_popup, "title,text", "Prompt");
+
+   /* Popup Content */
+   Evas_Object *box = elm_box_add(window->elm_window);
+   elm_box_padding_set(box, 0, 4);
+   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(box);
+
+   Evas_Object *prompt = elm_label_add(window->elm_window);
+   elm_object_text_set(prompt, message);
+   evas_object_size_hint_weight_set(prompt, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(prompt, EVAS_HINT_FILL, 0.5);
+   elm_box_pack_end(box, prompt);
+   evas_object_show(prompt);
+
+   Evas_Object *entry = elm_entry_add(window->elm_window);
+   elm_entry_scrollable_set(entry, EINA_TRUE);
+   elm_entry_single_line_set(entry, EINA_TRUE);
+   elm_entry_text_style_user_push(entry, "DEFAULT='font_size=18'");
+   elm_entry_entry_set(entry, default_value ? default_value : "");
+   elm_entry_select_all(entry);
+   evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
+   elm_box_pack_end(box, entry);
+   elm_object_focus_set(entry, EINA_TRUE);
+   evas_object_show(entry);
+
+   elm_object_content_set(prompt_popup, box);
+
+   /* Popup buttons */
+   Eina_Bool cancel = EINA_FALSE;
+   Evas_Object *cancel_button = elm_button_add(prompt_popup);
+   elm_object_text_set(cancel_button, "Cancel");
+   elm_object_part_content_set(prompt_popup, "button1", cancel_button);
+   evas_object_smart_callback_add(cancel_button, "clicked", _ok_clicked_cb, &cancel);
+   Eina_Bool ok = EINA_FALSE;
+   Evas_Object *ok_button = elm_button_add(prompt_popup);
+   elm_object_text_set(ok_button, "OK");
+   elm_object_part_content_set(prompt_popup, "button2", ok_button);
+   evas_object_smart_callback_add(ok_button, "clicked", _ok_clicked_cb, &ok);
+   evas_object_show(prompt_popup);
+
+   while (cancel != EINA_TRUE && ok != EINA_TRUE)
+      ecore_main_loop_iterate();
+
+   /* The return string need to be stringshared */
+   const char *prompt_text = ok ? eina_stringshare_add(elm_entry_entry_get(entry)) : NULL;
+   evas_object_del(prompt_popup);
+
+   return prompt_text;
+}
+
+static Eina_Bool
+_javascript_before_unload_confirm_cb(Ewk_View_Smart_Data *smartData, const char *message)
+{
+   return _javascript_confirm_cb(smartData, "Will you leave this page?");
+}
+
+static void
+_popup_menu_item_clicked_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   Elm_Object_Item *item = (Elm_Object_Item *)event_info;
+
+   INFO("Selected popup menu index: %u", elm_menu_item_index_get(item));
+   ewk_popup_menu_selected_index_set(window->popup.ewk_menu, elm_menu_item_index_get(item));
+
+   // Close popup menu.
+   ewk_popup_menu_close(window->popup.ewk_menu);
+}
+
+static void
+popup_menu_populate(Evas_Object *elm_menu, Ewk_Popup_Menu *ewk_menu, void *user_data)
+{
+   const Eina_List* ewk_items = ewk_popup_menu_items_get(ewk_menu);
+
+   void *data;
+   const Eina_List *l;
+   EINA_LIST_FOREACH(ewk_items, l, data) {
+     Ewk_Popup_Menu_Item *ewk_item = (Ewk_Popup_Menu_Item *)data;
+     switch (ewk_popup_menu_item_type_get(ewk_item)) {
+     case EWK_POPUP_MENU_SEPARATOR:
+       elm_menu_item_separator_add(elm_menu, NULL);
+       break;
+     case EWK_POPUP_MENU_ITEM:
+       if (ewk_popup_menu_item_is_label_get(ewk_item)) {
+         Elm_Object_Item *item = elm_menu_item_add(elm_menu, NULL, NULL, ewk_popup_menu_item_text_get(ewk_item), NULL, NULL);
+         elm_object_item_disabled_set(item, EINA_TRUE);
+       } else {
+         Elm_Object_Item *item = elm_menu_item_add(elm_menu, NULL, NULL, ewk_popup_menu_item_text_get(ewk_item), _popup_menu_item_clicked_cb, user_data);
+         const char *tooltip_text = ewk_popup_menu_item_tooltip_get(ewk_item);
+         if (tooltip_text && tooltip_text[0] != '\0')
+           elm_object_item_tooltip_text_set(item, tooltip_text);
+         elm_object_item_disabled_set(item, !ewk_popup_menu_item_enabled_get(ewk_item));
+         elm_menu_item_selected_set(item, ewk_popup_menu_item_selected_get(ewk_item));
+       }
+       break;
+     default:
+       INFO("Unrecognized popup menu item type!");
+       break;
+     }
+   }
+}
+
+static Eina_Bool
+_popup_menu_show(Ewk_View_Smart_Data *smartData, Eina_Rectangle rect, Ewk_Text_Direction text_direction, double page_scale_factor, Ewk_Popup_Menu *ewk_menu)
+{
+   Browser_Window *window = window_find_with_ewk_view(smartData->self);
+
+   if (window->popup.elm_menu)
+     evas_object_del(window->popup.elm_menu);
+
+   window->popup.elm_menu = elm_menu_add(window->elm_window);
+   window->popup.ewk_menu = ewk_menu;
+
+   popup_menu_populate(window->popup.elm_menu, ewk_menu, window);
+
+   INFO("Showing popup menu at (%d, %d)", rect.x, rect.y);
+   elm_menu_move(window->popup.elm_menu, rect.x, rect.y);
+   evas_object_show(window->popup.elm_menu);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_popup_menu_hide(Ewk_View_Smart_Data *smartData)
+{
+   Browser_Window *window = window_find_with_ewk_view(smartData->self);
+
+   if (!window->popup.elm_menu)
+     return EINA_FALSE;
+
+   elm_menu_close(window->popup.elm_menu);
+   window->popup.ewk_menu = NULL;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_window_geometry_get(Ewk_View_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *width, Evas_Coord *height)
+{
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+
+   evas_object_geometry_get(window->elm_window, x, y, width, height);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_window_geometry_set(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord width, Evas_Coord height)
+{
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+
+   evas_object_move(window->elm_window, x, y);
+   evas_object_resize(window->elm_window, width, height);
+
+   return EINA_TRUE;
+}
+
+typedef struct {
+   Evas_Object *ewk_view;
+   Evas_Object *permission_popup;
+} PermissionData;
+
+static void
+_fullscreen_accept_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   PermissionData *permission_data = (PermissionData *)user_data;
+   Browser_Window *window = window_find_with_ewk_view(permission_data->ewk_view);
+
+   elm_win_resize_object_del(window->elm_window, permission_data->permission_popup);
+   evas_object_del(permission_data->permission_popup);
+   evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
+   free(permission_data);
+}
+
+static void
+_fullscreen_deny_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   PermissionData *permission_data = (PermissionData *)user_data;
+   Browser_Window *window = window_find_with_ewk_view(permission_data->ewk_view);
+
+   ewk_view_fullscreen_exit(permission_data->ewk_view);
+   elm_win_resize_object_del(window->elm_window, permission_data->permission_popup);
+   evas_object_del(permission_data->permission_popup);
+   evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
+   free(permission_data);
+}
+
+static Eina_Bool
+_fullscreen_enter_cb(Ewk_View_Smart_Data *sd, Ewk_Security_Origin *origin)
+{
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+
+   /* Go fullscreen */
+   toggle_window_fullscreen(window, EINA_TRUE);
+
+   /* Show user popup */
+   Evas_Object *permission_popup = elm_popup_add(window->elm_window);
+   evas_object_size_hint_weight_set(permission_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+   Eina_Strbuf *message = eina_strbuf_new();
+   eina_strbuf_append_printf(message, "%s is now fullscreen.<br>Press ESC at any time to exit fullscreen.<br>Allow fullscreen?", ewk_security_origin_host_get(origin));
+   elm_object_text_set(permission_popup, eina_strbuf_string_get(message));
+   eina_strbuf_free(message);
+   elm_object_part_text_set(permission_popup, "title,text", "Fullscreen Permission");
+
+   /* Popup buttons */
+   PermissionData *permission_data = (PermissionData *)malloc(sizeof(PermissionData));
+   permission_data->ewk_view = window->ewk_view;
+   permission_data->permission_popup = permission_popup;
+   Evas_Object *accept_button = elm_button_add(permission_popup);
+   elm_object_text_set(accept_button, "Accept");
+   elm_object_part_content_set(permission_popup, "button1", accept_button);
+   evas_object_smart_callback_add(accept_button, "clicked", _fullscreen_accept_cb, permission_data);
+
+   Evas_Object *deny_button = elm_button_add(permission_popup);
+   elm_object_text_set(deny_button, "Deny");
+   elm_object_part_content_set(permission_popup, "button2", deny_button);
+   evas_object_smart_callback_add(deny_button, "clicked", _fullscreen_deny_cb, permission_data);
+   elm_win_resize_object_add(window->elm_window, permission_popup);
+   evas_object_show(permission_popup);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool _fullscreen_exit_cb(Ewk_View_Smart_Data *sd)
+{
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+
+   toggle_window_fullscreen(window, EINA_FALSE);
+
+   return EINA_TRUE;
+}
+
+static Evas_Object *
+_window_create_cb(Ewk_View_Smart_Data *smartData, Ewk_View_Configuration* configuration, const Ewk_Window_Features *window_features)
+{
+   int x = 0;
+   int y = 0;
+   int width = 0;
+   int height = 0;
+
+   ewk_window_features_geometry_get(window_features, &x, &y, &width, &height);
+
+   if (!width)
+     width = window_width;
+
+   if (!height)
+     height = window_height;
+
+   Browser_Window *window = window_create(configuration, width, height);
+   Evas_Object *new_view = window->ewk_view;
+
+   windows = eina_list_append(windows, window);
+
+   INFO("minibrowser: location(%d,%d) size=(%d,%d)", x, y, width, height);
+
+   return new_view;
+}
+
+static void
+_window_close_cb(Ewk_View_Smart_Data *smartData)
+{
+   Browser_Window *window = window_find_with_ewk_view(smartData->self);
+   window_close(window);
+}
+
+static void
+_context_menu_item_selected_cb(void *data, Evas_Object *obj, void *event_info)
+{
+   if (!data) {
+     ERROR("Context menu callback data is NULL.");
+     return;
+   }
+
+   Ewk_Context_Menu_Item *ewk_item = (Ewk_Context_Menu_Item *)data;
+   INFO("Selected context menu item: %s.", ewk_context_menu_item_title_get(ewk_item));
+   ewk_context_menu_item_select(ewk_context_menu_item_parent_menu_get(ewk_item), ewk_item);
+   ewk_context_menu_hide(ewk_context_menu_item_parent_menu_get(ewk_item));
+}
+
+static void
+context_menu_populate(Evas_Object* context_menu, Ewk_Context_Menu *ewk_menu, Elm_Object_Item *parent_item)
+{
+   if (!context_menu || !ewk_menu) {
+     ERROR("Necessary objects are NULL.");
+     return;
+   }
+
+   const Eina_List *list = ewk_context_menu_items_get(ewk_menu);
+   const Eina_List *l;
+   void *data;
+
+   Ewk_Context_Menu_Item *ewk_item;
+   Elm_Object_Item *elm_menu_item;
+   Evas_Object *elm_check_item;
+
+   EINA_LIST_FOREACH(list, l, data) {
+     ewk_item = (Ewk_Context_Menu_Item *)data;
+     switch (ewk_context_menu_item_type_get(ewk_item)) {
+     case EWK_ACTION_TYPE:
+       elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), _context_menu_item_selected_cb, ewk_item);
+       break;
+     case EWK_CHECKABLE_ACTION_TYPE:
+       elm_check_item = elm_check_add(context_menu);
+       elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), _context_menu_item_selected_cb, ewk_item);
+       elm_object_item_content_set(elm_menu_item, elm_check_item);
+       elm_check_state_set(elm_check_item, ewk_context_menu_item_checked_get(ewk_item));
+       break;
+     case EWK_SUBMENU_TYPE:
+       elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), NULL, ewk_item);
+       if (elm_menu_item)
+         context_menu_populate(context_menu, ewk_context_menu_item_submenu_get(ewk_item), elm_menu_item);
+       break;
+     default:
+       continue;
+     }
+     elm_object_item_disabled_set(elm_menu_item, !ewk_context_menu_item_enabled_get(ewk_item));
+   }
+}
+
+static Eina_Bool
+_context_menu_show(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Ewk_Context_Menu *menu)
+{
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+
+   if (!window || !menu) {
+     ERROR("Necessary objects are NULL.");
+     return EINA_FALSE;
+   }
+
+   window->context_menu.elm_menu = elm_menu_add(window->elm_window);
+
+   if (!window->context_menu.elm_menu) {
+     ERROR("Could not create menu widget.");
+     return EINA_FALSE;
+   }
+
+   window->context_menu.ewk_menu = menu;
+
+   context_menu_populate(window->context_menu.elm_menu, menu, NULL);
+
+   INFO("Showing context menu at (%d, %d).", x, y);
+   elm_menu_move(window->context_menu.elm_menu, x, y);
+   evas_object_show(window->context_menu.elm_menu);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_context_menu_hide(Ewk_View_Smart_Data *sd)
+{
+   Browser_Window *window = window_find_with_ewk_view(sd->self);
+
+   if (!window || !window->context_menu.elm_menu) {
+     ERROR("Necessary objects are NULL.");
+     return EINA_FALSE;
+   }
+
+   elm_menu_close(window->context_menu.elm_menu);
+   evas_object_del(window->context_menu.elm_menu);
+   window->context_menu.elm_menu = NULL;
+   window->context_menu.ewk_menu = NULL;
+
+   return EINA_TRUE;
+}
+
+static void
+auth_popup_close(Auth_Data *auth_data)
+{
+   ewk_object_unref(auth_data->request);
+   evas_object_del(auth_data->popup);
+   free(auth_data);
+}
+
+static void
+_auth_cancel_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Auth_Data *auth_data = (Auth_Data *)user_data;
+
+   ewk_auth_request_cancel(auth_data->request);
+
+   auth_popup_close(auth_data);
+}
+
+static void
+_auth_ok_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Auth_Data *auth_data = (Auth_Data *)user_data;
+
+   const char *username = elm_entry_entry_get(auth_data->username_entry);
+   const char *password = elm_entry_entry_get(auth_data->password_entry);
+   ewk_auth_request_authenticate(auth_data->request, username, password);
+
+   auth_popup_close(auth_data);
+}
+
+static void
+_authentication_request_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   Ewk_Auth_Request *request = ewk_object_ref((Ewk_Auth_Request *)event_info);
+
+   Auth_Data *auth_data = (Auth_Data *)malloc(sizeof(Auth_Data));
+   auth_data->request = request;
+
+   Evas_Object *auth_popup = elm_popup_add(window->elm_window);
+   auth_data->popup = auth_popup;
+   evas_object_size_hint_weight_set(auth_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_object_part_text_set(auth_popup, "title,text", "Authentication Required");
+
+   /* Popup Content */
+   Evas_Object *vbox = elm_box_add(auth_popup);
+   elm_box_padding_set(vbox, 0, 4);
+   evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_object_content_set(auth_popup, vbox);
+   evas_object_show(vbox);
+
+   /* Authentication message */
+   Evas_Object *label = elm_label_add(auth_popup);
+   elm_label_line_wrap_set(label, ELM_WRAP_WORD);
+   Eina_Strbuf *auth_text = eina_strbuf_new();
+   const char *host = ewk_auth_request_host_get(request);
+   const char *realm = ewk_auth_request_realm_get(request);
+   eina_strbuf_append_printf(auth_text, "A username and password are being requested by %s. The site says: \"%s\"", host, realm ? realm : "");
+   elm_object_text_set(label, eina_strbuf_string_get(auth_text));
+   eina_strbuf_free(auth_text);
+   evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(vbox, label);
+   evas_object_show(label);
+
+   /* Credential table */
+   Evas_Object *table = elm_table_add(auth_popup);
+   elm_table_padding_set(table, 2, 2);
+   elm_table_homogeneous_set(table, EINA_TRUE);
+   evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(vbox, table);
+   evas_object_show(table);
+
+   /* Username row */
+   Evas_Object *username_label = elm_label_add(auth_popup);
+   elm_object_text_set(username_label, "Username:");
+   evas_object_size_hint_weight_set(username_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(username_label, 1, EVAS_HINT_FILL);
+   elm_table_pack(table, username_label, 0, 0, 1, 1);
+   evas_object_show(username_label);
+
+   Evas_Object *username_entry = elm_entry_add(auth_popup);
+   auth_data->username_entry = username_entry;
+   elm_entry_scrollable_set(username_entry, EINA_TRUE);
+   elm_entry_single_line_set(username_entry, EINA_TRUE);
+   elm_entry_text_style_user_push(username_entry, "DEFAULT='font_size=18'");
+   const char *suggested_username = ewk_auth_request_suggested_username_get(request);
+   elm_entry_entry_set(username_entry, suggested_username ? suggested_username : "");
+   evas_object_size_hint_weight_set(username_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(username_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_table_pack(table, username_entry, 1, 0, 2, 1);
+   elm_object_focus_set(username_entry, EINA_TRUE);
+   evas_object_show(username_entry);
+
+   /* Password row */
+   Evas_Object *password_label = elm_label_add(auth_popup);
+   elm_object_text_set(password_label, "Password:");
+   evas_object_size_hint_weight_set(password_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(password_label, 1, EVAS_HINT_FILL);
+   elm_table_pack(table, password_label, 0, 1, 1, 1);
+   evas_object_show(password_label);
+
+   Evas_Object *password_entry = elm_entry_add(auth_popup);
+   auth_data->password_entry = password_entry;
+   elm_entry_scrollable_set(password_entry, EINA_TRUE);
+   elm_entry_single_line_set(password_entry, EINA_TRUE);
+   elm_entry_password_set(password_entry, EINA_TRUE);
+   elm_entry_text_style_user_push(password_entry, "DEFAULT='font_size=18'");
+   evas_object_size_hint_weight_set(password_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(password_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_table_pack(table, password_entry, 1, 1, 2, 1);
+   evas_object_show(password_entry);
+
+   /* Popup buttons */
+   Evas_Object *cancel_button = elm_button_add(auth_popup);
+   elm_object_text_set(cancel_button, "Cancel");
+   elm_object_part_content_set(auth_popup, "button1", cancel_button);
+   evas_object_smart_callback_add(cancel_button, "clicked", _auth_cancel_cb, auth_data);
+   Evas_Object *ok_button = elm_button_add(auth_popup);
+   elm_object_text_set(ok_button, "OK");
+   elm_object_part_content_set(auth_popup, "button2", ok_button);
+   evas_object_smart_callback_add(ok_button, "clicked", _auth_ok_cb, auth_data);
+   evas_object_show(auth_popup);
+}
+
+static void
+_search_text_found_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   const int *match_count = (const int *)(event_info);
+
+   if (*match_count) {
+     Eina_Strbuf *search_text = eina_strbuf_new();
+     eina_strbuf_append_printf(search_text, "  %d  Matches Found " , *match_count);
+     elm_object_text_set(window->search.search_field_count, eina_strbuf_string_get(search_text));
+     eina_strbuf_free(search_text);
+   } else
+     elm_object_text_set(window->search.search_field_count, " No Matches Found");
+
+   evas_object_focus_set(window->ewk_view, EINA_FALSE);
+   elm_object_focus_set(window->search.search_field_count, EINA_FALSE);
+   elm_object_focus_set(window->search.search_field, EINA_TRUE);
+}
+
+static void
+_tooltip_text_set(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   const char *message = (const char*)event_info;
+
+   elm_object_tooltip_text_set(window->elm_window, message);
+   window->tooltip.text_set = EINA_TRUE;
+   window_tooltip_update(window);
+}
+
+static void
+_tooltip_text_unset(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   window_tooltip_hide(window);
+   elm_object_tooltip_unset(window->elm_window);
+   window->tooltip.text_set = EINA_FALSE;
+}
+
+static void
+_navigation_policy_decision_cb(void *user_data, Evas_Object *obj, void *event_info)
+{
+   Ewk_Navigation_Policy_Decision *decision = (Ewk_Navigation_Policy_Decision *)event_info;
+
+   if (ewk_navigation_policy_mouse_button_get(decision) == EWK_EVENT_MOUSE_BUTTON_MIDDLE) {
+     Browser_Window *window = window_create(NULL, 0, 0);
+     ewk_view_url_set(window->ewk_view, ewk_url_request_url_get(ewk_navigation_policy_request_get(decision)));
+     windows = eina_list_append(windows, window);
+     INFO("Mouse middle button pressed, open link in new window");
+
+     ewk_navigation_policy_decision_reject(decision);
+   }
+}
+
+static void
+_search_button_clicked_cb(void *user_data, Evas_Object *home_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   search_box_show(window);
+}
+
+static void
+_home_button_clicked_cb(void *user_data, Evas_Object *home_button, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+
+   ewk_view_url_set(window->ewk_view, DEFAULT_URL);
+}
+
+static void
+_window_deletion_cb(void *user_data, Evas_Object *elm_window, void *event_info)
+{
+   Browser_Window *window = (Browser_Window *)user_data;
+   ewk_view_try_close(window->ewk_view);
+}
+
+static Evas_Object *
+_create_toolbar_button(Evas_Object *elm_window, const char *icon_name)
+{
+   Evas_Object *button = elm_button_add(elm_window);
+
+   Evas_Object *icon = elm_icon_add(elm_window);
+   elm_icon_standard_set(icon, icon_name);
+   evas_object_size_hint_max_set(icon, TOOL_BAR_ICON_SIZE, TOOL_BAR_ICON_SIZE);
+   evas_object_color_set(icon, 0, 255, 255, 255);
+   evas_object_show(icon);
+   elm_object_part_content_set(button, "icon", icon);
+   evas_object_size_hint_min_set(button, TOOL_BAR_BUTTON_SIZE, TOOL_BAR_BUTTON_SIZE);
+
+   return button;
+}
+
+static Browser_Window *window_create(Ewk_View_Configuration* configuration, int width, int height)
+{
+   Browser_Window *window = calloc(1, sizeof(Browser_Window));
+   if (!window) {
+     ERROR("Could not create browser window.");
+     return NULL;
+   }
+
+   /* Initialize tooltip information */
+   window->tooltip.show_timer = NULL;
+   window->tooltip.activated = EINA_FALSE;
+   window->tooltip.text_set = EINA_FALSE;
+   window->tooltip.shown = EINA_FALSE;
+
+   /* Create window */
+   window->elm_window = elm_win_add(NULL, "minibrowser-window", ELM_WIN_BASIC);
+   elm_win_title_set(window->elm_window, APP_NAME);
+   evas_object_smart_callback_add(window->elm_window, "delete,request", _window_deletion_cb, window);
+
+   /* Create window background */
+   Evas_Object *bg = elm_bg_add(window->elm_window);
+   elm_bg_color_set(bg, 193, 192, 191);
+   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(window->elm_window, bg);
+   evas_object_show(bg);
+
+   /* Create conformant widget. */
+   Evas_Object *conformant = elm_conformant_add(window->elm_window);
+   evas_object_size_hint_weight_set(conformant, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(window->elm_window, conformant);
+   evas_object_show(conformant);
+
+   /* Create vertical layout */
+   window->vertical_layout = elm_box_add(window->elm_window);
+   elm_object_content_set(conformant, window->vertical_layout);
+   elm_box_padding_set(window->vertical_layout, 0, 2);
+   evas_object_size_hint_weight_set(window->vertical_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_show(window->vertical_layout);
+
+   /* Create horizontal layout for top bar */
+   window->horizontal_layout = elm_box_add(window->elm_window);
+   elm_box_horizontal_set(window->horizontal_layout, EINA_TRUE);
+   evas_object_size_hint_weight_set(window->horizontal_layout, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(window->horizontal_layout, EVAS_HINT_FILL, 0.0);
+   elm_box_pack_end(window->vertical_layout, window->horizontal_layout);
+   evas_object_show(window->horizontal_layout);
+
+   /* Create Back button */
+   window->back_button = _create_toolbar_button(window->elm_window, "arrow_left");
+   evas_object_smart_callback_add(window->back_button, "clicked", _back_button_clicked_cb, window);
+   evas_object_smart_callback_add(window->back_button, "repeated", _back_button_longpress_cb, window);
+   elm_object_tooltip_text_set(window->back_button, "Click to go back, longpress to see session history");
+   elm_object_tooltip_window_mode_set(window->back_button, EINA_TRUE);
+   elm_object_disabled_set(window->back_button, EINA_TRUE);
+   evas_object_size_hint_weight_set(window->back_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->back_button, 0.0, 0.5);
+   elm_box_pack_end(window->horizontal_layout, window->back_button);
+   evas_object_show(window->back_button);
+
+   /* Create Forward button */
+   window->forward_button = _create_toolbar_button(window->elm_window, "arrow_right");
+   evas_object_smart_callback_add(window->forward_button, "clicked", _forward_button_clicked_cb, window);
+   evas_object_smart_callback_add(window->forward_button, "repeated", _forward_button_longpress_cb, window);
+   elm_object_tooltip_text_set(window->forward_button, "Click to go forward, longpress to see session history");
+   elm_object_tooltip_window_mode_set(window->forward_button, EINA_TRUE);
+   elm_object_disabled_set(window->forward_button, EINA_TRUE);
+   evas_object_size_hint_weight_set(window->forward_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->forward_button, 0.0, 0.5);
+   elm_box_pack_end(window->horizontal_layout, window->forward_button);
+   evas_object_show(window->forward_button);
+
+   /* Create Search button */
+   Evas_Object *search_button = _create_toolbar_button(window->elm_window, "toolbar/search");
+   evas_object_smart_callback_add(search_button, "clicked", _search_button_clicked_cb, window);
+   elm_object_tooltip_text_set(search_button, "Find text");
+   elm_object_tooltip_window_mode_set(search_button, EINA_TRUE);
+   evas_object_size_hint_weight_set(search_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(search_button, 1.0, 0.5);
+   elm_box_pack_end(window->horizontal_layout, search_button);
+   evas_object_show(search_button);
+
+   /* Create URL bar */
+   window->url_bar = elm_entry_add(window->elm_window);
+   elm_entry_scrollable_set(window->url_bar, EINA_TRUE);
+   elm_scroller_policy_set(window->url_bar, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   elm_entry_single_line_set(window->url_bar, EINA_TRUE);
+   elm_entry_cnp_mode_set(window->url_bar, ELM_CNP_MODE_PLAINTEXT);
+   elm_entry_text_style_user_push(window->url_bar, "DEFAULT='font_size=18'");
+   evas_object_smart_callback_add(window->url_bar, "activated", _url_bar_activated_cb, window);
+   evas_object_smart_callback_add(window->url_bar, "clicked", _url_bar_clicked_cb, window);
+   evas_object_size_hint_weight_set(window->url_bar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->url_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(window->horizontal_layout, window->url_bar);
+   evas_object_show(window->url_bar);
+
+   /* Create Refresh button */
+   Evas_Object *refresh_button = _create_toolbar_button(window->elm_window, "refresh");
+   evas_object_smart_callback_add(refresh_button, "clicked", _refresh_button_clicked_cb, window);
+   elm_object_tooltip_text_set(refresh_button, "Reload page");
+   elm_object_tooltip_window_mode_set(refresh_button, EINA_TRUE);
+   evas_object_size_hint_weight_set(refresh_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(refresh_button, 1.0, 0.5);
+   elm_box_pack_end(window->horizontal_layout, refresh_button);
+   evas_object_show(refresh_button);
+
+   /* Create Stop button */
+   Evas_Object *stop_button = _create_toolbar_button(window->elm_window, "close");
+   evas_object_smart_callback_add(stop_button, "clicked", _stop_button_clicked_cb, window);
+   elm_object_tooltip_text_set(stop_button, "Stop page load");
+   elm_object_tooltip_window_mode_set(stop_button, EINA_TRUE);
+   evas_object_size_hint_weight_set(stop_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(stop_button, 1.0, 0.5);
+   elm_box_pack_end(window->horizontal_layout, stop_button);
+   evas_object_show(stop_button);
+
+   /* Create Home button */
+   Evas_Object *home_button = _create_toolbar_button(window->elm_window, "home");
+   evas_object_smart_callback_add(home_button, "clicked", _home_button_clicked_cb, window);
+   elm_object_tooltip_text_set(home_button, "Home page");
+   elm_object_tooltip_window_mode_set(home_button, EINA_TRUE);
+   evas_object_size_hint_weight_set(home_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(home_button, 1.0, 0.5);
+   elm_box_pack_end(window->horizontal_layout, home_button);
+   evas_object_show(home_button);
+
+   /* Create Search bar */
+   window->search.search_bar = elm_box_add(window->elm_window);
+   elm_box_horizontal_set(window->search.search_bar, EINA_TRUE);
+   evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, 0);
+   evas_object_size_hint_align_set(window->search.search_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(window->vertical_layout, window->search.search_bar);
+
+   /* Create Search field */
+   window->search.search_field = elm_entry_add(window->elm_window);
+   elm_entry_scrollable_set(window->search.search_field, EINA_TRUE);
+   elm_scroller_policy_set(window->search.search_field, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   elm_entry_single_line_set(window->search.search_field, EINA_TRUE);
+   elm_entry_cnp_mode_set(window->search.search_field, ELM_CNP_MODE_PLAINTEXT);
+   elm_entry_text_style_user_push(window->search.search_field, "DEFAULT='font_size=14'");
+   evas_object_smart_callback_add(window->search.search_field, "activated", _search_field_activated_cb, window);
+   evas_object_smart_callback_add(window->search.search_field, "changed", _search_field_activated_cb, window);
+   evas_object_smart_callback_add(window->search.search_field, "aborted", _search_field_aborted_cb, window);
+   evas_object_smart_callback_add(window->search.search_field, "clicked", _search_field_clicked_cb, window);
+   evas_object_size_hint_weight_set(window->search.search_field, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->search.search_field, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(window->search.search_bar, window->search.search_field);
+
+   /* Create Search backward button */
+   window->search.backward_button = _create_toolbar_button(window->elm_window, "arrow_up");
+   evas_object_smart_callback_add(window->search.backward_button, "clicked", _search_backward_button_clicked_cb, window);
+   elm_object_disabled_set(window->search.backward_button, EINA_FALSE);
+   evas_object_size_hint_weight_set(window->search.backward_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->search.backward_button, 1.0, 0.5);
+   evas_object_size_hint_min_set(window->search.backward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
+   elm_box_pack_end(window->search.search_bar, window->search.backward_button);
+
+   /* Create Search forwardward button */
+   window->search.forward_button = _create_toolbar_button(window->elm_window, "arrow_down");
+   evas_object_smart_callback_add(window->search.forward_button, "clicked", _search_forward_button_clicked_cb, window);
+   elm_object_disabled_set(window->search.forward_button, EINA_FALSE);
+   evas_object_size_hint_weight_set(window->search.forward_button, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->search.forward_button, 1.0, 0.5);
+   evas_object_size_hint_min_set(window->search.forward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
+   elm_box_pack_end(window->search.search_bar, window->search.forward_button);
+
+   /* Create Search count field */
+   window->search.search_field_count = elm_label_add(window->elm_window);
+   evas_object_size_hint_weight_set(window->search.search_field_count, 0.0, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->search.search_field_count, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_object_text_set(window->search.search_field_count, "");
+   elm_box_pack_end(window->search.search_bar, window->search.search_field_count);
+
+   /* Create Search Case Sensitive Option check box */
+   window->search.search_case_check_box = elm_check_add(window->elm_window);
+   elm_object_text_set(window->search.search_case_check_box, "Case Sensitive");
+   evas_object_smart_callback_add(window->search.search_case_check_box, "changed", _search_case_option_changed, window);
+   elm_box_pack_end(window->search.search_bar, window->search.search_case_check_box);
+
+   /* Create Search Word Start Option check box */
+   window->search.search_word_start_check_box = elm_check_add(window->elm_window);
+   elm_object_text_set(window->search.search_word_start_check_box, "Only Word Start");
+   evas_object_smart_callback_add(window->search.search_word_start_check_box, "changed", _search_word_start_option_changed_cb, window);
+   elm_box_pack_end(window->search.search_bar, window->search.search_word_start_check_box);
+
+   /* Create Search close button */
+   window->search.close_button = _create_toolbar_button(window->elm_window, "close");
+   evas_object_smart_callback_add(window->search.close_button, "clicked", _search_close_button_clicked_cb, window);
+   elm_object_disabled_set(window->search.close_button, EINA_FALSE);
+   evas_object_size_hint_weight_set(window->search.close_button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->search.close_button, 1.0, 0.5);
+   evas_object_size_hint_min_set(window->search.close_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
+   elm_box_pack_end(window->search.search_bar, window->search.close_button);
+
+   /* Create history box */
+   window->history.history_box = elm_box_add(window->elm_window);
+   evas_object_size_hint_aspect_set(window->history.history_box, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
+   evas_object_size_hint_weight_set(window->history.history_box, EVAS_HINT_EXPAND , EVAS_HINT_EXPAND);
+
+   /* Create history list */
+   window->history.history_list = elm_genlist_add(window->elm_window);
+   evas_object_size_hint_weight_set(window->history.history_list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->history.history_list, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_win_resize_object_add(window->elm_window, window->history.history_box);
+   elm_box_pack_end(window->history.history_box, window->history.history_list);
+
+   /* Create ewk_view */
+   Ewk_View_Smart_Class *ewkViewClass = miniBrowserViewSmartClass();
+   ewkViewClass->run_javascript_alert = _javascript_alert_cb;
+   ewkViewClass->run_javascript_confirm = _javascript_confirm_cb;
+   ewkViewClass->run_javascript_prompt = _javascript_prompt_cb;
+   ewkViewClass->run_javascript_before_unload_confirm = _javascript_before_unload_confirm_cb;
+   ewkViewClass->window_geometry_get = _window_geometry_get;
+   ewkViewClass->window_geometry_set = _window_geometry_set;
+   ewkViewClass->fullscreen_enter = _fullscreen_enter_cb;
+   ewkViewClass->fullscreen_exit = _fullscreen_exit_cb;
+   ewkViewClass->window_create = _window_create_cb;
+   ewkViewClass->window_close = _window_close_cb;
+   ewkViewClass->popup_menu_show = _popup_menu_show;
+   ewkViewClass->popup_menu_hide = _popup_menu_hide;
+   ewkViewClass->context_menu_show = _context_menu_show;
+   ewkViewClass->context_menu_hide = _context_menu_hide;
+   ewkViewClass->input_picker_color_request = _color_picker_request_cb;
+   ewkViewClass->input_picker_color_dismiss = _color_picker_dismiss_cb;
+
+   Evas *evas = evas_object_evas_get(window->elm_window);
+   Evas_Smart *smart = evas_smart_class_new(&ewkViewClass->sc);
+   window->ewk_view = ewk_view_add_with_configuration(evas, smart, configuration);
+
+   Ewk_Context *context = ewk_view_context_get(window->ewk_view);
+   ewk_favicon_database_icon_change_callback_add(ewk_context_favicon_database_get(context), _icon_changed_cb, window);
+
+   ewk_view_theme_set(window->ewk_view, DEFAULT_THEME_DIR "/default.edj");
+   if (device_pixel_ratio)
+     ewk_view_device_pixel_ratio_set(window->ewk_view, (float)device_pixel_ratio);
+   ewk_view_user_agent_set(window->ewk_view, user_agent_string);
+   ewk_view_layout_fixed_set(window->ewk_view, fixed_layout_enabled);
+
+   if (touch_events_enabled) {
+     ewk_view_touch_events_enabled_set(window->ewk_view, EINA_TRUE);
+     ewk_view_mouse_events_enabled_set(window->ewk_view, EINA_FALSE);
+   }
+
+   if (background_color_string) {
+     int red, green, blue, alpha;
+
+     if (sscanf(background_color_string, "%d:%d:%d:%d", &red, &green, &blue, &alpha))
+       ewk_view_bg_color_set(window->ewk_view, red, green, blue, alpha);
+   }
+
+   /* Set the zoom level to default */
+   window->current_zoom_level = DEFAULT_ZOOM_LEVEL;
+
+   elm_win_fullscreen_set(window->elm_window, fullscreen_enabled);
+
+   evas_object_smart_callback_add(window->ewk_view, "authentication,request", _authentication_request_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "file,chooser,request", _file_chooser_request_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "load,error", _error_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "load,provisional,failed", _error_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "load,progress", _progress_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "title,changed", _title_changed_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "url,changed", _url_changed_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "back,forward,list,changed", _back_forward_list_changed_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "text,found", _search_text_found_cb, window);
+   evas_object_smart_callback_add(window->ewk_view, "tooltip,text,set", _tooltip_text_set, window);
+   evas_object_smart_callback_add(window->ewk_view, "tooltip,text,unset", _tooltip_text_unset, window);
+   evas_object_smart_callback_add(window->ewk_view, "policy,decision,navigation", _navigation_policy_decision_cb, window);
+
+   evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, window);
+   evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, window);
+
+   evas_object_size_hint_weight_set(window->ewk_view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(window->ewk_view, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_before(window->vertical_layout, window->ewk_view, window->search.search_bar);
+   evas_object_show(window->ewk_view);
+
+   evas_object_resize(window->elm_window, width ? width : window_width, height ? height : window_height);
+   evas_object_show(window->elm_window);
+   search_box_hide(window);
+
+   view_focus_set(window, EINA_TRUE);
+   // Prevent window from stealing web view's focus on start up.
+   elm_object_focus_allow_set(window->elm_window, EINA_FALSE);
+
+   evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_IN, _mouse_in_cb, window);
+   evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_OUT, _mouse_out_cb, window);
+   evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, window);
+   evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, window);
+   evas_object_event_callback_add(window->elm_window, EVAS_CALLBACK_RESIZE, _window_resize_cb, window);
+
+   elm_button_autorepeat_set(window->back_button, EINA_TRUE);
+   elm_button_autorepeat_set(window->forward_button, EINA_TRUE);
+   elm_button_autorepeat_initial_timeout_set(window->back_button, LONGPRESS_INTERVAL_SECONDS);
+   elm_button_autorepeat_initial_timeout_set(window->forward_button, LONGPRESS_INTERVAL_SECONDS);
+
+   return window;
+}
+
+static Ewk_View_Configuration* configuration()
+{
+    static Ewk_View_Configuration* default_configuration = 0;
+
+    if (default_configuration)
+      return default_configuration;
+
+    default_configuration = ewk_view_configuration_new();
+
+    Ewk_Settings* settings = ewk_view_configuration_settings_get(default_configuration);
+    ewk_settings_file_access_from_file_urls_allowed_set(settings, EINA_TRUE);
+    ewk_settings_encoding_detector_enabled_set(settings, encoding_detector_enabled);
+    ewk_settings_frame_flattening_enabled_set(settings, frame_flattening_enabled);
+    ewk_settings_local_storage_enabled_set(settings, local_storage_enabled);
+    ewk_settings_offline_web_application_cache_enabled_set(settings, offline_web_application_cache_enabled);
+    INFO("HTML5 local storage is %s for this view.", local_storage_enabled ? "enabled" : "disabled");
+    ewk_settings_developer_extras_enabled_set(settings, EINA_TRUE);
+    ewk_settings_preferred_minimum_contents_width_set(settings, 0);
+    ewk_text_checker_continuous_spell_checking_enabled_set(spell_checking_enabled);
+    ewk_settings_web_security_enabled_set(settings, web_security_enabled);
+
+    return default_configuration;
+}
+
+static Ewk_Cookie_Accept_Policy
+parse_cookies_policy(const char *input_string)
+{
+   if (!strcmp(input_string, "always"))
+     return EWK_COOKIE_ACCEPT_POLICY_ALWAYS;
+   if (!strcmp(input_string, "never"))
+     return EWK_COOKIE_ACCEPT_POLICY_NEVER;
+   if (strcmp(input_string, "no-third-party"))
+     INFO("Unrecognized type for cookies policy: %s.", input_string);
+   return EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY;
+}
+
+static void
+parse_window_size(const char *input_string, int *width, int *height)
+{
+   static const unsigned max_length = 4;
+   int parsed_width;
+   int parsed_height;
+   char **arr;
+   unsigned elements;
+
+   arr = eina_str_split_full(input_string, "x", 0, &elements);
+
+   if (elements == 2 && (strlen(arr[0]) <= max_length) && (strlen(arr[1]) <= max_length)) {
+     parsed_width = atoi(arr[0]);
+     if (width && parsed_width)
+       *width = parsed_width;
+
+     parsed_height = atoi(arr[1]);
+     if (height && parsed_height)
+       *height = parsed_height;
+   }
+
+   free(arr[0]);
+   free(arr);
+}
+
+EAPI_MAIN int
+elm_main(int argc, char *argv[])
+{
+   int args = 1;
+   unsigned char quitOption = 0;
+   Browser_Window *window;
+   char *window_size_string = NULL;
+   char *cookies_policy_string = NULL;
+
+   Ecore_Getopt_Value values[] = {
+     ECORE_GETOPT_VALUE_STR(evas_engine_name),
+     ECORE_GETOPT_VALUE_STR(window_size_string),
+     ECORE_GETOPT_VALUE_STR(user_agent_string),
+     ECORE_GETOPT_VALUE_STR(extensions_path),
+     ECORE_GETOPT_VALUE_DOUBLE(device_pixel_ratio),
+     ECORE_GETOPT_VALUE_BOOL(quitOption),
+     ECORE_GETOPT_VALUE_BOOL(encoding_detector_enabled),
+     ECORE_GETOPT_VALUE_STR(background_color_string),
+     ECORE_GETOPT_VALUE_BOOL(frame_flattening_enabled),
+     ECORE_GETOPT_VALUE_BOOL(local_storage_enabled),
+     ECORE_GETOPT_VALUE_BOOL(offline_web_application_cache_enabled),
+     ECORE_GETOPT_VALUE_BOOL(fullscreen_enabled),
+     ECORE_GETOPT_VALUE_BOOL(spell_checking_enabled),
+     ECORE_GETOPT_VALUE_BOOL(touch_events_enabled),
+     ECORE_GETOPT_VALUE_BOOL(fixed_layout_enabled),
+     ECORE_GETOPT_VALUE_STR(cookies_policy_string),
+     ECORE_GETOPT_VALUE_BOOL(web_security_enabled),
+     ECORE_GETOPT_VALUE_BOOL(separated_process_enabled),
+     ECORE_GETOPT_VALUE_BOOL(quitOption),
+     ECORE_GETOPT_VALUE_BOOL(quitOption),
+     ECORE_GETOPT_VALUE_BOOL(quitOption),
+     ECORE_GETOPT_VALUE_NONE
+   };
+
+   efreet_cache_update = 0;
+
+   if (!ewk_init())
+     return EXIT_FAILURE;
+
+   _log_domain_id = eina_log_domain_register("minibrowser", EINA_COLOR_YELLOW);
+
+   ewk_view_smart_class_set(miniBrowserViewSmartClass());
+
+   ecore_app_args_set(argc, (const char **) argv);
+   args = ecore_getopt_parse(&options, values, argc, argv);
+
+   if (args < 0)
+     return quit(EINA_FALSE, "Could not parse options.");
+
+   if (quitOption)
+     return quit(EINA_TRUE, NULL);
+
+   if (evas_engine_name)
+     elm_config_accel_preference_set(evas_engine_name);
+   else {
+     evas_engine_name = "opengl:depth24:stencil8";
+     elm_config_accel_preference_set(evas_engine_name);
+   }
+
+   Ewk_Context *context = ewk_context_default_get();
+
+   if (separated_process_enabled)
+     ewk_context_web_process_count_limit_set(context, 0);
+
+   // Enable favicon database.
+   ewk_context_favicon_database_directory_set(context, NULL);
+
+   // Use a proper cache model.
+   ewk_context_cache_model_set(context, EWK_CACHE_MODEL_PRIMARY_WEBBROWSER);
+
+   if (cookies_policy_string) {
+     Ewk_Cookie_Accept_Policy cookie_policy = parse_cookies_policy(cookies_policy_string);
+     ewk_cookie_manager_accept_policy_set(ewk_context_cookie_manager_get(context), cookie_policy);
+
+     if (cookie_policy == EWK_COOKIE_ACCEPT_POLICY_ALWAYS) {
+       const char cookie_storage_directory[] = "/tmp/ewebkit2_minibrowser_cookie/";
+       mkdir(cookie_storage_directory, S_IRWXU);
+       char storage_name[64];
+       snprintf(storage_name, sizeof(storage_name), "%stxt-cookie", cookie_storage_directory);
+       ewk_cookie_manager_persistent_storage_set(ewk_context_cookie_manager_get(context), storage_name, EWK_COOKIE_PERSISTENT_STORAGE_TEXT);
+     }
+   }
+
+   if (window_size_string)
+     parse_window_size(window_size_string, &window_width, &window_height);
+
+   window = window_create(configuration(), 0, 0);
+   if (!window)
+     return quit(EINA_FALSE, "Could not create browser window.");
+
+   // Set callbacks for download events.
+   ewk_context_download_callbacks_set(context, _download_request_cb, _download_failed_cb, 0, _download_finished_cb, window);
+
+   if (args < argc) {
+     char *url = url_from_user_input(argv[args]);
+     url_load_from_user_input(window->ewk_view, url);
+     free(url);
+   } else
+     ewk_view_url_set(window->ewk_view, DEFAULT_URL);
+
+   windows = eina_list_append(windows, window);
+
+   elm_run();
+
+   return quit(EINA_TRUE, NULL);
+}
+ELM_MAIN()
+
diff --git a/Tools/Scripts/run-efl-tests b/Tools/Scripts/run-efl-tests
new file mode 100755 (executable)
index 0000000..c8d3d7c
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -w
+# Copyright (C) 2012 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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.
+#     * Neither the name of Intel Corporation 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 THE COPYRIGHT HOLDERS AND 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
+# OWNER OR 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.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my $xvfb_display = ":55";
+
+my $xvfb_pid = fork();
+exit(1) if not defined $xvfb_pid;
+
+# Tell CTest to dump gtest output in case of failure.
+$ENV{CTEST_OUTPUT_ON_FAILURE} = "1";
+$ENV{DISPLAY} = $xvfb_display;
+
+if ($xvfb_pid == 0) {
+    # Start Xvfb
+    my @xvfb_args = ( "Xvfb $xvfb_display -screen 0 800x600x24 -nolisten tcp > /dev/null 2>&1" );
+    exec(@xvfb_args);
+} else {
+    setConfiguration();
+
+    # Manually add this for jhbuildWrapperPrefixIfNeeded().
+    push(@ARGV, "--efl");
+
+    my $returnCode = exitStatus(generateBuildSystemFromCMakeProject(undef, cmakeBasedPortArguments()));
+    exit($returnCode) if $returnCode;
+
+    $returnCode = exitStatus(buildCMakeGeneratedProject("test"));
+
+    # Kill Xvfb
+    kill(15, $xvfb_pid);
+
+    exit($returnCode);
+}
+
diff --git a/Tools/Scripts/update-webkitefl-libs b/Tools/Scripts/update-webkitefl-libs
new file mode 100755 (executable)
index 0000000..9e05ac0
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl -w
+# Copyright (C) 2012 Intel Corporation
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my $scriptsDir = relativeScriptsDir();
+system("perl", "$scriptsDir/update-webkit-libs-jhbuild", "--efl", @ARGV) == 0 or die $!;
diff --git a/Tools/Scripts/webkitpy/port/efl.py b/Tools/Scripts/webkitpy/port/efl.py
new file mode 100644 (file)
index 0000000..deb34ff
--- /dev/null
@@ -0,0 +1,146 @@
+# Copyright (C) 2011 ProFUSION Embedded Systems. All rights reserved.
+# Copyright (C) 2011 Samsung Electronics. All rights reserved.
+# Copyright (C) 2012 Intel Corporation
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * 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 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
+# OWNER OR 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.
+
+"""WebKit Efl implementation of the Port interface."""
+
+import os
+
+from webkitpy.common.system import path
+from webkitpy.layout_tests.models.test_configuration import TestConfiguration
+from webkitpy.port.base import Port
+from webkitpy.port.pulseaudio_sanitizer import PulseAudioSanitizer
+from webkitpy.port.xorgdriver import XorgDriver
+from webkitpy.port.xvfbdriver import XvfbDriver
+from webkitpy.port.linux_get_crash_log import GDBCrashLogGenerator
+
+
+class EflPort(Port):
+    port_name = 'efl'
+
+    def __init__(self, *args, **kwargs):
+        super(EflPort, self).__init__(*args, **kwargs)
+
+        self._jhbuild_wrapper = [self.path_from_webkit_base('Tools', 'jhbuild', 'jhbuild-wrapper'), '--efl', 'run']
+
+        self.set_option_default('wrapper', ' '.join(self._jhbuild_wrapper))
+        self.webprocess_cmd_prefix = self.get_option('webprocess_cmd_prefix')
+
+        self._pulseaudio_sanitizer = PulseAudioSanitizer()
+
+    def _port_flag_for_scripts(self):
+        return "--efl"
+
+    def setup_test_run(self, device_class=None):
+        super(EflPort, self).setup_test_run(device_class)
+        self._pulseaudio_sanitizer.unload_pulseaudio_module()
+
+    def setup_environ_for_server(self, server_name=None):
+        env = super(EflPort, self).setup_environ_for_server(server_name)
+
+        # If DISPLAY environment variable is unset in the system
+        # e.g. on build bot, remove DISPLAY variable from the dictionary
+        if not 'DISPLAY' in os.environ:
+            del env['DISPLAY']
+
+        if 'ACCESSIBILITY_EAIL_LIBRARY_PATH' in os.environ:
+            env['ACCESSIBILITY_EAIL_LIBRARY_PATH'] = os.environ['ACCESSIBILITY_EAIL_LIBRARY_PATH']
+
+        env['TEST_RUNNER_INJECTED_BUNDLE_FILENAME'] = self._build_path('lib', 'libTestRunnerInjectedBundle.so')
+        env['TEST_RUNNER_PLUGIN_PATH'] = self._build_path('lib', 'plugins')
+
+        # Silence GIO warnings about using the "memory" GSettings backend.
+        env['GSETTINGS_BACKEND'] = 'memory'
+
+        if self.webprocess_cmd_prefix:
+            env['WEB_PROCESS_CMD_PREFIX'] = self.webprocess_cmd_prefix
+
+        return env
+
+    def default_timeout_ms(self):
+        # Tests run considerably slower under gdb
+        # or valgrind.
+        if self.get_option('webprocess_cmd_prefix'):
+            return 350 * 1000
+        return super(EflPort, self).default_timeout_ms()
+
+    def clean_up_test_run(self):
+        super(EflPort, self).clean_up_test_run()
+        self._pulseaudio_sanitizer.restore_pulseaudio_module()
+
+    def _generate_all_test_configurations(self):
+        return [TestConfiguration(version=self._version, architecture='x86', build_type=build_type) for build_type in self.ALL_BUILD_TYPES]
+
+    def _driver_class(self):
+        if os.environ.get("USE_NATIVE_XDISPLAY"):
+            return XorgDriver
+        return XvfbDriver
+
+    def _path_to_driver(self):
+        return self._build_path('bin', self.driver_name())
+
+    def _path_to_image_diff(self):
+        return self._build_path('bin', 'ImageDiff')
+
+    def _image_diff_command(self, *args, **kwargs):
+        return self._jhbuild_wrapper + super(EflPort, self)._image_diff_command(*args, **kwargs)
+
+    def _path_to_webcore_library(self):
+        static_path = self._build_path('lib', 'libwebcore_efl.a')
+        dyn_path = self._build_path('lib', 'libwebcore_efl.so')
+        return static_path if self._filesystem.exists(static_path) else dyn_path
+
+    def _search_paths(self):
+        search_paths = []
+        search_paths.append(self.port_name)
+        search_paths.append('wk2')
+        return search_paths
+
+    def default_baseline_search_path(self):
+        return map(self._webkit_baseline_path, self._search_paths())
+
+    def _port_specific_expectations_files(self):
+        # FIXME: We should be able to use the default algorithm here.
+        return list(reversed([self._filesystem.join(self._webkit_baseline_path(p), 'TestExpectations') for p in self._search_paths()]))
+
+    def show_results_html_file(self, results_filename):
+        self._run_script("run-minibrowser", [path.abspath_to_uri(self.host.platform, results_filename)])
+
+    def check_sys_deps(self, needs_http):
+        return super(EflPort, self).check_sys_deps(needs_http) and self._driver_class().check_driver(self)
+
+    def build_webkit_command(self, build_style=None):
+        command = super(EflPort, self).build_webkit_command(build_style)
+        command.extend(["--efl", "--update-efl"])
+        command.append(super(EflPort, self).make_args())
+        return command
+
+    def _get_crash_log(self, name, pid, stdout, stderr, newer_than):
+        return GDBCrashLogGenerator(name, pid, newer_than, self._filesystem, self._path_to_driver).generate_crash_log(stdout, stderr)
+
+    def test_expectations_file_position(self):
+        # EFL port baseline search path is efl -> wk2 -> generic (as efl-wk2 and efl baselines are merged), so port test expectations file is at third to last position.
+        return 2
diff --git a/Tools/Scripts/webkitpy/port/efl_unittest.py b/Tools/Scripts/webkitpy/port/efl_unittest.py
new file mode 100644 (file)
index 0000000..f082155
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (C) 2011 ProFUSION Embedded Systems. All rights reserved.
+# Copyright (C) 2011 Samsung Electronics. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#    * 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 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
+# OWNER OR 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.
+
+import unittest
+
+from webkitpy.common.system.executive_mock import MockExecutive
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.port.efl import EflPort
+from webkitpy.port.pulseaudio_sanitizer_mock import PulseAudioSanitizerMock
+from webkitpy.port import port_testcase
+
+
+class EflPortTest(port_testcase.PortTestCase):
+    port_name = 'efl'
+    port_maker = EflPort
+
+    # Additionally mocks out the PulseAudioSanitizer methods.
+    def make_port(self, host=None, port_name=None, options=None, os_name=None, os_version=None, **kwargs):
+        port = super(EflPortTest, self).make_port(host, port_name, options, os_name, os_version, **kwargs)
+        port._pulseaudio_sanitizer = PulseAudioSanitizerMock()
+        return port
+
+    def test_show_results_html_file(self):
+        port = self.make_port()
+        port._executive = MockExecutive(should_log=True)
+        expected_logs = "MOCK run_command: ['Tools/Scripts/run-minibrowser', '--release', '--efl', 'file://test.html'], cwd=/mock-checkout\n"
+        OutputCapture().assert_outputs(self, port.show_results_html_file, ["test.html"], expected_logs=expected_logs)
+
+    def test_get_crash_log(self):
+        # This function tested in linux_get_crash_log_unittest.py
+        pass
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewClientWebProcessCallbacks.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewClientWebProcessCallbacks.cpp
new file mode 100644 (file)
index 0000000..96abad4
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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. 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 ``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
+ * 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 "ewk_view_private.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "Test.h"
+#include "WKView.h"
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+struct TestStatesData {
+    TestStatesData(WKViewRef view, WKURLRef url)
+        : view(view)
+        , url(url)
+        , didFinishLoad(false)
+        , didCrash(false)
+        , didRelaunch(false)
+    {
+    }
+
+    WKViewRef view;
+    WKURLRef url;
+    bool didFinishLoad;
+    bool didCrash;
+    bool didRelaunch;
+};
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void* clientInfo)
+{
+    TestStatesData* states = const_cast<TestStatesData*>(static_cast<const TestStatesData*>(clientInfo));
+    states->didFinishLoad = true;
+}
+
+static void setPageLoaderClient(WKPageRef page, const void* clientInfo)
+{
+    WKPageLoaderClientV3 loaderClient;
+    memset(&loaderClient, 0, sizeof(loaderClient));
+
+    loaderClient.base.version = 3;
+    loaderClient.base.clientInfo = clientInfo;
+    loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+    WKPageSetPageLoaderClient(page, &loaderClient.base);
+}
+
+void webProcessCrashed(WKViewRef view, WKURLRef url, const void* clientInfo)
+{
+    TestStatesData* states = const_cast<TestStatesData*>(static_cast<const TestStatesData*>(clientInfo));
+
+    EXPECT_EQ(states->view, view);
+    EXPECT_TRUE(WKURLIsEqual(url, states->url));
+
+    states->didCrash = true;
+}
+
+void webProcessDidRelaunch(WKViewRef view, const void* clientInfo)
+{
+    TestStatesData* states = const_cast<TestStatesData*>(static_cast<const TestStatesData*>(clientInfo));
+
+    EXPECT_EQ(states->view, view);
+
+    states->didRelaunch = true;
+}
+
+static void setViewClient(WKViewRef view, const void* clientInfo)
+{
+    WKViewClientV0 viewClient;
+    memset(&viewClient, 0, sizeof(WKViewClientV0));
+
+    viewClient.base.version = 0;
+    viewClient.base.clientInfo = clientInfo;
+    viewClient.webProcessCrashed = webProcessCrashed;
+    viewClient.webProcessDidRelaunch = webProcessDidRelaunch;
+
+    WKViewSetViewClient(view, &viewClient.base);
+}
+
+TEST(WebKit2, WKViewClientWebProcessCallbacks)
+{
+    WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("WKViewClientWebProcessCallbacksTest"));
+    WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+
+    PlatformWebView view(context.get());
+    WKViewRef wkView = EWKViewGetWKView(view.platformView());
+
+    TestStatesData states = TestStatesData(wkView, url.get());
+
+    setPageLoaderClient(view.page(), &states);
+    setViewClient(wkView, &states);
+
+    WKPageLoadURL(view.page(), url.get());
+    Util::run(&states.didFinishLoad);
+
+    WKContextPostMessageToInjectedBundle(context.get(), Util::toWK("Crash").get(), 0);
+    Util::run(&states.didCrash);
+
+    WKPageReload(view.page());
+    Util::run(&states.didRelaunch);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewClientWebProcessCallbacks_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewClientWebProcessCallbacks_Bundle.cpp
new file mode 100644 (file)
index 0000000..1c9e096
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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 ``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
+ * 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 "InjectedBundleTest.h"
+#include <WebKit/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+class WKViewClientWebProcessCallbacksTest : public InjectedBundleTest {
+public:
+    WKViewClientWebProcessCallbacksTest(const std::string& identifier);
+
+private:
+    virtual void didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef messageBody);
+};
+
+static InjectedBundleTest::Register<WKViewClientWebProcessCallbacksTest> registrar("WKViewClientWebProcessCallbacksTest");
+
+WKViewClientWebProcessCallbacksTest::WKViewClientWebProcessCallbacksTest(const std::string& identifier)
+    : InjectedBundleTest(identifier)
+{
+}
+
+void WKViewClientWebProcessCallbacksTest::didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef)
+{
+    if (!WKStringIsEqualToUTF8CString(messageName, "Crash"))
+        return;
+
+    // Simulating a crash
+    abort();
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewScrollTo.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/efl/WKViewScrollTo.cpp
new file mode 100644 (file)
index 0000000..b51c891
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics. 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. 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 ``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
+ * 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 "ewk_view_private.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit/WKContext.h>
+#include <WebKit/WKRetainPtr.h>
+#include "Test.h"
+
+namespace TestWebKitAPI {
+
+static bool finishedLoad = false;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+    finishedLoad = true;
+}
+
+TEST(WebKit2, WKViewScrollTo)
+{
+    WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+    PlatformWebView webView(context.get());
+    WKRetainPtr<WKViewRef> view = EWKViewGetWKView(webView.platformView());
+
+    WKPageSetUseFixedLayout(webView.page(), true);
+
+    WKPageLoaderClientV0 loaderClient;
+    memset(&loaderClient, 0, sizeof(loaderClient));
+    loaderClient.base.version = 0;
+    loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+    WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+
+    WKViewClientV0 viewClient;
+    memset(&viewClient, 0, sizeof(viewClient));
+    viewClient.base.version = 0;
+    viewClient.didChangeContentsPosition = 0;
+    WKViewSetViewClient(view.get(), &viewClient.base);
+
+    // Load page.
+    WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("efl/scrollTo", "html"));
+    WKPageLoadURL(webView.page(), url.get());
+    Util::run(&finishedLoad);
+
+    WKPoint currentPagePosition = WKViewGetContentPosition(view.get());
+    EXPECT_EQ(100, currentPagePosition.x);
+    EXPECT_EQ(300, currentPagePosition.y);
+}
+
+} // TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/efl/scrollTo.html b/Tools/TestWebKitAPI/Tests/WebKit2/efl/scrollTo.html
new file mode 100644 (file)
index 0000000..47f88f7
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+<body style="width:2000px;height:2000px;">
+scrollTo Test
+<script>
+window.scrollTo(100, 300);
+</script>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/efl/InjectedBundleController.cpp b/Tools/TestWebKitAPI/efl/InjectedBundleController.cpp
new file mode 100644 (file)
index 0000000..c2442bd
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Igalia S.L.
+ *
+ * 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 "InjectedBundleController.h"
+
+#include <wtf/Assertions.h>
+
+namespace TestWebKitAPI {
+
+void InjectedBundleController::platformInitialize()
+{
+    WTFInstallReportBacktraceOnCrashHook();
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/efl/PlatformUtilities.cpp b/Tools/TestWebKitAPI/efl/PlatformUtilities.cpp
new file mode 100644 (file)
index 0000000..65c54e1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Intel Corporation. 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. 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 "PlatformUtilities.h"
+
+#include <Ecore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+namespace TestWebKitAPI {
+
+namespace Util {
+
+void run(bool* done)
+{
+    while (!*done)
+        ecore_main_loop_iterate();
+}
+
+void sleep(double seconds)
+{
+    usleep(seconds * 1000000);
+}
+
+WKURLRef createURLForResource(const char* resource, const char* extension)
+{
+    char url[PATH_MAX];
+
+    snprintf(url, sizeof(url), "file://%s/%s.%s", TEST_WEBKIT2_RESOURCES_DIR, resource, extension);
+
+    return WKURLCreateWithUTF8CString(url);
+}
+
+WKStringRef createInjectedBundlePath()
+{
+    return WKStringCreateWithUTF8CString(TEST_INJECTED_BUNDLE_PATH);
+}
+
+WKURLRef URLForNonExistentResource()
+{
+    return WKURLCreateWithUTF8CString("file:///does-not-exist.html");
+}
+
+WKRetainPtr<WKStringRef> MIMETypeForWKURLResponse(WKURLResponseRef wkResponse)
+{
+    return adoptWK(WKURLResponseCopyMIMEType(wkResponse));
+}
+
+} // namespace Util
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/efl/PlatformWebView.cpp b/Tools/TestWebKitAPI/efl/PlatformWebView.cpp
new file mode 100644 (file)
index 0000000..4c71342
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012, 2014 Samsung Electronics
+ * Copyright (C) 2012 Intel Corporation. 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. 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 "ewk_main.h"
+#include "ewk_view_private.h"
+#include "PlatformWebView.h"
+#include "EWebKit2.h"
+#include <WebKit/WKAPICast.h>
+#include <WebKit/WKPageConfigurationRef.h>
+#include <WebKit/WKRetainPtr.h>
+#include <WebKit/WKViewEfl.h>
+#include <Ecore_Evas.h>
+
+extern bool useX11Window;
+
+using namespace WebKit;
+
+namespace TestWebKitAPI {
+
+static Ecore_Evas* createEcoreEvas()
+{
+    Ecore_Evas* ecoreEvas;
+#if defined(HAVE_ECORE_X)
+    ecoreEvas = ecore_evas_new("opengl_x11", 0, 0, 800, 600, 0);
+    // Graceful fallback to software rendering if evas_gl engine is not available.
+    if (!ecoreEvas)
+#endif
+    ecoreEvas = ecore_evas_new(0, 0, 0, 800, 600, 0);
+
+    ASSERT(ecoreEvas);
+
+    ecore_evas_show(ecoreEvas);
+
+    return ecoreEvas;
+}
+
+static void onWebProcessCrashed(void*, Evas_Object*, void* eventInfo)
+{
+    bool* handled = static_cast<bool*>(eventInfo);
+    *handled = true;
+}
+
+PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
+{
+    m_window = createEcoreEvas();
+
+    WKRetainPtr<WKPageConfigurationRef> pageConfiguration = adoptWK(WKPageConfigurationCreate());
+    WKPageConfigurationSetContext(pageConfiguration.get(), contextRef);
+    WKPageConfigurationSetPageGroup(pageConfiguration.get(), pageGroupRef);
+
+    m_view = EWKViewCreate(pageConfiguration.get(), ecore_evas_get(m_window), /* smart */ 0);
+
+    WKRetainPtr<WKStringRef> wkTheme = adoptWK(WKStringCreateWithUTF8CString(DEFAULT_THEME_DIR "/default.edj"));
+    WKViewSetThemePath(EWKViewGetWKView(m_view), wkTheme.get());
+
+    evas_object_smart_callback_add(m_view, "webprocess,crashed", onWebProcessCrashed, 0);
+    resizeTo(600, 800);
+}
+
+PlatformWebView::~PlatformWebView()
+{
+    evas_object_del(m_view);
+
+    ecore_evas_free(m_window);
+}
+
+void PlatformWebView::resizeTo(unsigned width, unsigned height)
+{
+    evas_object_resize(m_view, width, height);
+}
+
+WKPageRef PlatformWebView::page() const
+{
+    return WKViewGetPage(EWKViewGetWKView(m_view));
+}
+
+void PlatformWebView::simulateSpacebarKeyPress()
+{
+    Evas* evas = evas_object_evas_get(m_view);
+    evas_object_focus_set(m_view, true);
+    evas_event_feed_key_down(evas, "space", "space", " ", 0, 0, 0);
+    evas_event_feed_key_up(evas, "space", "space", " ", 0, 1, 0);
+}
+
+void PlatformWebView::simulateMouseMove(unsigned x, unsigned y)
+{
+    Evas* evas = evas_object_evas_get(m_view);
+    evas_object_show(m_view);
+    evas_event_feed_mouse_move(evas, x, y, 0, 0);
+}
+
+void PlatformWebView::simulateRightClick(unsigned x, unsigned y)
+{
+    Evas* evas = evas_object_evas_get(m_view);
+    evas_object_show(m_view);
+    evas_event_feed_mouse_move(evas, x, y, 0, 0);
+    evas_event_feed_mouse_down(evas, 3, EVAS_BUTTON_NONE, 0, 0);
+    evas_event_feed_mouse_up(evas, 3, EVAS_BUTTON_NONE, 0, 0);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/efl/main.cpp b/Tools/TestWebKitAPI/efl/main.cpp
new file mode 100644 (file)
index 0000000..9002bc7
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Copyright (C) 2012 Intel Corporation. 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. 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 "TestsController.h"
+#include <getopt.h>
+#include <EWebKit2.h>
+#include <wtf/Assertions.h>
+
+bool useX11Window = false;
+
+static bool checkForUseX11WindowArgument(int argc, char** argv)
+{
+    int hasUseX11Window = 0;
+
+    static const option options[] = {
+        {"useX11Window", no_argument, &hasUseX11Window, 1},
+        {0, 0, 0, 0}
+    };
+
+    while (getopt_long(argc, argv, "", options, 0) != -1) { }
+
+    return hasUseX11Window;
+}
+
+int main(int argc, char** argv)
+{
+    WTFInstallReportBacktraceOnCrashHook();
+    setenv("WEBKIT_EXEC_PATH", WEBKIT_EXEC_PATH, false);
+
+    if (!ewk_init())
+        return EXIT_FAILURE;
+
+    useX11Window = checkForUseX11WindowArgument(argc, argv);
+
+    int returnCode = TestWebKitAPI::TestsController::singleton().run(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE;
+
+    ewk_shutdown();
+
+    return returnCode;
+}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/efl/ActivateFontsEfl.cpp b/Tools/WebKitTestRunner/InjectedBundle/efl/ActivateFontsEfl.cpp
new file mode 100644 (file)
index 0000000..7785f77
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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 program 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 program; 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 "ActivateFonts.h"
+
+#include "FontManagement.h"
+
+namespace WTR {
+
+void activateFonts()
+{
+    addFontsToEnvironment();
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/efl/FontManagement.cpp b/Tools/WebKitTestRunner/InjectedBundle/efl/FontManagement.cpp
new file mode 100644 (file)
index 0000000..3ff3f08
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 ProFUSION Embedded Systems
+ * Copyright (C) 2011 Samsung Electronics
+ * Copyright (C) 2012 Intel Corporation. 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.  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/StringBuilder.h>
+
+static CString buildPath(const char* base, const char* first, ...)
+{
+    va_list ap;
+    StringBuilder result;
+    result.append(base);
+
+    if (const char* current = first) {
+        va_start(ap, first);
+        do {
+            result.append('/');
+            result.append(current);
+        } while ((current = va_arg(ap, const char*)));
+        va_end(ap);
+    }
+
+    return result.toString().utf8();
+}
+
+static Vector<CString> getCoreFontFiles()
+{
+    Vector<CString> fontFilePaths;
+
+    // Ahem is used by many layout tests.
+    fontFilePaths.append(CString(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(CString(FONTS_CONF_DIR "/FontWithNoValidEncoding.fon"));
+
+    for (int i = 1; i <= 9; i++) {
+        char fontPath[EINA_PATH_MAX];
+        snprintf(fontPath, EINA_PATH_MAX - 1, FONTS_CONF_DIR "/../../fonts/WebKitWeightWatcher%i00.ttf", i);
+        fontFilePaths.append(CString(fontPath));
+    }
+
+    return fontFilePaths;
+}
+
+static void addFontDirectory(const CString& fontDirectory, FcConfig* config)
+{
+    const char* fontPath = fontDirectory.data();
+    if (!fontPath || !FcConfigAppFontAddDir(config, reinterpret_cast<const FcChar8*>(fontPath)))
+        fprintf(stderr, "Could not add font directory %s!\n", fontPath);
+}
+
+static void addFontFiles(const Vector<CString>& fontFiles, FcConfig* config)
+{
+    Vector<CString>::const_iterator it, end = fontFiles.end();
+    for (it = fontFiles.begin(); it != end; ++it) {
+        const char* filePath = (*it).data();
+        if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(filePath)))
+            fprintf(stderr, "Could not load font at %s!\n", filePath);
+    }
+}
+
+static CString getCustomBuildDir()
+{
+    if (const char* userChosenBuildDir = getenv("WEBKIT_OUTPUTDIR")) {
+        if (ecore_file_is_dir(userChosenBuildDir))
+            return userChosenBuildDir;
+        fprintf(stderr, "WEBKIT_OUTPUTDIR set to '%s', but path doesn't exist.\n", userChosenBuildDir);
+    }
+
+    return CString();
+}
+
+static CString getPlatformFontsPath()
+{
+    CString customBuildDir = getCustomBuildDir();
+    if (!customBuildDir.isNull()) {
+        CString fontsPath = buildPath(customBuildDir.data(), "DependenciesEFL", "Root", "webkitgtk-test-fonts", 0);
+        if (!ecore_file_exists(fontsPath.data()))
+            fprintf(stderr, "WEBKIT_OUTPUTDIR set to '%s', but could not local test fonts.\n", customBuildDir.data());
+        return fontsPath;
+    }
+
+    CString fontsPath = CString(DOWNLOADED_FONTS_DIR);
+    if (ecore_file_exists(fontsPath.data()))
+        return fontsPath;
+
+    fprintf(stderr, "Could not locate tests fonts, try setting WEBKIT_OUTPUTDIR.\n");
+    return CString();
+}
+
+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);
+    }
+
+    addFontFiles(getCoreFontFiles(), config);
+    addFontDirectory(getPlatformFontsPath(), config);
+
+    if (!FcConfigSetCurrent(config)) {
+        fprintf(stderr, "Could not set the current font configuration!\n");
+        exit(1);
+    }
+}
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/efl/FontManagement.h b/Tools/WebKitTestRunner/InjectedBundle/efl/FontManagement.h
new file mode 100644 (file)
index 0000000..d497513
--- /dev/null
@@ -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/WebKitTestRunner/InjectedBundle/efl/InjectedBundleEfl.cpp b/Tools/WebKitTestRunner/InjectedBundle/efl/InjectedBundleEfl.cpp
new file mode 100644 (file)
index 0000000..1198320
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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 program 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 program; 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 "InjectedBundle.h"
+
+#include <wtf/Assertions.h>
+
+namespace WTR {
+
+void InjectedBundle::platformInitialize(WKTypeRef)
+{
+    WTFInstallReportBacktraceOnCrashHook();
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/efl/TestRunnerEfl.cpp b/Tools/WebKitTestRunner/InjectedBundle/efl/TestRunnerEfl.cpp
new file mode 100644 (file)
index 0000000..996318b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 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 program 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 program; 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 "TestRunner.h"
+
+#include "InjectedBundle.h"
+#include <Ecore.h>
+#include <JavaScriptCore/OpaqueJSString.h>
+#include <WebCore/EflInspectorUtilities.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTR {
+
+static Eina_Bool waitToDumpWatchdogTimerCallback(void*)
+{
+    InjectedBundle::singleton().testRunner()->waitToDumpWatchdogTimerFired();
+    return false;
+}
+
+void TestRunner::platformInitialize()
+{
+    m_waitToDumpWatchdogTimer = 0;
+}
+
+void TestRunner::invalidateWaitToDumpWatchdogTimer()
+{
+    if (!m_waitToDumpWatchdogTimer)
+        return;
+
+    ecore_timer_del(m_waitToDumpWatchdogTimer);
+    m_waitToDumpWatchdogTimer = 0;
+}
+
+void TestRunner::initializeWaitToDumpWatchdogTimerIfNeeded()
+{
+    if (m_waitToDumpWatchdogTimer)
+        return;
+
+    m_waitToDumpWatchdogTimer = ecore_timer_loop_add(m_timeout / 1000.0, waitToDumpWatchdogTimerCallback, 0);
+}
+
+JSRetainPtr<JSStringRef> TestRunner::pathToLocalResource(JSStringRef url)
+{
+    String requestedUrl(url->characters(), url->length());
+    String resourceRoot;
+    String requestedRoot;
+
+    if (requestedUrl.find("LayoutTests") != notFound) {
+        // If the URL contains LayoutTests we need to remap that to
+        // LOCAL_RESOURCE_ROOT which is the path of the LayoutTests directory
+        // within the WebKit source tree.
+        requestedRoot = "/tmp/LayoutTests";
+        resourceRoot = getenv("LOCAL_RESOURCE_ROOT");
+    } else if (requestedUrl.find("tmp") != notFound) {
+        // If the URL is a child of /tmp we need to convert it to be a child
+        // DUMPRENDERTREE_TEMP replace tmp with DUMPRENDERTREE_TEMP
+        requestedRoot = "/tmp";
+        resourceRoot = getenv("DUMPRENDERTREE_TEMP");
+    }
+
+    size_t indexOfRootStart = requestedUrl.reverseFind(requestedRoot);
+    size_t indexOfSeparatorAfterRoot = indexOfRootStart + requestedRoot.length();
+    String fullPathToUrl = "file://" + resourceRoot + requestedUrl.substring(indexOfSeparatorAfterRoot);
+
+    return JSStringCreateWithUTF8CString(fullPathToUrl.utf8().data());
+}
+
+JSRetainPtr<JSStringRef> TestRunner::inspectorTestStubURL()
+{
+    StringBuilder builder;
+    builder.append("file://");
+    builder.append(WebCore::inspectorResourcePath());
+    builder.appendLiteral("/TestStub.html");
+
+    return JSStringCreateWithUTF8CString(builder.toString().utf8().data());
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/efl/EventSenderProxyEfl.cpp b/Tools/WebKitTestRunner/efl/EventSenderProxyEfl.cpp
new file mode 100644 (file)
index 0000000..5fef029
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * 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) 2012 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 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
+ * OWNER OR 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 "EventSenderProxy.h"
+
+#include "NotImplemented.h"
+#include "PlatformWebView.h"
+#include "TestController.h"
+
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <unistd.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTR {
+
+static const char* modifierNames[] = { "Shift", "Control", "Alt", "Meta" };
+
+enum WTREventType {
+    WTREventTypeNone = 0,
+    WTREventTypeMouseDown,
+    WTREventTypeMouseUp,
+    WTREventTypeMouseMove,
+    WTREventTypeMouseScrollBy,
+    WTREventTypeLeapForward
+};
+
+enum EvasMouseButton {
+    EvasMouseButtonNone = 0,
+    EvasMouseButtonLeft,
+    EvasMouseButtonMiddle,
+    EvasMouseButtonRight
+};
+
+// Key event location code defined in DOM Level 3.
+enum KeyLocationCode {
+    DOMKeyLocationStandard      = 0x00,
+    DOMKeyLocationLeft          = 0x01,
+    DOMKeyLocationRight         = 0x02,
+    DOMKeyLocationNumpad        = 0x03
+};
+
+struct WTREvent {
+    WTREventType eventType;
+    unsigned delay;
+    WKEventModifiers modifiers;
+    int button;
+    int horizontal;
+    int vertical;
+
+    WTREvent()
+        : eventType(WTREventTypeNone)
+        , delay(0)
+        , modifiers(0)
+        , button(-1)
+        , horizontal(-1)
+        , vertical(-1)
+    {
+    }
+
+    WTREvent(WTREventType eventType, unsigned delay, WKEventModifiers modifiers, int button)
+        : eventType(eventType)
+        , delay(delay)
+        , modifiers(modifiers)
+        , button(button)
+        , horizontal(-1)
+        , vertical(-1)
+    {
+    }
+};
+
+struct KeyEventInfo : public RefCounted<KeyEventInfo> {
+    KeyEventInfo(const CString& keyName, const CString& keyString)
+        : keyName(keyName)
+        , keyString(keyString)
+    {
+    }
+
+    const CString keyName;
+    const CString keyString;
+};
+
+static unsigned evasMouseButton(unsigned button)
+{
+    // The common case involves converting from a WKEventMouseButton (which
+    // starts at -1) to an EvasMouseButton (which a starts at 0). The special
+    // case for button 3 exists because of fast/events/mouse-click-events.html,
+    // which tests whether a 4th mouse button behaves as the middle one.
+    if (button <= kWKEventMouseButtonRightButton)
+        return button + 1;
+    if (button == kWKEventMouseButtonRightButton + 1)
+        return EvasMouseButtonMiddle;
+    return EvasMouseButtonNone;
+}
+
+static void setEvasModifiers(Evas* evas, WKEventModifiers wkModifiers)
+{
+    for (unsigned modifier = 0; modifier < (sizeof(modifierNames) / sizeof(char*)); ++modifier) {
+        if (wkModifiers & (1 << modifier))
+            evas_key_modifier_on(evas, modifierNames[modifier]);
+        else
+            evas_key_modifier_off(evas, modifierNames[modifier]);
+    }
+}
+
+static void dispatchMouseDownEvent(Evas* evas, unsigned button, WKEventModifiers wkModifiers, int clickCount)
+{
+    Evas_Button_Flags buttonFlags = EVAS_BUTTON_NONE;
+    if (clickCount == 3)
+        buttonFlags = EVAS_BUTTON_TRIPLE_CLICK;
+    else if (clickCount == 2)
+        buttonFlags = EVAS_BUTTON_DOUBLE_CLICK;
+
+    setEvasModifiers(evas, wkModifiers);
+    evas_event_feed_mouse_down(evas, button, buttonFlags, 0, 0);
+    setEvasModifiers(evas, 0);
+}
+
+static void dispatchMouseUpEvent(Evas* evas, unsigned button, WKEventModifiers wkModifiers)
+{
+    setEvasModifiers(evas, wkModifiers);
+    evas_event_feed_mouse_up(evas, button, EVAS_BUTTON_NONE, 0, 0);
+    setEvasModifiers(evas, 0);
+}
+
+static void dispatchMouseMoveEvent(Evas* evas, int x, int y)
+{
+    evas_event_feed_mouse_move(evas, x, y, 0, 0);
+}
+
+static void dispatchMouseScrollByEvent(Evas* evas, int horizontal, int vertical)
+{
+    if (horizontal)
+        evas_event_feed_mouse_wheel(evas, 1, horizontal, 0, 0);
+
+    if (vertical)
+        evas_event_feed_mouse_wheel(evas, 0, vertical, 0, 0);
+}
+
+static const RefPtr<KeyEventInfo> keyPadName(WKStringRef keyRef)
+{
+    if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow"))
+        return adoptRef(new KeyEventInfo("KP_Left", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "rightArrow"))
+        return adoptRef(new KeyEventInfo("KP_Right", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "upArrow"))
+        return adoptRef(new KeyEventInfo("KP_Up", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "downArrow"))
+        return adoptRef(new KeyEventInfo("KP_Down", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "pageUp"))
+        return adoptRef(new KeyEventInfo("KP_Prior", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "pageDown"))
+        return adoptRef(new KeyEventInfo("KP_Next", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "home"))
+        return adoptRef(new KeyEventInfo("KP_Home", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "end"))
+        return adoptRef(new KeyEventInfo("KP_End", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "insert"))
+        return adoptRef(new KeyEventInfo("KP_Insert", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "delete"))
+        return adoptRef(new KeyEventInfo("KP_Delete", ""));
+
+    size_t bufferSize = WKStringGetMaximumUTF8CStringSize(keyRef);
+    auto buffer = std::make_unique<char[]>(bufferSize);
+    WKStringGetUTF8CString(keyRef, buffer.get(), bufferSize);
+    return adoptRef(new KeyEventInfo(buffer.get(), buffer.get()));
+}
+
+static const RefPtr<KeyEventInfo> keyName(WKStringRef keyRef)
+{
+    if (WKStringIsEqualToUTF8CString(keyRef, "leftArrow"))
+        return adoptRef(new KeyEventInfo("Left", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "rightArrow"))
+        return adoptRef(new KeyEventInfo("Right", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "upArrow"))
+        return adoptRef(new KeyEventInfo("Up", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "downArrow"))
+        return adoptRef(new KeyEventInfo("Down", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "pageUp"))
+        return adoptRef(new KeyEventInfo("Prior", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "pageDown"))
+        return adoptRef(new KeyEventInfo("Next", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "home"))
+        return adoptRef(new KeyEventInfo("Home", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "end"))
+        return adoptRef(new KeyEventInfo("End", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "insert"))
+        return adoptRef(new KeyEventInfo("Insert", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "delete"))
+        return adoptRef(new KeyEventInfo("Delete", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "printScreen"))
+        return adoptRef(new KeyEventInfo("Print", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "menu"))
+        return adoptRef(new KeyEventInfo("Menu", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "leftControl"))
+        return adoptRef(new KeyEventInfo("Control_L", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "rightControl"))
+        return adoptRef(new KeyEventInfo("Control_R", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "leftShift"))
+        return adoptRef(new KeyEventInfo("Shift_L", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "rightShift"))
+        return adoptRef(new KeyEventInfo("Shift_R", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "leftAlt"))
+        return adoptRef(new KeyEventInfo("Alt_L", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "rightAlt"))
+        return adoptRef(new KeyEventInfo("Alt_R", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F1"))
+        return adoptRef(new KeyEventInfo("F1", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F2"))
+        return adoptRef(new KeyEventInfo("F2", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F3"))
+        return adoptRef(new KeyEventInfo("F3", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F4"))
+        return adoptRef(new KeyEventInfo("F4", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F5"))
+        return adoptRef(new KeyEventInfo("F5", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F6"))
+        return adoptRef(new KeyEventInfo("F6", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F7"))
+        return adoptRef(new KeyEventInfo("F7", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F8"))
+        return adoptRef(new KeyEventInfo("F8", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F9"))
+        return adoptRef(new KeyEventInfo("F9", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F10"))
+        return adoptRef(new KeyEventInfo("F10", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F11"))
+        return adoptRef(new KeyEventInfo("F11", ""));
+    if (WKStringIsEqualToUTF8CString(keyRef, "F12"))
+        return adoptRef(new KeyEventInfo("F12", ""));
+
+    size_t bufferSize = WKStringGetMaximumUTF8CStringSize(keyRef);
+    auto buffer = std::make_unique<char[]>(bufferSize);
+    WKStringGetUTF8CString(keyRef, buffer.get(), bufferSize);
+    char charCode = buffer.get()[0];
+
+    if (charCode == '\n' || charCode == '\r')
+        return adoptRef(new KeyEventInfo("Return", "\r"));
+    if (charCode == '\t')
+        return adoptRef(new KeyEventInfo("Tab", "\t"));
+    if (charCode == '\x8')
+        return adoptRef(new KeyEventInfo("BackSpace", "\x8"));
+    if (charCode == ' ')
+        return adoptRef(new KeyEventInfo("space", " "));
+
+    return adoptRef(new KeyEventInfo(buffer.get(), buffer.get()));
+}
+
+EventSenderProxy::EventSenderProxy(TestController* testController)
+    : m_testController(testController)
+    , m_time(0)
+    , m_leftMouseButtonDown(false)
+    , m_clickCount(0)
+    , m_clickTime(0)
+    , m_clickButton(kWKEventMouseButtonNoButton)
+    , m_mouseButton(kWKEventMouseButtonNoButton)
+#if ENABLE(TOUCH_EVENTS)
+    , m_touchPoints(0)
+#endif
+{
+}
+
+EventSenderProxy::~EventSenderProxy()
+{
+#if ENABLE(TOUCH_EVENTS)
+    clearTouchPoints();
+#endif
+}
+
+void EventSenderProxy::updateClickCountForButton(int button)
+{
+    if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) {
+        ++m_clickCount;
+        m_clickTime = m_time;
+        return;
+    }
+
+    m_clickCount = 1;
+    m_clickTime = m_time;
+    m_clickPosition = m_position;
+    m_clickButton = button;
+}
+
+void EventSenderProxy::dispatchEvent(const WTREvent& event)
+{
+    Evas* evas = evas_object_evas_get(m_testController->mainWebView()->platformView());
+
+    if (event.eventType == WTREventTypeMouseDown)
+        dispatchMouseDownEvent(evas, event.button, event.modifiers, m_clickCount);
+    else if (event.eventType == WTREventTypeMouseUp)
+        dispatchMouseUpEvent(evas, event.button, event.modifiers);
+    else if (event.eventType == WTREventTypeMouseMove)
+        dispatchMouseMoveEvent(evas, static_cast<int>(m_position.x), static_cast<int>(m_position.y));
+    else if (event.eventType == WTREventTypeMouseScrollBy)
+        dispatchMouseScrollByEvent(evas, event.horizontal, event.vertical);
+}
+
+void EventSenderProxy::replaySavedEvents()
+{
+    while (!m_eventQueue.isEmpty()) {
+        WTREvent event = m_eventQueue.takeFirst();
+        if (event.delay)
+            usleep(event.delay * 1000);
+
+        dispatchEvent(event);
+    }
+}
+
+void EventSenderProxy::sendOrQueueEvent(const WTREvent& event)
+{
+    if (m_eventQueue.isEmpty() || !m_eventQueue.last().delay) {
+        dispatchEvent(event);
+        return;
+    }
+
+    m_eventQueue.append(event);
+    replaySavedEvents();
+}
+
+void EventSenderProxy::mouseDown(unsigned button, WKEventModifiers wkModifiers)
+{
+    if (m_mouseButton == button)
+        return;
+
+    m_mouseButton = button;
+    updateClickCountForButton(button);
+
+    sendOrQueueEvent(WTREvent(WTREventTypeMouseDown, 0, wkModifiers, evasMouseButton(button)));
+}
+
+void EventSenderProxy::mouseUp(unsigned button, WKEventModifiers wkModifiers)
+{
+    sendOrQueueEvent(WTREvent(WTREventTypeMouseUp, 0, wkModifiers, evasMouseButton(button)));
+
+    if (m_mouseButton == button)
+        m_mouseButton = kWKEventMouseButtonNoButton;
+
+    m_clickPosition = m_position;
+    m_clickTime = currentEventTime();
+}
+
+void EventSenderProxy::mouseMoveTo(double x, double y)
+{
+    m_position.x = x;
+    m_position.y = y;
+
+    sendOrQueueEvent(WTREvent(WTREventTypeMouseMove, 0, 0, kWKEventMouseButtonNoButton));
+}
+
+void EventSenderProxy::mouseScrollBy(int horizontal, int vertical)
+{
+    WTREvent event(WTREventTypeMouseScrollBy, 0, 0, kWKEventMouseButtonNoButton);
+    // We need to invert scrolling values since in EFL negative z value means that
+    // canvas is scrolling down
+    event.horizontal = -horizontal;
+    event.vertical = -vertical;
+    sendOrQueueEvent(event);
+}
+
+void EventSenderProxy::continuousMouseScrollBy(int horizontal, int vertical, bool paged)
+{
+    notImplemented();
+}
+
+void EventSenderProxy::mouseScrollByWithWheelAndMomentumPhases(int x, int y, int /*phase*/, int /*momentum*/)
+{
+    // EFL does not have the concept of wheel gesture phases or momentum. Just relay to
+    // the mouse wheel handler.
+    mouseScrollBy(x, y);
+}
+
+void EventSenderProxy::swipeGestureWithWheelAndMomentumPhases(int, int, int, int)
+{
+    notImplemented();
+}
+
+void EventSenderProxy::leapForward(int milliseconds)
+{
+    if (m_eventQueue.isEmpty())
+        m_eventQueue.append(WTREvent(WTREventTypeLeapForward, milliseconds, 0, kWKEventMouseButtonNoButton));
+
+    m_time += milliseconds / 1000.0;
+}
+
+void EventSenderProxy::keyDown(WKStringRef keyRef, WKEventModifiers wkModifiers, unsigned location)
+{
+    const RefPtr<KeyEventInfo> keyEventInfo = (location == DOMKeyLocationNumpad) ? keyPadName(keyRef) : keyName(keyRef);
+    if (!keyEventInfo)
+        return;
+
+    const char* keyName = keyEventInfo->keyName.data();
+    const char* keyString = keyEventInfo->keyString.data();
+
+    // Enforce 'Shift' modifier for caps.
+    if ((strlen(keyName) == 1) && (keyName[0] >= 'A' && keyName[0] <= 'Z'))
+        wkModifiers |= kWKEventModifiersShiftKey;
+
+    Evas* evas = evas_object_evas_get(m_testController->mainWebView()->platformView());
+
+    int eventIndex = 0;
+    // Mimic the emacs ctrl-o binding by inserting a paragraph
+    // separator and then putting the cursor back to its original
+    // position. Allows us to pass emacs-ctrl-o.html
+    if ((wkModifiers & kWKEventModifiersControlKey) && !strcmp(keyName, "o")) {
+        setEvasModifiers(evas, 0);
+        evas_event_feed_key_down(evas, "Return", "Return", "\r", 0, eventIndex++, 0);
+        evas_event_feed_key_up(evas, "Return", "Return", "\r", 0, eventIndex++, 0);
+        wkModifiers = 0;
+        keyName = "Left";
+        keyString = 0;
+    }
+
+    setEvasModifiers(evas, wkModifiers);
+    evas_event_feed_key_down(evas, keyName, keyName, keyString, 0, eventIndex++, 0);
+    evas_event_feed_key_up(evas, keyName, keyName, keyString, 0, eventIndex++, 0);
+    setEvasModifiers(evas, 0);
+}
+
+#if ENABLE(TOUCH_EVENTS)
+void EventSenderProxy::sendTouchEvent(Ewk_Touch_Event_Type eventType)
+{
+    ASSERT(m_touchPoints);
+
+    Evas_Object* ewkView = m_testController->mainWebView()->platformView();
+    ewk_view_feed_touch_event(ewkView, eventType, m_touchPoints, evas_key_modifier_get(evas_object_evas_get(ewkView)));
+
+    Eina_List* list;
+    Eina_List* listNext;
+    void* data;
+    EINA_LIST_FOREACH_SAFE(m_touchPoints, list, listNext, data) {
+         Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(data);
+         ASSERT(touchPoint);
+
+         if ((touchPoint->state == EVAS_TOUCH_POINT_UP) || (touchPoint->state == EVAS_TOUCH_POINT_CANCEL)) {
+             delete touchPoint;
+             m_touchPoints = eina_list_remove_list(m_touchPoints, list);
+         } else
+             touchPoint->state = EVAS_TOUCH_POINT_STILL;
+     }
+}
+
+void EventSenderProxy::addTouchPoint(int x, int y)
+{
+    int id = 0;
+    if (m_touchPoints) {
+        Eina_List* last = eina_list_last(m_touchPoints);
+        Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_data_get(last));
+        ASSERT(touchPoint);
+
+        id = touchPoint->id + 1;
+    }
+
+    Ewk_Touch_Point* touchPoint = new Ewk_Touch_Point;
+    touchPoint->id = id;
+    touchPoint->x = x;
+    touchPoint->y = y;
+    touchPoint->state = EVAS_TOUCH_POINT_DOWN;
+
+    m_touchPoints = eina_list_append(m_touchPoints, touchPoint);
+}
+
+void EventSenderProxy::updateTouchPoint(int index, int x, int y)
+{
+    ASSERT(index >= 0 && index < eina_list_count(m_touchPoints));
+
+    Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_nth(m_touchPoints, index));
+    ASSERT(touchPoint);
+
+    touchPoint->x = x;
+    touchPoint->y = y;
+    touchPoint->state = EVAS_TOUCH_POINT_MOVE;
+}
+
+void EventSenderProxy::setTouchModifier(WKEventModifiers modifier, bool enable)
+{
+    Evas_Object* ewkView = m_testController->mainWebView()->platformView();
+
+    for (unsigned index = 0; index < (sizeof(modifierNames) / sizeof(char*)); ++index) {
+        if (modifier & (1 << index)) {
+            if (enable)
+                evas_key_modifier_on(evas_object_evas_get(ewkView), modifierNames[index]);
+            else
+                evas_key_modifier_off(evas_object_evas_get(ewkView), modifierNames[index]);
+        }
+    }
+}
+
+void EventSenderProxy::touchStart()
+{
+    sendTouchEvent(EWK_TOUCH_START);
+}
+
+void EventSenderProxy::touchMove()
+{
+    sendTouchEvent(EWK_TOUCH_MOVE);
+}
+
+void EventSenderProxy::touchEnd()
+{
+    sendTouchEvent(EWK_TOUCH_END);
+}
+
+void EventSenderProxy::touchCancel()
+{
+    sendTouchEvent(EWK_TOUCH_CANCEL);
+}
+
+void EventSenderProxy::clearTouchPoints()
+{
+    void* data = 0;
+    EINA_LIST_FREE(m_touchPoints, data)
+        delete static_cast<Ewk_Touch_Point*>(data);
+}
+
+void EventSenderProxy::releaseTouchPoint(int index)
+{
+    ASSERT(index >= 0 && index < eina_list_count(m_touchPoints));
+
+    Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_nth(m_touchPoints, index));
+    ASSERT(touchPoint);
+
+    touchPoint->state = EVAS_TOUCH_POINT_UP;
+}
+
+void EventSenderProxy::cancelTouchPoint(int index)
+{
+    ASSERT(index >= 0 && index < eina_list_count(m_touchPoints));
+
+    Ewk_Touch_Point* touchPoint = static_cast<Ewk_Touch_Point*>(eina_list_nth(m_touchPoints, index));
+    ASSERT(touchPoint);
+
+    touchPoint->state = EVAS_TOUCH_POINT_CANCEL;
+}
+
+void EventSenderProxy::setTouchPointRadius(int radiusX, int radiusY)
+{
+    notImplemented();
+}
+
+#endif
+
+}
diff --git a/Tools/WebKitTestRunner/efl/PlatformWebViewEfl.cpp b/Tools/WebKitTestRunner/efl/PlatformWebViewEfl.cpp
new file mode 100644 (file)
index 0000000..abe2ecb
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * 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 program 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 program; 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 "ewk_view_private.h"
+#include "PlatformWebView.h"
+
+#include "EWebKit2.h"
+#include <Ecore_Evas.h>
+#include <WebCore/RefPtrCairo.h>
+#include <WebKit/WKImageCairo.h>
+#include <WebKit/WKViewEfl.h>
+#include <cairo.h>
+
+using namespace WebKit;
+
+namespace WTR {
+
+static Ecore_Evas* initEcoreEvas()
+{
+    Ecore_Evas* ecoreEvas = 0;
+#if defined(HAVE_ECORE_X)
+    const char* engine = "opengl_x11";
+    ecoreEvas = ecore_evas_new(engine, 0, 0, 800, 600, 0);
+    // Graceful fallback to software rendering if evas_gl engine is not available.
+    if (!ecoreEvas)
+#endif
+    ecoreEvas = ecore_evas_new(0, 0, 0, 800, 600, 0);
+
+    if (!ecoreEvas)
+        return 0;
+
+    ecore_evas_title_set(ecoreEvas, "EFL WebKitTestRunner");
+    ecore_evas_show(ecoreEvas);
+
+    return ecoreEvas;
+}
+
+PlatformWebView::PlatformWebView(WKPageConfigurationRef configuration, const TestOptions& options)
+    : m_options(options)
+{
+    WKRetainPtr<WKStringRef> useFixedLayoutKey(AdoptWK, WKStringCreateWithUTF8CString("UseFixedLayout"));
+    m_usingFixedLayout = options.useFixedLayout;
+
+    m_window = initEcoreEvas();
+
+    m_view = EWKViewCreate(configuration, ecore_evas_get(m_window), /* smart */ 0);
+
+    WKPageSetUseFixedLayout(WKViewGetPage(EWKViewGetWKView(m_view)), m_usingFixedLayout);
+
+    if (m_usingFixedLayout)
+        resizeTo(800, 600);
+
+    ewk_view_theme_set(m_view, DEFAULT_THEME_DIR "/default.edj");
+    m_windowIsKey = false;
+    evas_object_show(m_view);
+}
+
+PlatformWebView::~PlatformWebView()
+{
+    evas_object_del(m_view);
+
+    ecore_evas_free(m_window);
+}
+
+void PlatformWebView::setWindowIsKey(bool isKey)
+{
+    m_windowIsKey = isKey;
+}
+
+void PlatformWebView::resizeTo(unsigned width, unsigned height, WebViewSizingMode)
+{
+    // FIXME: Don't we need to resize the window too?
+    evas_object_resize(m_view, width, height);
+}
+
+WKPageRef PlatformWebView::page()
+{
+    return WKViewGetPage(EWKViewGetWKView(m_view));
+}
+
+void PlatformWebView::focus()
+{
+    // In a few cases, an iframe might receive focus from JavaScript and Evas is not aware of it at all
+    // (WebCoreSupport::focusedFrameChanged() does not emit any notification). We then manually remove the
+    // focus from the view to make the call give focus to evas_object_focus_set(..., true) to be effectful.
+    if (WKPageGetFocusedFrame(page()) != WKPageGetMainFrame(page()))
+        evas_object_focus_set(m_view, false);
+    evas_object_focus_set(m_view, true);
+}
+
+WKRect PlatformWebView::windowFrame()
+{
+    int x, y, width, height;
+
+    ecore_evas_request_geometry_get(m_window, &x, &y, &width, &height);
+
+    return WKRectMake(x, y, width, height);
+}
+
+void PlatformWebView::setWindowFrame(WKRect frame, WebViewSizingMode)
+{
+    ecore_evas_move_resize(m_window, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+    evas_object_resize(m_view, frame.size.width, frame.size.height);
+}
+
+void PlatformWebView::addChromeInputField()
+{
+}
+
+void PlatformWebView::removeChromeInputField()
+{
+}
+
+void PlatformWebView::addToWindow()
+{
+}
+
+void PlatformWebView::removeFromWindow()
+{
+}
+
+void PlatformWebView::makeWebViewFirstResponder()
+{
+}
+
+void PlatformWebView::changeWindowScaleIfNeeded(float)
+{
+}
+
+WKRetainPtr<WKImageRef> PlatformWebView::windowSnapshotImage()
+{
+    int width;
+    int height;
+    ecore_evas_geometry_get(m_window, 0, 0, &width, &height);
+    ASSERT(width > 0 && height > 0);
+
+    return adoptWK(WKViewCreateSnapshot(EWKViewGetWKView(m_view)));
+}
+
+bool PlatformWebView::viewSupportsOptions(const TestOptions& options) const
+{
+    if (m_options.useFixedLayout != options.useFixedLayout)
+        return false;
+
+    return true;
+}
+
+void PlatformWebView::didInitializeClients()
+{
+}
+
+void PlatformWebView::setNavigationGesturesEnabled(bool)
+{
+}
+
+} // namespace WTR
+
diff --git a/Tools/WebKitTestRunner/efl/TestControllerEfl.cpp b/Tools/WebKitTestRunner/efl/TestControllerEfl.cpp
new file mode 100644 (file)
index 0000000..def427c
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2012 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 program 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 program; 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 "TestController.h"
+
+#include "PlatformWebView.h"
+#include "TestInvocation.h"
+#include <Ecore.h>
+#include <Evas.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <wtf/Platform.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTR {
+
+static Ecore_Timer* timer = 0;
+
+static Eina_Bool timerFired(void*)
+{
+    timer = 0;
+    ecore_main_loop_quit();
+    return ECORE_CALLBACK_CANCEL;
+}
+
+void TestController::notifyDone()
+{
+    if (!timer)
+        return;
+
+    ecore_timer_del(timer);
+    timer = 0;
+    ecore_main_loop_quit();
+}
+
+void TestController::platformInitialize()
+{
+    const char* isDebugging = getenv("WEB_PROCESS_CMD_PREFIX");
+    if (isDebugging && *isDebugging) {
+        m_useWaitToDumpWatchdogTimer = false;
+        m_forceNoTimeout = true;
+    }
+}
+
+WKPreferencesRef TestController::platformPreferences()
+{
+    return WKPageGroupGetPreferences(m_pageGroup.get());
+}
+
+void TestController::platformDestroy()
+{
+}
+
+void TestController::platformRunUntil(bool& condition, double timeout)
+{
+    if (timeout <= 0) {
+        // Never timeout if we are debugging or not meant to timeout.
+        while (!condition)
+            ecore_main_loop_iterate();
+
+        return;
+    }
+    timer = ecore_timer_loop_add(timeout, timerFired, 0);
+    ecore_main_loop_begin();
+}
+
+static const char* getEnvironmentVariableOrExit(const char* variableName)
+{
+    const char* value = getenv(variableName);
+    if (!value) {
+        fprintf(stderr, "%s environment variable not found\n", variableName);
+        exit(0);
+    }
+
+    return value;
+}
+
+void TestController::initializeInjectedBundlePath()
+{
+    const char* bundlePath = getEnvironmentVariableOrExit("TEST_RUNNER_INJECTED_BUNDLE_FILENAME");
+    m_injectedBundlePath.adopt(WKStringCreateWithUTF8CString(bundlePath));
+}
+
+void TestController::initializeTestPluginDirectory()
+{
+    const char* pluginPath = getEnvironmentVariableOrExit("TEST_RUNNER_PLUGIN_PATH");
+    m_testPluginDirectory.adopt(WKStringCreateWithUTF8CString(pluginPath));
+}
+
+void TestController::platformInitializeContext()
+{
+}
+
+void TestController::setHidden(bool hidden)
+{
+    PlatformWKView view = mainWebView()->platformView();
+
+    if (!view) {
+        fprintf(stderr, "ERROR: view is null.\n");
+        return;
+    }
+
+    if (hidden)
+        evas_object_hide(view);
+    else
+        evas_object_show(view);
+}
+
+void TestController::runModal(PlatformWebView*)
+{
+    // FIXME: Need to implement this to test showModalDialog.
+}
+
+const char* TestController::platformLibraryPathForTesting()
+{
+    return 0;
+}
+
+static bool pathContains(const std::string& pathOrURL, const char* substring)
+{
+    String path(pathOrURL.c_str());
+    return path.contains(substring); // Case-insensitive.
+}
+
+static bool shouldUseFixedLayout(const std::string& pathOrURL)
+{
+#if USE(COORDINATED_GRAPHICS)
+    if (pathContains(pathOrURL, "sticky/") || pathContains(pathOrURL, "sticky\\"))
+        return true;
+#endif
+    return false;
+}
+
+void TestController::updatePlatformSpecificTestOptionsForTest(TestOptions& testOptions, const std::string& pathOrURL) const
+{
+    testOptions.useFixedLayout |= shouldUseFixedLayout(pathOrURL);
+}
+
+void TestController::platformConfigureViewForTest(const TestInvocation&)
+{
+    WKPageSetApplicationNameForUserAgent(mainWebView()->page(), WKStringCreateWithUTF8CString("WebKitTestRunnerEFL"));
+}
+
+void TestController::platformResetPreferencesToConsistentValues()
+{
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/efl/main.cpp b/Tools/WebKitTestRunner/efl/main.cpp
new file mode 100644 (file)
index 0000000..6b50669
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 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 program 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 program; 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 "EWebKit2.h"
+#include "TestController.h"
+#include <wtf/Assertions.h>
+#include <stdlib.h>
+
+#ifdef HAVE_ECORE_X
+#include <X11/Xlib.h>
+#include <X11/extensions/Xext.h>
+
+static int dummyExtensionErrorHandler(Display*, _Xconst char*, _Xconst char*)
+{
+    return 0;
+}
+#endif
+
+int main(int argc, char** argv)
+{
+    WTFInstallReportBacktraceOnCrashHook();
+
+#ifdef HAVE_ECORE_X
+    XSetExtensionErrorHandler(dummyExtensionErrorHandler);
+#endif
+
+    if (!ewk_init())
+        return 1;
+
+    {
+        // Test controller has own ptr containing WebView and WebView must be deleted
+        // before its evas object is deleted. Call of ewk_shutdown() leads to evas objects deletion.
+
+        WTR::TestController controller(argc, const_cast<const char**>(argv));
+    }
+
+    ewk_shutdown();
+
+    return 0;
+}
+
diff --git a/Tools/efl/install-dependencies b/Tools/efl/install-dependencies
new file mode 100755 (executable)
index 0000000..72038cc
--- /dev/null
@@ -0,0 +1,135 @@
+#!/bin/bash
+
+# This script needs to be run with root rights.
+if [ $UID -ne 0 ]; then
+    sudo $0
+    exit 0
+fi
+
+function printNotSupportedMessageAndExit() {
+    echo
+    echo "Currently this script only works for distributions supporting apt-get."
+    echo "Please add support for your distribution."
+    echo
+    exit 1
+}
+
+function checkCmakeVersion() {
+    CMAKE_VERSION=`cmake --version`
+
+    VERSION=`echo "$CMAKE_VERSION" | awk '{split($3,num,".");
+    if (!(num[1]>2 || num[2]>8 || num[3]>=10))
+        printf $3}'`
+
+    if [ -n "${VERSION}" ]; then
+        echo "Warning: CMake version detected (${VERSION}) is lower then 2.8.10."
+        echo "  This will probably cause errors, as older version didn't support CMAKE_NINJA_FORCE_RESPONSE_FILE,"
+        echo "  which is needed now for building. (look at: https://lists.webkit.org/pipermail/webkit-gtk/2014-March/001809.html )"
+        echo ""
+
+        if [ -f "/etc/issue" ]; then
+            ubuntu_version=`cat /etc/issue`
+            if [[ $ubuntu_version == *Ubuntu\ 12.04* ]]; then
+                echo "  For Ubuntu 12.04 or 12.10 You might consider adding ppa from https://launchpad.net/~kalakris/+archive/ubuntu/cmake"
+            fi
+        fi
+    fi
+}
+
+function checkInstaller {
+    # apt-get - Debian based distributions
+    apt-get --version &> /dev/null
+    if [ $? -eq 0 ]; then
+        installDependenciesWithApt
+        checkCmakeVersion;
+        exit 0
+    fi
+
+    printNotSupportedMessageAndExit
+}
+
+# If the package $1 is available, prints it. Otherwise prints $2.
+# Useful for handling when a package is renamed on new versions of Debian/Ubuntu.
+function aptIfElse {
+    if apt-cache show $1 &>/dev/null; then
+        echo $1
+    else
+        echo $2
+    fi
+}
+
+function installDependenciesWithApt {
+    # These are dependencies necessary for building WebKitEFL.
+    apt-get install \
+        bison \
+        cmake \
+        doxygen \
+        flex \
+        g++ \
+        geoclue-2.0 \
+        gperf \
+        gtk-doc-tools \
+        libatk1.0-dev \
+        libdbus-1-dev \
+        libedit-dev \
+        libenchant-dev \
+        libespeak-dev \
+        libfaad-dev \
+        libffi-dev \
+        libfreetype6-dev \
+        $(aptIfElse libgcrypt20-dev libgcrypt11-dev) \
+        $(aptIfElse libgeoclue-2-dev libgeoclue-dev) \
+        libgif-dev \
+        libgl1-mesa-dev \
+        libgpg-error-dev \
+        libhyphen-dev \
+        libicu-dev \
+        libjpeg-dev \
+        libjson-glib-dev \
+        liblua5.1-0-dev \
+        libluajit-5.1-dev \
+        libmpg123-dev \
+        liborc-0.4-dev \
+        libosmesa6-dev \
+        libp11-kit-dev \
+        $(aptIfElse libpng-dev libpng12-dev) \
+        libpoppler-cpp-dev \
+        libpulse-dev \
+        libraw-dev \
+        librsvg2-dev \
+        libspectre-dev \
+        libsqlite3-dev \
+        libssl-dev \
+        libtheora-dev \
+        libtiff5-dev \
+        libudev-dev \
+        libvorbis-dev \
+        libwebp-dev \
+        libxcomposite-dev \
+        libxcursor-dev \
+        libxinerama-dev \
+        libxrandr-dev \
+        libxrender-dev \
+        libxss-dev \
+        libxt-dev \
+        libxtst-dev \
+        ninja-build \
+        ragel \
+        ruby \
+        subversion \
+        x11proto-print-dev
+
+    # These are dependencies necessary for building WebKitEFL and not available on ARM64.
+    apt-get install \
+        luajit
+
+    # These are dependencies necessary for running tests.
+    apt-get install \
+        apache2 \
+        $(aptIfElse libapache2-mod-php7.0 libapache2-mod-php5) \
+        libruby \
+        xvfb
+}
+
+checkInstaller
+
diff --git a/Tools/efl/jhbuild-optional.modules b/Tools/efl/jhbuild-optional.modules
new file mode 100644 (file)
index 0000000..3fe3732
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!DOCTYPE moduleset SYSTEM "moduleset.dtd">
+<?xml-stylesheet type="text/xsl" href="moduleset.xsl"?>
+<moduleset>
+
+  <repository type="tarball" name="ftp.gnome.org"
+      href="http://ftp.gnome.org"/>
+
+  <autotools id="at-spi2-core"
+          autogenargs="--disable-introspection">
+    <branch module="pub/GNOME/sources/at-spi2-core/2.10/at-spi2-core-2.10.0.tar.xz" version="2.10.0"
+          repo="ftp.gnome.org"
+          hash="sha256:964155c7574220a00e11e1c0d91f2d3017ed603920eb1333ff9cbdb6a22744db">
+    </branch>
+    <dependencies>
+      <dep package="glib"/>
+    </dependencies>
+  </autotools>
+
+  <autotools id="at-spi2-atk">
+    <branch module="pub/GNOME/sources/at-spi2-atk/2.10/at-spi2-atk-2.10.0.tar.xz" version="2.10.0"
+            repo="ftp.gnome.org"
+            hash="sha256:dea7ff2f9bc9bbdb0351112616d738de718b55739cd2511afecac51604c31a94">
+    </branch>
+    <dependencies>
+      <dep package="glib"/>
+      <dep package="atk"/>
+      <dep package="at-spi2-core"/>
+    </dependencies>
+  </autotools>
+
+</moduleset>
diff --git a/Tools/efl/jhbuild.modules b/Tools/efl/jhbuild.modules
new file mode 100644 (file)
index 0000000..c9e9942
--- /dev/null
@@ -0,0 +1,317 @@
+<?xml version="1.0"?>
+<!DOCTYPE moduleset SYSTEM "moduleset.dtd">
+<?xml-stylesheet type="text/xsl" href="moduleset.xsl"?>
+<moduleset>
+
+  <metamodule id="webkitefl-testing-dependencies">
+    <dependencies>
+      <dep package="cairo"/>
+      <dep package="fonts"/>
+      <dep package="dicts"/>
+      <dep package="fontconfig"/>
+      <dep package="freetype6"/>
+      <dep package="harfbuzz"/>
+      <dep package="glib"/>
+      <dep package="glib-networking"/>
+      <dep package="libsoup"/>
+      <dep package="efl"/>
+      <dep package="libxml2"/>
+      <dep package="libxslt"/>
+      <dep package="gstreamer"/>
+      <dep package="gst-plugins-base"/>
+      <dep package="gst-plugins-good"/>
+      <dep package="gst-plugins-bad"/>
+      <dep package="gst-libav"/>
+      <dep package="atk"/>
+      <dep package="openwebrtc"/>
+    </dependencies>
+  </metamodule>
+
+  <include href="jhbuild-optional.modules"/>
+
+  <repository type="tarball" name="github.com"
+      href="https://github.com"/>
+  <repository type="tarball" name="sourceware.org"
+      href="ftp://sourceware.org"/>
+  <repository type="tarball" name="ftp.gnome.org"
+      href="http://ftp.gnome.org"/>
+  <repository type="git" name="git.gnome.org"
+      href="git://git.gnome.org/"/>
+  <repository type="tarball" name="cairographics.org"
+      href="http://cairographics.org"/>
+  <repository type="tarball" name="freedesktop.org"
+      href="http://www.freedesktop.org"/>
+  <repository type="tarball" name="nice.freedesktop.org"
+      href="http://nice.freedesktop.org/"/>
+  <repository type="tarball" name="enlightenment.fr"
+      href="http://git.enlightenment.fr/cgit.cgi/svn/"/>
+  <repository type="tarball" name="xmlsoft.org"
+      href="ftp://xmlsoft.org"/>
+  <repository type="tarball" name="download.enlightenment.org"
+      href="http://download.enlightenment.org"/>
+  <repository type="tarball" name="gstreamer"
+      href="http://gstreamer.freedesktop.org/src/"/>
+
+  <autotools id="cairo" autogen-sh="configure"
+             makeargs="CFLAGS='-fno-lto' CXXFLAGS='-fno-lto' LDFLAGS='-fno-lto'">
+    <dependencies>
+      <dep package="fontconfig"/>
+      <dep package="pixman"/>
+    </dependencies>
+    <branch module="releases/cairo-1.14.2.tar.xz" version="1.14.2"
+            repo="cairographics.org"
+            hash="sha256:c919d999ddb1bbbecd4bbe65299ca2abd2079c7e13d224577895afa7005ecceb"
+            md5sum="e1cdfaf1c6c995c4d4c54e07215b0118">
+    </branch>
+  </autotools>
+
+  <!-- FIXME: Pixman 0.32.6 isn't buildable with Clang, but disable-mmx option fixes
+              the build. This workaround can be removed once the original bug is fixed.
+              Details can be found here: https://bugs.webkit.org/show_bug.cgi?id=151441 -->
+  <autotools id="pixman" autogen-sh="configure"
+             autogenargs="--enable-gtk=no --disable-arm-iwmmxt --disable-mmx">
+    <branch module="releases/pixman-0.32.6.tar.gz" version="0.32.6"
+            repo="cairographics.org"
+            hash="sha256:3dfed13b8060eadabf0a4945c7045b7793cc7e3e910e748a8bb0f0dc3e794904"
+            md5sum="3a30859719a41bd0f5cccffbfefdd4c2">
+    </branch>
+  </autotools>
+
+  <autotools id="fonts" supports-non-srcdir-builds="no"
+             skip-autogen="true">
+    <branch module="mrobinson/webkitgtk-test-fonts/archive/0.0.5.tar.gz" version="0.0.5"
+            checkoutdir="webkitgtk-test-fonts"
+            repo="github.com"
+            hash="sha256:369aea9e18aa1a234400976c0a8135b9709805ce4b65a3b474a8d0ee0e298f34"
+            md5sum="39802b485f513842724e6cfd265335bb" size="22592847">
+    </branch>
+  </autotools>
+
+  <autotools id="dicts" supports-non-srcdir-builds="no"
+             skip-autogen="true">
+    <branch module="mrobinson/webkitgtk-test-dicts/archive/0.0.1.zip" version="0.0.1"
+            checkoutdir="webkitgtk-test-dicts"
+            repo="github.com"
+            hash="sha256:6cfc94a7846a0d8f76a7a733f729e8109c6e1d0fbc9e0e8587eb5c3ef9888c24"
+            md5sum="6bd8d32c157305fc69932ea8d1348723" size="99299">
+    </branch>
+  </autotools>
+
+  <autotools id="libffi" autogen-sh="configure">
+    <branch module="/pub/libffi/libffi-3.1.tar.gz" version="3.1"
+             repo="sourceware.org"
+             hash="sha256:97feeeadca5e21870fa4433bc953d1b3af3f698d5df8a428f68b73cd60aef6eb"
+             md5sum="f5898b29bbfd70502831a212d9249d10"/>
+  </autotools>
+
+  <!-- FIXME: Original download url doesn't work in Korea. So, Bug 133303 changes the url for now.
+             Original download url: http://download.savannah.gnu.org/releases/freetype/freetype-2.4.11.tar.bz2 -->
+  <tarball id="freetype6">
+    <source href="github.com/shivamidow/freetype/raw/master/freetype-2.4.11.tar.bz2" version="2.4.11"
+            hash="sha256:ef9d0bcb64647d9e5125dc7534d7ca371c98310fec87677c410f397f71ffbe3f"
+            md5sum="b93435488942486c8d0ca22e8f768034" />
+  </tarball>
+
+  <autotools id="glib"
+             autogen-sh="configure"
+             autogenargs="--disable-dtrace">
+    <dependencies>
+      <dep package="libffi"/>
+    </dependencies>
+    <branch module="/pub/GNOME/sources/glib/2.41/glib-2.41.2.tar.xz" version="2.41.2"
+            repo="ftp.gnome.org"
+            hash="sha256:da1f7258655f0e196b9304cb9515784634f3797437923e236bb3466348811c96"
+            md5sum="9636f60e99b98fd0fdb5239f905ac008"/>
+  </autotools>
+
+  <autotools id="glib-networking">
+    <dependencies>
+      <dep package="glib"/>
+    </dependencies>
+    <branch module="/pub/GNOME/sources/glib-networking/2.41/glib-networking-2.41.4.tar.xz" version="2.41.4"
+            repo="ftp.gnome.org"
+            hash="sha256:930ad618865dcf81765d0f48cb6f13e22d76203efa59d30604aed0384ce80fd7"
+            md5sum="f88e163322c0834f9781d6224771ab2e"/>
+  </autotools>
+
+  <autotools id="libsoup"
+             autogenargs="--without-gnome --disable-introspection">
+    <dependencies>
+      <dep package="glib-networking"/>
+      <dep package="libxml2"/>
+    </dependencies>
+    <branch module="/pub/gnome/sources/libsoup/2.50/libsoup-2.50.0.tar.xz" version="2.50.0"
+            repo="ftp.gnome.org"
+            hash="sha256:1e01365ac4af3817187ea847f9d3588c27eee01fc519a5a7cb212bb78b0f667b">
+    </branch>
+  </autotools>
+
+  <autotools id="fontconfig"
+             autogen-sh="configure"
+             autogenargs="--enable-libxml2">
+    <dependencies>
+      <dep package="freetype6"/>
+      <dep package="libxml2"/>
+    </dependencies>
+    <branch module="software/fontconfig/release/fontconfig-2.11.1.tar.gz" version="2.11.1"
+            repo="freedesktop.org"
+            hash="sha256:b6b066c7dce3f436fdc0dfbae9d36122b38094f4f53bd8dffd45e195b0540d8d"
+            md5sum="e75e303b4f7756c2b16203a57ac87eba"/>
+  </autotools>
+
+  <autotools id="harfbuzz" autogen-sh="configure">
+    <branch module="software/harfbuzz/release/harfbuzz-0.9.35.tar.bz2" version="0.9.35"
+           checkoutdir="harfbuzz-0.9.35"
+           repo="freedesktop.org"
+           hash="sha256:0aa1a8aba6f502321cf6fef3c9d2c73dde48389c5ed1d3615a7691944c2a06ed">
+    </branch>
+  </autotools>
+
+  <autotools id="efl" autogen-sh="configure"
+             autogenargs="--disable-fribidi --disable-audio --disable-libmount --disable-physics --enable-i-really-know-what-i-am-doing-and-that-this-will-probably-break-things-and-i-will-fix-them-myself-and-send-patches-abb">
+    <dependencies>
+      <dep package="fontconfig"/>
+      <dep package="gstreamer"/>
+      <dep package="gst-plugins-base"/>
+    </dependencies>
+    <branch module="rel/libs/efl/efl-1.18.4.tar.gz" version="1.18.4"
+            repo="download.enlightenment.org"
+            hash="sha256:d19669eece770cc09733568c7dfef9870daa0f8b9f613ab76ad14b2f5de20040">
+    </branch>
+  </autotools>
+
+  <autotools id="libxml2"
+             autogen-sh="configure"
+             autogenargs="--without-python">
+    <branch module="/libxml2/libxml2-2.9.1.tar.gz" version="2.9.1"
+            repo="xmlsoft.org"
+            hash="sha256:fd3c64cb66f2c4ea27e934d275904d92cec494a8e8405613780cbc8a71680fdb"
+            md5sum="9c0cfef285d5c4a5c80d00904ddab380"/>
+  </autotools>
+
+  <autotools id="libxslt">
+    <branch module="/libxslt/libxslt-1.1.29.tar.gz" version="1.1.29"
+            repo="xmlsoft.org"
+            hash="sha256:b5976e3857837e7617b29f2249ebb5eeac34e249208d31f1fbf7a6ba7a4090ce"/>
+    <dependencies>
+      <dep package="libxml2"/>
+    </dependencies>
+  </autotools>
+
+  <autotools id="orc" autogenargs="--disable-gtk-doc" autogen-sh="configure">
+    <branch module="orc/orc-0.4.17.tar.gz" version="0.4.17"
+            repo="gstreamer"
+            hash="sha256:4fc7cca48c59fff23afee78fb642cdbde001f56401c8f47b95a16578d1d5d7e8"
+            md5sum="af1bf3dab9e69f3c36f389285e2a12a1"/>
+  </autotools>
+
+  <autotools id="gstreamer" autogenargs="--disable-gtk-doc" autogen-sh="configure">
+    <dependencies>
+      <dep package="orc"/>
+    </dependencies>
+    <branch module="gstreamer/gstreamer-1.8.0.tar.xz" version="1.8.0"
+            repo="gstreamer"
+            hash="sha256:947a314a212b5d94985d89b43440dbe66b696e12bbdf9a2f78967b98d74abedc"
+            md5sum="6846d7289ec323c38c49b818171e955a"/>
+  </autotools>
+
+  <autotools id="gst-plugins-base"
+             autogen-sh="configure"
+             autogenargs="--disable-examples --disable-gtk-doc">
+    <dependencies>
+      <dep package="gstreamer"/>
+    </dependencies>
+    <branch module="gst-plugins-base/gst-plugins-base-1.8.0.tar.xz" version="1.8.0"
+            repo="gstreamer"
+            hash="sha256:abc0acc1d15b4b9c97c65cd9689bd6400081853b9980ea428d3c8572dd791522"
+            md5sum="20cc8231609318310f2a55f64c86cbb4">
+    </branch>
+  </autotools>
+
+  <autotools id="gst-plugins-good" autogenargs="--disable-examples --disable-soup --disable-gtk-doc" autogen-sh="configure">
+    <dependencies>
+      <dep package="gst-plugins-base"/>
+    </dependencies>
+    <branch module="gst-plugins-good/gst-plugins-good-1.8.0.tar.xz" version="1.8.0"
+            repo="gstreamer"
+            hash="sha256:c20c134d47dbc238d921707a3b66da709c2b4dd89f9d267cec13d1ddf16e9f4d"
+            md5sum="91ed4649c7c2e43a61f731d144f6f6d0">
+      <patch file="gst-plugins-good-use-the-tfdt-decode-time.patch" strip="1"/>
+      <patch file="gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch" strip="1"/>
+    </branch>
+  </autotools>
+
+  <autotools id="gst-plugins-bad" autogenargs="--disable-examples --disable-gtk-doc">
+    <dependencies>
+      <dep package="gst-plugins-base"/>
+    </dependencies>
+    <branch module="gst-plugins-bad/gst-plugins-bad-1.8.0.tar.xz" version="1.8.0"
+            repo="gstreamer"
+            hash="sha256:116376dd1085082422e0b21b0ecd3d1cb345c469c58e32463167d4675f4ca90e"
+            md5sum="1c2d797bb96a81e9ef570c7a0a37203e">
+    </branch>
+  </autotools>
+
+  <autotools id="gst-libav" autogenargs="--with-libav-extra-configure='--disable-yasm' --disable-gtk-doc" autogen-sh="configure">
+    <dependencies>
+      <dep package="gst-plugins-base"/>
+    </dependencies>
+    <branch module="gst-libav/gst-libav-1.8.0.tar.xz" version="1.8.0"
+            repo="gstreamer"
+            hash="sha256:5a1ce28876aee93cb4f3d090f0e807915a5d9bc1325e3480dd302b85aeb4291c"
+            md5sum="361638fa45466c5050bcde6bfe10fa46">
+      <patch file="gst-libav.patch" strip="1"/>
+    </branch>
+  </autotools>
+
+  <autotools id="atk"
+             autogen-sh="configure"
+             autogenargs="--disable-introspection">
+    <branch module="pub/GNOME/sources/atk/2.15/atk-2.15.2.tar.xz" version="2.15.2"
+            repo="ftp.gnome.org"
+            hash="sha256:179d15424b8aa3a5726903f0da458de68e0585dfd9d451c6dcfcdb6b7b509cbe"/>
+    <dependencies>
+        <dep package="glib"/>
+    </dependencies>
+  </autotools>
+
+  <autotools id="libusrsctp" supports-non-srcdir-builds="no" autogen-sh="./bootstrap; ./configure --disable-warnings-as-errors">
+    <branch repo="github.com" module="sctplab/usrsctp/archive/078ff3252f73327e0ac11d6fd5eff62011f6646e.tar.gz" version="078ff3252f73327e0ac11d6fd5eff62011f6646e" checkoutdir="libusrsctp"
+            hash="sha256:175938887dc7554e000152055c818bdd15dd0e4ccc94ef93e38e9f952ea82edc" size="648925">
+    </branch>
+  </autotools>
+
+  <autotools id="gst-plugins-openwebrtc" supports-parallel-builds="no" supports-non-srcdir-builds="no" autogen-sh="./autogen.sh; ./configure">
+    <dependencies>
+      <dep package="gst-plugins-base"/>
+      <dep package="libusrsctp"/>
+    </dependencies>
+   <branch repo="github.com" module="EricssonResearch/openwebrtc-gst-plugins/archive/e359b67484af90f416ea35e301205d2b53c77a14.tar.gz" checkoutdir="gst-plugins-openwebrtc" version="gst-plugins-openwebrtc-20150317"
+           hash="sha256:a456425efb88de39c16a4f8ac4214aaf53157f9df1323f08de375c77f227b6b7"
+           md5sum="827f13634ffa83cccf1a6312effbceaa" size="92883">
+      <patch file="openwebrtc-gst-plugins-clang-warning-fix.patch" strip="1"/>
+   </branch>
+  </autotools>
+
+  <autotools id="libnice" supports-non-srcdir-builds="no">
+    <dependencies>
+      <dep package="gstreamer"/>
+    </dependencies>
+    <branch repo="nice.freedesktop.org" module="releases/libnice-0.1.13.tar.gz" checkoutdir="libnice" version="0.1.13"
+            hash="sha256:61112d9f3be933a827c8365f20551563953af6718057928f51f487bfe88419e1"
+            md5sum="3226faeaf48a9150ada00da2e2865959" size="912374">
+    </branch>
+  </autotools>
+
+  <autotools id="openwebrtc" autogenargs="--enable-bridge=no --enable-owr-gst=yes">
+    <dependencies>
+      <dep package="gst-plugins-openwebrtc"/>
+      <dep package="libnice"/>
+     </dependencies>
+    <branch repo="github.com" module="EricssonResearch/openwebrtc/archive/f511ea1fa79a33fa3d52bfd1c0969c28084aeb35.tar.gz" checkoutdir="openwebrtc" version="f511ea1fa79a33fa3d52bfd1c0969c28084aeb35"
+            hash="sha256:af80b80512b5f5a6b82b4cf43afa28da9c94c86800f6fadd10762361079fb5e3"
+            md5sum="4555d20821af8f5334f74b4f0327f178" size="296143">
+    </branch>
+  </autotools>
+
+</moduleset>
diff --git a/Tools/efl/jhbuildrc b/Tools/efl/jhbuildrc
new file mode 100644 (file)
index 0000000..a04b393
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# Copyright (C) 2011 Igalia S.L.
+# Copyright (C) 2012 Intel Corporation
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+import sys
+import platform
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../jhbuild") )
+import jhbuildrc_common
+
+jhbuildrc_common.init(globals(), "efl") 
+
+addpath('XDG_DATA_DIRS', '/usr/share')
+addpath('XDG_CONFIG_DIRS', '/etc/xdg')
+
+partial_build = False
diff --git a/Tools/efl/patches/evas-fix-build-with-giflib5.patch b/Tools/efl/patches/evas-fix-build-with-giflib5.patch
new file mode 100644 (file)
index 0000000..203fbdd
--- /dev/null
@@ -0,0 +1,54 @@
+Patch from Doug Newgard, available at https://phab.enlightenment.org/D200
+
+diff --git a/src/modules/loaders/gif/evas_image_load_gif.c b/src/modules/loaders/gif/evas_image_load_gif.c
+index 18a6e23..6b6ef3d 100644
+--- a/src/modules/loaders/gif/evas_image_load_gif.c
++++ b/src/modules/loaders/gif/evas_image_load_gif.c
+@@ -700,7 +700,11 @@ evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key
+         return EINA_FALSE;
+      }
++#if GIFLIB_MAJOR >= 5
++   gif = DGifOpenFileHandle(fd, NULL);
++#else
+    gif = DGifOpenFileHandle(fd);
++#endif
+    if (!gif)
+      {
+         if (fd) close(fd);
+@@ -838,7 +842,11 @@ evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_inde
+         return EINA_FALSE;
+      }
++#if GIFLIB_MAJOR >= 5
++   gif = DGifOpenFileHandle(fd, NULL);
++#else
+    gif = DGifOpenFileHandle(fd);
++#endif
+    if (!gif)
+      {
+         if (fd) close(fd);
+@@ -927,7 +935,11 @@ evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key
+                   return EINA_FALSE;
+                }
++#if GIFLIB_MAJOR >= 5
++             gif = DGifOpenFileHandle(fd, NULL);
++#else
+              gif = DGifOpenFileHandle(fd);
++#endif
+              if (!gif)
+                {
+                   if (fd) close(fd);
+@@ -1000,7 +1012,11 @@ evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int
+ #endif
+    if (fd < 0) return -1;
++#if GIFLIB_MAJOR >=5
++   gif = DGifOpenFileHandle(fd, NULL);
++#else
+    gif = DGifOpenFileHandle(fd);
++#endif
+    if (!gif)
+      {
+         if (fd) close(fd);
diff --git a/Tools/efl/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch b/Tools/efl/patches/fontconfig-C-11-requires-a-space-between-literal-and-identifier.patch
new file mode 100644 (file)
index 0000000..b4e0a54
--- /dev/null
@@ -0,0 +1,30 @@
+From 7069d717e982adcf8e1d300cbd10eec6322a65c9 Mon Sep 17 00:00:00 2001
+From: Akira TAGOH <akira@tagoh.org>
+Date: Sun, 22 Apr 2012 21:40:44 +0900
+Subject: [PATCH] C++11 requires a space between literal and identifier
+
+Reported by Buganini
+---
+ fontconfig/fontconfig.h | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
+index 0e2ca50..b27ccb5 100644
+--- a/fontconfig/fontconfig.h
++++ b/fontconfig/fontconfig.h
+@@ -112,9 +112,9 @@ typedef int                FcBool;
+ #define FC_DECORATIVE     "decorative"        /* Bool - true if style is a decorative variant */
+ #define FC_LCD_FILTER     "lcdfilter"         /* Int */
+-#define FC_CACHE_SUFFIX                   ".cache-"FC_CACHE_VERSION
+-#define FC_DIR_CACHE_FILE         "fonts.cache-"FC_CACHE_VERSION
+-#define FC_USER_CACHE_FILE        ".fonts.cache-"FC_CACHE_VERSION
++#define FC_CACHE_SUFFIX                   ".cache-" FC_CACHE_VERSION
++#define FC_DIR_CACHE_FILE         "fonts.cache-" FC_CACHE_VERSION
++#define FC_USER_CACHE_FILE        ".fonts.cache-" FC_CACHE_VERSION
+ /* Adjust outline rasterizer */
+ #define FC_CHAR_WIDTH     "charwidth" /* Int */
+-- 
+1.8.3.2
+
diff --git a/Tools/efl/patches/gst-libav.patch b/Tools/efl/patches/gst-libav.patch
new file mode 100644 (file)
index 0000000..35ec99e
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/gst-libs/ext/libav/libavcodec/arm/videodsp_armv5te.S
++++ b/gst-libs/ext/libav/libavcodec/arm/videodsp_armv5te.S
+@@ -27,6 +27,7 @@
+         subs            r2,  r2,  #1
+         pld             [r0]
+         add             r0,  r0,  r1
++        it              ne
+         bne             1b
+         bx              lr
+
+--- a/gst-libs/ext/libav/libswresample/arm/audio_convert_neon.S
++++ b/gst-libs/ext/libav/libswresample/arm/audio_convert_neon.S
+@@ -134,6 +134,7 @@ function swri_oldapi_conv_fltp_to_s16_nch_neon, export=1
+         itt             lt
+         ldrlt           r1,  [r1]
+         blt             X(swri_oldapi_conv_flt_to_s16_neon)
++        it              eq
+         beq             X(swri_oldapi_conv_fltp_to_s16_2ch_neon)
+         push            {r4-r8, lr}
diff --git a/Tools/efl/patches/gst-plugins-base-rtp-rtcpbuffer-fix-typo-in-enum.patch b/Tools/efl/patches/gst-plugins-base-rtp-rtcpbuffer-fix-typo-in-enum.patch
new file mode 100644 (file)
index 0000000..e3ddb72
--- /dev/null
@@ -0,0 +1,45 @@
+From dfc34c58411f50b37b2e1300560ae8a0b6a9a7d4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= <tim@centricular.com>
+Date: Tue, 7 Apr 2015 16:43:59 +0100
+Subject: [PATCH] rtp: rtcpbuffer: fix typo in enum
+
+and in docs. Spotted by Rob Swain.
+---
+ gst-libs/gst/rtp/gstrtcpbuffer.h | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h
+index b5ff4a1..47378cf 100644
+--- a/gst-libs/gst/rtp/gstrtcpbuffer.h
++++ b/gst-libs/gst/rtp/gstrtcpbuffer.h
+@@ -59,6 +59,9 @@ typedef enum
+   GST_RTCP_TYPE_PSFB    = 206
+ } GstRTCPType;
++/* FIXME 2.0: backwards compatibility define for enum typo */
++#define GST_RTCP_RTPFB_TYPE_RCTP_SR_REQ GST_RTCP_RTPFB_TYPE_RTCP_SR_REQ
++
+ /**
+  * GstRTCPFBType:
+  * @GST_RTCP_FB_TYPE_INVALID: Invalid type
+@@ -66,7 +69,7 @@ typedef enum
+  * @GST_RTCP_RTPFB_TYPE_TMMBR: Temporary Maximum Media Stream Bit Rate Request
+  * @GST_RTCP_RTPFB_TYPE_TMMBN: Temporary Maximum Media Stream Bit Rate
+  *    Notification
+- * @GST_RTCP_RTPFB_TYPE_RTCP_SR_SEQ: Request an SR packet for early
++ * @GST_RTCP_RTPFB_TYPE_RTCP_SR_REQ: Request an SR packet for early
+  *    synchronization
+  * @GST_RTCP_PSFB_TYPE_PLI: Picture Loss Indication
+  * @GST_RTCP_PSFB_TYPE_SLI: Slice Loss Indication
+@@ -89,7 +92,7 @@ typedef enum
+   GST_RTCP_RTPFB_TYPE_TMMBR       = 3,
+   GST_RTCP_RTPFB_TYPE_TMMBN       = 4,
+   /* RTPFB types assigned in RFC 6051 */
+-  GST_RTCP_RTPFB_TYPE_RCTP_SR_REQ = 5,
++  GST_RTCP_RTPFB_TYPE_RTCP_SR_REQ = 5,
+   /* PSFB types */
+   GST_RTCP_PSFB_TYPE_PLI          = 1,
+   GST_RTCP_PSFB_TYPE_SLI          = 2,
+-- 
+2.1.4
+
diff --git a/Tools/efl/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch b/Tools/efl/patches/gst-plugins-good-Revert-qtdemux-expose-streams-with-first-moof-for-fr.patch
new file mode 100644 (file)
index 0000000..3a60db4
--- /dev/null
@@ -0,0 +1,133 @@
+From 1a81bd90d4a3e59d6669a0bbfa456f1ed4e5db48 Mon Sep 17 00:00:00 2001
+From: Xabier Rodriguez Calvar <calvaris@igalia.com>
+Date: Thu, 7 Apr 2016 13:57:16 +0200
+Subject: [PATCH] Revert "qtdemux: expose streams with first moof for
+ fragmented format"
+
+This reverts commit d8bb6687ea251570c331038279a43d448167d6ad.
+---
+ gst/isomp4/qtdemux.c | 54 ++++++++++++++++------------------------------------
+ gst/isomp4/qtdemux.h |  1 -
+ 2 files changed, 16 insertions(+), 39 deletions(-)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index 39be163..9636b4b 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -609,7 +609,6 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
+   qtdemux->state = QTDEMUX_STATE_INITIAL;
+   qtdemux->pullbased = FALSE;
+   qtdemux->posted_redirect = FALSE;
+-  qtdemux->pending_configure = FALSE;
+   qtdemux->neededbytes = 16;
+   qtdemux->todrop = 0;
+   qtdemux->adapter = gst_adapter_new ();
+@@ -2049,7 +2048,6 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
+     gst_caps_replace (&qtdemux->media_caps, NULL);
+     qtdemux->timescale = 0;
+     qtdemux->got_moov = FALSE;
+-    qtdemux->pending_configure = FALSE;
+   } else if (qtdemux->mss_mode) {
+     gst_flow_combiner_reset (qtdemux->flowcombiner);
+     for (n = 0; n < qtdemux->n_streams; n++)
+@@ -6104,7 +6102,6 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+             &fourcc);
+         if (fourcc == FOURCC_moov) {
+           gint n;
+-          gboolean got_samples = FALSE;
+           /* in usual fragmented setup we could try to scan for more
+            * and end up at the the moov (after mdat) again */
+@@ -6136,27 +6133,19 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+             qtdemux_node_dump (demux, demux->moov_node);
+             qtdemux_parse_tree (demux);
+             qtdemux_prepare_streams (demux);
++            if (!demux->got_moov)
++              qtdemux_expose_streams (demux);
++            else {
+-            for (n = 0; n < demux->n_streams; n++) {
+-              QtDemuxStream *stream = demux->streams[n];
+-              got_samples |= stream->stbl_index >= 0;
+-            }
+-            if (!demux->fragmented || got_samples) {
+-              if (!demux->got_moov) {
+-                qtdemux_expose_streams (demux);
+-              } else {
+-                for (n = 0; n < demux->n_streams; n++) {
+-                  QtDemuxStream *stream = demux->streams[n];
+-                  gst_qtdemux_configure_stream (demux, stream);
+-                }
++              for (n = 0; n < demux->n_streams; n++) {
++                QtDemuxStream *stream = demux->streams[n];
++
++                gst_qtdemux_configure_stream (demux, stream);
+               }
+-              gst_qtdemux_check_send_pending_segment (demux);
+-              demux->pending_configure = FALSE;
+-            } else {
+-              demux->pending_configure = TRUE;
+             }
+             demux->got_moov = TRUE;
++            gst_qtdemux_check_send_pending_segment (demux);
+             /* fragmented streams headers shouldn't contain edts atoms */
+             if (!demux->fragmented) {
+@@ -6175,7 +6164,6 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+             guint64 dist = 0;
+             GstClockTime prev_pts;
+             guint64 prev_offset;
+-            gint n;
+             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
+@@ -6209,25 +6197,15 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
+               ret = GST_FLOW_ERROR;
+               goto done;
+             }
+-            /* in MSS we need to expose the pads after the first moof as we won't get a moov 
+-             * Also, fragmented format need to be exposed if a moov have no valid sample data */
+-            if (demux->mss_mode || demux->pending_configure) {
+-              if (!demux->exposed) {
+-                if (!demux->pending_newsegment) {
+-                  GstSegment segment;
+-                  gst_segment_init (&segment, GST_FORMAT_TIME);
+-                  GST_DEBUG_OBJECT (demux, "new pending_newsegment");
+-                  demux->pending_newsegment = gst_event_new_segment (&segment);
+-                }
+-                qtdemux_expose_streams (demux);
+-              } else {
+-                for (n = 0; n < demux->n_streams; n++) {
+-                  QtDemuxStream *stream = demux->streams[n];
+-                  gst_qtdemux_configure_stream (demux, stream);
+-                }
++            /* in MSS we need to expose the pads after the first moof as we won't get a moov */
++            if (demux->mss_mode && !demux->exposed) {
++              if (!demux->pending_newsegment) {
++                GstSegment segment;
++                gst_segment_init (&segment, GST_FORMAT_TIME);
++                GST_DEBUG_OBJECT (demux, "new pending_newsegment");
++                demux->pending_newsegment = gst_event_new_segment (&segment);
+               }
+-              gst_qtdemux_check_send_pending_segment (demux);
+-              demux->pending_configure = FALSE;
++              qtdemux_expose_streams (demux);
+             }
+           } else {
+             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
+diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
+index 6061215..ecf0c63 100644
+--- a/gst/isomp4/qtdemux.h
++++ b/gst/isomp4/qtdemux.h
+@@ -89,7 +89,6 @@ struct _GstQTDemux {
+   gboolean posted_redirect;
+   /* push based variables */
+-  gboolean pending_configure;
+   guint neededbytes;
+   guint todrop;
+   GstAdapter *adapter;
+-- 
+2.8.0.rc3
+
diff --git a/Tools/efl/patches/gst-plugins-good-use-the-tfdt-decode-time.patch b/Tools/efl/patches/gst-plugins-good-use-the-tfdt-decode-time.patch
new file mode 100644 (file)
index 0000000..1e9dd97
--- /dev/null
@@ -0,0 +1,146 @@
+From 46d3e0faa922643094a5e46a32e4f82f774ae772 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Enrique=20Oca=C3=B1a=20Gonz=C3=A1lez?= <eocanha@igalia.com>
+Date: Tue, 10 Nov 2015 13:09:00 +0100
+Subject: [PATCH] Use the tfdt decode time when it's significantly different
+ than the time in the last sample if always-honor-tfdt is enabled
+
+https://bugzilla.gnome.org/show_bug.cgi?id=754230
+---
+ gst/isomp4/qtdemux.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ gst/isomp4/qtdemux.h |  1 +
+ 2 files changed, 73 insertions(+)
+
+diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
+index 880595e..d8b54f0 100644
+--- a/gst/isomp4/qtdemux.c
++++ b/gst/isomp4/qtdemux.c
+@@ -535,6 +535,11 @@ static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
+     const gchar * id);
+ static void qtdemux_gst_structure_free (GstStructure * gststructure);
++static void gst_qtdemux_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * spec);
++static void gst_qtdemux_get_property (GObject * object, guint prop_id,
++    GValue * value, GParamSpec * spec);
++
+ static void
+ gst_qtdemux_class_init (GstQTDemuxClass * klass)
+ {
+@@ -546,8 +551,21 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass)
+   parent_class = g_type_class_peek_parent (klass);
++  gobject_class->set_property = gst_qtdemux_set_property;
++  gobject_class->get_property = gst_qtdemux_get_property;
++
+   gobject_class->dispose = gst_qtdemux_dispose;
++ /**
++   * GstQtDemux::always-honor-tfdt:
++   *
++   * Requests the demuxer to respect what the TFDT atom says in order to produce presentation timestamps. Defaults to FALSE.
++   */
++  g_object_class_install_property (gobject_class, PROP_ALWAYS_HONOR_TFDT,
++      g_param_spec_boolean ("always-honor-tfdt", "Always honor TFDT",
++          "When enabled, TFDT atom will always be respected in order to produce presentation timestamps",
++          FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
++
+   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
+ #if 0
+   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
+@@ -611,6 +629,7 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
+   qtdemux->cenc_aux_info_sizes = NULL;
+   qtdemux->cenc_aux_sample_count = 0;
+   qtdemux->protection_system_ids = NULL;
++  qtdemux->always_honor_tfdt = FALSE;
+   g_queue_init (&qtdemux->protection_event_queue);
+   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+   qtdemux->flowcombiner = gst_flow_combiner_new ();
+@@ -639,6 +658,42 @@ gst_qtdemux_dispose (GObject * object)
+ }
+ static void
++gst_qtdemux_set_property (GObject * object, guint prop_id,
++    const GValue * value, GParamSpec * pspec)
++{
++  GstQTDemux *qtdemux = GST_QTDEMUX (object);
++
++  switch (prop_id) {
++    case PROP_ALWAYS_HONOR_TFDT:
++      GST_OBJECT_LOCK (qtdemux);
++      qtdemux->always_honor_tfdt = g_value_get_boolean (value);
++      GST_OBJECT_UNLOCK (qtdemux);
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++}
++
++static void
++gst_qtdemux_get_property (GObject * object, guint prop_id, GValue * value,
++    GParamSpec * pspec)
++{
++  GstQTDemux *qtdemux = GST_QTDEMUX (object);
++
++  switch (prop_id) {
++    case PROP_ALWAYS_HONOR_TFDT:
++      GST_OBJECT_LOCK (qtdemux);
++      g_value_set_boolean (value, qtdemux->always_honor_tfdt);
++      GST_OBJECT_UNLOCK (qtdemux);
++      break;
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++  }
++}
++
++static void
+ gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
+ {
+   if (qtdemux->posted_redirect) {
+@@ -2995,6 +3050,16 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
+           stream->samples[stream->n_samples - 1].timestamp +
+           stream->samples[stream->n_samples - 1].duration;
++      /* If we're always honoring TFDT and there's a significative difference
++       * between the decode_ts and the timestamp, prefer decode_ts */
++      if (qtdemux->always_honor_tfdt == TRUE
++          && abs (decode_ts - timestamp) >
++          stream->samples[stream->n_samples - 1].duration) {
++        GST_INFO_OBJECT (qtdemux,
++            "decode_ts is significantly different from timestamp, using decode_ts");
++        timestamp = decode_ts;
++      }
++
+       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
+       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
+           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
+diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
+index 53bd071..ecf0c63 100644
+--- a/gst/isomp4/qtdemux.h
++++ b/gst/isomp4/qtdemux.h
+@@ -154,12 +154,20 @@ struct _GstQTDemux {
+   guint8 *cenc_aux_info_sizes;
+   guint32 cenc_aux_sample_count;
++  gboolean always_honor_tfdt;
+ };
+ struct _GstQTDemuxClass {
+   GstElementClass parent_class;
+ };
++/* props */
++enum
++{
++  PROP_0,
++  PROP_ALWAYS_HONOR_TFDT
++};
++
+ GType gst_qtdemux_get_type (void);
+ G_END_DECLS
+-- 
+2.6.1
+
diff --git a/Tools/efl/patches/openwebrtc-gst-plugins-clang-warning-fix.patch b/Tools/efl/patches/openwebrtc-gst-plugins-clang-warning-fix.patch
new file mode 100644 (file)
index 0000000..a26ba7e
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/gst/videorepair/Makefile.am b/gst/videorepair/Makefile.am
+index 34487b5..34c3887 100644
+--- a/gst/videorepair/Makefile.am
++++ b/gst/videorepair/Makefile.am
+@@ -17,7 +17,7 @@ plugin_LTLIBRARIES = libgstvideorepair.la
+ libgstvideorepair_la_SOURCES = gstvideorepair.c
+ # compiler and linker flags used to compile this plugin, set in configure.ac
+-libgstvideorepair_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) -Wall -Wextra -Werror
++libgstvideorepair_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) -Wall -Wextra
+ libgstvideorepair_la_LIBADD = $(GST_LIBS) -lgstvideo-1.0
+ libgstvideorepair_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+ if !GST_PLUGIN_BUILD_STATIC