blob: 103484a5d28ad0f2e7d07f0bd5a11bc8aae4c284 [file] [log] [blame]
// Copyright 2017 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.
#include "cc/paint/paint_op_buffer_serializer.h"
#include "base/bind.h"
#include "cc/paint/scoped_raster_flags.h"
#include "ui/gfx/skia_util.h"
namespace cc {
namespace {
class ScopedFlagsOverride {
public:
ScopedFlagsOverride(PaintOp::SerializeOptions* options,
const PaintFlags* flags)
: options_(options) {
options_->flags_to_serialize = flags;
}
~ScopedFlagsOverride() { options_->flags_to_serialize = nullptr; }
private:
PaintOp::SerializeOptions* options_;
};
} // namespace
PaintOpBufferSerializer::PaintOpBufferSerializer(
SerializeCallback serialize_cb,
ImageProvider* image_provider,
TransferCacheSerializeHelper* transfer_cache)
: serialize_cb_(std::move(serialize_cb)),
canvas_(100, 100),
image_provider_(image_provider),
transfer_cache_(transfer_cache) {
DCHECK(serialize_cb_);
}
PaintOpBufferSerializer::~PaintOpBufferSerializer() = default;
void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer,
const std::vector<size_t>* offsets,
const Preamble& preamble) {
// Reset the canvas to the maximum extents of our playback rect, ensuring this
// rect will not reject images.
canvas_.resetCanvas(preamble.playback_rect.right(),
preamble.playback_rect.bottom());
DCHECK(canvas_.getTotalMatrix().isIdentity());
static const int kInitialSaveCount = 1;
DCHECK_EQ(kInitialSaveCount, canvas_.getSaveCount());
// These SerializeOptions and PlaybackParams use the initial (identity) canvas
// matrix, as they are only used for serializing the preamble and the initial
// save / final restore. SerializeBuffer will create its own SerializeOptions
// and PlaybackParams based on the post-preamble canvas.
PaintOp::SerializeOptions options(image_provider_, transfer_cache_, &canvas_,
canvas_.getTotalMatrix());
PlaybackParams params(image_provider_, canvas_.getTotalMatrix());
Save(options, params);
SerializePreamble(preamble, options, params);
SerializeBuffer(buffer, offsets);
RestoreToCount(kInitialSaveCount, options, params);
}
void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer) {
// Use half of the max int as the extent for the SkNoDrawCanvas.
static const int extent = std::numeric_limits<int>::max() >> 1;
// Reset the canvas to the maximum extents of our playback rect, ensuring this
// rect will not reject images.
canvas_.resetCanvas(extent, extent);
DCHECK(canvas_.getTotalMatrix().isIdentity());
SerializeBuffer(buffer, nullptr);
}
void PaintOpBufferSerializer::SerializePreamble(
const Preamble& preamble,
const PaintOp::SerializeOptions& options,
const PlaybackParams& params) {
if (!preamble.translation.IsZero()) {
TranslateOp translate_op(-preamble.translation.x(),
-preamble.translation.y());
SerializeOp(&translate_op, options, params);
}
if (!preamble.playback_rect.IsEmpty()) {
ClipRectOp clip_op(
SkRect::MakeFromIRect(gfx::RectToSkIRect(preamble.playback_rect)),
SkClipOp::kIntersect, false);
SerializeOp(&clip_op, options, params);
}
if (!preamble.post_translation.IsZero()) {
TranslateOp translate_op(preamble.post_translation.x(),
preamble.post_translation.y());
SerializeOp(&translate_op, options, params);
}
if (preamble.post_scale != 1.f) {
ScaleOp scale_op(preamble.post_scale, preamble.post_scale);
SerializeOp(&scale_op, options, params);
}
}
void PaintOpBufferSerializer::SerializeBuffer(
const PaintOpBuffer* buffer,
const std::vector<size_t>* offsets) {
DCHECK(buffer);
PaintOp::SerializeOptions options(image_provider_, transfer_cache_, &canvas_,
canvas_.getTotalMatrix());
PlaybackParams params(image_provider_, canvas_.getTotalMatrix());
for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter;
++iter) {
const PaintOp* op = *iter;
// Skip ops outside the current clip if they have images. This saves
// performing an unnecessary expensive decode.
const bool skip_op = PaintOp::OpHasDiscardableImages(op) &&
PaintOp::QuickRejectDraw(op, &canvas_);
if (skip_op)
continue;
if (op->GetType() != PaintOpType::DrawRecord) {
bool success = false;
if (op->IsPaintOpWithFlags()) {
success = SerializeOpWithFlags(static_cast<const PaintOpWithFlags*>(op),
&options, params, iter.alpha());
} else {
success = SerializeOp(op, options, params);
}
if (!success)
return;
continue;
}
int save_count = canvas_.getSaveCount();
Save(options, params);
SerializeBuffer(static_cast<const DrawRecordOp*>(op)->record.get(),
nullptr);
RestoreToCount(save_count, options, params);
}
}
bool PaintOpBufferSerializer::SerializeOpWithFlags(
const PaintOpWithFlags* flags_op,
PaintOp::SerializeOptions* options,
const PlaybackParams& params,
uint8_t alpha) {
const ScopedRasterFlags scoped_flags(
&flags_op->flags, options->image_provider,
options->canvas->getTotalMatrix(), alpha);
const PaintFlags* flags_to_serialize = scoped_flags.flags();
if (!flags_to_serialize)
return true;
ScopedFlagsOverride override_flags(options, flags_to_serialize);
return SerializeOp(flags_op, *options, params);
}
bool PaintOpBufferSerializer::SerializeOp(
const PaintOp* op,
const PaintOp::SerializeOptions& options,
const PlaybackParams& params) {
if (!valid_)
return false;
size_t bytes = serialize_cb_.Run(op, options);
if (!bytes) {
valid_ = false;
return false;
}
DCHECK_GE(bytes, 4u);
DCHECK_EQ(bytes % PaintOpBuffer::PaintOpAlign, 0u);
// Only pass state-changing operations to the canvas.
if (!op->IsDrawOp()) {
// Note that we don't need to use overridden flags during raster here since
// the override must not affect any state being tracked by this canvas.
op->Raster(&canvas_, params);
}
return true;
}
void PaintOpBufferSerializer::Save(const PaintOp::SerializeOptions& options,
const PlaybackParams& params) {
SaveOp save_op;
SerializeOp(&save_op, options, params);
}
void PaintOpBufferSerializer::RestoreToCount(
int count,
const PaintOp::SerializeOptions& options,
const PlaybackParams& params) {
RestoreOp restore_op;
while (canvas_.getSaveCount() > count) {
if (!SerializeOp(&restore_op, options, params))
return;
}
}
SimpleBufferSerializer::SimpleBufferSerializer(
void* memory,
size_t size,
ImageProvider* image_provider,
TransferCacheSerializeHelper* transfer_cache)
: PaintOpBufferSerializer(
base::Bind(&SimpleBufferSerializer::SerializeToMemory,
base::Unretained(this)),
image_provider,
transfer_cache),
memory_(memory),
total_(size) {}
SimpleBufferSerializer::~SimpleBufferSerializer() = default;
size_t SimpleBufferSerializer::SerializeToMemory(
const PaintOp* op,
const PaintOp::SerializeOptions& options) {
if (written_ == total_)
return 0u;
size_t bytes = op->Serialize(static_cast<char*>(memory_) + written_,
total_ - written_, options);
if (!bytes)
return 0u;
written_ += bytes;
DCHECK_GE(total_, written_);
return bytes;
}
} // namespace cc