| // Copyright 2014 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_PAINT_DISPLAY_ITEM_LIST_H_ | 
 | #define CC_PAINT_DISPLAY_ITEM_LIST_H_ | 
 |  | 
 | #include <cstddef> | 
 | #include <memory> | 
 | #include <string> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include "base/gtest_prod_util.h" | 
 | #include "base/memory/ref_counted.h" | 
 | #include "base/trace_event/trace_event.h" | 
 | #include "cc/base/rtree.h" | 
 | #include "cc/paint/discardable_image_map.h" | 
 | #include "cc/paint/image_id.h" | 
 | #include "cc/paint/paint_export.h" | 
 | #include "cc/paint/paint_op_buffer.h" | 
 | #include "third_party/skia/include/core/SkPicture.h" | 
 | #include "ui/gfx/color_space.h" | 
 | #include "ui/gfx/geometry/rect.h" | 
 | #include "ui/gfx/geometry/rect_conversions.h" | 
 |  | 
 | class SkCanvas; | 
 |  | 
 | namespace gpu { | 
 | namespace raster { | 
 | class RasterImplementation; | 
 | class RasterImplementationGLES; | 
 | }  // namespace raster | 
 | }  // namespace gpu | 
 |  | 
 | namespace base { | 
 | namespace trace_event { | 
 | class TracedValue; | 
 | } | 
 | } | 
 |  | 
 | namespace cc { | 
 |  | 
 | // DisplayItemList is a container of paint operations. One can populate the list | 
 | // using StartPaint, followed by push{,_with_data,_with_array} functions | 
 | // specialized with ops coming from paint_op_buffer.h. Internally, the | 
 | // DisplayItemList contains a PaintOpBuffer and defers op saving to it. | 
 | // Additionally, it store some meta information about the paint operations. | 
 | // Specifically, it creates an rtree to assist in rasterization: when | 
 | // rasterizing a rect, it queries the rtree to extract only the byte offsets of | 
 | // the ops required and replays those into a canvas. | 
 | class CC_PAINT_EXPORT DisplayItemList | 
 |     : public base::RefCountedThreadSafe<DisplayItemList> { | 
 |  public: | 
 |   // TODO(vmpstr): It would be cool if we didn't need this, and instead used | 
 |   // PaintOpBuffer directly when we needed to release this as a paint op buffer. | 
 |   enum UsageHint { kTopLevelDisplayItemList, kToBeReleasedAsPaintOpBuffer }; | 
 |  | 
 |   explicit DisplayItemList(UsageHint = kTopLevelDisplayItemList); | 
 |   DisplayItemList(const DisplayItemList&) = delete; | 
 |   DisplayItemList& operator=(const DisplayItemList&) = delete; | 
 |  | 
 |   void Raster(SkCanvas* canvas, ImageProvider* image_provider = nullptr) const; | 
 |  | 
 |   // Captures |DrawTextBlobOp|s intersecting |rect| and returns the associated | 
 |   // |NodeId|s in |content|. | 
 |   void CaptureContent(const gfx::Rect& rect, | 
 |                       std::vector<NodeInfo>* content) const; | 
 |  | 
 |   // Returns the approximate total area covered by |DrawTextBlobOp|s | 
 |   // intersecting |rect|, used for statistics purpose. | 
 |   double AreaOfDrawText(const gfx::Rect& rect) const; | 
 |  | 
 |   void StartPaint() { | 
 | #if DCHECK_IS_ON() | 
 |     DCHECK(!IsPainting()); | 
 |     current_range_start_ = paint_op_buffer_.size(); | 
 | #endif | 
 |   } | 
 |  | 
 |   // Push functions construct a new op on the paint op buffer, while maintaining | 
 |   // bookkeeping information. Must be called after invoking StartPaint(). | 
 |   // Returns the id (which is an opaque value) of the operation that can be used | 
 |   // in UpdateSaveLayerBounds(). | 
 |   template <typename T, typename... Args> | 
 |   size_t push(Args&&... args) { | 
 | #if DCHECK_IS_ON() | 
 |     DCHECK(IsPainting()); | 
 | #endif | 
 |     size_t offset = paint_op_buffer_.next_op_offset(); | 
 |     if (usage_hint_ == kTopLevelDisplayItemList) | 
 |       offsets_.push_back(offset); | 
 |     const T* op = paint_op_buffer_.push<T>(std::forward<Args>(args)...); | 
 |     DCHECK(op->IsValid()); | 
 |     return offset; | 
 |   } | 
 |  | 
 |   // Called by blink::PaintChunksToCcLayer when an effect ends, to update the | 
 |   // bounds of a SaveLayer[Alpha]Op which was emitted when the effect started. | 
 |   // This is needed because blink doesn't know the bounds when an effect starts. | 
 |   // Don't add other mutation methods like this if there is better alternative. | 
 |   void UpdateSaveLayerBounds(size_t id, const SkRect& bounds) { | 
 |     paint_op_buffer_.UpdateSaveLayerBounds(id, bounds); | 
 |   } | 
 |  | 
 |   void EndPaintOfUnpaired(const gfx::Rect& visual_rect) { | 
 | #if DCHECK_IS_ON() | 
 |     DCHECK(IsPainting()); | 
 |     current_range_start_ = kNotPainting; | 
 | #endif | 
 |     if (usage_hint_ == kToBeReleasedAsPaintOpBuffer) | 
 |       return; | 
 |  | 
 |     visual_rects_.resize(paint_op_buffer_.size(), visual_rect); | 
 |     GrowCurrentBeginItemVisualRect(visual_rect); | 
 |   } | 
 |  | 
 |   void EndPaintOfPairedBegin() { | 
 | #if DCHECK_IS_ON() | 
 |     DCHECK(IsPainting()); | 
 |     DCHECK_LT(current_range_start_, paint_op_buffer_.size()); | 
 |     current_range_start_ = kNotPainting; | 
 | #endif | 
 |     if (usage_hint_ == kToBeReleasedAsPaintOpBuffer) | 
 |       return; | 
 |  | 
 |     DCHECK_LT(visual_rects_.size(), paint_op_buffer_.size()); | 
 |     size_t count = paint_op_buffer_.size() - visual_rects_.size(); | 
 |     paired_begin_stack_.push_back({visual_rects_.size(), count}); | 
 |     visual_rects_.resize(paint_op_buffer_.size()); | 
 |   } | 
 |  | 
 |   void EndPaintOfPairedEnd(); | 
 |  | 
 |   // Called after all items are appended, to process the items. | 
 |   void Finalize(); | 
 |  | 
 |   struct DirectlyCompositedImageResult { | 
 |     gfx::Size intrinsic_image_size; | 
 |     bool nearest_neighbor; | 
 |   }; | 
 |  | 
 |   // If this list represents an image that should be directly composited (i.e. | 
 |   // rasterized at the intrinsic size of the image), return the intrinsic size | 
 |   // of the image and whether or not to use nearest neighbor filtering when | 
 |   // scaling the layer. | 
 |   base::Optional<DirectlyCompositedImageResult> | 
 |   GetDirectlyCompositedImageResult(gfx::Size containing_layer_bounds) const; | 
 |  | 
 |   int NumSlowPaths() const { return paint_op_buffer_.numSlowPaths(); } | 
 |   bool HasNonAAPaint() const { return paint_op_buffer_.HasNonAAPaint(); } | 
 |  | 
 |   // This gives the total number of PaintOps. | 
 |   size_t TotalOpCount() const { return paint_op_buffer_.total_op_count(); } | 
 |   size_t BytesUsed() const; | 
 |  | 
 |   const DiscardableImageMap& discardable_image_map() const { | 
 |     return image_map_; | 
 |   } | 
 |   base::flat_map<PaintImage::Id, PaintImage::DecodingMode> | 
 |   TakeDecodingModeMap() { | 
 |     return image_map_.TakeDecodingModeMap(); | 
 |   } | 
 |  | 
 |   void EmitTraceSnapshot() const; | 
 |   void GenerateDiscardableImagesMetadata(); | 
 |  | 
 |   gfx::Rect VisualRectForTesting(int index) { return visual_rects_[index]; } | 
 |  | 
 |   // Generate a PaintRecord from this DisplayItemList, leaving |this| in | 
 |   // an empty state. | 
 |   sk_sp<PaintRecord> ReleaseAsRecord(); | 
 |  | 
 |   // If a rectangle is solid color, returns that color. |max_ops_to_analyze| | 
 |   // indicates the maximum number of draw ops we consider when determining if a | 
 |   // rectangle is solid color. | 
 |   bool GetColorIfSolidInRect(const gfx::Rect& rect, | 
 |                              SkColor* color, | 
 |                              int max_ops_to_analyze = 1); | 
 |  | 
 |   std::string ToString() const; | 
 |  | 
 |   bool has_draw_ops() const { return paint_op_buffer_.has_draw_ops(); } | 
 |   bool has_draw_text_ops() const { | 
 |     return paint_op_buffer_.has_draw_text_ops(); | 
 |   } | 
 |  | 
 |   // Ops with nested paint ops are considered as a single op. | 
 |   size_t num_paint_ops() const { return paint_op_buffer_.size(); } | 
 |  | 
 |   bool NeedsAdditionalInvalidationForLCDText( | 
 |       const DisplayItemList& old_list) const { | 
 |     return paint_op_buffer_.NeedsAdditionalInvalidationForLCDText( | 
 |         old_list.paint_op_buffer_); | 
 |   } | 
 |  | 
 |  private: | 
 |   friend class DisplayItemListTest; | 
 |   friend gpu::raster::RasterImplementation; | 
 |   friend gpu::raster::RasterImplementationGLES; | 
 |  | 
 |   ~DisplayItemList(); | 
 |  | 
 |   void Reset(); | 
 |  | 
 |   std::unique_ptr<base::trace_event::TracedValue> CreateTracedValue( | 
 |       bool include_items) const; | 
 |   void AddToValue(base::trace_event::TracedValue*, bool include_items) const; | 
 |  | 
 |   // If we're currently within a paired display item block, unions the | 
 |   // given visual rect with the begin display item's visual rect. | 
 |   void GrowCurrentBeginItemVisualRect(const gfx::Rect& visual_rect) { | 
 |     DCHECK_EQ(usage_hint_, kTopLevelDisplayItemList); | 
 |     if (!paired_begin_stack_.empty()) | 
 |       visual_rects_[paired_begin_stack_.back().first_index].Union(visual_rect); | 
 |   } | 
 |  | 
 |   // RTree stores indices into the paint op buffer. | 
 |   // TODO(vmpstr): Update the rtree to store offsets instead. | 
 |   RTree<size_t> rtree_; | 
 |   DiscardableImageMap image_map_; | 
 |   PaintOpBuffer paint_op_buffer_; | 
 |  | 
 |   // The visual rects associated with each of the display items in the | 
 |   // display item list. These rects are intentionally kept separate because they | 
 |   // are used to decide which ops to walk for raster. | 
 |   std::vector<gfx::Rect> visual_rects_; | 
 |   // Byte offsets associated with each of the ops. | 
 |   std::vector<size_t> offsets_; | 
 |   // A stack of paired begin sequences that haven't been closed. | 
 |   struct PairedBeginInfo { | 
 |     // Index (into virual_rects_ and offsets_) of the first operation in the | 
 |     // paired begin sequence. | 
 |     size_t first_index; | 
 |     // Number of operations in the paired begin sequence. | 
 |     size_t count; | 
 |   }; | 
 |   std::vector<PairedBeginInfo> paired_begin_stack_; | 
 |  | 
 | #if DCHECK_IS_ON() | 
 |   // While recording a range of ops, this is the position in the PaintOpBuffer | 
 |   // where the recording started. | 
 |   bool IsPainting() const { return current_range_start_ != kNotPainting; } | 
 |   const size_t kNotPainting = static_cast<size_t>(-1); | 
 |   size_t current_range_start_ = kNotPainting; | 
 | #endif | 
 |  | 
 |   UsageHint usage_hint_; | 
 |  | 
 |   friend class base::RefCountedThreadSafe<DisplayItemList>; | 
 |   FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, BytesUsed); | 
 | }; | 
 |  | 
 | }  // namespace cc | 
 |  | 
 | #endif  // CC_PAINT_DISPLAY_ITEM_LIST_H_ |