// Copyright 2012 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_TILES_PICTURE_LAYER_TILING_SET_H_
#define CC_TILES_PICTURE_LAYER_TILING_SET_H_

#include <stddef.h>

#include <list>
#include <set>
#include <vector>

#include "base/macros.h"
#include "cc/base/region.h"
#include "cc/tiles/picture_layer_tiling.h"
#include "ui/gfx/geometry/size.h"

namespace base {
namespace trace_event {
class TracedValue;
}
}

namespace cc {

class CC_EXPORT PictureLayerTilingSet {
 public:
  enum TilingRangeType {
    HIGHER_THAN_HIGH_RES,
    HIGH_RES,
    BETWEEN_HIGH_AND_LOW_RES,
    LOW_RES,
    LOWER_THAN_LOW_RES
  };
  struct TilingRange {
    TilingRange(size_t start, size_t end) : start(start), end(end) {}

    size_t start;
    size_t end;
  };

  static std::unique_ptr<PictureLayerTilingSet> Create(
      WhichTree tree,
      PictureLayerTilingClient* client,
      int tiling_interest_area_padding,
      float skewport_target_time_in_seconds,
      int skewport_extrapolation_limit_in_screen_pixels,
      float max_preraster_distance);

  ~PictureLayerTilingSet();

  const PictureLayerTilingClient* client() const { return client_; }

  void CleanUpTilings(float min_acceptable_high_res_scale_key,
                      float max_acceptable_high_res_scale_key,
                      const std::vector<PictureLayerTiling*>& needed_tilings,
                      PictureLayerTilingSet* twin_set);
  void RemoveNonIdealTilings();

  // This function is called on the active tree during activation.
  void UpdateTilingsToCurrentRasterSourceForActivation(
      scoped_refptr<RasterSource> raster_source,
      const PictureLayerTilingSet* pending_twin_set,
      const Region& layer_invalidation,
      float minimum_contents_scale_key,
      float maximum_contents_scale_key);

  // This function is called on the sync tree during commit.
  void UpdateTilingsToCurrentRasterSourceForCommit(
      scoped_refptr<RasterSource> raster_source,
      const Region& layer_invalidation,
      float minimum_contents_scale_key,
      float maximum_contents_scale_key);

  // This function is called on the sync tree right after commit.
  void UpdateRasterSourceDueToLCDChange(
      scoped_refptr<RasterSource> raster_source,
      const Region& layer_invalidation);

  PictureLayerTiling* AddTiling(float contents_scale_key,
                                scoped_refptr<RasterSource> raster_source);
  size_t num_tilings() const { return tilings_.size(); }
  int NumHighResTilings() const;
  PictureLayerTiling* tiling_at(size_t idx) { return tilings_[idx].get(); }
  const PictureLayerTiling* tiling_at(size_t idx) const {
    return tilings_[idx].get();
  }
  WhichTree tree() const { return tree_; }

  PictureLayerTiling* FindTilingWithScaleKey(float scale_key) const;
  PictureLayerTiling* FindTilingWithResolution(TileResolution resolution) const;

  void MarkAllTilingsNonIdeal();

  // If a tiling exists whose scale is within |snap_to_existing_tiling_ratio|
  // ratio of |start_scale|, then return that tiling's scale. Otherwise, return
  // |start_scale|. If multiple tilings match the criteria, return the one with
  // the least ratio to |start_scale|.
  float GetSnappedContentsScaleKey(float start_scale,
                                   float snap_to_existing_tiling_ratio) const;

  // Returns the maximum contents scale of all tilings, or 0 if no tilings
  // exist. Note that this returns the maximum of x and y scales depending on
  // the aspect ratio.
  float GetMaximumContentsScale() const;

  // Removes all tilings with a contents scale key < |minimum_scale_key|.
  void RemoveTilingsBelowScaleKey(float minimum_scale_key);

  // Removes all tilings with a contents scale key > |maximum_scale_key|.
  void RemoveTilingsAboveScaleKey(float maximum_scale);

  // Remove all tilings.
  void RemoveAllTilings();

  // Remove all tiles; keep all tilings.
  void RemoveAllTiles();

  // Update the rects and priorities for tiles based on the given information.
  // Returns true if PrepareTiles is required.
  bool UpdateTilePriorities(const gfx::Rect& required_rect_in_layer_space,
                            float ideal_contents_scale,
                            double current_frame_time_in_seconds,
                            const Occlusion& occlusion_in_layer_space,
                            bool can_require_tiles_for_activation);

  void SetAspectRatio(float ratio);
  float aspect_ratio() const { return aspect_ratio_; }

  void GetAllPrioritizedTilesForTracing(
      std::vector<PrioritizedTile>* prioritized_tiles) const;

  // For a given rect, iterates through tiles that can fill it.  If no
  // set of tiles with resources can fill the rect, then it will iterate
  // through null tiles with valid geometry_rect() until the rect is full.
  // If all tiles have resources, the union of all geometry_rects will
  // exactly fill rect with no overlap.
  class CC_EXPORT CoverageIterator {
   public:
    // |coverage_scale| is the scale at which we want to produce the coverage.
    // This is the scale at which |coverage_rect| is specified (relative to
    // identity).
    // |coverage_rect| is a rect that we want to cover during this iteration.
    // |ideal_contents_scale| is the ideal scale that we want, which determines
    // the order in which tilings are processed to get the best ("crispest")
    // coverage.
    CoverageIterator(const PictureLayerTilingSet* set,
                     float coverage_scale,
                     const gfx::Rect& coverage_rect,
                     float ideal_contents_scale);
    ~CoverageIterator();

    // Visible rect (no borders), in the space of |coverage_rect| (ie at
    // |coverage_scale| from identity). This is clipped to the coverage_rect.
    gfx::Rect geometry_rect() const;
    // A geometry_rect scaled to the tiling's contents scale, which represents
    // the texture rect in texels.
    gfx::RectF texture_rect() const;

    Tile* operator->() const;
    Tile* operator*() const;

    CoverageIterator& operator++();
    operator bool() const;

    TileResolution resolution() const;
    PictureLayerTiling* CurrentTiling() const;

   private:
    size_t NextTiling() const;

    const PictureLayerTilingSet* set_;
    float coverage_scale_;
    PictureLayerTiling::CoverageIterator tiling_iter_;
    size_t current_tiling_;
    size_t ideal_tiling_;

    Region current_region_;
    Region missing_region_;
    Region::Iterator region_iter_;
  };

  void AsValueInto(base::trace_event::TracedValue* array) const;
  size_t GPUMemoryUsageInBytes() const;

  TilingRange GetTilingRange(TilingRangeType type) const;

 protected:
  struct FrameVisibleRect {
    FrameVisibleRect(const gfx::Rect& rect, double time_in_seconds)
        : visible_rect_in_layer_space(rect),
          frame_time_in_seconds(time_in_seconds) {}

    gfx::Rect visible_rect_in_layer_space;
    double frame_time_in_seconds;
  };

  struct StateSinceLastTilePriorityUpdate {
    class AutoClear {
     public:
      explicit AutoClear(StateSinceLastTilePriorityUpdate* state_to_clear)
          : state_to_clear_(state_to_clear) {}
      ~AutoClear() { *state_to_clear_ = StateSinceLastTilePriorityUpdate(); }

     private:
      StateSinceLastTilePriorityUpdate* state_to_clear_;
    };

    StateSinceLastTilePriorityUpdate()
        : invalidated(false), added_tilings(false) {}

    bool invalidated;
    bool added_tilings;
  };

  explicit PictureLayerTilingSet(
      WhichTree tree,
      PictureLayerTilingClient* client,
      int tiling_interest_area_padding,
      float skewport_target_time_in_seconds,
      int skewport_extrapolation_limit_in_screen_pixels,
      float max_preraster_distance);

  void CopyTilingsAndPropertiesFromPendingTwin(
      const PictureLayerTilingSet* pending_twin_set,
      scoped_refptr<RasterSource> raster_source,
      const Region& layer_invalidation);

  // Remove one tiling.
  void Remove(PictureLayerTiling* tiling);
  void VerifyTilings(const PictureLayerTilingSet* pending_twin_set) const;

  bool TilingsNeedUpdate(const gfx::Rect& required_rect_in_layer_space,
                         double current_frame_time_in_Seconds);
  gfx::Rect ComputeSkewport(const gfx::Rect& visible_rect_in_layer_space,
                            double current_frame_time_in_seconds,
                            float ideal_contents_scale);
  gfx::Rect ComputeSoonBorderRect(const gfx::Rect& visible_rect_in_layer_space,
                                  float ideal_contents_scale);
  void UpdatePriorityRects(const gfx::Rect& visible_rect_in_layer_space,
                           double current_frame_time_in_seconds,
                           float ideal_contents_scale);

  std::vector<std::unique_ptr<PictureLayerTiling>> tilings_;

  const int tiling_interest_area_padding_;
  const float skewport_target_time_in_seconds_;
  const int skewport_extrapolation_limit_in_screen_pixels_;
  WhichTree tree_;
  PictureLayerTilingClient* client_;
  const float max_preraster_distance_;
  // State saved for computing velocities based on finite differences.
  // .front() of the list refers to the most recent FrameVisibleRect.
  std::list<FrameVisibleRect> visible_rect_history_;
  StateSinceLastTilePriorityUpdate state_since_last_tile_priority_update_;

  scoped_refptr<RasterSource> raster_source_;

  gfx::Rect visible_rect_in_layer_space_;
  gfx::Rect skewport_in_layer_space_;
  gfx::Rect soon_border_rect_in_layer_space_;
  gfx::Rect eventually_rect_in_layer_space_;

  float aspect_ratio_ = 1.f;

  friend class Iterator;

 private:
  DISALLOW_COPY_AND_ASSIGN(PictureLayerTilingSet);
};

}  // namespace cc

#endif  // CC_TILES_PICTURE_LAYER_TILING_SET_H_
