diff --git a/printing/BUILD.gn b/printing/BUILD.gn index ae715ad5cb65f4..11549b4f7b8c45 100644 --- a/printing/BUILD.gn +++ b/printing/BUILD.gn @@ -269,6 +269,7 @@ test("printing_unittests") { "page_range_unittest.cc", "page_setup_unittest.cc", "pdf_metafile_cg_mac_unittest.cc", + "pdf_metafile_skia_unittest.cc", "printing_context_win_unittest.cc", "printing_test.h", "printing_utils_unittest.cc", @@ -279,6 +280,7 @@ test("printing_unittests") { ":printing", "//base/test:run_all_unittests", "//base/test:test_support", + "//printing/common", "//testing/gtest", "//ui/base", "//ui/gfx", diff --git a/printing/pdf_metafile_skia.cc b/printing/pdf_metafile_skia.cc index 4daaf91389ad98..6235d63e365beb 100644 --- a/printing/pdf_metafile_skia.cc +++ b/printing/pdf_metafile_skia.cc @@ -369,6 +369,22 @@ const ContentToProxyIdMap& PdfMetafileSkia::GetSubframeContentInfo() const { return data_->subframe_content_info_; } +void PdfMetafileSkia::AppendPage(const SkSize& page_size, + sk_sp record) { + data_->pages_.emplace_back(page_size, std::move(record)); +} + +void PdfMetafileSkia::AppendSubframeInfo(uint32_t content_id, + int proxy_id, + sk_sp pic_holder) { + data_->subframe_content_info_[content_id] = proxy_id; + data_->subframe_pics_[content_id] = pic_holder; +} + +SkStreamAsset* PdfMetafileSkia::GetPdfData() const { + return data_->pdf_data_.get(); +} + void PdfMetafileSkia::CustomDataToSkPictureCallback(SkCanvas* canvas, uint32_t content_id) { // Check whether this is the one we need to handle. diff --git a/printing/pdf_metafile_skia.h b/printing/pdf_metafile_skia.h index 602f0f61e9c393..9fa92fa86cc04b 100644 --- a/printing/pdf_metafile_skia.h +++ b/printing/pdf_metafile_skia.h @@ -9,6 +9,7 @@ #include +#include "base/gtest_prod_util.h" #include "base/macros.h" #include "build/build_config.h" #include "cc/paint/paint_canvas.h" @@ -96,6 +97,15 @@ class PRINTING_EXPORT PdfMetafileSkia : public Metafile { const ContentToProxyIdMap& GetSubframeContentInfo() const; private: + FRIEND_TEST_ALL_PREFIXES(PdfMetafileSkiaTest, TestFrameContent); + + // The following three functions are used for tests only. + void AppendPage(const SkSize& page_size, sk_sp record); + void AppendSubframeInfo(uint32_t content_id, + int proxy_id, + sk_sp subframe_pic_holder); + SkStreamAsset* GetPdfData() const; + // Callback function used during page content drawing to replace a custom // data holder with corresponding place holder SkPicture. void CustomDataToSkPictureCallback(SkCanvas* canvas, uint32_t content_id); diff --git a/printing/pdf_metafile_skia_unittest.cc b/printing/pdf_metafile_skia_unittest.cc new file mode 100644 index 00000000000000..70a118ed7c1f36 --- /dev/null +++ b/printing/pdf_metafile_skia_unittest.cc @@ -0,0 +1,80 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing/pdf_metafile_skia.h" + +#include "cc/paint/paint_record.h" +#include "printing/common/pdf_metafile_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" + +namespace printing { + +TEST(PdfMetafileSkiaTest, TestFrameContent) { + constexpr int kPictureSideLen = 100; + constexpr int kPageSideLen = 150; + + // Create a placeholder picture. + sk_sp pic_holder = SkPicture::MakePlaceholder( + SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen)); + + // Create the page with nested content which is the placeholder and will be + // replaced later. + sk_sp record = sk_make_sp(); + cc::PaintFlags flags; + flags.setColor(SK_ColorWHITE); + const SkRect page_rect = SkRect::MakeXYWH(0, 0, kPageSideLen, kPageSideLen); + record->push(page_rect, flags); + const uint32_t content_id = pic_holder->uniqueID(); + record->push(content_id); + SkSize page_size = SkSize::Make(kPageSideLen, kPageSideLen); + + // Finish creating the entire metafile. + PdfMetafileSkia metafile(SkiaDocumentType::MSKP, 1); + metafile.AppendPage(page_size, std::move(record)); + metafile.AppendSubframeInfo(content_id, 2, std::move(pic_holder)); + metafile.FinishFrameContent(); + SkStreamAsset* metafile_stream = metafile.GetPdfData(); + ASSERT_TRUE(metafile_stream); + + // Draw a 100 by 100 red square which will be the actual content of + // the placeholder. + SkPictureRecorder recorder; + SkCanvas* canvas = recorder.beginRecording(kPictureSideLen, kPictureSideLen); + SkPaint paint; + paint.setStyle(SkPaint::kStrokeAndFill_Style); + paint.setColor(SK_ColorRED); + paint.setAlpha(SK_AlphaOPAQUE); + canvas->drawRect(SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen), + paint); + sk_sp picture(recorder.finishRecordingAsPicture()); + EXPECT_TRUE(picture); + + // Get the complete picture by replacing the placeholder. + DeserializationContext subframes; + subframes[content_id] = picture; + SkDeserialProcs procs = DeserializationProcs(&subframes); + sk_sp pic = SkPicture::MakeFromStream(metafile_stream, &procs); + ASSERT_TRUE(pic); + + // Verify the resultant picture is as expected by comparing the sizes and + // detecting the color inside and outside of the square area. + EXPECT_TRUE(pic->cullRect() == page_rect); + SkBitmap bitmap; + bitmap.allocN32Pixels(kPageSideLen, kPageSideLen); + SkCanvas bitmap_canvas(bitmap); + pic->playback(&bitmap_canvas); + // Check top left pixel color of the red square. + EXPECT_EQ(bitmap.getColor(0, 0), SK_ColorRED); + // Check bottom right pixel of the red square. + EXPECT_EQ(bitmap.getColor(kPictureSideLen - 1, kPictureSideLen - 1), + SK_ColorRED); + // Check inside of the red square. + EXPECT_EQ(bitmap.getColor(kPictureSideLen / 2, kPictureSideLen / 2), + SK_ColorRED); + // Check outside of the red square. + EXPECT_EQ(bitmap.getColor(kPictureSideLen, kPictureSideLen), SK_ColorWHITE); +} + +} // namespace printing