diff options
author | halcanary <halcanary@google.com> | 2015-01-22 12:34:32 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-01-22 20:35:24 +0000 |
commit | ff21476a27b22e7819fc9874456e31aa516a9c1c (patch) | |
tree | f414df0e8cd81b1ea15d01b209e36abb2d4e6561 /printing | |
parent | a98f15b7d247d2d22a9b363380b333ca20597858 (diff) | |
download | chromium_src-ff21476a27b22e7819fc9874456e31aa516a9c1c.zip chromium_src-ff21476a27b22e7819fc9874456e31aa516a9c1c.tar.gz chromium_src-ff21476a27b22e7819fc9874456e31aa516a9c1c.tar.bz2 |
Remove calls to deprecated SkPDFDevice and SkPDFDocuemnt.
This relands http://crrev.com/694213002
In the PdfMetafileSkia class, Instead of storing a
SkPDFDocument, store a vector of pages as
SkPictures. This allows access to individual at any
time. When FinishDocument() is called, use the
SkDocument API to print all pages to PDF.
In PrintWebViewHelper::RenderPageContent, skip clipping
content to content area, since Windows printing prints
content just outside of the content area, as noted in
http://crbug.com/434079 .
BUG=278148
Committed: https://crrev.com/18387e7ebb0eae6e4944e841d63ea058adab6e11
Cr-Commit-Position: refs/heads/master@{#310032}
Review URL: https://codereview.chromium.org/821703005
Cr-Commit-Position: refs/heads/master@{#312672}
Diffstat (limited to 'printing')
-rw-r--r-- | printing/pdf_metafile_skia.cc | 212 |
1 files changed, 127 insertions, 85 deletions
diff --git a/printing/pdf_metafile_skia.cc b/printing/pdf_metafile_skia.cc index 7f640ad..ae402ab 100644 --- a/printing/pdf_metafile_skia.cc +++ b/printing/pdf_metafile_skia.cc @@ -12,15 +12,18 @@ #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/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/skia_util.h" #if defined(OS_MACOSX) #include "printing/pdf_metafile_cg_mac.h" @@ -30,13 +33,39 @@ #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 bool WriteAssetToBuffer(const SkStreamAsset* asset, + void* buffer, + size_t size) { + // Calling duplicate() keeps original asset state unchanged. + scoped_ptr<SkStreamAsset> assetCopy(asset->duplicate()); + size_t length = assetCopy->getLength(); + if (length > size) + return false; + return (length == assetCopy->read(buffer, length)); +} + namespace printing { struct PdfMetafileSkiaData { - skia::RefPtr<SkPDFDevice> current_page_; - skia::RefPtr<SkCanvas> current_page_canvas_; - SkPDFDocument pdf_doc_; - SkDynamicMemoryWStream pdf_stream_; + SkPictureRecorder recorder_; // Current recording + + std::vector<Page> pages_; + scoped_ptr<SkStreamAsset> pdf_data_; + #if defined(OS_MACOSX) PdfMetafileCg pdf_cg_; #endif @@ -47,31 +76,31 @@ PdfMetafileSkia::~PdfMetafileSkia() {} 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) { - return data_->pdf_stream_.write(src_buffer, src_buffer_size); + data_->pdf_data_.reset(new SkMemoryStream(src_buffer, src_buffer_size, true)); + return true; } bool PdfMetafileSkia::StartPage(const gfx::Size& page_size, const gfx::Rect& content_area, const float& 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())); + if (data_->recorder_.getRecordingCanvas()) + this->FinishPage(); + DCHECK(!data_->recorder_.getRecordingCanvas()); + SkSize sk_page_size = gfx::SizeFToSkSize(gfx::SizeF(page_size)); + data_->pages_.push_back(Page(sk_page_size, gfx::RectToSkRect(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); return true; } @@ -81,68 +110,66 @@ skia::VectorCanvas* PdfMetafileSkia::GetVectorCanvasForNewPage( const float& scale_factor) { if (!StartPage(page_size, content_area, scale_factor)) return nullptr; - return data_->current_page_canvas_.get(); + return data_->recorder_.getRecordingCanvas(); } bool PdfMetafileSkia::FinishPage() { - DCHECK(data_->current_page_canvas_); - DCHECK(data_->current_page_); - - data_->current_page_canvas_.clear(); // Unref SkCanvas. - data_->pdf_doc_.appendPage(data_->current_page_.get()); + if (!data_->recorder_.getRecordingCanvas()) + return false; + DCHECK(!(data_->pages_.back().content_)); + data_->pages_.back().content_ = + skia::AdoptRef(data_->recorder_.endRecording()); return true; } bool PdfMetafileSkia::FinishDocument() { - // 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); - } + // If we've already set the data in InitFromData, leave it be. + if (data_->pdf_data_) + return false; + + if (data_->recorder_.getRecordingCanvas()) + 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; - return data_->pdf_doc_.emitPDF(&data_->pdf_stream_); + data_->pdf_data_.reset(pdf_stream.detachAsStream()); + return true; } uint32 PdfMetafileSkia::GetDataSize() const { - return base::checked_cast<uint32>(data_->pdf_stream_.getOffset()); + if (!data_->pdf_data_) + return 0; + return base::checked_cast<uint32>(data_->pdf_data_->getLength()); } bool PdfMetafileSkia::GetData(void* dst_buffer, uint32 dst_buffer_size) const { - if (dst_buffer_size < GetDataSize()) + if (!data_->pdf_data_) return false; - - SkAutoDataUnref data(data_->pdf_stream_.copyToData()); - memcpy(dst_buffer, data->bytes(), dst_buffer_size); - return true; + return WriteAssetToBuffer(data_->pdf_data_.get(), dst_buffer, + base::checked_cast<size_t>(dst_buffer_size)); } gfx::Rect PdfMetafileSkia::GetPageBounds(unsigned int page_number) const { - // TODO(vandebo) add a method to get the page size for a given page to - // SkPDFDocument. - NOTIMPLEMENTED(); + if (page_number < data_->pages_.size()) { + return gfx::Rect(gfx::ToFlooredSize( + gfx::SkSizeToSizeF(data_->pages_[page_number].page_size_))); + } return gfx::Rect(); } unsigned int PdfMetafileSkia::GetPageCount() const { - // TODO(vandebo) add a method to get the number of pages to SkPDFDocument. - NOTIMPLEMENTED(); - return 0; + return base::checked_cast<unsigned int>(data_->pages_.size()); } gfx::NativeDrawingContext PdfMetafileSkia::context() const { @@ -174,10 +201,14 @@ bool PdfMetafileSkia::RenderPage(unsigned int page_number, CGContextRef context, const CGRect rect, const MacRenderPageParams& params) const { - DCHECK_GT(data_->pdf_stream_.getOffset(), 0U); + DCHECK_GT(GetDataSize(), 0U); if (data_->pdf_cg_.GetDataSize() == 0) { - SkAutoDataUnref data(data_->pdf_stream_.copyToData()); - data_->pdf_cg_.InitFromData(data->bytes(), data->size()); + 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)); } return data_->pdf_cg_.RenderPage(page_number, context, rect, params); } @@ -186,17 +217,29 @@ bool PdfMetafileSkia::RenderPage(unsigned int page_number, bool PdfMetafileSkia::SaveTo(base::File* file) const { if (GetDataSize() == 0U) return false; - 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; + + // Calling duplicate() keeps original asset state unchanged. + scoped_ptr<SkStreamAsset> asset(data_->pdf_data_->duplicate()); + + 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))) { + return false; + } + } while (!asset->isAtEnd()); + + return true; } #if defined(OS_CHROMEOS) || defined(OS_ANDROID) bool PdfMetafileSkia::SaveToFD(const base::FileDescriptor& fd) const { - DCHECK_GT(data_->pdf_stream_.getOffset(), 0U); + DCHECK_GT(GetDataSize(), 0U); if (fd.fd < 0) { DLOG(ERROR) << "Invalid file descriptor!"; @@ -216,24 +259,23 @@ PdfMetafileSkia::PdfMetafileSkia() : data_(new PdfMetafileSkiaData) { } scoped_ptr<PdfMetafileSkia> PdfMetafileSkia::GetMetafileForCurrentPage() { - scoped_ptr<PdfMetafileSkia> metafile; - SkPDFDocument pdf_doc(SkPDFDocument::kDraftMode_Flags); - if (!pdf_doc.appendPage(data_->current_page_.get())) + // 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) return metafile.Pass(); - SkDynamicMemoryWStream pdf_stream; - if (!pdf_doc.emitPDF(&pdf_stream)) + if (data_->recorder_.getRecordingCanvas()) // page outstanding return metafile.Pass(); - SkAutoDataUnref data_copy(pdf_stream.copyToData()); - if (data_copy->size() == 0) - return scoped_ptr<PdfMetafileSkia>(); + const Page& page = data_->pages_.back(); - metafile.reset(new PdfMetafileSkia); - if (!metafile->InitFromData(data_copy->bytes(), - base::checked_cast<uint32>(data_copy->size()))) { + metafile->data_->pages_.push_back(page); + + if (!metafile->FinishDocument()) // Generate PDF. metafile.reset(); - } + return metafile.Pass(); } |