// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Display backend interface.
 * Copyright (C) 2022 PBS <pbs3141@gmail.com>
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#ifndef INKSCAPE_UI_WIDGET_CANVAS_GRAPHICS_H
#define INKSCAPE_UI_WIDGET_CANVAS_GRAPHICS_H

#include <memory>
#include <cstdint>
#include <boost/noncopyable.hpp>
#include <2geom/rect.h>
#include <cairomm/cairomm.h>
#include "display/rendermode.h"
#include "fragment.h"

namespace Inkscape {
namespace UI {
namespace Widget {
class Stores;
class Prefs;

struct PageInfo
{
    std::vector<Geom::Rect> pages;
};

class Graphics
{
public:
    // Creation/destruction.
    static std::unique_ptr<Graphics> create_gl   (Prefs const &prefs, Stores const &stores, PageInfo const &pi);
    static std::unique_ptr<Graphics> create_cairo(Prefs const &prefs, Stores const &stores, PageInfo const &pi);
    virtual ~Graphics() = default;

    // State updating.
    virtual void set_scale_factor(int) = 0; ///< Set the HiDPI scale factor.
    virtual void set_outlines_enabled(bool) = 0; ///< Whether to maintain a second layer of outline content.
    virtual void set_background_in_stores(bool) = 0; ///< Whether to assume the first layer is drawn on top of background or transparency.
    virtual void set_colours(uint32_t page, uint32_t desk, uint32_t border) = 0; ///< Set colours for background/page shadow drawing.

    // Store manipulation.
    virtual void recreate_store(Geom::IntPoint const &dims) = 0; ///< Set the store to a surface of the given size, of unspecified contents.
    virtual void shift_store(Fragment const &dest) = 0; ///< Called when the store fragment shifts position to \a dest.
    virtual void swap_stores() = 0; ///< Exchange the store and snapshot surfaces.
    virtual void fast_snapshot_combine() = 0; ///< Paste the store onto the snapshot.
    virtual void snapshot_combine(Fragment const &dest) = 0; ///< Paste the snapshot followed by the store onto a new snapshot at \a dest.
    virtual void invalidate_snapshot() = 0; ///< Indicate that the content in the snapshot store is not going to be used again.

    // Misc.
    virtual bool is_opengl() const = 0; ///< Whether this is an OpenGL backend.
    virtual void invalidated_glstate() = 0; ///< Tells the Graphics to no longer rely on any OpenGL state it had set up.

    // Tile drawing.
    /// Return a surface for drawing on. If nogl is true, no GL commands are issued, as is a requirement off-main-thread. All such surfaces must be
    /// returned by passing them either to draw_tile() or junk_tile_surface().
    virtual Cairo::RefPtr<Cairo::ImageSurface> request_tile_surface(Geom::IntRect const &rect, bool nogl) = 0;
    /// Commit the contents of a surface previously issued by request_tile_surface() to the canvas. In outline mode, a second surface must be passed
    /// containing the outline content, otherwise it should be null.
    virtual void draw_tile(Fragment const &fragment, Cairo::RefPtr<Cairo::ImageSurface> surface, Cairo::RefPtr<Cairo::ImageSurface> outline_surface) = 0;
    /// Get rid of a surface previously issued by request_tile_surface() without committing it to the canvas. Usually useful only to dispose of
    /// surfaces which have gone into an error state while rendering, which is irreversible, and therefore we can't do anything useful with them.
    virtual void junk_tile_surface(Cairo::RefPtr<Cairo::ImageSurface> surface) = 0;

    // Widget painting.
    struct PaintArgs
    {
        std::optional<Geom::IntPoint> mouse;
        RenderMode render_mode;
        SplitMode splitmode;
        Geom::Point splitfrac;
        SplitDirection splitdir;
        SplitDirection hoverdir;
        double yaxisdir;
    };
    virtual void paint_widget(Fragment const &view, PaintArgs const &args, Cairo::RefPtr<Cairo::Context> const &cr) = 0;

    // Static functions providing common functionality.
    static bool check_single_page(Fragment const &view, PageInfo const &pi);
    static std::pair<Geom::IntRect, Geom::IntRect> calc_splitview_cliprects(Geom::IntPoint const &size, Geom::Point const &splitfrac, SplitDirection splitdir);
    static void paint_splitview_controller(Geom::IntPoint const &size, Geom::Point const &splitfrac, SplitDirection splitdir, SplitDirection hoverdir, Cairo::RefPtr<Cairo::Context> const &cr);
    static void paint_background(Fragment const &fragment, PageInfo const &pi, uint32_t page, uint32_t desk, Cairo::RefPtr<Cairo::Context> const &cr);
};

} // namespace Widget
} // namespace UI
} // namespace Inkscape

#endif // INKSCAPE_UI_WIDGET_CANVAS_GRAPHICS_H
