#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "printing/metafile_skia.h"
#include <algorithm>
#include <map>
#include <tuple>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/files/file.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/not_fatal_until.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/paint_recorder.h"
#include "cc/paint/skia_paint_canvas.h"
#include "printing/metafile_agent.h"
#include "printing/mojom/print.mojom.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkSerialProcs.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/docs/SkMultiPictureDocument.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#if BUILDFLAG(IS_APPLE)
#include "printing/pdf_metafile_cg_mac.h"
#endif
#if BUILDFLAG(IS_POSIX)
#include "base/file_descriptor_posix.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "base/files/file_util.h"
#endif
namespace {
constexpr bool kInitFromDataCopyData = …;
bool WriteAssetToBuffer(const SkStreamAsset* asset, void* buffer, size_t size) { … }
}
namespace printing {
struct Page { … };
struct MetafileSkiaData { … };
MetafileSkia::MetafileSkia() : … { … }
MetafileSkia::MetafileSkia(mojom::SkiaDocumentType type, int document_cookie)
: … { … }
MetafileSkia::~MetafileSkia() = default;
bool MetafileSkia::Init() { … }
void MetafileSkia::UtilizeTypefaceContext(
ContentProxySet* typeface_content_info) { … }
bool MetafileSkia::InitFromData(base::span<const uint8_t> data) { … }
void MetafileSkia::StartPage(const gfx::Size& page_size,
const gfx::Rect& content_area,
float scale_factor,
mojom::PageOrientation page_orientation) { … }
cc::PaintCanvas* MetafileSkia::GetVectorCanvasForNewPage(
const gfx::Size& page_size,
const gfx::Rect& content_area,
float scale_factor,
mojom::PageOrientation page_orientation) { … }
bool MetafileSkia::FinishPage() { … }
bool MetafileSkia::FinishDocument() { … }
void MetafileSkia::FinishFrameContent() { … }
uint32_t MetafileSkia::GetDataSize() const { … }
bool MetafileSkia::GetData(void* dst_buffer, uint32_t dst_buffer_size) const { … }
bool MetafileSkia::ShouldCopySharedMemoryRegionData() const { … }
mojom::MetafileDataType MetafileSkia::GetDataType() const { … }
gfx::Rect MetafileSkia::GetPageBounds(unsigned int page_number) const { … }
unsigned int MetafileSkia::GetPageCount() const { … }
printing::NativeDrawingContext MetafileSkia::context() const { … }
#if BUILDFLAG(IS_WIN)
bool MetafileSkia::Playback(printing::NativeDrawingContext hdc,
const RECT* rect) const {
NOTREACHED_IN_MIGRATION();
return false;
}
bool MetafileSkia::SafePlayback(printing::NativeDrawingContext hdc) const {
NOTREACHED_IN_MIGRATION();
return false;
}
#elif BUILDFLAG(IS_APPLE)
bool MetafileSkia::RenderPage(unsigned int page_number,
CGContextRef context,
const CGRect& rect,
bool autorotate,
bool fit_to_page) const {
DCHECK_GT(GetDataSize(), 0U);
if (data_->pdf_cg.GetDataSize() == 0) {
if (GetDataSize() == 0)
return false;
size_t length = data_->data_stream->getLength();
std::vector<uint8_t> buffer(length);
std::ignore =
WriteAssetToBuffer(data_->data_stream.get(), &buffer[0], length);
data_->pdf_cg.InitFromData(buffer);
}
return data_->pdf_cg.RenderPage(page_number, context, rect, autorotate,
fit_to_page);
}
#endif
#if BUILDFLAG(IS_ANDROID)
bool MetafileSkia::SaveToFileDescriptor(int fd) const {
if (GetDataSize() == 0u)
return false;
std::unique_ptr<SkStreamAsset> asset(data_->data_stream->duplicate());
static constexpr size_t kMaximumBufferSize = 1024 * 1024;
std::vector<uint8_t> buffer(std::min(kMaximumBufferSize, asset->getLength()));
do {
size_t read_size = asset->read(&buffer[0], buffer.size());
bool is_at_end = read_size < buffer.size();
if (read_size == 0u) {
break;
}
DCHECK_GE(buffer.size(), read_size);
buffer.resize(read_size);
if (!base::WriteFileDescriptor(fd, buffer)) {
return false;
} else if (is_at_end) {
break;
}
} while (true);
return true;
}
#else
bool MetafileSkia::SaveTo(base::File* file) const { … }
#endif
std::unique_ptr<MetafileSkia> MetafileSkia::GetMetafileForCurrentPage(
mojom::SkiaDocumentType type) { … }
uint32_t MetafileSkia::CreateContentForRemoteFrame(
const gfx::Rect& rect,
const base::UnguessableToken& render_proxy_token) { … }
int MetafileSkia::GetDocumentCookie() const { … }
const ContentToProxyTokenMap& MetafileSkia::GetSubframeContentInfo() const { … }
void MetafileSkia::AppendPage(const SkSize& page_size, cc::PaintRecord record) { … }
void MetafileSkia::AppendSubframeInfo(uint32_t content_id,
const base::UnguessableToken& proxy_token,
sk_sp<SkPicture> pic_holder) { … }
SkStreamAsset* MetafileSkia::GetPdfData() const { … }
void MetafileSkia::CustomDataToSkPictureCallback(SkCanvas* canvas,
uint32_t content_id) { … }
}