blob: 6235d63e365beb21ce73e8542eafb064c18dac87 [file] [log] [blame]
[email protected]0a4392a2012-03-23 17:50:191// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]8f879292011-04-08 00:21:202// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "printing/pdf_metafile_skia.h"
6
thestig6b4461f2016-10-28 19:34:307#include <algorithm>
8#include <string>
9#include <utility>
10#include <vector>
11
Wei Lie13ea642018-02-17 07:55:1912#include "base/bind.h"
13#include "base/bind_helpers.h"
halcanary223f70a2016-06-09 00:07:4214#include "base/files/file.h"
Wei Lie13ea642018-02-17 07:55:1915#include "base/stl_util.h"
halcanary67ce00b82015-09-27 21:59:5316#include "base/time/time.h"
enne7b64edf32017-02-16 20:10:0217#include "cc/paint/paint_record.h"
18#include "cc/paint/paint_recorder.h"
enne59df29de2017-05-02 03:23:3719#include "cc/paint/skia_paint_canvas.h"
halcanary73b63fd2015-11-06 00:02:1420#include "printing/print_settings.h"
Wei Lie13ea642018-02-17 07:55:1921#include "third_party/skia/include/core/SkCanvas.h"
22#include "third_party/skia/include/core/SkPicture.h"
Wei Li5bb659742018-02-14 03:07:5823#include "third_party/skia/include/core/SkSerialProcs.h"
[email protected]8f879292011-04-08 00:21:2024#include "third_party/skia/include/core/SkStream.h"
halcanaryffa005b2016-06-15 17:13:1625// Note that headers in third_party/skia/src are fragile. This is
26// an experimental, fragile, and diagnostic-only document type.
27#include "third_party/skia/src/utils/SkMultiPictureDocument.h"
halcanary223f70a2016-06-09 00:07:4228#include "ui/gfx/geometry/safe_integer_conversions.h"
halcanaryff214762015-01-22 20:34:3229#include "ui/gfx/skia_util.h"
[email protected]8f879292011-04-08 00:21:2030
thestig99fc2132017-04-27 03:37:5431#if defined(OS_MACOSX)
32#include "printing/pdf_metafile_cg_mac.h"
33#endif
34
35#if defined(OS_POSIX)
36#include "base/file_descriptor_posix.h"
37#endif
38
halcanaryff214762015-01-22 20:34:3239namespace {
thestige3f5f5d42015-07-16 19:46:2440
thestige3f5f5d42015-07-16 19:46:2441bool WriteAssetToBuffer(const SkStreamAsset* asset,
42 void* buffer,
43 size_t size) {
halcanaryff214762015-01-22 20:34:3244 // Calling duplicate() keeps original asset state unchanged.
dchengc3df9ba2016-04-07 23:09:3245 std::unique_ptr<SkStreamAsset> assetCopy(asset->duplicate());
halcanaryff214762015-01-22 20:34:3246 size_t length = assetCopy->getLength();
Lei Zhang662e4222017-12-14 20:18:3447 return length <= size && length == assetCopy->read(buffer, length);
halcanaryff214762015-01-22 20:34:3248}
49
thestige3f5f5d42015-07-16 19:46:2450} // namespace
51
[email protected]8f879292011-04-08 00:21:2052namespace printing {
53
Lei Zhang662e4222017-12-14 20:18:3454// TODO(thestig): struct members should not have trailing underscore.
halcanary8dd6f0242016-06-13 19:40:2355struct Page {
enne7b64edf32017-02-16 20:10:0256 Page(SkSize s, sk_sp<cc::PaintRecord> c) : size_(s), content_(std::move(c)) {}
halcanary8dd6f0242016-06-13 19:40:2357 Page(Page&& that) : size_(that.size_), content_(std::move(that.content_)) {}
58 Page(const Page&) = default;
59 Page& operator=(const Page&) = default;
60 Page& operator=(Page&& that) {
61 size_ = that.size_;
62 content_ = std::move(that.content_);
63 return *this;
64 }
65 SkSize size_;
enne7b64edf32017-02-16 20:10:0266 sk_sp<cc::PaintRecord> content_;
halcanary8dd6f0242016-06-13 19:40:2367};
68
Wei Li5bb659742018-02-14 03:07:5869// TODO(weili): Remove pdf from struct name and field names since it is used for
Wei Lie13ea642018-02-17 07:55:1970// other formats as well. Also change member variable names to
71// conform with our style guide.
[email protected]8f879292011-04-08 00:21:2072struct PdfMetafileSkiaData {
enne7b64edf32017-02-16 20:10:0273 cc::PaintRecorder recorder_; // Current recording
halcanaryff214762015-01-22 20:34:3274
halcanary8dd6f0242016-06-13 19:40:2375 std::vector<Page> pages_;
dchengc3df9ba2016-04-07 23:09:3276 std::unique_ptr<SkStreamAsset> pdf_data_;
Wei Lie13ea642018-02-17 07:55:1977 ContentToProxyIdMap subframe_content_info_;
78 std::map<uint32_t, sk_sp<SkPicture>> subframe_pics_;
79 int document_cookie_ = 0;
halcanaryff214762015-01-22 20:34:3280
halcanary223f70a2016-06-09 00:07:4281 // The scale factor is used because Blink occasionally calls
enne7b64edf32017-02-16 20:10:0282 // PaintCanvas::getTotalMatrix() even though the total matrix is not as
halcanary223f70a2016-06-09 00:07:4283 // meaningful for a vector canvas as for a raster canvas.
84 float scale_factor_;
halcanary8dd6f0242016-06-13 19:40:2385 SkSize size_;
halcanaryffa005b2016-06-15 17:13:1686 SkiaDocumentType type_;
thestig99fc2132017-04-27 03:37:5487
88#if defined(OS_MACOSX)
89 PdfMetafileCg pdf_cg_;
90#endif
[email protected]8f879292011-04-08 00:21:2091};
92
Wei Lie13ea642018-02-17 07:55:1993PdfMetafileSkia::PdfMetafileSkia()
94 : data_(std::make_unique<PdfMetafileSkiaData>()) {
95 data_->type_ = SkiaDocumentType::PDF;
96}
97
98PdfMetafileSkia::PdfMetafileSkia(SkiaDocumentType type, int document_cookie)
Lei Zhang662e4222017-12-14 20:18:3499 : data_(std::make_unique<PdfMetafileSkiaData>()) {
100 data_->type_ = type;
Wei Lie13ea642018-02-17 07:55:19101 data_->document_cookie_ = document_cookie;
Lei Zhang662e4222017-12-14 20:18:34102}
103
Chris Watkinsc360b972017-12-01 05:50:23104PdfMetafileSkia::~PdfMetafileSkia() = default;
[email protected]8f879292011-04-08 00:21:20105
106bool PdfMetafileSkia::Init() {
107 return true;
108}
halcanaryff214762015-01-22 20:34:32109
110// TODO(halcanary): Create a Metafile class that only stores data.
111// Metafile::InitFromData is orthogonal to what the rest of
112// PdfMetafileSkia does.
[email protected]8f879292011-04-08 00:21:20113bool PdfMetafileSkia::InitFromData(const void* src_buffer,
thestig6b4461f2016-10-28 19:34:30114 size_t src_buffer_size) {
Lei Zhang662e4222017-12-14 20:18:34115 data_->pdf_data_ = std::make_unique<SkMemoryStream>(
thestig6b4461f2016-10-28 19:34:30116 src_buffer, src_buffer_size, true /* copy_data? */);
halcanaryff214762015-01-22 20:34:32117 return true;
[email protected]8f879292011-04-08 00:21:20118}
119
thestig192677ec2016-06-09 07:43:17120void PdfMetafileSkia::StartPage(const gfx::Size& page_size,
halcanary5be808e2014-11-10 22:20:05121 const gfx::Rect& content_area,
122 const float& scale_factor) {
halcanary223f70a2016-06-09 00:07:42123 DCHECK_GT(page_size.width(), 0);
124 DCHECK_GT(page_size.height(), 0);
125 DCHECK_GT(scale_factor, 0.0f);
halcanaryff214762015-01-22 20:34:32126 if (data_->recorder_.getRecordingCanvas())
thestig5ff7db22016-02-13 04:42:45127 FinishPage();
halcanaryff214762015-01-22 20:34:32128 DCHECK(!data_->recorder_.getRecordingCanvas());
halcanary223f70a2016-06-09 00:07:42129
130 float inverse_scale = 1.0 / scale_factor;
enne7b64edf32017-02-16 20:10:02131 cc::PaintCanvas* canvas = data_->recorder_.beginRecording(
halcanary223f70a2016-06-09 00:07:42132 inverse_scale * page_size.width(), inverse_scale * page_size.height());
halcanaryffa005b2016-06-15 17:13:16133 // Recording canvas is owned by the data_->recorder_. No ref() necessary.
halcanary223f70a2016-06-09 00:07:42134 if (content_area != gfx::Rect(page_size)) {
135 canvas->scale(inverse_scale, inverse_scale);
136 SkRect sk_content_area = gfx::RectToSkRect(content_area);
137 canvas->clipRect(sk_content_area);
138 canvas->translate(sk_content_area.x(), sk_content_area.y());
139 canvas->scale(scale_factor, scale_factor);
140 }
141
halcanary8dd6f0242016-06-13 19:40:23142 data_->size_ = gfx::SizeFToSkSize(gfx::SizeF(page_size));
halcanary223f70a2016-06-09 00:07:42143 data_->scale_factor_ = scale_factor;
halcanary5baa8fb42015-04-03 21:39:30144 // We scale the recording canvas's size so that
145 // canvas->getTotalMatrix() returns a value that ignores the scale
halcanary223f70a2016-06-09 00:07:42146 // factor. We store the scale factor and re-apply it later.
147 // http://crbug.com/469656
[email protected]8f879292011-04-08 00:21:20148}
149
enne7b64edf32017-02-16 20:10:02150cc::PaintCanvas* PdfMetafileSkia::GetVectorCanvasForNewPage(
halcanary5be808e2014-11-10 22:20:05151 const gfx::Size& page_size,
152 const gfx::Rect& content_area,
153 const float& scale_factor) {
halcanary223f70a2016-06-09 00:07:42154 StartPage(page_size, content_area, scale_factor);
halcanaryff214762015-01-22 20:34:32155 return data_->recorder_.getRecordingCanvas();
[email protected]8f879292011-04-08 00:21:20156}
157
158bool PdfMetafileSkia::FinishPage() {
halcanaryff214762015-01-22 20:34:32159 if (!data_->recorder_.getRecordingCanvas())
160 return false;
halcanary223f70a2016-06-09 00:07:42161
enne7b64edf32017-02-16 20:10:02162 sk_sp<cc::PaintRecord> pic = data_->recorder_.finishRecordingAsPicture();
halcanary223f70a2016-06-09 00:07:42163 if (data_->scale_factor_ != 1.0f) {
enne7b64edf32017-02-16 20:10:02164 cc::PaintCanvas* canvas = data_->recorder_.beginRecording(
165 data_->size_.width(), data_->size_.height());
halcanary223f70a2016-06-09 00:07:42166 canvas->scale(data_->scale_factor_, data_->scale_factor_);
167 canvas->drawPicture(pic);
168 pic = data_->recorder_.finishRecordingAsPicture();
169 }
halcanary8dd6f0242016-06-13 19:40:23170 data_->pages_.emplace_back(data_->size_, std::move(pic));
[email protected]8f879292011-04-08 00:21:20171 return true;
172}
173
174bool PdfMetafileSkia::FinishDocument() {
halcanaryff214762015-01-22 20:34:32175 // If we've already set the data in InitFromData, leave it be.
176 if (data_->pdf_data_)
177 return false;
[email protected]8f879292011-04-08 00:21:20178
halcanaryff214762015-01-22 20:34:32179 if (data_->recorder_.getRecordingCanvas())
thestig5ff7db22016-02-13 04:42:45180 FinishPage();
[email protected]67e16b392011-05-30 20:58:09181
halcanary223f70a2016-06-09 00:07:42182 SkDynamicMemoryWStream stream;
halcanaryffa005b2016-06-15 17:13:16183 sk_sp<SkDocument> doc;
Wei Lie13ea642018-02-17 07:55:19184 cc::PlaybackParams::CustomDataRasterCallback custom_callback;
halcanaryffa005b2016-06-15 17:13:16185 switch (data_->type_) {
Wei Lid0e05022017-08-22 03:56:52186 case SkiaDocumentType::PDF:
weilifabbf7572017-05-22 19:05:16187 doc = MakePdfDocument(printing::GetAgent(), &stream);
halcanaryffa005b2016-06-15 17:13:16188 break;
Wei Lid0e05022017-08-22 03:56:52189 case SkiaDocumentType::MSKP:
Wei Lie13ea642018-02-17 07:55:19190 SkSerialProcs procs = SerializationProcs(&data_->subframe_content_info_);
191 doc = SkMakeMultiPictureDocument(&stream, &procs);
192 // It is safe to use base::Unretained(this) because the callback
193 // is only used by |canvas| in the following loop which has shorter
194 // lifetime than |this|.
195 custom_callback =
196 base::BindRepeating(&PdfMetafileSkia::CustomDataToSkPictureCallback,
197 base::Unretained(this));
halcanaryffa005b2016-06-15 17:13:16198 break;
199 }
halcanaryfb232282016-04-28 18:34:24200
halcanary8dd6f0242016-06-13 19:40:23201 for (const Page& page : data_->pages_) {
enne98c9f8052017-03-15 19:38:22202 cc::SkiaPaintCanvas canvas(
enne7b64edf32017-02-16 20:10:02203 doc->beginPage(page.size_.width(), page.size_.height()));
Wei Lie13ea642018-02-17 07:55:19204 canvas.drawPicture(page.content_, custom_callback);
halcanary223f70a2016-06-09 00:07:42205 doc->endPage();
halcanary0aeeb3332016-03-18 14:32:39206 }
reede35e0532016-09-22 17:30:29207 doc->close();
[email protected]67e16b392011-05-30 20:58:09208
halcanaryde655aa2017-04-03 16:16:13209 data_->pdf_data_ = stream.detachAsStream();
halcanaryff214762015-01-22 20:34:32210 return true;
[email protected]8f879292011-04-08 00:21:20211}
212
Wei Li5bb659742018-02-14 03:07:58213void PdfMetafileSkia::FinishFrameContent() {
214 // Sanity check to make sure we print the entire frame as a single page
215 // content.
216 DCHECK_EQ(data_->pages_.size(), 1u);
217 // Also make sure it is in skia multi-picture document format.
218 DCHECK_EQ(data_->type_, SkiaDocumentType::MSKP);
219 DCHECK(!data_->pdf_data_);
220
Wei Li6b0cfc92018-08-08 19:52:25221 cc::PlaybackParams::CustomDataRasterCallback custom_callback =
222 base::BindRepeating(&PdfMetafileSkia::CustomDataToSkPictureCallback,
223 base::Unretained(this));
Wei Li5bb659742018-02-14 03:07:58224 sk_sp<SkPicture> pic = ToSkPicture(data_->pages_[0].content_,
Wei Li6b0cfc92018-08-08 19:52:25225 SkRect::MakeSize(data_->pages_[0].size_),
226 nullptr, custom_callback);
Wei Lie13ea642018-02-17 07:55:19227 SkSerialProcs procs = SerializationProcs(&data_->subframe_content_info_);
Wei Li6b0cfc92018-08-08 19:52:25228 SkDynamicMemoryWStream stream;
Wei Li5bb659742018-02-14 03:07:58229 pic->serialize(&stream, &procs);
230 data_->pdf_data_ = stream.detachAsStream();
231}
232
thestig707a24b22015-09-14 18:16:33233uint32_t PdfMetafileSkia::GetDataSize() const {
halcanaryff214762015-01-22 20:34:32234 if (!data_->pdf_data_)
235 return 0;
thestig707a24b22015-09-14 18:16:33236 return base::checked_cast<uint32_t>(data_->pdf_data_->getLength());
[email protected]8f879292011-04-08 00:21:20237}
238
239bool PdfMetafileSkia::GetData(void* dst_buffer,
thestig707a24b22015-09-14 18:16:33240 uint32_t dst_buffer_size) const {
halcanaryff214762015-01-22 20:34:32241 if (!data_->pdf_data_)
[email protected]8f879292011-04-08 00:21:20242 return false;
halcanaryff214762015-01-22 20:34:32243 return WriteAssetToBuffer(data_->pdf_data_.get(), dst_buffer,
244 base::checked_cast<size_t>(dst_buffer_size));
[email protected]8f879292011-04-08 00:21:20245}
246
[email protected]8f879292011-04-08 00:21:20247gfx::Rect PdfMetafileSkia::GetPageBounds(unsigned int page_number) const {
halcanaryff214762015-01-22 20:34:32248 if (page_number < data_->pages_.size()) {
halcanary8dd6f0242016-06-13 19:40:23249 SkSize size = data_->pages_[page_number].size_;
250 return gfx::Rect(gfx::ToRoundedInt(size.width()),
251 gfx::ToRoundedInt(size.height()));
halcanaryff214762015-01-22 20:34:32252 }
[email protected]8f879292011-04-08 00:21:20253 return gfx::Rect();
254}
255
256unsigned int PdfMetafileSkia::GetPageCount() const {
halcanaryff214762015-01-22 20:34:32257 return base::checked_cast<unsigned int>(data_->pages_.size());
[email protected]8f879292011-04-08 00:21:20258}
259
Nico Weber8e559562017-10-03 01:25:26260printing::NativeDrawingContext PdfMetafileSkia::context() const {
[email protected]8f879292011-04-08 00:21:20261 NOTREACHED();
thestig192677ec2016-06-09 07:43:17262 return nullptr;
[email protected]8f879292011-04-08 00:21:20263}
264
thestig192677ec2016-06-09 07:43:17265
[email protected]8f879292011-04-08 00:21:20266#if defined(OS_WIN)
Nico Weber8e559562017-10-03 01:25:26267bool PdfMetafileSkia::Playback(printing::NativeDrawingContext hdc,
thestig3109df12017-04-26 21:57:25268 const RECT* rect) const {
269 NOTREACHED();
270 return false;
271}
272
Nico Weber8e559562017-10-03 01:25:26273bool PdfMetafileSkia::SafePlayback(printing::NativeDrawingContext hdc) const {
[email protected]8f879292011-04-08 00:21:20274 NOTREACHED();
275 return false;
276}
thestig99fc2132017-04-27 03:37:54277
278#elif defined(OS_MACOSX)
279/* TODO(caryclark): The set up of PluginInstance::PrintPDFOutput may result in
280 rasterized output. Even if that flow uses PdfMetafileCg::RenderPage,
281 the drawing of the PDF into the canvas may result in a rasterized output.
282 PDFMetafileSkia::RenderPage should be not implemented as shown and instead
283 should do something like the following CL in PluginInstance::PrintPDFOutput:
284http://codereview.chromium.org/7200040/diff/1/webkit/plugins/ppapi/ppapi_plugin_instance.cc
285*/
286bool PdfMetafileSkia::RenderPage(unsigned int page_number,
287 CGContextRef context,
288 const CGRect rect,
289 const MacRenderPageParams& params) const {
290 DCHECK_GT(GetDataSize(), 0U);
291 if (data_->pdf_cg_.GetDataSize() == 0) {
292 if (GetDataSize() == 0)
293 return false;
294 size_t length = data_->pdf_data_->getLength();
295 std::vector<uint8_t> buffer(length);
296 (void)WriteAssetToBuffer(data_->pdf_data_.get(), &buffer[0], length);
297 data_->pdf_cg_.InitFromData(&buffer[0], length);
298 }
299 return data_->pdf_cg_.RenderPage(page_number, context, rect, params);
300}
[email protected]b8d85bc2011-06-22 13:34:57301#endif
[email protected]8f879292011-04-08 00:21:20302
halcanary5be808e2014-11-10 22:20:05303bool PdfMetafileSkia::SaveTo(base::File* file) const {
304 if (GetDataSize() == 0U)
305 return false;
halcanaryff214762015-01-22 20:34:32306
307 // Calling duplicate() keeps original asset state unchanged.
dchengc3df9ba2016-04-07 23:09:32308 std::unique_ptr<SkStreamAsset> asset(data_->pdf_data_->duplicate());
halcanaryff214762015-01-22 20:34:32309
thestig192677ec2016-06-09 07:43:17310 const size_t kMaximumBufferSize = 1024 * 1024;
311 std::vector<char> buffer(std::min(kMaximumBufferSize, asset->getLength()));
halcanaryff214762015-01-22 20:34:32312 do {
313 size_t read_size = asset->read(&buffer[0], buffer.size());
314 if (read_size == 0)
315 break;
316 DCHECK_GE(buffer.size(), read_size);
317 if (!file->WriteAtCurrentPos(&buffer[0],
318 base::checked_cast<int>(read_size))) {
319 return false;
320 }
321 } while (!asset->isAtEnd());
322
323 return true;
halcanary5be808e2014-11-10 22:20:05324}
325
halcanaryffa005b2016-06-15 17:13:16326std::unique_ptr<PdfMetafileSkia> PdfMetafileSkia::GetMetafileForCurrentPage(
327 SkiaDocumentType type) {
halcanaryff214762015-01-22 20:34:32328 // If we only ever need the metafile for the last page, should we
enne7b64edf32017-02-16 20:10:02329 // only keep a handle on one PaintRecord?
Wei Lie13ea642018-02-17 07:55:19330 auto metafile =
331 std::make_unique<PdfMetafileSkia>(type, data_->document_cookie_);
halcanaryff214762015-01-22 20:34:32332 if (data_->pages_.size() == 0)
dchenge48600452015-12-28 02:24:50333 return metafile;
[email protected]597516372011-07-01 05:10:44334
halcanaryff214762015-01-22 20:34:32335 if (data_->recorder_.getRecordingCanvas()) // page outstanding
dchenge48600452015-12-28 02:24:50336 return metafile;
[email protected]597516372011-07-01 05:10:44337
halcanary223f70a2016-06-09 00:07:42338 metafile->data_->pages_.push_back(data_->pages_.back());
Wei Lie13ea642018-02-17 07:55:19339 metafile->data_->subframe_content_info_ = data_->subframe_content_info_;
340 metafile->data_->subframe_pics_ = data_->subframe_pics_;
halcanaryff214762015-01-22 20:34:32341
342 if (!metafile->FinishDocument()) // Generate PDF.
vitalybuka5d1290582014-09-12 09:19:59343 metafile.reset();
halcanaryff214762015-01-22 20:34:32344
dchenge48600452015-12-28 02:24:50345 return metafile;
[email protected]597516372011-07-01 05:10:44346}
[email protected]8f879292011-04-08 00:21:20347
Wei Lie13ea642018-02-17 07:55:19348uint32_t PdfMetafileSkia::CreateContentForRemoteFrame(const gfx::Rect& rect,
349 int render_proxy_id) {
350 // Create a place holder picture.
351 sk_sp<SkPicture> pic = SkPicture::MakePlaceholder(
352 SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()));
353
354 // Store the map between content id and the proxy id.
355 uint32_t content_id = pic->uniqueID();
356 DCHECK(!base::ContainsKey(data_->subframe_content_info_, content_id));
357 data_->subframe_content_info_[content_id] = render_proxy_id;
358
359 // Store the picture content.
360 data_->subframe_pics_[content_id] = pic;
361 return content_id;
362}
363
364int PdfMetafileSkia::GetDocumentCookie() const {
365 return data_->document_cookie_;
366}
367
368const ContentToProxyIdMap& PdfMetafileSkia::GetSubframeContentInfo() const {
369 return data_->subframe_content_info_;
370}
371
Wei Li1d345bf2018-08-10 02:52:37372void PdfMetafileSkia::AppendPage(const SkSize& page_size,
373 sk_sp<cc::PaintRecord> record) {
374 data_->pages_.emplace_back(page_size, std::move(record));
375}
376
377void PdfMetafileSkia::AppendSubframeInfo(uint32_t content_id,
378 int proxy_id,
379 sk_sp<SkPicture> pic_holder) {
380 data_->subframe_content_info_[content_id] = proxy_id;
381 data_->subframe_pics_[content_id] = pic_holder;
382}
383
384SkStreamAsset* PdfMetafileSkia::GetPdfData() const {
385 return data_->pdf_data_.get();
386}
387
Wei Lie13ea642018-02-17 07:55:19388void PdfMetafileSkia::CustomDataToSkPictureCallback(SkCanvas* canvas,
389 uint32_t content_id) {
390 // Check whether this is the one we need to handle.
391 if (!base::ContainsKey(data_->subframe_content_info_, content_id))
392 return;
393
394 auto it = data_->subframe_pics_.find(content_id);
395 DCHECK(it != data_->subframe_pics_.end());
396
397 // Found the picture, draw it on canvas.
398 sk_sp<SkPicture> pic = it->second;
399 SkRect rect = pic->cullRect();
400 SkMatrix matrix = SkMatrix::MakeTrans(rect.x(), rect.y());
401 canvas->drawPicture(it->second, &matrix, nullptr);
402}
403
[email protected]8f879292011-04-08 00:21:20404} // namespace printing