/*
 * Copyright (C) 2012-2016 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. ``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
 * 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 "AcceleratedSurfaceX11.h"

#if PLATFORM(X11)

#include "WebPage.h"
#include <WebCore/PlatformDisplayX11.h>
#include <WebCore/RefPtrCairo.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xcomposite.h>
#include <cairo-xlib.h>
#if USE(GTK4)
#include <gdk/x11/gdkx.h>
#else
#include <gdk/gdkx.h>
#endif
#include <wtf/RunLoop.h>

namespace WebKit {
using namespace WebCore;

std::unique_ptr<AcceleratedSurfaceX11> AcceleratedSurfaceX11::create(WebPage& webPage, Client& client)
{
    if (!downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).supportsXComposite())
        return nullptr;
    return std::unique_ptr<AcceleratedSurfaceX11>(new AcceleratedSurfaceX11(webPage, client));
}

#if !USE(GTK4)
static GdkVisual* defaultVisual()
{
    if (GdkVisual* visual = gdk_screen_get_rgba_visual(gdk_screen_get_default()))
        return visual;
    return gdk_screen_get_system_visual(gdk_screen_get_default());
}
#endif

AcceleratedSurfaceX11::AcceleratedSurfaceX11(WebPage& webPage, Client& client)
    : AcceleratedSurface(webPage, client)
    , m_display(downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native())
{
    Screen* screen = DefaultScreenOfDisplay(m_display);

    ASSERT(downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native() == m_display);

#if USE(GTK4)
    auto* visual = WK_XVISUAL(downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()));
#else
    auto* visual = GDK_VISUAL_XVISUAL(defaultVisual());
#endif
    XUniqueColormap colormap(XCreateColormap(m_display, RootWindowOfScreen(screen), visual, AllocNone));

    int depth = visual == screen->root_visual ? screen->root_depth : 32;

    XSetWindowAttributes windowAttributes;
    windowAttributes.override_redirect = True;
    windowAttributes.colormap = colormap.get();

    // CWBorderPixel must be present when the depth doesn't match the parent's one.
    // See http://cgit.freedesktop.org/xorg/xserver/tree/dix/window.c?id=xorg-server-1.16.0#n703.
    windowAttributes.border_pixel = 0;

    m_parentWindow = XCreateWindow(m_display,
        RootWindowOfScreen(screen),
        -1, -1, 1, 1,
        0,
        depth,
        InputOutput,
        visual,
        CWOverrideRedirect | CWColormap | CWBorderPixel,
        &windowAttributes);
    XMapWindow(m_display, m_parentWindow.get());

    windowAttributes.event_mask = StructureNotifyMask;
    windowAttributes.override_redirect = False;

    // Create the window of at last 1x1 since X doesn't allow to create empty windows.
    m_window = XCreateWindow(m_display,
        m_parentWindow.get(),
        0, 0,
        std::max(1, m_size.width()),
        std::max(1, m_size.height()),
        0,
        CopyFromParent,
        InputOutput,
        CopyFromParent,
        CWEventMask,
        &windowAttributes);
    XMapWindow(m_display, m_window.get());

    while (1) {
        XEvent event;
        XWindowEvent(m_display, m_window.get(), StructureNotifyMask, &event);
        if (event.type == MapNotify && event.xmap.window == m_window.get())
            break;
    }
    XSelectInput(m_display, m_window.get(), NoEventMask);
    XCompositeRedirectWindow(m_display, m_window.get(), CompositeRedirectManual);
    createPixmap();
}

AcceleratedSurfaceX11::~AcceleratedSurfaceX11()
{
    ASSERT(m_display);
    ASSERT(m_window);
    ASSERT(m_parentWindow);

    // Explicitly reset these because we need to ensure it happens in this order.
    m_window.reset();
    m_parentWindow.reset();
}

void AcceleratedSurfaceX11::createPixmap()
{
    m_pixmap = XCompositeNameWindowPixmap(m_display, m_window.get());
#if USE(GTK4)
    auto* visual = WK_XVISUAL(downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()));
#else
    auto* visual = GDK_VISUAL_XVISUAL(defaultVisual());
#endif
    RefPtr<cairo_surface_t> surface = adoptRef(cairo_xlib_surface_create(m_display, m_pixmap.get(), visual, m_size.width(), m_size.height()));
    RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get()));
    cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR);
    cairo_paint(cr.get());
    XSync(m_display, False);
}

bool AcceleratedSurfaceX11::hostResize(const IntSize& size)
{
    if (!AcceleratedSurface::hostResize(size))
        return false;

    // Resize the window to at last 1x1 since X doesn't allow to create empty windows.
    XResizeWindow(m_display, m_window.get(), std::max(1, m_size.width()), std::max(1, m_size.height()));
    XFlush(m_display);

    // Release the previous pixmap later to give some time to the UI process to update.
    RunLoop::main().dispatchAfter(5_s, [pixmap = WTFMove(m_pixmap)] { });
    createPixmap();
    return true;
}

void AcceleratedSurfaceX11::didRenderFrame()
{
    // FIXME: frameComplete() should be called when the frame was actually rendered in the screen.
    m_client.frameComplete();
}

} // namespace WebKit

#endif // PLATFORM(X11)
