blob: 4bd5a071f598b29dbba29767ddc7518da0629d25 [file] [log] [blame]
// Copyright 2019 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 "components/paint_preview/renderer/paint_preview_recorder_utils.h"
#include <utility>
#include "base/bind.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "cc/paint/paint_image.h"
#include "components/paint_preview/common/file_stream.h"
#include "components/paint_preview/common/paint_preview_tracker.h"
#include "mojo/public/cpp/base/shared_memory_utils.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkRefCnt.h"
namespace paint_preview {
void ParseGlyphsAndLinks(const cc::PaintOpBuffer* buffer,
PaintPreviewTracker* tracker) {
for (cc::PaintOpBuffer::Iterator it(buffer); it; ++it) {
switch (it->GetType()) {
case cc::PaintOpType::DrawTextBlob: {
auto* text_blob_op = static_cast<cc::DrawTextBlobOp*>(*it);
tracker->AddGlyphs(text_blob_op->blob.get());
break;
}
case cc::PaintOpType::DrawRecord: {
// Recurse into nested records if they contain text blobs (equivalent to
// nested SkPictures).
auto* record_op = static_cast<cc::DrawRecordOp*>(*it);
ParseGlyphsAndLinks(record_op->record.get(), tracker);
break;
}
case cc::PaintOpType::Annotate: {
auto* annotate_op = static_cast<cc::AnnotateOp*>(*it);
tracker->AnnotateLink(GURL(std::string(reinterpret_cast<const char*>(
annotate_op->data->data()),
annotate_op->data->size())),
annotate_op->rect);
// Delete the data. We no longer need it.
annotate_op->data.reset();
break;
}
case cc::PaintOpType::CustomData: {
auto* custom_op = static_cast<cc::CustomDataOp*>(*it);
custom_op->id = tracker->TransformContentForRemoteFrame(custom_op->id);
break;
}
case cc::PaintOpType::Save: {
tracker->Save();
break;
}
case cc::PaintOpType::SaveLayer: {
tracker->Save();
break;
}
case cc::PaintOpType::SaveLayerAlpha: {
tracker->Save();
break;
}
case cc::PaintOpType::Restore: {
tracker->Restore();
break;
}
case cc::PaintOpType::SetMatrix: {
auto* matrix_op = static_cast<cc::SetMatrixOp*>(*it);
tracker->SetMatrix(matrix_op->matrix);
break;
}
case cc::PaintOpType::Concat: {
auto* concat_op = static_cast<cc::ConcatOp*>(*it);
tracker->Concat(concat_op->matrix);
break;
}
case cc::PaintOpType::Scale: {
auto* scale_op = static_cast<cc::ScaleOp*>(*it);
tracker->Scale(scale_op->sx, scale_op->sy);
break;
}
case cc::PaintOpType::Rotate: {
auto* rotate_op = static_cast<cc::RotateOp*>(*it);
tracker->Rotate(rotate_op->degrees);
break;
}
case cc::PaintOpType::Translate: {
auto* translate_op = static_cast<cc::TranslateOp*>(*it);
tracker->Translate(translate_op->dx, translate_op->dy);
break;
}
default:
continue;
}
}
}
sk_sp<const SkPicture> PaintRecordToSkPicture(
sk_sp<const cc::PaintRecord> recording,
PaintPreviewTracker* tracker,
const gfx::Rect& bounds) {
// base::Unretained is safe as |tracker| outlives the usage of
// |custom_callback|.
cc::PlaybackParams::CustomDataRasterCallback custom_callback =
base::BindRepeating(&PaintPreviewTracker::CustomDataToSkPictureCallback,
base::Unretained(tracker));
DCHECK_EQ(bounds.x(), 0);
DCHECK_EQ(bounds.y(), 0);
auto skp =
ToSkPicture(recording, SkRect::MakeWH(bounds.width(), bounds.height()),
nullptr, custom_callback);
if (!skp || skp->cullRect().width() == 0 || skp->cullRect().height() == 0)
return nullptr;
return skp;
}
void BuildResponse(PaintPreviewTracker* tracker,
mojom::PaintPreviewCaptureResponse* response) {
response->embedding_token = tracker->EmbeddingToken();
PictureSerializationContext* picture_context =
tracker->GetPictureSerializationContext();
if (picture_context) {
for (const auto& id_pair : *picture_context) {
response->content_id_to_embedding_token.insert(
{id_pair.first, id_pair.second});
}
}
tracker->MoveLinks(&response->links);
}
} // namespace paint_preview