// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CCLayerTreeHostImpl_h
#define CCLayerTreeHostImpl_h

#include "CCAnimationEvents.h"
#include "CCInputHandler.h"
#include "CCLayerSorter.h"
#include "CCRenderPass.h"
#include "CCRenderPassSink.h"
#include "CCRenderer.h"
#include "SkColor.h"
#include "base/time.h"
#include <public/WebCompositorOutputSurfaceClient.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/RefPtr.h>

namespace cc {

class CCCompletionEvent;
class CCDebugRectHistory;
class CCFrameRateCounter;
class CCHeadsUpDisplayLayerImpl;
class CCLayerImpl;
class CCLayerTreeHostImplTimeSourceAdapter;
class CCPageScaleAnimation;
class CCRenderPassDrawQuad;
class CCResourceProvider;
struct RendererCapabilities;
struct CCRenderingStats;

// CCLayerTreeHost->CCProxy callback interface.
class CCLayerTreeHostImplClient {
public:
    virtual void didLoseContextOnImplThread() = 0;
    virtual void onSwapBuffersCompleteOnImplThread() = 0;
    virtual void onVSyncParametersChanged(double monotonicTimebase, double intervalInSeconds) = 0;
    virtual void onCanDrawStateChanged(bool canDraw) = 0;
    virtual void setNeedsRedrawOnImplThread() = 0;
    virtual void setNeedsCommitOnImplThread() = 0;
    virtual void postAnimationEventsToMainThreadOnImplThread(PassOwnPtr<CCAnimationEventsVector>, double wallClockTime) = 0;
    virtual void releaseContentsTexturesOnImplThread() = 0;
};

// CCLayerTreeHostImpl owns the CCLayerImpl tree as well as associated rendering state
class CCLayerTreeHostImpl : public CCInputHandlerClient,
                            public CCRendererClient,
                            public WebKit::WebCompositorOutputSurfaceClient {
    WTF_MAKE_NONCOPYABLE(CCLayerTreeHostImpl);
    typedef Vector<CCLayerImpl*> CCLayerList;

public:
    static PassOwnPtr<CCLayerTreeHostImpl> create(const CCLayerTreeSettings&, CCLayerTreeHostImplClient*);
    virtual ~CCLayerTreeHostImpl();

    // CCInputHandlerClient implementation
    virtual CCInputHandlerClient::ScrollStatus scrollBegin(const IntPoint&, CCInputHandlerClient::ScrollInputType) OVERRIDE;
    virtual void scrollBy(const IntPoint&, const IntSize&) OVERRIDE;
    virtual void scrollEnd() OVERRIDE;
    virtual void pinchGestureBegin() OVERRIDE;
    virtual void pinchGestureUpdate(float, const IntPoint&) OVERRIDE;
    virtual void pinchGestureEnd() OVERRIDE;
    virtual void startPageScaleAnimation(const IntSize& targetPosition, bool anchorPoint, float pageScale, double startTime, double duration) OVERRIDE;
    virtual void scheduleAnimation() OVERRIDE;

    struct FrameData : public CCRenderPassSink {
        FrameData();
        ~FrameData();

        Vector<IntRect> occludingScreenSpaceRects;
        CCRenderPassList renderPasses;
        CCRenderPassIdHashMap renderPassesById;
        CCLayerList* renderSurfaceLayerList;
        CCLayerList willDrawLayers;

        // CCRenderPassSink implementation.
        virtual void appendRenderPass(scoped_ptr<CCRenderPass>) OVERRIDE;
    };

    // Virtual for testing.
    virtual void beginCommit();
    virtual void commitComplete();
    virtual void animate(double monotonicTime, double wallClockTime);

    // Returns false if problems occured preparing the frame, and we should try
    // to avoid displaying the frame. If prepareToDraw is called,
    // didDrawAllLayers must also be called, regardless of whether drawLayers is
    // called between the two.
    virtual bool prepareToDraw(FrameData&);
    virtual void drawLayers(const FrameData&);
    // Must be called if and only if prepareToDraw was called.
    void didDrawAllLayers(const FrameData&);

    // CCRendererClient implementation
    virtual const IntSize& deviceViewportSize() const OVERRIDE;
    virtual const CCLayerTreeSettings& settings() const OVERRIDE;
    virtual void didLoseContext() OVERRIDE;
    virtual void onSwapBuffersComplete() OVERRIDE;
    virtual void setFullRootLayerDamage() OVERRIDE;
    virtual void releaseContentsTextures() OVERRIDE;
    virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE;

    // WebCompositorOutputSurfaceClient implementation.
    virtual void onVSyncParametersChanged(double monotonicTimebase, double intervalInSeconds) OVERRIDE;

    // Implementation
    bool canDraw();
    CCGraphicsContext* context() const;

    std::string layerTreeAsText() const;

    void finishAllRendering();
    int sourceAnimationFrameNumber() const;

    bool initializeRenderer(PassOwnPtr<CCGraphicsContext>);
    bool isContextLost();
    CCRenderer* renderer() { return m_renderer.get(); }
    const RendererCapabilities& rendererCapabilities() const;

    bool swapBuffers();

    void readback(void* pixels, const IntRect&);

    void setRootLayer(PassOwnPtr<CCLayerImpl>);
    CCLayerImpl* rootLayer() { return m_rootLayerImpl.get(); }

    void setHudLayer(CCHeadsUpDisplayLayerImpl* layerImpl) { m_hudLayerImpl = layerImpl; }
    CCHeadsUpDisplayLayerImpl* hudLayer() { return m_hudLayerImpl; }

    // Release ownership of the current layer tree and replace it with an empty
    // tree. Returns the root layer of the detached tree.
    PassOwnPtr<CCLayerImpl> detachLayerTree();

    CCLayerImpl* rootScrollLayer() const { return m_rootScrollLayerImpl; }

    bool visible() const { return m_visible; }
    void setVisible(bool);

    int sourceFrameNumber() const { return m_sourceFrameNumber; }
    void setSourceFrameNumber(int frameNumber) { m_sourceFrameNumber = frameNumber; }

    bool contentsTexturesPurged() const { return m_contentsTexturesPurged; }
    void setContentsTexturesPurged();
    void resetContentsTexturesPurged();
    size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes; }

    void setViewportSize(const IntSize& layoutViewportSize, const IntSize& deviceViewportSize);
    const IntSize& layoutViewportSize() const { return m_layoutViewportSize; }

    float deviceScaleFactor() const { return m_deviceScaleFactor; }
    void setDeviceScaleFactor(float);

    float pageScale() const { return m_pageScale; }
    void setPageScaleFactorAndLimits(float pageScale, float minPageScale, float maxPageScale);

    PassOwnPtr<CCScrollAndScaleSet> processScrollDeltas();

    void startPageScaleAnimation(const IntSize& tragetPosition, bool useAnchor, float scale, double durationSec);

    SkColor backgroundColor() const { return m_backgroundColor; }
    void setBackgroundColor(SkColor color) { m_backgroundColor = color; }

    bool hasTransparentBackground() const { return m_hasTransparentBackground; }
    void setHasTransparentBackground(bool transparent) { m_hasTransparentBackground = transparent; }

    bool needsAnimateLayers() const { return m_needsAnimateLayers; }
    void setNeedsAnimateLayers() { m_needsAnimateLayers = true; }

    void setNeedsRedraw();

    void renderingStats(CCRenderingStats&) const;

    CCFrameRateCounter* fpsCounter() const { return m_fpsCounter.get(); }
    CCDebugRectHistory* debugRectHistory() const { return m_debugRectHistory.get(); }
    CCResourceProvider* resourceProvider() const { return m_resourceProvider.get(); }

    class CullRenderPassesWithCachedTextures {
    public:
        bool shouldRemoveRenderPass(const CCRenderPassDrawQuad&, const FrameData&) const;

        // Iterates from the root first, in order to remove the surfaces closest
        // to the root with cached textures, and all surfaces that draw into
        // them.
        size_t renderPassListBegin(const CCRenderPassList& list) const { return list.size() - 1; }
        size_t renderPassListEnd(const CCRenderPassList&) const { return 0 - 1; }
        size_t renderPassListNext(size_t it) const { return it - 1; }

        CullRenderPassesWithCachedTextures(CCRenderer& renderer) : m_renderer(renderer) { }
    private:
        CCRenderer& m_renderer;
    };

    class CullRenderPassesWithNoQuads {
    public:
        bool shouldRemoveRenderPass(const CCRenderPassDrawQuad&, const FrameData&) const;

        // Iterates in draw order, so that when a surface is removed, and its
        // target becomes empty, then its target can be removed also.
        size_t renderPassListBegin(const CCRenderPassList&) const { return 0; }
        size_t renderPassListEnd(const CCRenderPassList& list) const { return list.size(); }
        size_t renderPassListNext(size_t it) const { return it + 1; }
    };

    template<typename RenderPassCuller>
    static void removeRenderPasses(RenderPassCuller, FrameData&);

protected:
    CCLayerTreeHostImpl(const CCLayerTreeSettings&, CCLayerTreeHostImplClient*);

    void animatePageScale(double monotonicTime);
    void animateScrollbars(double monotonicTime);

    // Exposed for testing.
    void calculateRenderSurfaceLayerList(CCLayerList&);

    // Virtual for testing.
    virtual void animateLayers(double monotonicTime, double wallClockTime);

    // Virtual for testing.
    virtual base::TimeDelta lowFrequencyAnimationInterval() const;

    CCLayerTreeHostImplClient* m_client;
    int m_sourceFrameNumber;

private:
    void computeDoubleTapZoomDeltas(CCScrollAndScaleSet* scrollInfo);
    void computePinchZoomDeltas(CCScrollAndScaleSet* scrollInfo);
    void makeScrollAndScaleSet(CCScrollAndScaleSet* scrollInfo, const IntSize& scrollOffset, float pageScale);

    void setPageScaleDelta(float);
    void updateMaxScrollPosition();
    void trackDamageForAllSurfaces(CCLayerImpl* rootDrawLayer, const CCLayerList& renderSurfaceLayerList);

    // Returns false if the frame should not be displayed. This function should
    // only be called from prepareToDraw, as didDrawAllLayers must be called
    // if this helper function is called.
    bool calculateRenderPasses(FrameData&);
    void animateLayersRecursive(CCLayerImpl*, double monotonicTime, double wallClockTime, CCAnimationEventsVector*, bool& didAnimate, bool& needsAnimateLayers);
    void setBackgroundTickingEnabled(bool);
    IntSize contentSize() const;

    void sendDidLoseContextRecursive(CCLayerImpl*);
    void clearRenderSurfaces();
    bool ensureRenderSurfaceLayerList();
    void clearCurrentlyScrollingLayer();

    void animateScrollbarsRecursive(CCLayerImpl*, double monotonicTime);

    void dumpRenderSurfaces(std::string*, int indent, const CCLayerImpl*) const;

    OwnPtr<CCGraphicsContext> m_context;
    OwnPtr<CCResourceProvider> m_resourceProvider;
    OwnPtr<CCRenderer> m_renderer;
    OwnPtr<CCLayerImpl> m_rootLayerImpl;
    CCLayerImpl* m_rootScrollLayerImpl;
    CCLayerImpl* m_currentlyScrollingLayerImpl;
    CCHeadsUpDisplayLayerImpl* m_hudLayerImpl;
    int m_scrollingLayerIdFromPreviousTree;
    bool m_scrollDeltaIsInScreenSpace;
    CCLayerTreeSettings m_settings;
    IntSize m_layoutViewportSize;
    IntSize m_deviceViewportSize;
    float m_deviceScaleFactor;
    bool m_visible;
    bool m_contentsTexturesPurged;
    size_t m_memoryAllocationLimitBytes;

    float m_pageScale;
    float m_pageScaleDelta;
    float m_sentPageScaleDelta;
    float m_minPageScale, m_maxPageScale;

    SkColor m_backgroundColor;
    bool m_hasTransparentBackground;

    // If this is true, it is necessary to traverse the layer tree ticking the animators.
    bool m_needsAnimateLayers;
    bool m_pinchGestureActive;
    IntPoint m_previousPinchAnchor;

    OwnPtr<CCPageScaleAnimation> m_pageScaleAnimation;

    // This is used for ticking animations slowly when hidden.
    OwnPtr<CCLayerTreeHostImplTimeSourceAdapter> m_timeSourceClientAdapter;

    CCLayerSorter m_layerSorter;

    // List of visible layers for the most recently prepared frame. Used for
    // rendering and input event hit testing.
    CCLayerList m_renderSurfaceLayerList;

    OwnPtr<CCFrameRateCounter> m_fpsCounter;
    OwnPtr<CCDebugRectHistory> m_debugRectHistory;
};

};

#endif