Index: printing/pdf_metafile_skia.cc |
diff --git a/printing/pdf_metafile_skia.cc b/printing/pdf_metafile_skia.cc |
index e00ca9f1c2af1e3ade43eccc2aea6bb1289daffc..c63e308cc54abbfb2b526a02c09aef63fe99beb3 100644 |
--- a/printing/pdf_metafile_skia.cc |
+++ b/printing/pdf_metafile_skia.cc |
@@ -12,13 +12,12 @@ |
#include "skia/ext/refptr.h" |
#include "skia/ext/vector_canvas.h" |
#include "third_party/skia/include/core/SkData.h" |
-#include "third_party/skia/include/core/SkDocument.h" |
-#include "third_party/skia/include/core/SkPictureRecorder.h" |
-#include "third_party/skia/include/core/SkRect.h" |
#include "third_party/skia/include/core/SkRefCnt.h" |
#include "third_party/skia/include/core/SkScalar.h" |
-#include "third_party/skia/include/core/SkSize.h" |
#include "third_party/skia/include/core/SkStream.h" |
+#include "third_party/skia/include/core/SkTypeface.h" |
+#include "third_party/skia/include/pdf/SkPDFDevice.h" |
+#include "third_party/skia/include/pdf/SkPDFDocument.h" |
#include "ui/gfx/point.h" |
#include "ui/gfx/rect.h" |
#include "ui/gfx/size.h" |
@@ -31,56 +30,13 @@ |
#include "base/file_descriptor_posix.h" |
#endif |
-namespace { |
-// This struct represents all the data we need to draw and redraw this |
-// page into a SkDocument. |
-struct Page { |
- Page(const SkSize& page_size, const SkRect& content_area) |
- : page_size_(page_size), |
- content_area_(content_area), |
- content_(/*NULL*/) {} |
- SkSize page_size_; |
- SkRect content_area_; |
- skia::RefPtr<SkPicture> content_; |
-}; |
-} // namespace |
- |
-static SkSize ToSkSize(const gfx::Size& size) { |
- return SkSize::Make(SkIntToScalar(size.width()), |
- SkIntToScalar(size.height())); |
-} |
- |
-static SkRect ToSkRect(const gfx::Rect& rect) { |
- return SkRect::MakeLTRB(SkIntToScalar(rect.x()), SkIntToScalar(rect.y()), |
- SkIntToScalar(rect.right()), |
- SkIntToScalar(rect.bottom())); |
-} |
- |
-static gfx::Size ToGfxSize(const SkSize& size) { |
- return gfx::Size(SkScalarTruncToInt(size.width()), |
- SkScalarTruncToInt(size.height())); |
-} |
- |
-static bool WriteAssetToBuffer(SkStreamAsset* asset, |
- void* buffer, |
- size_t size) { |
- DCHECK(asset->getPosition() == 0); // Be kind: please rewind. |
- size_t length = asset->getLength(); |
- if (length > size) |
- return false; |
- bool success = (length == asset->read(buffer, length)); |
- (void)asset->rewind(); |
- return success; |
-} |
- |
namespace printing { |
struct PdfMetafileSkiaData { |
- scoped_ptr<SkPictureRecorder> recorder_; // Current recording |
- |
- std::vector<Page> pages_; |
- skia::RefPtr<SkStreamAsset> pdf_data_; |
- |
+ skia::RefPtr<SkPDFDevice> current_page_; |
+ skia::RefPtr<SkCanvas> current_page_canvas_; |
+ SkPDFDocument pdf_doc_; |
+ SkDynamicMemoryWStream pdf_stream_; |
#if defined(OS_MACOSX) |
PdfMetafileCg pdf_cg_; |
#endif |
@@ -91,37 +47,31 @@ |
bool PdfMetafileSkia::Init() { |
return true; |
} |
- |
-// TODO(halcanary): Create a Metafile class that only stores data. |
-// Metafile::InitFromData is orthogonal to what the rest of |
-// PdfMetafileSkia does. |
bool PdfMetafileSkia::InitFromData(const void* src_buffer, |
uint32 src_buffer_size) { |
- if (data_->pdf_data_) |
- data_->pdf_data_.clear(); // free up RAM first. |
- SkDynamicMemoryWStream dynamic_memory; |
- if (!dynamic_memory.write(src_buffer, src_buffer_size)) |
- return false; |
- data_->pdf_data_ = skia::AdoptRef(dynamic_memory.detachAsStream()); |
- return true; |
+ return data_->pdf_stream_.write(src_buffer, src_buffer_size); |
} |
bool PdfMetafileSkia::StartPage(const gfx::Size& page_size, |
const gfx::Rect& content_area, |
const float& scale_factor) { |
- if (data_->recorder_) |
- this->FinishPage(); |
- DCHECK(!data_->recorder_); |
- data_->recorder_.reset(SkNEW(SkPictureRecorder)); |
- SkSize sk_page_size = ToSkSize(page_size); |
- data_->pages_.push_back(Page(sk_page_size, ToSkRect(content_area))); |
- |
- SkCanvas* recordingCanvas = data_->recorder_->beginRecording( |
- sk_page_size.width(), sk_page_size.height(), NULL, 0); |
- // recordingCanvas is owned by the data_->recorder_. No ref() necessary. |
- if (!recordingCanvas) |
- return false; |
- recordingCanvas->scale(scale_factor, scale_factor); |
+ DCHECK(!data_->current_page_canvas_); |
+ |
+ // Adjust for the margins and apply the scale factor. |
+ SkMatrix transform; |
+ transform.setTranslate(SkIntToScalar(content_area.x()), |
+ SkIntToScalar(content_area.y())); |
+ transform.preScale(SkFloatToScalar(scale_factor), |
+ SkFloatToScalar(scale_factor)); |
+ |
+ SkISize pdf_page_size = SkISize::Make(page_size.width(), page_size.height()); |
+ SkISize pdf_content_size = |
+ SkISize::Make(content_area.width(), content_area.height()); |
+ |
+ data_->current_page_ = skia::AdoptRef( |
+ new SkPDFDevice(pdf_page_size, pdf_content_size, transform)); |
+ data_->current_page_canvas_ = |
+ skia::AdoptRef(new SkCanvas(data_->current_page_.get())); |
return true; |
} |
@@ -131,65 +81,68 @@ |
const float& scale_factor) { |
if (!StartPage(page_size, content_area, scale_factor)) |
return nullptr; |
- return data_->recorder_->getRecordingCanvas(); |
+ return data_->current_page_canvas_.get(); |
} |
bool PdfMetafileSkia::FinishPage() { |
- if (!data_->recorder_) |
- return false; |
- DCHECK(!(data_->pages_.back().content_)); |
- data_->pages_.back().content_ = |
- skia::AdoptRef(data_->recorder_->endRecording()); |
- data_->recorder_.reset(); |
+ DCHECK(data_->current_page_canvas_); |
+ DCHECK(data_->current_page_); |
+ |
+ data_->current_page_canvas_.clear(); // Unref SkCanvas. |
+ data_->pdf_doc_.appendPage(data_->current_page_.get()); |
return true; |
} |
bool PdfMetafileSkia::FinishDocument() { |
- // If we've already set the data in InitFromData, overwrite it. |
- if (data_->pdf_data_) |
- data_->pdf_data_.clear(); // Free up RAM first. |
- |
- if (data_->recorder_) |
- this->FinishPage(); |
- |
- SkDynamicMemoryWStream pdf_stream; |
- skia::RefPtr<SkDocument> pdf_doc = |
- skia::AdoptRef(SkDocument::CreatePDF(&pdf_stream)); |
- for (const auto& page : data_->pages_) { |
- SkCanvas* canvas = pdf_doc->beginPage( |
- page.page_size_.width(), page.page_size_.height(), &page.content_area_); |
- canvas->drawPicture(page.content_.get()); |
- pdf_doc->endPage(); |
- } |
- if (!pdf_doc->close()) |
- return false; |
- |
- data_->pdf_data_ = skia::AdoptRef(pdf_stream.detachAsStream()); |
- return true; |
+ // Don't do anything if we've already set the data in InitFromData. |
+ if (data_->pdf_stream_.getOffset()) |
+ return true; |
+ |
+ if (data_->current_page_canvas_) |
+ FinishPage(); |
+ |
+ data_->current_page_.clear(); |
+ |
+ int font_counts[SkAdvancedTypefaceMetrics::kOther_Font + 2]; |
+ data_->pdf_doc_.getCountOfFontTypes(font_counts); |
+ for (int type = 0; |
+ type <= SkAdvancedTypefaceMetrics::kOther_Font + 1; |
+ type++) { |
+ for (int count = 0; count < font_counts[type]; count++) { |
+ UMA_HISTOGRAM_ENUMERATION( |
+ "PrintPreview.FontType", type, |
+ SkAdvancedTypefaceMetrics::kOther_Font + 2); |
+ } |
+ } |
+ |
+ return data_->pdf_doc_.emitPDF(&data_->pdf_stream_); |
} |
uint32 PdfMetafileSkia::GetDataSize() const { |
- if (!data_->pdf_data_) |
- return 0; |
- return base::checked_cast<uint32>(data_->pdf_data_->getLength()); |
+ return base::checked_cast<uint32>(data_->pdf_stream_.getOffset()); |
} |
bool PdfMetafileSkia::GetData(void* dst_buffer, |
uint32 dst_buffer_size) const { |
- if (!data_->pdf_data_) |
+ if (dst_buffer_size < GetDataSize()) |
return false; |
- return WriteAssetToBuffer(data_->pdf_data_.get(), dst_buffer, |
- base::checked_cast<size_t>(dst_buffer_size)); |
+ |
+ SkAutoDataUnref data(data_->pdf_stream_.copyToData()); |
+ memcpy(dst_buffer, data->bytes(), dst_buffer_size); |
+ return true; |
} |
gfx::Rect PdfMetafileSkia::GetPageBounds(unsigned int page_number) const { |
- if (page_number < data_->pages_.size()) |
- return gfx::Rect(ToGfxSize(data_->pages_[page_number].page_size_)); |
+ // TODO(vandebo) add a method to get the page size for a given page to |
+ // SkPDFDocument. |
+ NOTIMPLEMENTED(); |
return gfx::Rect(); |
} |
unsigned int PdfMetafileSkia::GetPageCount() const { |
- return base::checked_cast<unsigned int>(data_->pages_.size()); |
+ // TODO(vandebo) add a method to get the number of pages to SkPDFDocument. |
+ NOTIMPLEMENTED(); |
+ return 0; |
} |
gfx::NativeDrawingContext PdfMetafileSkia::context() const { |
@@ -221,14 +174,10 @@ |
CGContextRef context, |
const CGRect rect, |
const MacRenderPageParams& params) const { |
- DCHECK_GT(GetDataSize(), 0U); |
+ DCHECK_GT(data_->pdf_stream_.getOffset(), 0U); |
if (data_->pdf_cg_.GetDataSize() == 0) { |
- if (GetDataSize() == 0) |
- return false; |
- size_t length = data_->pdf_data_->getLength(); |
- std::vector<uint8_t> buffer(length); |
- (void)WriteAssetToBuffer(data_->pdf_data_.get(), &buffer[0], length); |
- data_->pdf_cg_.InitFromData(&buffer[0], base::checked_cast<uint32>(length)); |
+ SkAutoDataUnref data(data_->pdf_stream_.copyToData()); |
+ data_->pdf_cg_.InitFromData(data->bytes(), data->size()); |
} |
return data_->pdf_cg_.RenderPage(page_number, context, rect, params); |
} |
@@ -237,31 +186,17 @@ |
bool PdfMetafileSkia::SaveTo(base::File* file) const { |
if (GetDataSize() == 0U) |
return false; |
- DCHECK(data_->pdf_data_.get()); |
- SkStreamAsset* asset = data_->pdf_data_.get(); |
- DCHECK_EQ(asset->getPosition(), 0U); |
- |
- const size_t maximum_buffer_size = 1024 * 1024; |
- std::vector<char> buffer(std::min(maximum_buffer_size, asset->getLength())); |
- do { |
- size_t read_size = asset->read(&buffer[0], buffer.size()); |
- if (read_size == 0) |
- break; |
- DCHECK_GE(buffer.size(), read_size); |
- if (!file->WriteAtCurrentPos(&buffer[0], |
- base::checked_cast<int>(read_size))) { |
- (void)asset->rewind(); |
- return false; |
- } |
- } while (!asset->isAtEnd()); |
- |
- (void)asset->rewind(); |
- return true; |
+ SkAutoDataUnref data(data_->pdf_stream_.copyToData()); |
+ // TODO(halcanary): rewrite this function without extra data copy |
+ // using SkStreamAsset. |
+ const char* ptr = reinterpret_cast<const char*>(data->data()); |
+ int size = base::checked_cast<int>(data->size()); |
+ return file->WriteAtCurrentPos(ptr, size) == size; |
} |
#if defined(OS_CHROMEOS) || defined(OS_ANDROID) |
bool PdfMetafileSkia::SaveToFD(const base::FileDescriptor& fd) const { |
- DCHECK_GT(GetDataSize(), 0U); |
+ DCHECK_GT(data_->pdf_stream_.getOffset(), 0U); |
if (fd.fd < 0) { |
DLOG(ERROR) << "Invalid file descriptor!"; |
@@ -281,24 +216,24 @@ |
} |
scoped_ptr<PdfMetafileSkia> PdfMetafileSkia::GetMetafileForCurrentPage() { |
- // If we only ever need the metafile for the last page, should we |
- // only keep a handle on one SkPicture? |
- scoped_ptr<PdfMetafileSkia> metafile(new PdfMetafileSkia); |
- |
- if (data_->pages_.size() == 0) |
+ scoped_ptr<PdfMetafileSkia> metafile; |
+ SkPDFDocument pdf_doc(SkPDFDocument::kDraftMode_Flags); |
+ if (!pdf_doc.appendPage(data_->current_page_.get())) |
return metafile.Pass(); |
- if (data_->recorder_) // page outstanding |
+ SkDynamicMemoryWStream pdf_stream; |
+ if (!pdf_doc.emitPDF(&pdf_stream)) |
return metafile.Pass(); |
- const Page& page = data_->pages_.back(); |
- |
- metafile->data_->pages_.push_back(page); // Copy page data; |
- // Should increment refcnt on page->content_. |
- |
- if (!metafile->FinishDocument()) // Generate PDF. |
+ SkAutoDataUnref data_copy(pdf_stream.copyToData()); |
+ if (data_copy->size() == 0) |
+ return scoped_ptr<PdfMetafileSkia>(); |
+ |
+ metafile.reset(new PdfMetafileSkia); |
+ if (!metafile->InitFromData(data_copy->bytes(), |
+ base::checked_cast<uint32>(data_copy->size()))) { |
metafile.reset(); |
- |
+ } |
return metafile.Pass(); |
} |