#ifndef CC_PAINT_DISPLAY_ITEM_LIST_H_
#define CC_PAINT_DISPLAY_ITEM_LIST_H_
#include <cstddef>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/ref_counted.h"
#include "cc/base/rtree.h"
#include "cc/paint/directly_composited_image_info.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.h"
#include "cc/paint/paint_op_buffer.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
class SkCanvas;
namespace base::trace_event {
class TracedValue;
}
namespace cc {
class CC_PAINT_EXPORT DisplayItemList
: public base::RefCountedThreadSafe<DisplayItemList> {
public:
DisplayItemList();
DisplayItemList(const DisplayItemList&) = delete;
DisplayItemList& operator=(const DisplayItemList&) = delete;
void Raster(
SkCanvas* canvas,
ImageProvider* image_provider = nullptr,
const ScrollOffsetMap* raster_inducing_scroll_offsets = nullptr) const;
void Raster(SkCanvas* canvas, const PlaybackParams& params) const;
std::vector<size_t> OffsetsOfOpsToRaster(SkCanvas* canvas) const;
void CaptureContent(const gfx::Rect& rect,
std::vector<NodeInfo>* content) const;
double AreaOfDrawText(const gfx::Rect& rect) const;
void StartPaint() {
#if DCHECK_IS_ON()
DCHECK(!IsPainting());
current_range_start_ = paint_op_buffer_.size();
#endif
}
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();
offsets_.push_back(offset);
const T& op = paint_op_buffer_.push<T>(std::forward<Args>(args)...);
DCHECK(op.IsValid());
return offset;
}
void PushDrawScrollingContentsOp(
ElementId scroll_element_id,
scoped_refptr<DisplayItemList> display_item_list,
const gfx::Rect& visual_rect);
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
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
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();
void Finalize();
PaintRecord FinalizeAndReleaseAsRecordForTesting();
const PaintOpBuffer& paint_op_buffer() const { return paint_op_buffer_; }
void SearchOpsByRect(const gfx::Rect& query,
std::vector<size_t>* op_indices) const {
return rtree_.Search(query, op_indices);
}
std::optional<DirectlyCompositedImageInfo> GetDirectlyCompositedImageInfo()
const;
int num_slow_paths_up_to_min_for_MSAA() const {
return paint_op_buffer_.num_slow_paths_up_to_min_for_MSAA();
}
bool has_non_aa_paint() const { return paint_op_buffer_.has_non_aa_paint(); }
size_t TotalOpCount() const { return paint_op_buffer_.total_op_count(); }
size_t BytesUsed() const {
return sizeof(*this) + paint_op_buffer_.bytes_used();
}
size_t OpBytesUsed() const { return paint_op_buffer_.paint_ops_size(); }
scoped_refptr<DiscardableImageMap> GenerateDiscardableImageMap(
const ScrollOffsetMap& raster_inducing_scroll_offsets,
DiscardableImageMap::DecodingModeMap* = nullptr,
DiscardableImageMap::PaintWorkletInputs* = nullptr) const;
void EmitTraceSnapshot() const;
gfx::Rect VisualRectForTesting(int index) const {
return visual_rects_[static_cast<size_t>(index)];
}
bool GetColorIfSolidInRect(const gfx::Rect& rect,
SkColor4f* color,
int max_ops_to_analyze = 1) const;
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();
}
bool has_save_layer_ops() const {
return paint_op_buffer_.has_save_layer_ops();
}
bool has_save_layer_alpha_ops() const {
return paint_op_buffer_.has_save_layer_alpha_ops();
}
bool has_effects_preventing_lcd_text_for_save_layer_alpha() const {
return paint_op_buffer_
.has_effects_preventing_lcd_text_for_save_layer_alpha();
}
bool has_discardable_images() const {
return paint_op_buffer_.has_discardable_images();
}
gfx::ContentColorUsage content_color_usage() const {
return paint_op_buffer_.content_color_usage();
}
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_);
}
std::optional<gfx::Rect> bounds() const { return rtree_.bounds(); }
struct RasterInducingScrollInfo {
gfx::Rect visual_rect;
bool has_discardable_images;
};
using RasterInducingScrollMap =
base::flat_map<ElementId, RasterInducingScrollInfo>;
const RasterInducingScrollMap& raster_inducing_scrolls() const {
return raster_inducing_scrolls_;
}
private:
friend class DisplayItemListTest;
~DisplayItemList();
std::unique_ptr<base::trace_event::TracedValue> CreateTracedValue(
bool include_items) const;
void AddToValue(base::trace_event::TracedValue*, bool include_items) const;
void GrowCurrentBeginItemVisualRect(const gfx::Rect& visual_rect) {
if (!paired_begin_stack_.empty())
visual_rects_[paired_begin_stack_.back().first_index].Union(visual_rect);
}
RasterInducingScrollMap raster_inducing_scrolls_;
RTree<size_t> rtree_;
PaintOpBuffer paint_op_buffer_;
std::vector<gfx::Rect> visual_rects_;
std::vector<size_t> offsets_;
struct PairedBeginInfo {
size_t first_index;
size_t count;
};
std::vector<PairedBeginInfo> paired_begin_stack_;
#if DCHECK_IS_ON()
bool IsPainting() const {
DCHECK(!IsFinalized());
return current_range_start_ != kNotPainting;
}
bool IsFinalized() const { return current_range_start_ == kFinalized; }
static constexpr size_t kNotPainting = static_cast<size_t>(-1);
static constexpr size_t kFinalized = static_cast<size_t>(-2);
size_t current_range_start_ = kNotPainting;
#endif
friend class base::RefCountedThreadSafe<DisplayItemList>;
FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, BytesUsed);
};
}
#endif