// Copyright 2010 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 CC_LAYER_H_
#define CC_LAYER_H_

#include <string>
#include <vector>

#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "cc/cc_export.h"
#include "cc/draw_properties.h"
#include "cc/layer_animation_controller.h"
#include "cc/layer_animation_event_observer.h"
#include "cc/layer_animation_value_observer.h"
#include "cc/occlusion_tracker.h"
#include "cc/region.h"
#include "cc/render_surface.h"
#include "skia/ext/refptr.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_f.h"
#include "ui/gfx/transform.h"

namespace WebKit {
class WebAnimationDelegate;
class WebLayerScrollClient;
}

namespace cc {

class Animation;
struct AnimationEvent;
class LayerAnimationDelegate;
class LayerImpl;
class LayerTreeHost;
class LayerTreeImpl;
class PriorityCalculator;
class ResourceUpdateQueue;
class ScrollbarLayer;
struct AnimationEvent;
struct RenderingStats;

// Base class for composited layers. Special layer types are derived from
// this class.
class CC_EXPORT Layer : public base::RefCounted<Layer>,
                        public LayerAnimationValueObserver {
public:
    typedef std::vector<scoped_refptr<Layer> > LayerList;

    static scoped_refptr<Layer> create();

    int id() const;

    Layer* rootLayer();
    Layer* parent() { return m_parent; }
    const Layer* parent() const { return m_parent; }
    void addChild(scoped_refptr<Layer>);
    void insertChild(scoped_refptr<Layer>, size_t index);
    void replaceChild(Layer* reference, scoped_refptr<Layer> newLayer);
    void removeFromParent();
    void removeAllChildren();
    void setChildren(const LayerList&);

    const LayerList& children() const { return m_children; }
    Layer* childAt(size_t index);

    void setAnchorPoint(const gfx::PointF&);
    gfx::PointF anchorPoint() const { return m_anchorPoint; }

    void setAnchorPointZ(float);
    float anchorPointZ() const { return m_anchorPointZ; }

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

    // A layer's bounds are in logical, non-page-scaled pixels (however, the
    // root layer's bounds are in physical pixels).
    void setBounds(const gfx::Size&);
    const gfx::Size& bounds() const { return m_bounds; }

    void setMasksToBounds(bool);
    bool masksToBounds() const { return m_masksToBounds; }

    void setMaskLayer(Layer*);
    Layer* maskLayer() { return m_maskLayer.get(); }
    const Layer* maskLayer() const { return m_maskLayer.get(); }

    virtual void setNeedsDisplayRect(const gfx::RectF& dirtyRect);
    void setNeedsDisplay() { setNeedsDisplayRect(gfx::RectF(gfx::PointF(), bounds())); }

    void setOpacity(float);
    float opacity() const;
    bool opacityIsAnimating() const;

    void setFilters(const WebKit::WebFilterOperations&);
    const WebKit::WebFilterOperations& filters() const { return m_filters; }

    void setFilter(const skia::RefPtr<SkImageFilter>& filter);
    skia::RefPtr<SkImageFilter> filter() const { return m_filter; }

    // Background filters are filters applied to what is behind this layer, when they are viewed through non-opaque
    // regions in this layer. They are used through the WebLayer interface, and are not exposed to HTML.
    void setBackgroundFilters(const WebKit::WebFilterOperations&);
    const WebKit::WebFilterOperations& backgroundFilters() const { return m_backgroundFilters; }

    virtual void setContentsOpaque(bool);
    bool contentsOpaque() const { return m_contentsOpaque; }

    void setPosition(const gfx::PointF&);
    gfx::PointF position() const { return m_position; }

    void setIsContainerForFixedPositionLayers(bool);
    bool isContainerForFixedPositionLayers() const { return m_isContainerForFixedPositionLayers; }

    void setFixedToContainerLayer(bool);
    bool fixedToContainerLayer() const { return m_fixedToContainerLayer; }

    void setSublayerTransform(const gfx::Transform&);
    const gfx::Transform& sublayerTransform() const { return m_sublayerTransform; }

    void setTransform(const gfx::Transform&);
    const gfx::Transform& transform() const;
    bool transformIsAnimating() const;

    DrawProperties<Layer, RenderSurface>& drawProperties() { return m_drawProperties; }
    const DrawProperties<Layer, RenderSurface>& drawProperties() const { return m_drawProperties; }

    // The following are shortcut accessors to get various information from m_drawProperties
    const gfx::Transform& drawTransform() const { return m_drawProperties.target_space_transform; }
    const gfx::Transform& screenSpaceTransform() const { return m_drawProperties.screen_space_transform; }
    float drawOpacity() const { return m_drawProperties.opacity; }
    bool drawOpacityIsAnimating() const { return m_drawProperties.opacity_is_animating; }
    bool drawTransformIsAnimating() const { return m_drawProperties.target_space_transform_is_animating; }
    bool screenSpaceTransformIsAnimating() const { return m_drawProperties.screen_space_transform_is_animating; }
    bool screenSpaceOpacityIsAnimating() const { return m_drawProperties.screen_space_opacity_is_animating; }
    bool canUseLCDText() const { return m_drawProperties.can_use_lcd_text; }
    bool isClipped() const { return m_drawProperties.is_clipped; }
    const gfx::Rect& clipRect() const { return m_drawProperties.clip_rect; }
    const gfx::Rect& drawableContentRect() const { return m_drawProperties.drawable_content_rect; }
    const gfx::Rect& visibleContentRect() const { return m_drawProperties.visible_content_rect; }
    Layer* renderTarget() { DCHECK(!m_drawProperties.render_target || m_drawProperties.render_target->renderSurface()); return m_drawProperties.render_target; }
    const Layer* renderTarget() const { DCHECK(!m_drawProperties.render_target || m_drawProperties.render_target->renderSurface()); return m_drawProperties.render_target; }
    RenderSurface* renderSurface() const { return m_drawProperties.render_surface.get(); }

    void setScrollOffset(gfx::Vector2d);
    gfx::Vector2d scrollOffset() const { return m_scrollOffset; }

    void setMaxScrollOffset(gfx::Vector2d);
    gfx::Vector2d maxScrollOffset() const { return m_maxScrollOffset; }

    void setScrollable(bool);
    bool scrollable() const { return m_scrollable; }

    void setShouldScrollOnMainThread(bool);
    bool shouldScrollOnMainThread() const { return m_shouldScrollOnMainThread; }

    void setHaveWheelEventHandlers(bool);
    bool haveWheelEventHandlers() const { return m_haveWheelEventHandlers; }

    void setNonFastScrollableRegion(const Region&);
    const Region& nonFastScrollableRegion() const { return m_nonFastScrollableRegion; }

    void setTouchEventHandlerRegion(const Region&);
    const Region& touchEventHandlerRegion() const { return m_touchEventHandlerRegion; }

    void setLayerScrollClient(WebKit::WebLayerScrollClient* layerScrollClient) { m_layerScrollClient = layerScrollClient; }

    void setDrawCheckerboardForMissingTiles(bool);
    bool drawCheckerboardForMissingTiles() const { return m_drawCheckerboardForMissingTiles; }

    bool forceRenderSurface() const { return m_forceRenderSurface; }
    void setForceRenderSurface(bool);

    gfx::Vector2d scrollDelta() const { return gfx::Vector2d(); }

    void setImplTransform(const gfx::Transform&);
    const gfx::Transform& implTransform() const { return m_implTransform; }

    void setDoubleSided(bool);
    bool doubleSided() const { return m_doubleSided; }

    void setPreserves3D(bool preserve3D) { m_preserves3D = preserve3D; }
    bool preserves3D() const { return m_preserves3D; }

    void setUseParentBackfaceVisibility(bool useParentBackfaceVisibility) { m_useParentBackfaceVisibility = useParentBackfaceVisibility; }
    bool useParentBackfaceVisibility() const { return m_useParentBackfaceVisibility; }

    virtual void setLayerTreeHost(LayerTreeHost*);

    bool hasDelegatedContent() const { return false; }
    bool hasContributingDelegatedRenderPasses() const { return false; }

    void setIsDrawable(bool);

    void setReplicaLayer(Layer*);
    Layer* replicaLayer() { return m_replicaLayer.get(); }
    const Layer* replicaLayer() const { return m_replicaLayer.get(); }

    bool hasMask() const { return !!m_maskLayer; }
    bool hasReplica() const { return !!m_replicaLayer; }
    bool replicaHasMask() const { return m_replicaLayer && (m_maskLayer || m_replicaLayer->m_maskLayer); }

    // These methods typically need to be overwritten by derived classes.
    virtual bool drawsContent() const;
    virtual void update(ResourceUpdateQueue&, const OcclusionTracker*, RenderingStats*) { }
    virtual bool needMoreUpdates();
    virtual void setIsMask(bool) { }

    void setDebugName(const std::string&);

    virtual void pushPropertiesTo(LayerImpl*);

    void clearRenderSurface() { m_drawProperties.render_surface.reset(); }
    void createRenderSurface();

    // The contentsScale converts from logical, non-page-scaled pixels to target pixels.
    // The contentsScale is 1 for the root layer as it is already in physical pixels.
    // By default contentsScale is forced to be 1 except for subclasses of ContentsScalingLayer.
    float contentsScaleX() const { return m_drawProperties.contents_scale_x; }
    float contentsScaleY() const { return m_drawProperties.contents_scale_y; }
    gfx::Size contentBounds() const { return m_drawProperties.content_bounds; }
    virtual void calculateContentsScale(
        float idealContentsScale,
        bool animatingTransformToScreen,
        float* contentsScaleX,
        float* contentsScaleY,
        gfx::Size* contentBounds);

    // The scale at which contents should be rastered, to match the scale at
    // which they will drawn to the screen. This scale is a component of the
    // contentsScale() but does not include page/device scale factors.
    float rasterScale() const { return m_rasterScale; }
    void setRasterScale(float scale);

    // When true, the rasterScale() will be set by the compositor. If false, it
    // will use whatever value is given to it by the embedder.
    bool automaticallyComputeRasterScale() { return m_automaticallyComputeRasterScale; }
    void setAutomaticallyComputeRasterScale(bool);

    void forceAutomaticRasterScaleToBeRecomputed();

    // When true, the layer's contents are not scaled by the current page scale factor.
    // setBoundsContainPageScale recursively sets the value on all child layers.
    void setBoundsContainPageScale(bool);
    bool boundsContainPageScale() const { return m_boundsContainPageScale; }

    LayerTreeHost* layerTreeHost() const { return m_layerTreeHost; }

    // Set the priority of all desired textures in this layer.
    virtual void setTexturePriorities(const PriorityCalculator&) { }

    bool AddAnimation(scoped_ptr<Animation>);
    void PauseAnimation(int animationId, double timeOffset);
    void RemoveAnimation(int animationId);

    void suspendAnimations(double monotonicTime);
    void resumeAnimations(double monotonicTime);

    LayerAnimationController* layerAnimationController() { return m_layerAnimationController.get(); }
    void setLayerAnimationController(scoped_refptr<LayerAnimationController>);
    scoped_refptr<LayerAnimationController> releaseLayerAnimationController();

    void setLayerAnimationDelegate(WebKit::WebAnimationDelegate* layerAnimationDelegate) { m_layerAnimationDelegate = layerAnimationDelegate; }

    bool hasActiveAnimation() const;

    virtual void notifyAnimationStarted(const AnimationEvent&, double wallClockTime);
    virtual void notifyAnimationFinished(double wallClockTime);
    virtual void notifyAnimationPropertyUpdate(const AnimationEvent& event);

    void addLayerAnimationEventObserver(LayerAnimationEventObserver* animationObserver);
    void removeLayerAnimationEventObserver(LayerAnimationEventObserver* animationObserver);

    virtual Region visibleContentOpaqueRegion() const;

    virtual ScrollbarLayer* toScrollbarLayer();

    gfx::Rect layerRectToContentRect(const gfx::RectF& layerRect) const;

    // In impl-side painting, this returns true if this layer type is not
    // compatible with the main thread running freely, such as a double-buffered
    // canvas that doesn't want to be triple-buffered across all three trees.
    virtual bool blocksPendingCommit() const;
    // Returns true if anything in this tree blocksPendingCommit.
    bool blocksPendingCommitRecursive() const;

    virtual bool canClipSelf() const;

    // Constructs a LayerImpl of the correct runtime type for this Layer type.
    virtual scoped_ptr<LayerImpl> createLayerImpl(LayerTreeImpl* treeImpl);

    bool needsDisplayForTesting() const { return m_needsDisplay; }
    void resetNeedsDisplayForTesting() { m_needsDisplay = false; }

protected:
    friend class LayerImpl;
    friend class TreeSynchronizer;
    virtual ~Layer();

    Layer();

    void setNeedsCommit();
    void setNeedsFullTreeSync();

    // This flag is set when layer need repainting/updating.
    bool m_needsDisplay;

    // Tracks whether this layer may have changed stacking order with its siblings.
    bool m_stackingOrderChanged;

    // The update rect is the region of the compositor resource that was actually updated by the compositor.
    // For layers that may do updating outside the compositor's control (i.e. plugin layers), this information
    // is not available and the update rect will remain empty.
    // Note this rect is in layer space (not content space).
    gfx::RectF m_updateRect;

    scoped_refptr<Layer> m_maskLayer;

    int m_layerId;

    // When true, the layer is about to perform an update. Any commit requests
    // will be handled implcitly after the update completes.
    bool m_ignoreSetNeedsCommit;

private:
    friend class base::RefCounted<Layer>;

    void setParent(Layer*);
    bool hasAncestor(Layer*) const;
    bool descendantIsFixedToContainerLayer() const;

    // Returns the index of the child or -1 if not found.
    int indexOfChild(const Layer*);

    // This should only be called from removeFromParent.
    void removeChildOrDependent(Layer*);

    // LayerAnimationValueObserver implementation.
    virtual void OnOpacityAnimated(float) OVERRIDE;
    virtual void OnTransformAnimated(const gfx::Transform&) OVERRIDE;
    virtual bool IsActive() const OVERRIDE;

    LayerList m_children;
    Layer* m_parent;

    // Layer instances have a weak pointer to their LayerTreeHost.
    // This pointer value is nil when a Layer is not in a tree and is
    // updated via setLayerTreeHost() if a layer moves between trees.
    LayerTreeHost* m_layerTreeHost;

    ObserverList<LayerAnimationEventObserver> m_layerAnimationObservers;

    scoped_refptr<LayerAnimationController> m_layerAnimationController;

    // Layer properties.
    gfx::Size m_bounds;

    gfx::Vector2d m_scrollOffset;
    gfx::Vector2d m_maxScrollOffset;
    bool m_scrollable;
    bool m_shouldScrollOnMainThread;
    bool m_haveWheelEventHandlers;
    Region m_nonFastScrollableRegion;
    Region m_touchEventHandlerRegion;
    gfx::PointF m_position;
    gfx::PointF m_anchorPoint;
    SkColor m_backgroundColor;
    std::string m_debugName;
    float m_opacity;
    skia::RefPtr<SkImageFilter> m_filter;
    WebKit::WebFilterOperations m_filters;
    WebKit::WebFilterOperations m_backgroundFilters;
    float m_anchorPointZ;
    bool m_isContainerForFixedPositionLayers;
    bool m_fixedToContainerLayer;
    bool m_isDrawable;
    bool m_masksToBounds;
    bool m_contentsOpaque;
    bool m_doubleSided;
    bool m_preserves3D;
    bool m_useParentBackfaceVisibility;
    bool m_drawCheckerboardForMissingTiles;
    bool m_forceRenderSurface;

    gfx::Transform m_transform;
    gfx::Transform m_sublayerTransform;

    // Replica layer used for reflections.
    scoped_refptr<Layer> m_replicaLayer;

    // Transient properties.
    float m_rasterScale;
    bool m_automaticallyComputeRasterScale;
    bool m_boundsContainPageScale;

    gfx::Transform m_implTransform;

    WebKit::WebAnimationDelegate* m_layerAnimationDelegate;
    WebKit::WebLayerScrollClient* m_layerScrollClient;

    DrawProperties<Layer, RenderSurface> m_drawProperties;
};

void sortLayers(std::vector<scoped_refptr<Layer> >::iterator, std::vector<scoped_refptr<Layer> >::iterator, void*);

}  // namespace cc

#endif  // CC_LAYER_H_