#include "cc/paint/paint_op_buffer_iterator.h"
#include <variant>
namespace cc {
namespace {
static bool SupportsFoldingAlpha(const PaintOp* op) {
if (!op->IsPaintOpWithFlags()) {
return false;
}
if (!static_cast<const PaintOpWithFlags*>(op)->flags.SupportsFoldingAlpha()) {
return false;
}
if (op->GetType() == PaintOpType::kDrawTextBlob) {
return false;
}
if (op->GetType() == PaintOpType::kDrawImage &&
static_cast<const DrawImageOp*>(op)->image.IsPaintWorklet()) {
return false;
}
if (op->GetType() == PaintOpType::kDrawImageRect &&
static_cast<const DrawImageRectOp*>(op)->image.IsPaintWorklet()) {
return false;
}
return true;
}
static const PaintOp* GetNestedSingleDrawingOp(const PaintOp* op) {
if (!op->IsDrawOp())
return nullptr;
while (op->GetType() == PaintOpType::kDrawRecord) {
auto* draw_record_op = static_cast<const DrawRecordOp*>(op);
if (draw_record_op->record.empty()) {
return nullptr;
}
if (draw_record_op->record.size() > 1) {
return nullptr;
}
op = &draw_record_op->record.GetFirstOp();
if (!op->IsDrawOp())
return nullptr;
}
return op;
}
}
PaintOpBuffer::CompositeIterator::CompositeIterator(
const PaintOpBuffer& buffer,
const std::vector<size_t>* offsets)
: iter_(offsets == nullptr ? std::variant<Iterator, OffsetIterator>(
std::in_place_type<Iterator>,
buffer)
: std::variant<Iterator, OffsetIterator>(
std::in_place_type<OffsetIterator>,
buffer,
*offsets)) {}
PaintOpBuffer::CompositeIterator::CompositeIterator(
const CompositeIterator& other) = default;
PaintOpBuffer::CompositeIterator::CompositeIterator(CompositeIterator&& other) =
default;
PaintOpBuffer::PlaybackFoldingIterator::PlaybackFoldingIterator(
const PaintOpBuffer& buffer,
const std::vector<size_t>* offsets)
: iter_(buffer, offsets),
folded_draw_color_(SkColors::kTransparent, SkBlendMode::kSrcOver) {
FindNextOp();
}
PaintOpBuffer::PlaybackFoldingIterator::~PlaybackFoldingIterator() = default;
void PaintOpBuffer::PlaybackFoldingIterator::FindNextOp() {
current_alpha_ = 1.0f;
for (current_op_ = NextUnfoldedOp(); current_op_;
current_op_ = NextUnfoldedOp()) {
if (current_op_->GetType() != PaintOpType::kSaveLayerAlpha) {
break;
}
const PaintOp* second = NextUnfoldedOp();
if (!second)
break;
if (second->GetType() == PaintOpType::kRestore) {
continue;
}
const PaintOp* draw_op = GetNestedSingleDrawingOp(second);
const PaintOp* third = nullptr;
if (draw_op) {
third = NextUnfoldedOp();
if (third && third->GetType() == PaintOpType::kRestore) {
auto* save_op = static_cast<const SaveLayerAlphaOp*>(current_op_);
if (SupportsFoldingAlpha(draw_op)) {
current_alpha_ = save_op->alpha;
current_op_ = draw_op;
break;
} else if (draw_op->GetType() == PaintOpType::kDrawColor &&
static_cast<const DrawColorOp*>(draw_op)->mode ==
SkBlendMode::kSrcOver) {
auto* draw_color_op = static_cast<const DrawColorOp*>(draw_op);
SkColor4f color = draw_color_op->color;
folded_draw_color_.color = {color.fR, color.fG, color.fB,
save_op->alpha * color.fA};
current_op_ = &folded_draw_color_;
break;
}
}
}
stack_.push_back(second);
if (third)
stack_.push_back(third);
break;
}
}
const PaintOp* PaintOpBuffer::PlaybackFoldingIterator::NextUnfoldedOp() {
if (stack_.size()) {
const PaintOp* op = stack_.front();
stack_.erase(stack_.begin());
return op;
}
if (!iter_)
return nullptr;
const PaintOp& op = *iter_;
++iter_;
return &op;
}
}