summaryrefslogtreecommitdiffstats
path: root/printing
diff options
context:
space:
mode:
authorhalcanary <halcanary@google.com>2015-01-22 12:34:32 -0800
committerCommit bot <commit-bot@chromium.org>2015-01-22 20:35:24 +0000
commitff21476a27b22e7819fc9874456e31aa516a9c1c (patch)
treef414df0e8cd81b1ea15d01b209e36abb2d4e6561 /printing
parenta98f15b7d247d2d22a9b363380b333ca20597858 (diff)
downloadchromium_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.cc212
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();
}