/*
 * Copyright (C) Research In Motion Limited 2009-2010. 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 library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifndef SurfaceOpenVG_h
#define SurfaceOpenVG_h

#include "IntSize.h"

#if USE(ACCELERATED_COMPOSITING)
#include "PlatformLayer.h"
#endif

#include <openvg.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>

struct EspialTexture;
struct EspialSurface;

namespace WebCore {

class PainterOpenVG;
class IntSize;
class TiledImageOpenVG;

/**
 * SurfaceOpenVG provides the functionality of surfaces and contexts that are
 * underlying the OpenVG implementation. In the vast majority of cases, that
 * underlying technology is EGL, but OpenVG doesn't depend on EGL per se.
 * Wrapping surface/context functionality into a separate class avoids lots
 * of #ifdefs and should make it easy to add different surface/context
 * implementations than EGL.
 */
class SurfaceOpenVG
#if USE(ACCELERATED_COMPOSITING)
: public PlatformLayer
#endif
{
    WTF_MAKE_NONCOPYABLE(SurfaceOpenVG); WTF_MAKE_FAST_ALLOCATED;
public:
    enum MakeCurrentMode {
        ApplyPainterStateOnSurfaceSwitch,
        DontApplyPainterState,
        DontSaveOrApplyPainterState
    };

    static SurfaceOpenVG* currentSurface();

    ~SurfaceOpenVG();

    /**
     * Create a new surface backed by a VGImage of the given size and format.
     */
    SurfaceOpenVG(const IntSize& size, VGImageFormat format = VG_sARGB_8888_PRE, bool accelerated = false);

    /**
     * Create a new surface that wraps the given EspialSurface. This does not
     * take ownership over the EspialSurface.
     */
    SurfaceOpenVG(EspialSurface* espialSurface);


    /**
     * If a surface is invalid (could not be created), all method calls will
     * crash horribly.
     */
    bool isValid() const;

    int width() const {return m_size.width();}
    int height() const {return m_size.height();}

    /**
     * Make a surface/context combination current that is "compatible"
     * (i.e. can access its shared resources) to the given one. If no
     * surface/context is current, the given one is made current.
     *
     * This method is meant to avoid context changes if they're not
     * necessary, particularly tailored for the case where something
     * compatible to the shared surface is requested while actual painting
     * happens on another surface.
     */
    static void makeCompatibleCurrent();

    /**
     * Empty the OpenVG pipeline and make sure all the performed paint
     * operations show up on the surface as actual drawn pixels.
     */
    void flush();

    void setActivePainter(PainterOpenVG*);

    PainterOpenVG* activePainter() { return m_activePainter; }

    /**
     * Returns the VGImage backing this surface, if any.
     */
    VGImage image() const { return m_image; }

    /**
     * Returns the TiledImageOpenVG backing this surface, if any.
     */
    TiledImageOpenVG* tiledImage() { return m_tiledImage; }

    /**
     * Releases the TiledImageOpenVG backing this surface, if any.
     */
    TiledImageOpenVG* releaseTiledImage() {
        TiledImageOpenVG* image = m_tiledImage;
        m_tiledImage = NULL;
        return image;
    }

#if USE(ACCELERATED_COMPOSITING)
    bool isAccelerated() {return m_espialTexture != NULL;}
    virtual uint32_t glTexture();
    virtual uint32_t webglTexture();
    virtual bool flipped();
#endif

    EspialSurface* espialSurface();

private:

    bool init(EspialSurface* espialSurface);

    PainterOpenVG* m_activePainter;
    static PainterOpenVG* s_currentPainter; // global currently active painter
    IntSize m_size; // cached so we don't need to fetch it from EGL

    // image backing
    VGImage m_image;
    TiledImageOpenVG* m_tiledImage;

#if USE(ACCELERATED_COMPOSITING)
    EspialTexture* m_espialTexture;
#endif
    EspialSurface* m_espialSurface;

    bool owned; // whether we own the espial surface, or we are just a wrapper to it
};

}

#endif
