blob: 155fe3b75b8c4c8751d9b46592decfe2814f1ff7 [file] [log] [blame]
Tom Sepezd483eb42016-01-06 10:03:59 -08001// Copyright 2016 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05005#include <memory>
6#include <string>
Nicolas Penad03ca422017-03-06 13:54:33 -05007#include <utility>
Jane Liu548334e2017-08-03 16:33:40 -04008#include <vector>
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05009
Lei Zhange4cdac52019-04-30 16:45:57 +000010#include "build/build_config.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050011#include "core/fpdfapi/font/cpdf_font.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050012#include "core/fpdfapi/page/cpdf_page.h"
Henrique Nakashima6eb79392018-06-12 20:27:35 +000013#include "core/fpdfapi/page/cpdf_pageobject.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050014#include "core/fpdfapi/parser/cpdf_array.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050015#include "core/fpdfapi/parser/cpdf_dictionary.h"
Nicolas Penad03ca422017-03-06 13:54:33 -050016#include "core/fpdfapi/parser/cpdf_number.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050017#include "core/fpdfapi/parser/cpdf_stream.h"
Artem Strygineababa12018-06-06 12:31:18 +000018#include "core/fpdfapi/parser/cpdf_stream_acc.h"
Tom Sepez6c57cda2021-07-23 19:41:57 +000019#include "core/fxcrt/fx_codepage.h"
Nicolas Pena0fc185e2017-02-08 12:13:20 -050020#include "core/fxcrt/fx_system.h"
Lei Zhang0dcb8fd2019-02-07 00:46:04 +000021#include "core/fxge/fx_font.h"
Dan Sinclair00d47a62018-03-28 18:39:04 +000022#include "fpdfsdk/cpdfsdk_helpers.h"
Tom Sepeze08d2b12018-04-25 18:49:32 +000023#include "public/cpp/fpdf_scopers.h"
Jane Liueda65252017-06-07 11:31:27 -040024#include "public/fpdf_annot.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080025#include "public/fpdf_edit.h"
26#include "public/fpdfview.h"
27#include "testing/embedder_test.h"
Hui Yingstb4baceb2020-04-28 23:46:10 +000028#include "testing/embedder_test_constants.h"
Lei Zhangb6992dd2019-02-05 23:30:20 +000029#include "testing/fx_string_testhelpers.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080030#include "testing/gmock/include/gmock/gmock-matchers.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080031#include "testing/gtest/include/gtest/gtest.h"
Hui Yingst8e88e382020-11-02 18:19:56 +000032#include "testing/utils/file_util.h"
Lei Zhang4c64e962019-02-05 19:24:12 +000033#include "testing/utils/hash.h"
Hui Yingst8e88e382020-11-02 18:19:56 +000034#include "testing/utils/path_service.h"
Tom Sepez9c78c0d2021-01-27 20:13:14 +000035#include "third_party/base/check.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080036
Hui Yingstb4baceb2020-04-28 23:46:10 +000037using pdfium::kHelloWorldChecksum;
38
39namespace {
40
Hui Yingst3b6136a2020-06-09 00:39:33 +000041const char kAllRemovedChecksum[] = "eee4600ac08b458ac7ac2320e225674c";
42
43const wchar_t kBottomText[] = L"I'm at the bottom of the page";
44
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000045#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
46static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000047 "84461cd5d952b6ae3d57a5070da84e19";
Lei Zhang42d30c22022-01-12 19:24:43 +000048#elif BUILDFLAG(IS_APPLE)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000049static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000050 "81636489006a31fcb00cf29efcdf7909";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000051#else
52static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000053 "891dcb6e914c8360998055f1f47c9727";
Hui Yingst3b6136a2020-06-09 00:39:33 +000054#endif
Hui Yingstb4baceb2020-04-28 23:46:10 +000055
Hui Yingst08c40712020-04-29 01:37:35 +000056#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +000057const char kFirstRemovedChecksum[] = "f46cbf12eb4e9bbdc3a5d8e1f2103446";
Lei Zhang42d30c22022-01-12 19:24:43 +000058#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +000059const char kFirstRemovedChecksum[] = "a1dc2812692fcc7ee4f01ca77435df9d";
Hui Yingstb4baceb2020-04-28 23:46:10 +000060#else
Tom Andersond4fe5f72021-12-03 20:52:52 +000061const char kFirstRemovedChecksum[] = "e1477dc3b5b3b9c560814c4d1135a02b";
Hui Yingstb4baceb2020-04-28 23:46:10 +000062#endif
63
Hui Yingst3b6136a2020-06-09 00:39:33 +000064const wchar_t kLoadedFontText[] = L"I am testing my loaded font, WEE.";
65
Hui Yingst9d6ec8f2020-11-05 23:35:38 +000066#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingste1215fc2022-03-26 22:29:08 +000067const char kLoadedFontTextChecksum[] = "d58570cc045dfb818b92cbabbd1a364c";
Lei Zhang42d30c22022-01-12 19:24:43 +000068#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +000069const char kLoadedFontTextChecksum[] = "0f3e4a7d71f9e7eb8a1a0d69403b9848";
Hui Yingst3b6136a2020-06-09 00:39:33 +000070#else
Tom Andersond4fe5f72021-12-03 20:52:52 +000071const char kLoadedFontTextChecksum[] = "d58570cc045dfb818b92cbabbd1a364c";
Hui Yingst3b6136a2020-06-09 00:39:33 +000072#endif
73
74const char kRedRectangleChecksum[] = "66d02eaa6181e2c069ce2ea99beda497";
75
Lei Zhang85166512020-07-14 23:28:56 +000076// In embedded_images.pdf.
77const char kEmbeddedImage33Checksum[] = "cb3637934bb3b95a6e4ae1ea9eb9e56e";
78
Hui Yingstb4baceb2020-04-28 23:46:10 +000079} // namespace
80
Lei Zhangab41f252018-12-23 03:10:50 +000081class FPDFEditEmbedderTest : public EmbedderTest {
Nicolas Penad03ca422017-03-06 13:54:33 -050082 protected:
83 FPDF_DOCUMENT CreateNewDocument() {
Lei Zhang935fb862021-11-05 00:15:05 +000084 CreateEmptyDocumentWithoutFormFillEnvironment();
Lei Zhang38e2b0e2021-11-05 00:28:05 +000085 cpdf_doc_ = CPDFDocumentFromFPDFDocument(document());
86 return document();
Nicolas Penad03ca422017-03-06 13:54:33 -050087 }
88
Lei Zhang710fa992018-05-25 16:24:48 +000089 void CheckFontDescriptor(const CPDF_Dictionary* font_dict,
Nicolas Penad03ca422017-03-06 13:54:33 -050090 int font_type,
91 bool bold,
92 bool italic,
Tom Sepez20c41a52018-08-29 23:53:53 +000093 pdfium::span<const uint8_t> span) {
Lei Zhangb1ec2802018-05-25 21:55:24 +000094 const CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
Nicolas Penad03ca422017-03-06 13:54:33 -050095 ASSERT_TRUE(font_desc);
Lei Zhanga228ff32020-06-24 17:39:33 +000096 EXPECT_EQ("FontDescriptor", font_desc->GetNameFor("Type"));
97 ByteString font_name = font_desc->GetNameFor("FontName");
98 EXPECT_FALSE(font_name.IsEmpty());
99 EXPECT_EQ(font_dict->GetNameFor("BaseFont"), font_name);
Nicolas Penad03ca422017-03-06 13:54:33 -0500100
101 // Check that the font descriptor has the required keys according to spec
102 // 1.7 Table 5.19
103 ASSERT_TRUE(font_desc->KeyExist("Flags"));
Dan Sinclair10e1f052017-09-28 15:59:42 -0400104
Nicolas Penad03ca422017-03-06 13:54:33 -0500105 int font_flags = font_desc->GetIntegerFor("Flags");
Lei Zhang44d03832019-10-18 18:45:31 +0000106 EXPECT_EQ(bold, FontStyleIsForceBold(font_flags));
Dan Sinclair10e1f052017-09-28 15:59:42 -0400107 EXPECT_EQ(italic, FontStyleIsItalic(font_flags));
108 EXPECT_TRUE(FontStyleIsNonSymbolic(font_flags));
Nicolas Penad03ca422017-03-06 13:54:33 -0500109 ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
Nicolás Peña5f95f362017-09-28 13:00:45 +0900110
Lei Zhangb1ec2802018-05-25 21:55:24 +0000111 const CPDF_Array* fontBBox = font_desc->GetArrayFor("FontBBox");
Nicolás Peña5f95f362017-09-28 13:00:45 +0900112 ASSERT_TRUE(fontBBox);
Lei Zhangf40380f2018-10-12 18:31:51 +0000113 EXPECT_EQ(4u, fontBBox->size());
Nicolás Peña5f95f362017-09-28 13:00:45 +0900114 // Check that the coordinates are in the preferred order according to spec
115 // 1.7 Section 3.8.4
116 EXPECT_TRUE(fontBBox->GetIntegerAt(0) < fontBBox->GetIntegerAt(2));
117 EXPECT_TRUE(fontBBox->GetIntegerAt(1) < fontBBox->GetIntegerAt(3));
118
Nicolas Penad03ca422017-03-06 13:54:33 -0500119 EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
120 EXPECT_TRUE(font_desc->KeyExist("Ascent"));
121 EXPECT_TRUE(font_desc->KeyExist("Descent"));
122 EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
123 EXPECT_TRUE(font_desc->KeyExist("StemV"));
Ryan Harrison275e2602017-09-18 14:23:18 -0400124 ByteString present("FontFile");
125 ByteString absent("FontFile2");
Nicolas Penad03ca422017-03-06 13:54:33 -0500126 if (font_type == FPDF_FONT_TRUETYPE)
127 std::swap(present, absent);
128 EXPECT_TRUE(font_desc->KeyExist(present));
129 EXPECT_FALSE(font_desc->KeyExist(absent));
130
Artem Strygineababa12018-06-06 12:31:18 +0000131 auto streamAcc =
132 pdfium::MakeRetain<CPDF_StreamAcc>(font_desc->GetStreamFor(present));
133 streamAcc->LoadAllDataRaw();
134
Nicolas Penad03ca422017-03-06 13:54:33 -0500135 // Check that the font stream is the one that was provided
Tom Sepez20c41a52018-08-29 23:53:53 +0000136 ASSERT_EQ(span.size(), streamAcc->GetSize());
Nicolás Peña79eab232017-09-28 13:29:05 +0900137 if (font_type == FPDF_FONT_TRUETYPE) {
Tom Sepez20c41a52018-08-29 23:53:53 +0000138 ASSERT_EQ(static_cast<int>(span.size()),
Artem Strygineababa12018-06-06 12:31:18 +0000139 streamAcc->GetDict()->GetIntegerFor("Length1"));
Nicolás Peña79eab232017-09-28 13:29:05 +0900140 }
Artem Strygineababa12018-06-06 12:31:18 +0000141
142 const uint8_t* stream_data = streamAcc->GetData();
Tom Sepez20c41a52018-08-29 23:53:53 +0000143 for (size_t j = 0; j < span.size(); j++)
144 EXPECT_EQ(span[j], stream_data[j]) << " at byte " << j;
Nicolas Penad03ca422017-03-06 13:54:33 -0500145 }
146
Lei Zhangde579ab2018-05-25 21:49:49 +0000147 void CheckCompositeFontWidths(const CPDF_Array* widths_array,
Nicolas Penad03ca422017-03-06 13:54:33 -0500148 CPDF_Font* typed_font) {
149 // Check that W array is in a format that conforms to PDF spec 1.7 section
150 // "Glyph Metrics in CIDFonts" (these checks are not
151 // implementation-specific).
Lei Zhangf40380f2018-10-12 18:31:51 +0000152 EXPECT_GT(widths_array->size(), 1u);
Nicolas Penad03ca422017-03-06 13:54:33 -0500153 int num_cids_checked = 0;
154 int cur_cid = 0;
Lei Zhangf40380f2018-10-12 18:31:51 +0000155 for (size_t idx = 0; idx < widths_array->size(); idx++) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500156 int cid = widths_array->GetNumberAt(idx);
157 EXPECT_GE(cid, cur_cid);
Lei Zhangf40380f2018-10-12 18:31:51 +0000158 ASSERT_FALSE(++idx == widths_array->size());
Lei Zhangde579ab2018-05-25 21:49:49 +0000159 const CPDF_Object* next = widths_array->GetObjectAt(idx);
Nicolas Penad03ca422017-03-06 13:54:33 -0500160 if (next->IsArray()) {
161 // We are in the c [w1 w2 ...] case
Lei Zhangde579ab2018-05-25 21:49:49 +0000162 const CPDF_Array* arr = next->AsArray();
Lei Zhangf40380f2018-10-12 18:31:51 +0000163 int cnt = static_cast<int>(arr->size());
Nicolas Penad03ca422017-03-06 13:54:33 -0500164 size_t inner_idx = 0;
165 for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
Lei Zhang70e66192020-09-18 20:50:51 +0000166 int width = arr->GetNumberAt(inner_idx++);
Dan Sinclair971a6742018-03-28 19:23:25 +0000167 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
168 << " at cid " << cur_cid;
Nicolas Penad03ca422017-03-06 13:54:33 -0500169 }
170 num_cids_checked += cnt;
171 continue;
172 }
173 // Otherwise, are in the c_first c_last w case.
174 ASSERT_TRUE(next->IsNumber());
175 int last_cid = next->AsNumber()->GetInteger();
Lei Zhangf40380f2018-10-12 18:31:51 +0000176 ASSERT_FALSE(++idx == widths_array->size());
Lei Zhang70e66192020-09-18 20:50:51 +0000177 int width = widths_array->GetNumberAt(idx);
Nicolas Penad03ca422017-03-06 13:54:33 -0500178 for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
Dan Sinclair971a6742018-03-28 19:23:25 +0000179 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
180 << " at cid " << cur_cid;
Nicolas Penad03ca422017-03-06 13:54:33 -0500181 }
182 num_cids_checked += last_cid - cid + 1;
183 }
184 // Make sure we have a good amount of cids described
Tom Andersond4fe5f72021-12-03 20:52:52 +0000185 EXPECT_GT(num_cids_checked, 200);
Nicolas Penad03ca422017-03-06 13:54:33 -0500186 }
187 CPDF_Document* cpdf_doc() { return cpdf_doc_; }
188
189 private:
190 CPDF_Document* cpdf_doc_;
191};
Tom Sepezd483eb42016-01-06 10:03:59 -0800192
etienneb7712c262016-04-26 08:13:45 -0700193namespace {
thestigdc7ec032016-11-21 15:32:52 -0800194
etienneb7712c262016-04-26 08:13:45 -0700195const char kExpectedPDF[] =
196 "%PDF-1.7\r\n"
197 "%\xA1\xB3\xC5\xD7\r\n"
198 "1 0 obj\r\n"
199 "<</Pages 2 0 R /Type/Catalog>>\r\n"
200 "endobj\r\n"
201 "2 0 obj\r\n"
202 "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
203 "endobj\r\n"
204 "3 0 obj\r\n"
205 "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
206 "endobj\r\n"
207 "4 0 obj\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400208 "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R "
209 "/Resources<</ExtGState<</FXE1 5 0 R >>>>"
Nicolas Penad9d6c292017-06-06 16:12:10 -0400210 "/Rotate 0/Type/Page"
etienneb7712c262016-04-26 08:13:45 -0700211 ">>\r\n"
212 "endobj\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400213 "5 0 obj\r\n"
214 "<</BM/Normal/CA 1/ca 1>>\r\n"
215 "endobj\r\n"
etienneb7712c262016-04-26 08:13:45 -0700216 "xref\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400217 "0 6\r\n"
etienneb7712c262016-04-26 08:13:45 -0700218 "0000000000 65535 f\r\n"
219 "0000000017 00000 n\r\n"
220 "0000000066 00000 n\r\n"
221 "0000000122 00000 n\r\n"
222 "0000000192 00000 n\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400223 "0000000311 00000 n\r\n"
etienneb7712c262016-04-26 08:13:45 -0700224 "trailer\r\n"
225 "<<\r\n"
226 "/Root 1 0 R\r\n"
227 "/Info 3 0 R\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400228 "/Size 6/ID\\[<.*><.*>\\]>>\r\n"
etienneb7712c262016-04-26 08:13:45 -0700229 "startxref\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400230 "354\r\n"
etienneb7712c262016-04-26 08:13:45 -0700231 "%%EOF\r\n";
thestigdc7ec032016-11-21 15:32:52 -0800232
etienneb7712c262016-04-26 08:13:45 -0700233} // namespace
234
Hui Yingst8e88e382020-11-02 18:19:56 +0000235TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFont) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000236 CreateEmptyDocument();
Hui Yingst8e88e382020-11-02 18:19:56 +0000237 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
238 std::string font_path;
Hui Yingst8532ef02020-11-04 19:17:17 +0000239 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
240 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
Hui Yingst8e88e382020-11-02 18:19:56 +0000241
242 size_t file_length = 0;
243 std::unique_ptr<char, pdfium::FreeDeleter> font_data =
244 GetFileContents(font_path.c_str(), &file_length);
Lei Zhang786544d2021-07-27 21:25:24 +0000245 ASSERT_TRUE(font_data);
Hui Yingst8e88e382020-11-02 18:19:56 +0000246
247 ScopedFPDFFont font(FPDFText_LoadFont(
248 document(), reinterpret_cast<const uint8_t*>(font_data.get()),
249 file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
250 FPDF_PAGEOBJECT text_object =
251 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
252 EXPECT_TRUE(text_object);
253
254 // Test the characters which are either mapped to one single unicode or
255 // multiple unicodes in the embedded font.
256 ScopedFPDFWideString text = GetFPDFWideString(L"这是第一句。 这是第二行。");
257 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
258
259 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
260 FPDFPage_InsertObject(page.get(), text_object);
261 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
262
Hui Yingst8e88e382020-11-02 18:19:56 +0000263 const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
Hui Yingst8e88e382020-11-02 18:19:56 +0000264 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
265 CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
266
Lei Zhang786544d2021-07-27 21:25:24 +0000267 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
268 VerifySavedDocument(400, 400, kChecksum);
269}
270
271TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFontWithCharcodes) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000272 CreateEmptyDocument();
Lei Zhang786544d2021-07-27 21:25:24 +0000273 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
274 std::string font_path;
275 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
276 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
277
278 size_t file_length = 0;
279 std::unique_ptr<char, pdfium::FreeDeleter> font_data =
280 GetFileContents(font_path.c_str(), &file_length);
281 ASSERT_TRUE(font_data);
282
283 ScopedFPDFFont font(FPDFText_LoadFont(
284 document(), reinterpret_cast<const uint8_t*>(font_data.get()),
285 file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
286 FPDF_PAGEOBJECT text_object =
287 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
288 EXPECT_TRUE(text_object);
289
290 // Same as `text` in the EmbedNotoSansSCFont test case above.
291 const std::vector<uint32_t> charcodes = {9, 6, 7, 3, 5, 2, 1,
292 9, 6, 7, 4, 8, 2};
293 EXPECT_TRUE(
294 FPDFText_SetCharcodes(text_object, charcodes.data(), charcodes.size()));
295
296 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
297 FPDFPage_InsertObject(page.get(), text_object);
298 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
299
Lei Zhang786544d2021-07-27 21:25:24 +0000300 const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
Lei Zhang786544d2021-07-27 21:25:24 +0000301 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
302 CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
303
304 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Hui Yingst8e88e382020-11-02 18:19:56 +0000305 VerifySavedDocument(400, 400, kChecksum);
306}
307
Lei Zhangab41f252018-12-23 03:10:50 +0000308TEST_F(FPDFEditEmbedderTest, EmptyCreation) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000309 CreateEmptyDocument();
weili9b777de2016-08-19 16:19:46 -0700310 FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
Tom Sepezd483eb42016-01-06 10:03:59 -0800311 EXPECT_NE(nullptr, page);
Nicolas Penad9d6c292017-06-06 16:12:10 -0400312 // The FPDFPage_GenerateContent call should do nothing.
Tom Sepezd483eb42016-01-06 10:03:59 -0800313 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepez0aec19b2016-01-07 12:22:44 -0800314 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
etienneb7712c262016-04-26 08:13:45 -0700315
Nicolas Penad9d6c292017-06-06 16:12:10 -0400316 EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
317 kExpectedPDF, sizeof(kExpectedPDF))));
weili9b777de2016-08-19 16:19:46 -0700318 FPDF_ClosePage(page);
Tom Sepezd483eb42016-01-06 10:03:59 -0800319}
thestigdc7ec032016-11-21 15:32:52 -0800320
321// Regression test for https://crbug.com/667012
Lei Zhangab41f252018-12-23 03:10:50 +0000322TEST_F(FPDFEditEmbedderTest, RasterizePDF) {
thestigdc7ec032016-11-21 15:32:52 -0800323 const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
324
Lei Zhangf0542892019-01-17 18:46:27 +0000325 // Get the bitmap for the original document.
Tom Sepeze08d2b12018-04-25 18:49:32 +0000326 ScopedFPDFBitmap orig_bitmap;
thestigdc7ec032016-11-21 15:32:52 -0800327 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000328 ASSERT_TRUE(OpenDocument("black.pdf"));
thestigdc7ec032016-11-21 15:32:52 -0800329 FPDF_PAGE orig_page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000330 ASSERT_TRUE(orig_page);
331 orig_bitmap = RenderLoadedPage(orig_page);
332 CompareBitmap(orig_bitmap.get(), 612, 792, kAllBlackMd5sum);
thestigdc7ec032016-11-21 15:32:52 -0800333 UnloadPage(orig_page);
334 }
335
336 // Create a new document from |orig_bitmap| and save it.
337 {
338 FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
339 FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
340
341 // Add the bitmap to an image object and add the image object to the output
342 // page.
Lei Zhangcbd89572017-03-15 17:35:47 -0700343 FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000344 EXPECT_TRUE(
345 FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap.get()));
Lei Zhangc8601bf2021-06-29 23:19:27 +0000346 static constexpr FS_MATRIX kLetterScaleMatrix{612, 0, 0, 792, 0, 0};
347 EXPECT_TRUE(FPDFPageObj_SetMatrix(temp_img, &kLetterScaleMatrix));
thestigdc7ec032016-11-21 15:32:52 -0800348 FPDFPage_InsertObject(temp_page, temp_img);
349 EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
350 EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
351 FPDF_ClosePage(temp_page);
352 FPDF_CloseDocument(temp_doc);
353 }
thestigdc7ec032016-11-21 15:32:52 -0800354
355 // Get the generated content. Make sure it is at least as big as the original
356 // PDF.
Lei Zhangd72fd582018-07-27 19:37:27 +0000357 EXPECT_GT(GetString().size(), 923u);
Dan Sinclair04e4dc82017-10-18 12:17:14 -0400358 VerifySavedDocument(612, 792, kAllBlackMd5sum);
thestigdc7ec032016-11-21 15:32:52 -0800359}
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500360
Hui Yingsta929df72021-02-26 23:56:18 +0000361TEST_F(FPDFEditEmbedderTest, AddPaths) {
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500362 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500363 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000364 ASSERT_TRUE(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500365
366 // We will first add a red rectangle
367 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000368 ASSERT_TRUE(red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500369 // Expect false when trying to set colors out of range
Lei Zhang3475b482019-05-13 18:30:57 +0000370 EXPECT_FALSE(FPDFPageObj_SetStrokeColor(red_rect, 100, 100, 100, 300));
371 EXPECT_FALSE(FPDFPageObj_SetFillColor(red_rect, 200, 256, 200, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500372
373 // Fill rectangle with red and insert to the page
Lei Zhang3475b482019-05-13 18:30:57 +0000374 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500375 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
Miklos Vajna491112b2018-05-30 13:30:10 +0000376
377 int fillmode = FPDF_FILLMODE_NONE;
378 FPDF_BOOL stroke = true;
379 EXPECT_TRUE(FPDFPath_GetDrawMode(red_rect, &fillmode, &stroke));
380 EXPECT_EQ(FPDF_FILLMODE_ALTERNATE, fillmode);
381 EXPECT_FALSE(stroke);
382
Lei Zhangc8601bf2021-06-29 23:19:27 +0000383 static constexpr FS_MATRIX kMatrix = {1, 2, 3, 4, 5, 6};
384 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &kMatrix));
Lei Zhang8da98232019-12-11 23:29:33 +0000385
386 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +0000387 EXPECT_TRUE(FPDFPageObj_GetMatrix(red_rect, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +0000388 EXPECT_FLOAT_EQ(1.0f, matrix.a);
389 EXPECT_FLOAT_EQ(2.0f, matrix.b);
390 EXPECT_FLOAT_EQ(3.0f, matrix.c);
391 EXPECT_FLOAT_EQ(4.0f, matrix.d);
392 EXPECT_FLOAT_EQ(5.0f, matrix.e);
393 EXPECT_FLOAT_EQ(6.0f, matrix.f);
394
395 // Set back the identity matrix.
396 matrix = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
Lei Zhangc8601bf2021-06-29 23:19:27 +0000397 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &matrix));
Miklos Vajna97f4d672018-06-04 14:47:17 +0000398
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500399 FPDFPage_InsertObject(page, red_rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000400 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000401 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000402 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000403 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500404
405 // Now add to that a green rectangle with some medium alpha
406 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
Lei Zhang3475b482019-05-13 18:30:57 +0000407 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 128));
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200408
Miklos Vajna1ef04c92017-05-08 18:14:19 +0200409 // Make sure the type of the rectangle is a path.
410 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
411
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200412 // Make sure we get back the same color we set previously.
413 unsigned int R;
414 unsigned int G;
415 unsigned int B;
416 unsigned int A;
Lei Zhang3475b482019-05-13 18:30:57 +0000417 EXPECT_TRUE(FPDFPageObj_GetFillColor(green_rect, &R, &G, &B, &A));
Lei Zhangd72fd582018-07-27 19:37:27 +0000418 EXPECT_EQ(0u, R);
419 EXPECT_EQ(255u, G);
420 EXPECT_EQ(0u, B);
421 EXPECT_EQ(128u, A);
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200422
Lei Zhang9b4b8df2021-06-12 06:38:48 +0000423 // Make sure the path has 5 points (1 CFX_Path::Point::Type::kMove and 4
424 // CFX_Path::Point::Type::kLine).
Miklos Vajna0150a542017-09-21 21:46:56 +0200425 ASSERT_EQ(5, FPDFPath_CountSegments(green_rect));
Miklos Vajna36eed872017-09-20 22:52:43 +0200426 // Verify actual coordinates.
427 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0);
428 float x;
429 float y;
430 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
431 EXPECT_EQ(100, x);
432 EXPECT_EQ(100, y);
433 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
434 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
435 segment = FPDFPath_GetPathSegment(green_rect, 1);
436 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
437 EXPECT_EQ(100, x);
438 EXPECT_EQ(140, y);
439 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
440 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
441 segment = FPDFPath_GetPathSegment(green_rect, 2);
442 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
443 EXPECT_EQ(140, x);
444 EXPECT_EQ(140, y);
445 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
446 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
447 segment = FPDFPath_GetPathSegment(green_rect, 3);
448 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
449 EXPECT_EQ(140, x);
450 EXPECT_EQ(100, y);
451 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
452 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
453 segment = FPDFPath_GetPathSegment(green_rect, 4);
454 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
455 EXPECT_EQ(100, x);
456 EXPECT_EQ(100, y);
457 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
458 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200459
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500460 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
461 FPDFPage_InsertObject(page, green_rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000462 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000463 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000464 CompareBitmap(page_bitmap.get(), 612, 792,
465 "7b0b87604594e773add528fae567a558");
466 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500467
468 // Add a black triangle.
469 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
Lei Zhang3475b482019-05-13 18:30:57 +0000470 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 200));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500471 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
472 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
473 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
474 EXPECT_TRUE(FPDFPath_Close(black_path));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200475
Lei Zhang9b4b8df2021-06-12 06:38:48 +0000476 // Make sure the path has 3 points (1 CFX_Path::Point::Type::kMove and 2
477 // CFX_Path::Point::Type::kLine).
Miklos Vajna0150a542017-09-21 21:46:56 +0200478 ASSERT_EQ(3, FPDFPath_CountSegments(black_path));
Miklos Vajna36eed872017-09-20 22:52:43 +0200479 // Verify actual coordinates.
480 segment = FPDFPath_GetPathSegment(black_path, 0);
481 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
482 EXPECT_EQ(400, x);
483 EXPECT_EQ(100, y);
484 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
485 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
486 segment = FPDFPath_GetPathSegment(black_path, 1);
487 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
488 EXPECT_EQ(400, x);
489 EXPECT_EQ(200, y);
490 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
491 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
492 segment = FPDFPath_GetPathSegment(black_path, 2);
493 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
494 EXPECT_EQ(300, x);
495 EXPECT_EQ(100, y);
496 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
497 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
498 // Make sure out of bounds index access fails properly.
499 EXPECT_EQ(nullptr, FPDFPath_GetPathSegment(black_path, 3));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200500
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500501 FPDFPage_InsertObject(page, black_path);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000502 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000503 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000504 CompareBitmap(page_bitmap.get(), 612, 792,
505 "eadc8020a14dfcf091da2688733d8806");
506 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500507
508 // Now add a more complex blue path.
509 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
Lei Zhang3475b482019-05-13 18:30:57 +0000510 EXPECT_TRUE(FPDFPageObj_SetFillColor(blue_path, 0, 0, 255, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500511 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
512 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
513 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
514 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
515 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
516 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
517 EXPECT_TRUE(FPDFPath_Close(blue_path));
518 FPDFPage_InsertObject(page, blue_path);
Hui Yingsta929df72021-02-26 23:56:18 +0000519#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
520 static constexpr char kLastChecksum[] = "ed14c60702b1489c597c7d46ece7f86d";
521#else
522 static constexpr char kLastChecksum[] = "9823e1a21bd9b72b6a442ba4f12af946";
523#endif
Lei Zhang107fa7b2018-02-09 21:48:15 +0000524 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000525 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingsta929df72021-02-26 23:56:18 +0000526 CompareBitmap(page_bitmap.get(), 612, 792, kLastChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000527 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500528
529 // Now save the result, closing the page and document
Nicolas Pena207b7272017-05-26 17:37:06 -0400530 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penad03ca422017-03-06 13:54:33 -0500531 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500532 FPDF_ClosePage(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500533
534 // Render the saved result
Hui Yingsta929df72021-02-26 23:56:18 +0000535 VerifySavedDocument(612, 792, kLastChecksum);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500536}
537
Miklos Vajna45501f32019-07-30 07:41:02 +0000538TEST_F(FPDFEditEmbedderTest, ClipPath) {
539 // Load document with a clipped rectangle.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000540 ASSERT_TRUE(OpenDocument("clip_path.pdf"));
Miklos Vajna45501f32019-07-30 07:41:02 +0000541 FPDF_PAGE page = LoadPage(0);
542 ASSERT_TRUE(page);
543
544 ASSERT_EQ(1, FPDFPage_CountObjects(page));
545
546 FPDF_PAGEOBJECT triangle = FPDFPage_GetObject(page, 0);
547 ASSERT_TRUE(triangle);
548
549 // Test that we got the expected triangle.
550 ASSERT_EQ(4, FPDFPath_CountSegments(triangle));
551
552 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(triangle, 0);
553 float x;
554 float y;
555 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
556 EXPECT_EQ(10, x);
557 EXPECT_EQ(10, y);
558 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
559 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
560
561 segment = FPDFPath_GetPathSegment(triangle, 1);
562 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
563 EXPECT_EQ(25, x);
564 EXPECT_EQ(40, y);
565 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
566 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
567
568 segment = FPDFPath_GetPathSegment(triangle, 2);
569 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
570 EXPECT_EQ(40, x);
571 EXPECT_EQ(10, y);
572 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
573 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
574
575 segment = FPDFPath_GetPathSegment(triangle, 3);
576 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
577 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
578
579 // Test FPDFPageObj_GetClipPath().
580 ASSERT_EQ(nullptr, FPDFPageObj_GetClipPath(nullptr));
581
582 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(triangle);
583 ASSERT_TRUE(clip_path);
584
585 // Test FPDFClipPath_CountPaths().
586 ASSERT_EQ(-1, FPDFClipPath_CountPaths(nullptr));
587 ASSERT_EQ(1, FPDFClipPath_CountPaths(clip_path));
588
589 // Test FPDFClipPath_CountPathSegments().
590 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(nullptr, 0));
591 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, -1));
592 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 1));
593 ASSERT_EQ(4, FPDFClipPath_CountPathSegments(clip_path, 0));
594
595 // FPDFClipPath_GetPathSegment() negative testing.
596 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(nullptr, 0, 0));
597 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, -1, 0));
598 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 1, 0));
599 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, -1));
600 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, 4));
601
602 // FPDFClipPath_GetPathSegment() positive testing.
603 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 0);
604 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
605 EXPECT_EQ(10, x);
606 EXPECT_EQ(15, y);
607 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
608 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
609
610 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 1);
611 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
612 EXPECT_EQ(40, x);
613 EXPECT_EQ(15, y);
614 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
615 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
616
617 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 2);
618 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
619 EXPECT_EQ(40, x);
620 EXPECT_EQ(35, y);
621 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
622 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
623
624 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 3);
625 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
626 EXPECT_EQ(10, x);
627 EXPECT_EQ(35, y);
628 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
629 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
630
631 UnloadPage(page);
632}
633
Lei Zhang571f9322019-09-25 12:40:25 +0000634TEST_F(FPDFEditEmbedderTest, BUG_1399) {
635 // Load document with a clipped rectangle.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000636 ASSERT_TRUE(OpenDocument("bug_1399.pdf"));
Lei Zhang571f9322019-09-25 12:40:25 +0000637 FPDF_PAGE page = LoadPage(0);
638 ASSERT_TRUE(page);
639
640 ASSERT_EQ(7, FPDFPage_CountObjects(page));
641
642 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
643 ASSERT_TRUE(obj);
644
645 ASSERT_EQ(2, FPDFPath_CountSegments(obj));
646
647 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(obj, 0);
648 float x;
649 float y;
650 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
651 EXPECT_FLOAT_EQ(107.718f, x);
652 EXPECT_FLOAT_EQ(719.922f, y);
653 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
654 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
655
656 segment = FPDFPath_GetPathSegment(obj, 1);
657 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
658 EXPECT_FLOAT_EQ(394.718f, x);
659 EXPECT_FLOAT_EQ(719.922f, y);
660 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
661 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
662
663 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(obj);
664 ASSERT_TRUE(clip_path);
665
666 EXPECT_EQ(-1, FPDFClipPath_CountPaths(clip_path));
667 EXPECT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 0));
668 EXPECT_FALSE(FPDFClipPath_GetPathSegment(clip_path, 0, 0));
669
670 UnloadPage(page);
671}
672
Lei Zhangfcf7e7f2021-07-02 18:46:54 +0000673TEST_F(FPDFEditEmbedderTest, BUG_1549) {
674 static const char kOriginalChecksum[] = "126366fb95e6caf8ea196780075b22b2";
675 static const char kRemovedChecksum[] = "6ec2f27531927882624b37bc7d8e12f4";
676
677 ASSERT_TRUE(OpenDocument("bug_1549.pdf"));
678 FPDF_PAGE page = LoadPage(0);
679
680 {
681 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
682 CompareBitmap(bitmap.get(), 100, 150, kOriginalChecksum);
683
684 ScopedFPDFPageObject obj(FPDFPage_GetObject(page, 0));
685 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj.get()));
686 ASSERT_TRUE(FPDFPage_RemoveObject(page, obj.get()));
687 }
688
689 ASSERT_TRUE(FPDFPage_GenerateContent(page));
690
691 {
692 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
693 CompareBitmap(bitmap.get(), 100, 150, kRemovedChecksum);
694 }
695
696 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
697 UnloadPage(page);
698
699 // TODO(crbug.com/pdfium/1549): Should be `kRemovedChecksum`.
700 VerifySavedDocument(100, 150, "4f9889cd5993db20f1ab37d677ac8d26");
701}
702
Hui Yingstcb4203d2020-06-09 01:48:47 +0000703TEST_F(FPDFEditEmbedderTest, SetText) {
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000704 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000705 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000706 FPDF_PAGE page = LoadPage(0);
707 ASSERT_TRUE(page);
708
709 // Get the "Hello, world!" text object and change it.
710 ASSERT_EQ(2, FPDFPage_CountObjects(page));
711 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
712 ASSERT_TRUE(page_object);
Lei Zhangf0f67682019-04-08 17:03:21 +0000713 ScopedFPDFWideString text1 = GetFPDFWideString(L"Changed for SetText test");
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000714 EXPECT_TRUE(FPDFText_SetText(page_object, text1.get()));
715
716 // Verify the "Hello, world!" text is gone and "Changed for SetText test" is
717 // now displayed.
718 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Hui Yingstcb4203d2020-06-09 01:48:47 +0000719
720#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +0000721 const char kChangedChecksum[] = "49c8602cb60508009a34d0caaac63bb4";
Lei Zhang42d30c22022-01-12 19:24:43 +0000722#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +0000723 const char kChangedChecksum[] = "b720e83476fd6819d47c533f1f43c728";
Hui Yingstcb4203d2020-06-09 01:48:47 +0000724#else
Tom Andersond4fe5f72021-12-03 20:52:52 +0000725 const char kChangedChecksum[] = "9a85b9354a69c61772ed24151c140f46";
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000726#endif
727 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000728 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstcb4203d2020-06-09 01:48:47 +0000729 CompareBitmap(page_bitmap.get(), 200, 200, kChangedChecksum);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000730 }
731
732 // Now save the result.
733 EXPECT_TRUE(FPDFPage_GenerateContent(page));
734 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
735
736 UnloadPage(page);
737
738 // Re-open the file and check the changes were kept in the saved .pdf.
Lei Zhang0b494052019-01-31 21:41:15 +0000739 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000740 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +0000741 ASSERT_TRUE(saved_page);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000742 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
743 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000744 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstcb4203d2020-06-09 01:48:47 +0000745 CompareBitmap(page_bitmap.get(), 200, 200, kChangedChecksum);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000746 }
747
748 CloseSavedPage(saved_page);
749 CloseSavedDocument();
750}
751
Lei Zhang786544d2021-07-27 21:25:24 +0000752TEST_F(FPDFEditEmbedderTest, SetCharcodesBadParams) {
753 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
754 FPDF_PAGE page = LoadPage(0);
755 ASSERT_TRUE(page);
756
757 ASSERT_EQ(2, FPDFPage_CountObjects(page));
758 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
759 ASSERT_TRUE(page_object);
760
761 const uint32_t kDummyValue = 42;
762 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 0));
763 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 1));
764 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 0));
765 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 1));
766 EXPECT_FALSE(FPDFText_SetCharcodes(page_object, nullptr, 1));
767
768 UnloadPage(page);
769}
770
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000771TEST_F(FPDFEditEmbedderTest, SetTextKeepClippingPath) {
Daniel Hosseinianda651442020-07-17 23:30:22 +0000772 // Load document with some text, with parts clipped.
773 ASSERT_TRUE(OpenDocument("bug_1558.pdf"));
774 FPDF_PAGE page = LoadPage(0);
775 ASSERT_TRUE(page);
776
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000777#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Daniel Hosseinianda651442020-07-17 23:30:22 +0000778 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000779 "92ff84385a0f986eacfa4bbecf8d7a7a";
Lei Zhang42d30c22022-01-12 19:24:43 +0000780#elif BUILDFLAG(IS_APPLE)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000781 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000782 "ae7a25c85e0e2dd0c5cb9dd5cd37f6df";
Daniel Hosseinianda651442020-07-17 23:30:22 +0000783#else
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000784 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000785 "7af7fe5b281298261eb66ac2d22f5054";
Daniel Hosseinianda651442020-07-17 23:30:22 +0000786#endif
787 {
788 // When opened before any editing and saving, the clipping path is rendered.
789 ScopedFPDFBitmap original_bitmap = RenderPage(page);
790 CompareBitmap(original_bitmap.get(), 200, 200, kOriginalChecksum);
791 }
792
793 // "Change" the text in the objects to their current values to force them to
794 // regenerate when saving.
795 {
796 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
797 ASSERT_TRUE(text_page);
798 const int obj_count = FPDFPage_CountObjects(page);
799 ASSERT_EQ(2, obj_count);
800 for (int i = 0; i < obj_count; ++i) {
801 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, i);
802 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
803 unsigned long size =
804 FPDFTextObj_GetText(text_obj, text_page.get(),
805 /*buffer=*/nullptr, /*length=*/0);
806 ASSERT_GT(size, 0u);
807 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
808 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
809 buffer.data(), size));
810 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
811 }
812 }
813
814 {
815 // After editing but before saving, the clipping path is retained.
816 ScopedFPDFBitmap edited_bitmap = RenderPage(page);
817 CompareBitmap(edited_bitmap.get(), 200, 200, kOriginalChecksum);
818 }
819
820 // Save the file.
821 EXPECT_TRUE(FPDFPage_GenerateContent(page));
822 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
823 UnloadPage(page);
824
825 // Open the saved copy and render it.
826 ASSERT_TRUE(OpenSavedDocument());
827 FPDF_PAGE saved_page = LoadSavedPage(0);
828 ASSERT_TRUE(saved_page);
829
830 {
Daniel Hosseinianda651442020-07-17 23:30:22 +0000831 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
Daniel Hosseinian75efd912020-07-21 08:07:28 +0000832 CompareBitmap(saved_bitmap.get(), 200, 200, kOriginalChecksum);
Daniel Hosseinianda651442020-07-17 23:30:22 +0000833 }
834
835 CloseSavedPage(saved_page);
836 CloseSavedDocument();
837}
838
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000839TEST_F(FPDFEditEmbedderTest, BUG_1574) {
840 // Load document with some text within a clipping path.
841 ASSERT_TRUE(OpenDocument("bug_1574.pdf"));
842 FPDF_PAGE page = LoadPage(0);
843 ASSERT_TRUE(page);
844
845#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
846 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000847 "1e022a0360f053ecb41cc431a36834a6";
Lei Zhang42d30c22022-01-12 19:24:43 +0000848#elif BUILDFLAG(IS_APPLE)
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000849 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000850 "1226bc2b8072622eb28f52321876e814";
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000851#else
852 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000853 "c5241eef60b9eac68ed1f2a5fd002703";
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000854#endif
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000855 {
856 // When opened before any editing and saving, the text object is rendered.
857 ScopedFPDFBitmap original_bitmap = RenderPage(page);
858 CompareBitmap(original_bitmap.get(), 200, 300, kOriginalChecksum);
859 }
860
861 // "Change" the text in the objects to their current values to force them to
862 // regenerate when saving.
863 {
864 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
865 ASSERT_TRUE(text_page);
866
867 ASSERT_EQ(2, FPDFPage_CountObjects(page));
868 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, 1);
869 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
870
871 unsigned long size = FPDFTextObj_GetText(text_obj, text_page.get(),
872 /*buffer=*/nullptr, /*length=*/0);
873 ASSERT_GT(size, 0u);
874 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
875 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
876 buffer.data(), size));
877 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
878 }
879
880 // Save the file.
881 EXPECT_TRUE(FPDFPage_GenerateContent(page));
882 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
883 UnloadPage(page);
884
885 // Open the saved copy and render it.
886 ASSERT_TRUE(OpenSavedDocument());
887 FPDF_PAGE saved_page = LoadSavedPage(0);
888 ASSERT_TRUE(saved_page);
889
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000890 {
891 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
Daniel Hosseinian91eeeb92021-01-27 19:53:24 +0000892 CompareBitmap(saved_bitmap.get(), 200, 300, kOriginalChecksum);
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000893 }
894
895 CloseSavedPage(saved_page);
896 CloseSavedDocument();
897}
898
Hui Yingst08c40712020-04-29 01:37:35 +0000899TEST_F(FPDFEditEmbedderTest, RemovePageObject) {
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000900 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000901 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000902 FPDF_PAGE page = LoadPage(0);
903 ASSERT_TRUE(page);
904
Henrique Nakashimac90adc52018-03-27 16:26:44 +0000905 // Show what the original file looks like.
906 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000907 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000908 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000909 }
910
911 // Get the "Hello, world!" text object and remove it.
912 ASSERT_EQ(2, FPDFPage_CountObjects(page));
913 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
914 ASSERT_TRUE(page_object);
915 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
916
Henrique Nakashimac90adc52018-03-27 16:26:44 +0000917 // Verify the "Hello, world!" text is gone.
918 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000919 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000920 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000921 }
922 ASSERT_EQ(1, FPDFPage_CountObjects(page));
923
924 UnloadPage(page);
925 FPDFPageObj_Destroy(page_object);
926}
927
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000928void CheckMarkCounts(FPDF_PAGE page,
929 int start_from,
930 int expected_object_count,
931 size_t expected_prime_count,
932 size_t expected_square_count,
933 size_t expected_greater_than_ten_count,
934 size_t expected_bounds_count) {
935 int object_count = FPDFPage_CountObjects(page);
936 ASSERT_EQ(expected_object_count, object_count);
937
938 size_t prime_count = 0;
939 size_t square_count = 0;
940 size_t greater_than_ten_count = 0;
941 size_t bounds_count = 0;
942 for (int i = 0; i < object_count; ++i) {
943 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
944
945 int mark_count = FPDFPageObj_CountMarks(page_object);
946 for (int j = 0; j < mark_count; ++j) {
947 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
948
949 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000950 unsigned long name_len = 999u;
951 ASSERT_TRUE(
952 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
953 EXPECT_GT(name_len, 0u);
954 EXPECT_NE(999u, name_len);
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000955 std::wstring name =
956 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
957 if (name == L"Prime") {
958 prime_count++;
959 } else if (name == L"Square") {
960 square_count++;
961 int expected_square = start_from + i;
962 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
963
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000964 unsigned long get_param_key_return = 999u;
965 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
966 &get_param_key_return));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000967 EXPECT_EQ((6u + 1u) * 2u, get_param_key_return);
968 std::wstring key =
969 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
970 EXPECT_EQ(L"Factor", key);
971
972 EXPECT_EQ(FPDF_OBJECT_NUMBER,
Henrique Nakashima94230e52018-07-11 22:02:02 +0000973 FPDFPageObjMark_GetParamValueType(mark, "Factor"));
Henrique Nakashima140dead2018-07-11 21:40:03 +0000974 int square_root;
Henrique Nakashima94230e52018-07-11 22:02:02 +0000975 EXPECT_TRUE(
976 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &square_root));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000977 EXPECT_EQ(expected_square, square_root * square_root);
978 } else if (name == L"GreaterThanTen") {
979 greater_than_ten_count++;
980 } else if (name == L"Bounds") {
981 bounds_count++;
982 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
983
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000984 unsigned long get_param_key_return = 999u;
985 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
986 &get_param_key_return));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000987 EXPECT_EQ((8u + 1u) * 2u, get_param_key_return);
988 std::wstring key =
989 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
990 EXPECT_EQ(L"Position", key);
991
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000992 EXPECT_EQ(FPDF_OBJECT_STRING,
Henrique Nakashima94230e52018-07-11 22:02:02 +0000993 FPDFPageObjMark_GetParamValueType(mark, "Position"));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000994 unsigned long length;
Henrique Nakashimaa3406772018-07-13 19:10:53 +0000995 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
996 mark, "Position", buffer, sizeof(buffer), &length));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000997 ASSERT_GT(length, 0u);
Henrique Nakashima140dead2018-07-11 21:40:03 +0000998 std::wstring value =
999 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00001000
Henrique Nakashimaa3406772018-07-13 19:10:53 +00001001 // "Position" can be "First", "Last", or "End".
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00001002 if (i == 0) {
1003 EXPECT_EQ((5u + 1u) * 2u, length);
1004 EXPECT_EQ(L"First", value);
1005 } else if (i == object_count - 1) {
Henrique Nakashimaa3406772018-07-13 19:10:53 +00001006 if (length == (4u + 1u) * 2u) {
1007 EXPECT_EQ(L"Last", value);
1008 } else if (length == (3u + 1u) * 2u) {
1009 EXPECT_EQ(L"End", value);
1010 } else {
1011 FAIL();
1012 }
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00001013 } else {
1014 FAIL();
1015 }
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001016 } else {
1017 FAIL();
1018 }
1019 }
1020 }
1021
1022 // Expect certain number of tagged objects. The test file contains strings
1023 // from 1 to 19.
1024 EXPECT_EQ(expected_prime_count, prime_count);
1025 EXPECT_EQ(expected_square_count, square_count);
1026 EXPECT_EQ(expected_greater_than_ten_count, greater_than_ten_count);
1027 EXPECT_EQ(expected_bounds_count, bounds_count);
1028}
1029
Lei Zhangab41f252018-12-23 03:10:50 +00001030TEST_F(FPDFEditEmbedderTest, ReadMarkedObjectsIndirectDict) {
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001031 // Load document with some text marked with an indirect property.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001032 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001033 FPDF_PAGE page = LoadPage(0);
1034 ASSERT_TRUE(page);
1035
1036 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1037
1038 UnloadPage(page);
1039}
1040
Hui Yingstf26b5f82020-11-17 05:26:03 +00001041TEST_F(FPDFEditEmbedderTest, RemoveMarkedObjectsPrime) {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001042 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001043 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001044 FPDF_PAGE page = LoadPage(0);
1045 ASSERT_TRUE(page);
1046
1047 // Show what the original file looks like.
1048 {
Hui Yingstf26b5f82020-11-17 05:26:03 +00001049#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1050 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001051 "8a8bed7820764522955f422e27f4292f";
Lei Zhang42d30c22022-01-12 19:24:43 +00001052#elif BUILDFLAG(IS_APPLE)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001053 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001054 "966579fb98206858ce2f0a1f94a74d05";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001055#else
1056 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001057 "3d5a3de53d5866044c2b6bf339742c97";
1058#endif
Lei Zhang30ff2532019-01-31 21:37:55 +00001059 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001060 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalChecksum);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001061 }
1062
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001063 constexpr int expected_object_count = 19;
1064 CheckMarkCounts(page, 1, expected_object_count, 8, 4, 9, 1);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001065
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001066 // Get all objects marked with "Prime"
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001067 std::vector<FPDF_PAGEOBJECT> primes;
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001068 for (int i = 0; i < expected_object_count; ++i) {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001069 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1070
1071 int mark_count = FPDFPageObj_CountMarks(page_object);
1072 for (int j = 0; j < mark_count; ++j) {
1073 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1074
1075 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001076 unsigned long name_len = 999u;
1077 ASSERT_TRUE(
1078 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1079 EXPECT_GT(name_len, 0u);
1080 EXPECT_NE(999u, name_len);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001081 std::wstring name =
1082 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1083 if (name == L"Prime") {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001084 primes.push_back(page_object);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001085 }
1086 }
1087 }
1088
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001089 // Remove all objects marked with "Prime".
1090 for (FPDF_PAGEOBJECT page_object : primes) {
1091 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1092 FPDFPageObj_Destroy(page_object);
1093 }
1094
1095 EXPECT_EQ(11, FPDFPage_CountObjects(page));
Hui Yingstf26b5f82020-11-17 05:26:03 +00001096#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1097 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001098 "1573b85dd9a2c59401c1c30abbee3b25";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001099 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001100 "1573b85dd9a2c59401c1c30abbee3b25";
Lei Zhang42d30c22022-01-12 19:24:43 +00001101#elif BUILDFLAG(IS_APPLE)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001102 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001103 "6e19a4dd674b522cd39cf41956559bd6";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001104 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001105 "3cb35c681f8fb5a43a49146ac7caa818";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001106#else
1107 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001108 "bc8623c052f12376c3d8dd09a6cd27df";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001109 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001110 "bc8623c052f12376c3d8dd09a6cd27df";
1111#endif
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001112 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001113 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001114 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesChecksum);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001115 }
1116
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001117 // Save the file.
1118 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1119 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001120 UnloadPage(page);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001121
1122 // Re-open the file and check the prime marks are not there anymore.
Lei Zhang0b494052019-01-31 21:41:15 +00001123 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001124 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001125 ASSERT_TRUE(saved_page);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001126 EXPECT_EQ(11, FPDFPage_CountObjects(saved_page));
1127
1128 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001129 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001130 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesAfterSaveChecksum);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001131 }
1132
1133 CloseSavedPage(saved_page);
1134 CloseSavedDocument();
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001135}
1136
Lei Zhangab41f252018-12-23 03:10:50 +00001137TEST_F(FPDFEditEmbedderTest, RemoveMarks) {
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001138 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001139 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001140 FPDF_PAGE page = LoadPage(0);
1141 ASSERT_TRUE(page);
1142
1143 constexpr int kExpectedObjectCount = 19;
1144 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1145
1146 // Remove all "Prime" content marks.
1147 for (int i = 0; i < kExpectedObjectCount; ++i) {
1148 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1149
1150 int mark_count = FPDFPageObj_CountMarks(page_object);
1151 for (int j = mark_count - 1; j >= 0; --j) {
1152 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1153
1154 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001155 unsigned long name_len = 999u;
1156 ASSERT_TRUE(
1157 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1158 EXPECT_GT(name_len, 0u);
1159 EXPECT_NE(999u, name_len);
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001160 std::wstring name =
1161 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1162 if (name == L"Prime") {
1163 // Remove mark.
1164 EXPECT_TRUE(FPDFPageObj_RemoveMark(page_object, mark));
1165
1166 // Verify there is now one fewer mark in the page object.
1167 EXPECT_EQ(mark_count - 1, FPDFPageObj_CountMarks(page_object));
1168 }
1169 }
1170 }
1171
1172 // Verify there are 0 "Prime" content marks now.
1173 CheckMarkCounts(page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1174
1175 // Save the file.
1176 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1177 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1178 UnloadPage(page);
1179
1180 // Re-open the file and check the prime marks are not there anymore.
Lei Zhang0b494052019-01-31 21:41:15 +00001181 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001182 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001183 ASSERT_TRUE(saved_page);
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001184
1185 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1186
1187 CloseSavedPage(saved_page);
1188 CloseSavedDocument();
1189}
1190
Lei Zhangab41f252018-12-23 03:10:50 +00001191TEST_F(FPDFEditEmbedderTest, RemoveMarkParam) {
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001192 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001193 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001194 FPDF_PAGE page = LoadPage(0);
1195 ASSERT_TRUE(page);
1196
1197 constexpr int kExpectedObjectCount = 19;
1198 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1199
1200 // Remove all "Square" content marks parameters.
1201 for (int i = 0; i < kExpectedObjectCount; ++i) {
1202 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1203
1204 int mark_count = FPDFPageObj_CountMarks(page_object);
1205 for (int j = 0; j < mark_count; ++j) {
1206 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1207
1208 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001209 unsigned long name_len = 999u;
1210 ASSERT_TRUE(
1211 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1212 EXPECT_GT(name_len, 0u);
1213 EXPECT_NE(999u, name_len);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001214 std::wstring name =
1215 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1216 if (name == L"Square") {
1217 // Show the mark has a "Factor" parameter.
1218 int out_value;
1219 EXPECT_TRUE(
1220 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1221
1222 // Remove parameter.
1223 EXPECT_TRUE(FPDFPageObjMark_RemoveParam(page_object, mark, "Factor"));
1224
1225 // Verify the "Factor" parameter is gone.
1226 EXPECT_FALSE(
1227 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1228 }
1229 }
1230 }
1231
1232 // Save the file.
1233 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1234 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1235 UnloadPage(page);
1236
1237 // Re-open the file and check the "Factor" parameters are still gone.
Lei Zhang0b494052019-01-31 21:41:15 +00001238 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001239 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001240 ASSERT_TRUE(saved_page);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001241
1242 size_t square_count = 0;
1243 for (int i = 0; i < kExpectedObjectCount; ++i) {
1244 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1245
1246 int mark_count = FPDFPageObj_CountMarks(page_object);
1247 for (int j = 0; j < mark_count; ++j) {
1248 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1249
1250 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001251 unsigned long name_len = 999u;
1252 ASSERT_TRUE(
1253 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1254 EXPECT_GT(name_len, 0u);
1255 EXPECT_NE(999u, name_len);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001256 std::wstring name =
1257 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1258 if (name == L"Square") {
1259 // Verify the "Factor" parameter is still gone.
1260 int out_value;
1261 EXPECT_FALSE(
1262 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1263
1264 ++square_count;
1265 }
1266 }
1267 }
1268
1269 // Verify the parameters are gone, but the marks are not.
1270 EXPECT_EQ(4u, square_count);
1271
1272 CloseSavedPage(saved_page);
1273 CloseSavedDocument();
1274}
1275
Lei Zhangab41f252018-12-23 03:10:50 +00001276TEST_F(FPDFEditEmbedderTest, MaintainMarkedObjects) {
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001277 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001278 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001279 FPDF_PAGE page = LoadPage(0);
1280 ASSERT_TRUE(page);
1281
1282 // Iterate over all objects, counting the number of times each content mark
1283 // name appears.
1284 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1285
1286 // Remove first page object.
1287 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1288 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1289 FPDFPageObj_Destroy(page_object);
1290
1291 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1292
1293 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1294 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1295
1296 UnloadPage(page);
1297
Lei Zhang0b494052019-01-31 21:41:15 +00001298 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001299 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001300 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001301
1302 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1303
1304 CloseSavedPage(saved_page);
1305 CloseSavedDocument();
1306}
1307
Lei Zhangab41f252018-12-23 03:10:50 +00001308TEST_F(FPDFEditEmbedderTest, MaintainIndirectMarkedObjects) {
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001309 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001310 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001311 FPDF_PAGE page = LoadPage(0);
1312 ASSERT_TRUE(page);
1313
1314 // Iterate over all objects, counting the number of times each content mark
1315 // name appears.
1316 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1317
1318 // Remove first page object.
1319 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1320 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1321 FPDFPageObj_Destroy(page_object);
1322
1323 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1324
1325 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1326 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1327
1328 UnloadPage(page);
1329
Lei Zhang0b494052019-01-31 21:41:15 +00001330 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001331 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001332 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001333
1334 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1335
1336 CloseSavedPage(saved_page);
1337 CloseSavedDocument();
1338}
1339
Lei Zhangab41f252018-12-23 03:10:50 +00001340TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObject) {
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001341 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001342 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001343 FPDF_PAGE page = LoadPage(0);
1344 ASSERT_TRUE(page);
1345
1346 // Get the "Hello, world!" text object and remove it.
1347 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1348 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1349 ASSERT_TRUE(page_object);
1350 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1351
1352 // Verify the "Hello, world!" text is gone.
1353 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1354
1355 // Save the file
1356 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1357 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1358 UnloadPage(page);
1359 FPDFPageObj_Destroy(page_object);
1360
1361 // Re-open the file and check the page object count is still 1.
Lei Zhang0b494052019-01-31 21:41:15 +00001362 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001363 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001364 ASSERT_TRUE(saved_page);
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001365 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
1366 CloseSavedPage(saved_page);
1367 CloseSavedDocument();
1368}
1369
Hui Yingstcb4203d2020-06-09 01:48:47 +00001370TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsNotLonely) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001371 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001372 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001373 FPDF_PAGE page = LoadPage(0);
1374 ASSERT_TRUE(page);
1375
1376 // Get the "Hello, world!" text object and remove it. There is another object
1377 // in the same stream that says "Goodbye, world!"
1378 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1379 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1380 ASSERT_TRUE(page_object);
1381 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1382
1383 // Verify the "Hello, world!" text is gone.
1384 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Hui Yingstcb4203d2020-06-09 01:48:47 +00001385#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001386 const char kHelloRemovedChecksum[] = "fc2a40a3d1edfe6e972be104b5ae87ad";
Lei Zhang42d30c22022-01-12 19:24:43 +00001387#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001388 const char kHelloRemovedChecksum[] = "5508c2f06d104050f74f655693e38c2c";
Hui Yingstcb4203d2020-06-09 01:48:47 +00001389#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00001390 const char kHelloRemovedChecksum[] = "a8cd82499cf744e0862ca468c9d4ceb8";
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001391#endif
1392 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001393 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstcb4203d2020-06-09 01:48:47 +00001394 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001395 }
1396
1397 // Save the file
1398 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1399 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1400 UnloadPage(page);
1401 FPDFPageObj_Destroy(page_object);
1402
1403 // Re-open the file and check the page object count is still 2.
Lei Zhang0b494052019-01-31 21:41:15 +00001404 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001405 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001406 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001407
1408 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1409 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001410 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstcb4203d2020-06-09 01:48:47 +00001411 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001412 }
1413
1414 CloseSavedPage(saved_page);
1415 CloseSavedDocument();
1416}
1417
Hui Yingst08c40712020-04-29 01:37:35 +00001418TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsLonely) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001419 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001420 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001421 FPDF_PAGE page = LoadPage(0);
1422 ASSERT_TRUE(page);
1423
1424 // Get the "Greetings, world!" text object and remove it. This is the only
1425 // object in the stream.
1426 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1427 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 2);
1428 ASSERT_TRUE(page_object);
1429 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1430
1431 // Verify the "Greetings, world!" text is gone.
1432 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001433 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001434 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001435 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001436 }
1437
1438 // Save the file
1439 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1440 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1441 UnloadPage(page);
1442 FPDFPageObj_Destroy(page_object);
1443
1444 // Re-open the file and check the page object count is still 2.
Lei Zhang0b494052019-01-31 21:41:15 +00001445 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001446 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001447 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001448
1449 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1450 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001451 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001452 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001453 }
1454
1455 CloseSavedPage(saved_page);
1456 CloseSavedDocument();
1457}
1458
Lei Zhangab41f252018-12-23 03:10:50 +00001459TEST_F(FPDFEditEmbedderTest, GetContentStream) {
Henrique Nakashima6eb79392018-06-12 20:27:35 +00001460 // Load document with some text split across streams.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001461 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
Henrique Nakashima6eb79392018-06-12 20:27:35 +00001462 FPDF_PAGE page = LoadPage(0);
1463 ASSERT_TRUE(page);
1464
1465 // Content stream 0: page objects 0-14.
1466 // Content stream 1: page objects 15-17.
1467 // Content stream 2: page object 18.
1468 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1469 for (int i = 0; i < 19; i++) {
1470 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1471 ASSERT_TRUE(page_object);
1472 CPDF_PageObject* cpdf_page_object =
1473 CPDFPageObjectFromFPDFPageObject(page_object);
1474 if (i < 15)
1475 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1476 else if (i < 18)
1477 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1478 else
1479 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1480 }
1481
1482 UnloadPage(page);
1483}
1484
Hui Yingst0d692fe2020-11-06 17:32:50 +00001485TEST_F(FPDFEditEmbedderTest, RemoveAllFromStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001486 // Load document with some text split across streams.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001487 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001488 FPDF_PAGE page = LoadPage(0);
1489 ASSERT_TRUE(page);
1490
1491 // Content stream 0: page objects 0-14.
1492 // Content stream 1: page objects 15-17.
1493 // Content stream 2: page object 18.
1494 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1495
1496 // Loop backwards because objects will being removed, which shifts the indexes
1497 // after the removed position.
1498 for (int i = 18; i >= 0; i--) {
1499 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1500 ASSERT_TRUE(page_object);
1501 CPDF_PageObject* cpdf_page_object =
1502 CPDFPageObjectFromFPDFPageObject(page_object);
1503
1504 // Empty content stream 1.
1505 if (cpdf_page_object->GetContentStream() == 1) {
1506 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1507 FPDFPageObj_Destroy(page_object);
1508 }
1509 }
1510
1511 // Content stream 0: page objects 0-14.
1512 // Content stream 2: page object 15.
1513 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1514 for (int i = 0; i < 16; i++) {
1515 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1516 ASSERT_TRUE(page_object);
1517 CPDF_PageObject* cpdf_page_object =
1518 CPDFPageObjectFromFPDFPageObject(page_object);
1519 if (i < 15)
1520 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1521 else
1522 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1523 }
1524
1525 // Generate contents should remove the empty stream and update the page
1526 // objects' contents stream indexes.
1527 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1528
1529 // Content stream 0: page objects 0-14.
1530 // Content stream 1: page object 15.
1531 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1532 for (int i = 0; i < 16; i++) {
1533 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1534 ASSERT_TRUE(page_object);
1535 CPDF_PageObject* cpdf_page_object =
1536 CPDFPageObjectFromFPDFPageObject(page_object);
1537 if (i < 15)
1538 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1539 else
1540 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1541 }
1542
Hui Yingst0d692fe2020-11-06 17:32:50 +00001543#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001544 const char kStream1RemovedChecksum[] = "7fe07f182b37d40afc6ae36a4e89fe73";
Lei Zhang42d30c22022-01-12 19:24:43 +00001545#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001546 const char kStream1RemovedChecksum[] = "3cdc75af44c15bed80998facd6e674c9";
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001547#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00001548 const char kStream1RemovedChecksum[] = "b474826df1acedb05c7b82e1e49e64a6";
1549#endif
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001550 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001551 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst0d692fe2020-11-06 17:32:50 +00001552 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001553 }
1554
1555 // Save the file
1556 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1557 UnloadPage(page);
1558
1559 // Re-open the file and check the page object count is still 16, and that
1560 // content stream 1 was removed.
Lei Zhang0b494052019-01-31 21:41:15 +00001561 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001562 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001563 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001564
1565 // Content stream 0: page objects 0-14.
1566 // Content stream 1: page object 15.
1567 EXPECT_EQ(16, FPDFPage_CountObjects(saved_page));
1568 for (int i = 0; i < 16; i++) {
1569 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1570 ASSERT_TRUE(page_object);
1571 CPDF_PageObject* cpdf_page_object =
1572 CPDFPageObjectFromFPDFPageObject(page_object);
1573 if (i < 15)
1574 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1575 else
1576 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1577 }
1578
1579 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001580 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst0d692fe2020-11-06 17:32:50 +00001581 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001582 }
1583
1584 CloseSavedPage(saved_page);
1585 CloseSavedDocument();
1586}
1587
Lei Zhangab41f252018-12-23 03:10:50 +00001588TEST_F(FPDFEditEmbedderTest, RemoveAllFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001589 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001590 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001591 FPDF_PAGE page = LoadPage(0);
1592 ASSERT_TRUE(page);
1593
1594 // Content stream 0: page objects 0-1.
1595 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1596
1597 // Loop backwards because objects will being removed, which shifts the indexes
1598 // after the removed position.
1599 for (int i = 1; i >= 0; i--) {
1600 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1601 ASSERT_TRUE(page_object);
1602 CPDF_PageObject* cpdf_page_object =
1603 CPDFPageObjectFromFPDFPageObject(page_object);
1604 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1605 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1606 FPDFPageObj_Destroy(page_object);
1607 }
1608
1609 // No more objects in the stream
1610 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1611
1612 // Generate contents should remove the empty stream and update the page
1613 // objects' contents stream indexes.
1614 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1615
1616 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1617
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001618 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001619 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001620 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001621 }
1622
1623 // Save the file
1624 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1625 UnloadPage(page);
1626
1627 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001628 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001629 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001630 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001631
1632 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1633 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001634 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001635 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001636 }
1637
1638 CloseSavedPage(saved_page);
1639 CloseSavedDocument();
1640}
1641
Hui Yingst08c40712020-04-29 01:37:35 +00001642TEST_F(FPDFEditEmbedderTest, RemoveFirstFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001643 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001644 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001645 FPDF_PAGE page = LoadPage(0);
1646 ASSERT_TRUE(page);
1647
1648 // Content stream 0: page objects 0-1.
1649 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1650
1651 // Remove first object.
1652 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1653 ASSERT_TRUE(page_object);
1654 CPDF_PageObject* cpdf_page_object =
1655 CPDFPageObjectFromFPDFPageObject(page_object);
1656 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1657 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1658 FPDFPageObj_Destroy(page_object);
1659
1660 // One object left in the stream.
1661 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1662 page_object = FPDFPage_GetObject(page, 0);
1663 ASSERT_TRUE(page_object);
1664 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1665 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1666
1667 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1668
1669 // Still one object left in the stream.
1670 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1671 page_object = FPDFPage_GetObject(page, 0);
1672 ASSERT_TRUE(page_object);
1673 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1674 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1675
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001676 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001677 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001678 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001679 }
1680
1681 // Save the file
1682 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1683 UnloadPage(page);
1684
1685 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001686 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001687 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001688 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001689
1690 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1691 page_object = FPDFPage_GetObject(saved_page, 0);
1692 ASSERT_TRUE(page_object);
1693 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1694 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1695 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001696 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001697 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001698 }
1699
1700 CloseSavedPage(saved_page);
1701 CloseSavedDocument();
1702}
1703
Hui Yingst08c40712020-04-29 01:37:35 +00001704TEST_F(FPDFEditEmbedderTest, RemoveLastFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001705 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001706 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001707 FPDF_PAGE page = LoadPage(0);
1708 ASSERT_TRUE(page);
1709
1710 // Content stream 0: page objects 0-1.
1711 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1712
1713 // Remove last object
1714 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 1);
1715 ASSERT_TRUE(page_object);
1716 CPDF_PageObject* cpdf_page_object =
1717 CPDFPageObjectFromFPDFPageObject(page_object);
1718 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1719 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1720 FPDFPageObj_Destroy(page_object);
1721
1722 // One object left in the stream.
1723 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1724 page_object = FPDFPage_GetObject(page, 0);
1725 ASSERT_TRUE(page_object);
1726 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1727 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1728
1729 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1730
1731 // Still one object left in the stream.
1732 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1733 page_object = FPDFPage_GetObject(page, 0);
1734 ASSERT_TRUE(page_object);
1735 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1736 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1737
Hui Yingstb4baceb2020-04-28 23:46:10 +00001738 using pdfium::kHelloWorldRemovedChecksum;
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001739 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001740 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001741 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001742 }
1743
1744 // Save the file
1745 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1746 UnloadPage(page);
1747
1748 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001749 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001750 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001751 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001752
1753 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1754 page_object = FPDFPage_GetObject(saved_page, 0);
1755 ASSERT_TRUE(page_object);
1756 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1757 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1758 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001759 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001760 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001761 }
1762
1763 CloseSavedPage(saved_page);
1764 CloseSavedDocument();
1765}
1766
Lei Zhangab41f252018-12-23 03:10:50 +00001767TEST_F(FPDFEditEmbedderTest, RemoveAllFromMultipleStreams) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001768 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001769 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001770 FPDF_PAGE page = LoadPage(0);
1771 ASSERT_TRUE(page);
1772
1773 // Content stream 0: page objects 0-1.
1774 // Content stream 1: page object 2.
1775 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1776
1777 // Loop backwards because objects will being removed, which shifts the indexes
1778 // after the removed position.
1779 for (int i = 2; i >= 0; i--) {
1780 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1781 ASSERT_TRUE(page_object);
1782 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1783 FPDFPageObj_Destroy(page_object);
1784 }
1785
1786 // No more objects in the page.
1787 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1788
1789 // Generate contents should remove the empty streams and update the page
1790 // objects' contents stream indexes.
1791 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1792
1793 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1794
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001795 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001796 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001797 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001798 }
1799
1800 // Save the file
1801 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1802 UnloadPage(page);
1803
1804 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001805 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001806 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001807 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001808
1809 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1810 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001811 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001812 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001813 }
1814
1815 CloseSavedPage(saved_page);
1816 CloseSavedDocument();
1817}
1818
Lei Zhangab41f252018-12-23 03:10:50 +00001819TEST_F(FPDFEditEmbedderTest, InsertPageObjectAndSave) {
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001820 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001821 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001822 FPDF_PAGE page = LoadPage(0);
1823 ASSERT_TRUE(page);
1824
1825 // Add a red rectangle.
1826 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1827 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001828 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001829 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1830 FPDFPage_InsertObject(page, red_rect);
1831
1832 // Verify the red rectangle was added.
1833 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1834
1835 // Save the file
1836 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1837 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1838 UnloadPage(page);
1839
1840 // Re-open the file and check the page object count is still 3.
Lei Zhang0b494052019-01-31 21:41:15 +00001841 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001842 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001843 ASSERT_TRUE(saved_page);
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001844 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1845 CloseSavedPage(saved_page);
1846 CloseSavedDocument();
1847}
1848
Lei Zhangab41f252018-12-23 03:10:50 +00001849TEST_F(FPDFEditEmbedderTest, InsertPageObjectEditAndSave) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001850 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001851 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001852 FPDF_PAGE page = LoadPage(0);
1853 ASSERT_TRUE(page);
1854
1855 // Add a red rectangle.
1856 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1857 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001858 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 100, 100, 255));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001859 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1860 FPDFPage_InsertObject(page, red_rect);
1861
1862 // Verify the red rectangle was added.
1863 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1864
1865 // Generate content but change it again
1866 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhang3475b482019-05-13 18:30:57 +00001867 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001868
1869 // Save the file
1870 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1871 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1872 UnloadPage(page);
1873
1874 // Re-open the file and check the page object count is still 3.
Lei Zhang0b494052019-01-31 21:41:15 +00001875 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001876 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001877 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001878 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1879 CloseSavedPage(saved_page);
1880 CloseSavedDocument();
1881}
1882
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001883TEST_F(FPDFEditEmbedderTest, InsertAndRemoveLargeFile) {
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001884 const int kOriginalObjectCount = 600;
1885
1886 // Load document with many objects.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001887 ASSERT_TRUE(OpenDocument("many_rectangles.pdf"));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001888 FPDF_PAGE page = LoadPage(0);
1889 ASSERT_TRUE(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001890
1891 using pdfium::kManyRectanglesChecksum;
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001892 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001893 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001894 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001895 }
1896
1897 // Add a black rectangle.
1898 ASSERT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(page));
1899 FPDF_PAGEOBJECT black_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001900 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_rect, 0, 0, 0, 255));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001901 EXPECT_TRUE(FPDFPath_SetDrawMode(black_rect, FPDF_FILLMODE_ALTERNATE, 0));
1902 FPDFPage_InsertObject(page, black_rect);
1903
1904 // Verify the black rectangle was added.
1905 ASSERT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(page));
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001906#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1907 const char kPlusRectangleMD5[] = "0d3715fcfb9bd0dd25dcce60800bff47";
1908#else
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001909 const char kPlusRectangleMD5[] = "6b9396ab570754b32b04ca629e902f77";
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001910#endif
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001911 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001912 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001913 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1914 }
1915
1916 // Save the file.
1917 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1918 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1919 UnloadPage(page);
1920
1921 // Re-open the file and check the rectangle added is still there.
Lei Zhang0b494052019-01-31 21:41:15 +00001922 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001923 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001924 ASSERT_TRUE(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001925 EXPECT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(saved_page));
1926 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001927 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001928 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1929 }
1930
1931 // Remove the added rectangle.
1932 FPDF_PAGEOBJECT added_object =
1933 FPDFPage_GetObject(saved_page, kOriginalObjectCount);
1934 EXPECT_TRUE(FPDFPage_RemoveObject(saved_page, added_object));
1935 FPDFPageObj_Destroy(added_object);
1936 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001937 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001938 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001939 }
1940 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1941
1942 // Save the file again.
1943 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
Lei Zhang38e2b0e2021-11-05 00:28:05 +00001944 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001945
1946 CloseSavedPage(saved_page);
1947 CloseSavedDocument();
1948
1949 // Re-open the file (again) and check the black rectangle was removed and the
1950 // rest is intact.
Lei Zhang0b494052019-01-31 21:41:15 +00001951 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001952 saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001953 ASSERT_TRUE(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001954 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1955 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001956 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001957 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001958 }
1959
1960 CloseSavedPage(saved_page);
1961 CloseSavedDocument();
1962}
1963
Lei Zhangab41f252018-12-23 03:10:50 +00001964TEST_F(FPDFEditEmbedderTest, AddAndRemovePaths) {
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001965 // Start with a blank page.
1966 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
1967 ASSERT_TRUE(page);
1968
1969 // Render the blank page and verify it's a blank bitmap.
Hui Yingstb4baceb2020-04-28 23:46:10 +00001970 using pdfium::kBlankPage612By792Checksum;
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001971 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001972 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001973 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001974 }
1975 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1976
1977 // Add a red rectangle.
1978 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
1979 ASSERT_TRUE(red_rect);
Lei Zhang3475b482019-05-13 18:30:57 +00001980 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001981 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1982 FPDFPage_InsertObject(page, red_rect);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001983 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001984 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001985 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001986 }
1987 EXPECT_EQ(1, FPDFPage_CountObjects(page));
1988
1989 // Remove rectangle and verify it does not render anymore and the bitmap is
1990 // back to a blank one.
1991 EXPECT_TRUE(FPDFPage_RemoveObject(page, red_rect));
1992 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001993 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001994 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001995 }
1996 EXPECT_EQ(0, FPDFPage_CountObjects(page));
1997
1998 // Trying to remove an object not in the page should return false.
1999 EXPECT_FALSE(FPDFPage_RemoveObject(page, red_rect));
2000
2001 FPDF_ClosePage(page);
2002 FPDFPageObj_Destroy(red_rect);
2003}
2004
Lei Zhangab41f252018-12-23 03:10:50 +00002005TEST_F(FPDFEditEmbedderTest, PathsPoints) {
Miklos Vajna12abfd02017-09-15 07:49:03 +02002006 CreateNewDocument();
Lei Zhang38e2b0e2021-11-05 00:28:05 +00002007 FPDF_PAGEOBJECT img = FPDFPageObj_NewImageObj(document());
Miklos Vajna12abfd02017-09-15 07:49:03 +02002008 // This should fail gracefully, even if img is not a path.
Miklos Vajna0150a542017-09-21 21:46:56 +02002009 ASSERT_EQ(-1, FPDFPath_CountSegments(img));
Miklos Vajna12abfd02017-09-15 07:49:03 +02002010
2011 // This should fail gracefully, even if path is NULL.
Miklos Vajna0150a542017-09-21 21:46:56 +02002012 ASSERT_EQ(-1, FPDFPath_CountSegments(nullptr));
Miklos Vajna12abfd02017-09-15 07:49:03 +02002013
Miklos Vajna36eed872017-09-20 22:52:43 +02002014 // FPDFPath_GetPathSegment() with a non-path.
2015 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0));
2016 // FPDFPath_GetPathSegment() with a NULL path.
2017 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0));
2018 float x;
2019 float y;
2020 // FPDFPathSegment_GetPoint() with a NULL segment.
2021 EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y));
2022
2023 // FPDFPathSegment_GetType() with a NULL segment.
2024 ASSERT_EQ(FPDF_SEGMENT_UNKNOWN, FPDFPathSegment_GetType(nullptr));
2025
2026 // FPDFPathSegment_GetClose() with a NULL segment.
2027 EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr));
2028
Miklos Vajna12abfd02017-09-15 07:49:03 +02002029 FPDFPageObj_Destroy(img);
2030}
2031
Hui Yingste95d5772020-08-24 23:58:26 +00002032TEST_F(FPDFEditEmbedderTest, PathOnTopOfText) {
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002033 // Load document with some text
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002034 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002035 FPDF_PAGE page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002036 ASSERT_TRUE(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002037
2038 // Add an opaque rectangle on top of some of the text.
2039 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002040 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002041 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2042 FPDFPage_InsertObject(page, red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002043
2044 // Add a transparent triangle on top of other part of the text.
2045 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002046 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 100));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002047 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
2048 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
2049 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
2050 EXPECT_TRUE(FPDFPath_Close(black_path));
2051 FPDFPage_InsertObject(page, black_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002052
Hui Yingste95d5772020-08-24 23:58:26 +00002053 // Render and check the result.
Tom Sepeze08d2b12018-04-25 18:49:32 +00002054 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
Hui Yingste95d5772020-08-24 23:58:26 +00002055#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002056 const char kChecksum[] = "3490f699d894351a554d79e1fcdf7981";
Lei Zhang42d30c22022-01-12 19:24:43 +00002057#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002058 const char kChecksum[] = "279693baca9f48da2d75a8e289aed58e";
Hui Yingste95d5772020-08-24 23:58:26 +00002059#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002060 const char kChecksum[] = "fe415d47945c10b9cc8e9ca08887369e";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002061#endif
Hui Yingste95d5772020-08-24 23:58:26 +00002062 CompareBitmap(bitmap.get(), 200, 200, kChecksum);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002063 UnloadPage(page);
2064}
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002065
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002066TEST_F(FPDFEditEmbedderTest, EditOverExistingContent) {
wileyryae858aa42017-05-31 14:49:05 -05002067 // Load document with existing content
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002068 ASSERT_TRUE(OpenDocument("bug_717.pdf"));
wileyryae858aa42017-05-31 14:49:05 -05002069 FPDF_PAGE page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002070 ASSERT_TRUE(page);
wileyryae858aa42017-05-31 14:49:05 -05002071
2072 // Add a transparent rectangle on top of the existing content
2073 FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002074 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect2, 255, 0, 0, 100));
wileyryae858aa42017-05-31 14:49:05 -05002075 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
2076 FPDFPage_InsertObject(page, red_rect2);
2077
2078 // Add an opaque rectangle on top of the existing content
2079 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002080 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
wileyryae858aa42017-05-31 14:49:05 -05002081 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2082 FPDFPage_InsertObject(page, red_rect);
2083
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002084#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2085 const char kOriginalChecksum[] = "1e82fbdd21490cee9d3479fe6125af67";
2086#else
2087 const char kOriginalChecksum[] = "ad04e5bd0f471a9a564fb034bd0fb073";
2088#endif
Tom Sepeze08d2b12018-04-25 18:49:32 +00002089 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002090 CompareBitmap(bitmap.get(), 612, 792, kOriginalChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002091 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2092
2093 // Now save the result, closing the page and document
2094 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena3ff54002017-07-05 11:55:35 -04002095 UnloadPage(page);
wileyryae858aa42017-05-31 14:49:05 -05002096
Lei Zhang0b494052019-01-31 21:41:15 +00002097 ASSERT_TRUE(OpenSavedDocument());
Lei Zhang107fa7b2018-02-09 21:48:15 +00002098 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00002099 ASSERT_TRUE(saved_page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002100 VerifySavedRendering(saved_page, 612, 792, kOriginalChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002101
2102 ClearString();
2103 // Add another opaque rectangle on top of the existing content
2104 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002105 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 255));
wileyryae858aa42017-05-31 14:49:05 -05002106 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002107 FPDFPage_InsertObject(saved_page, green_rect);
wileyryae858aa42017-05-31 14:49:05 -05002108
2109 // Add another transparent rectangle on top of existing content
2110 FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002111 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect2, 0, 255, 0, 100));
wileyryae858aa42017-05-31 14:49:05 -05002112 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002113 FPDFPage_InsertObject(saved_page, green_rect2);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002114#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2115 const char kLastChecksum[] = "8705d023e5fec3499d1e30cf2bcc5dc1";
2116#else
2117 const char kLastChecksum[] = "4b5b00f824620f8c9b8801ebb98e1cdd";
2118#endif
Lei Zhangc113c7a2018-02-12 14:58:44 +00002119 {
Tom Sepeze08d2b12018-04-25 18:49:32 +00002120 ScopedFPDFBitmap new_bitmap = RenderSavedPage(saved_page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002121 CompareBitmap(new_bitmap.get(), 612, 792, kLastChecksum);
Lei Zhangc113c7a2018-02-12 14:58:44 +00002122 }
Lei Zhang107fa7b2018-02-09 21:48:15 +00002123 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
wileyryae858aa42017-05-31 14:49:05 -05002124
2125 // Now save the result, closing the page and document
Lei Zhang38e2b0e2021-11-05 00:28:05 +00002126 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
Dan Sinclair04e4dc82017-10-18 12:17:14 -04002127
Lei Zhang107fa7b2018-02-09 21:48:15 +00002128 CloseSavedPage(saved_page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04002129 CloseSavedDocument();
wileyryae858aa42017-05-31 14:49:05 -05002130
2131 // Render the saved result
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002132 VerifySavedDocument(612, 792, kLastChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002133}
2134
Hui Yingst041116e2021-03-01 21:27:50 +00002135// TODO(crbug.com/pdfium/1651): Fix this issue and enable the test for Skia.
2136#if defined(_SKIA_SUPPORT_)
Lei Zhang03e5e682019-09-16 19:45:55 +00002137#define MAYBE_AddStrokedPaths DISABLED_AddStrokedPaths
2138#else
2139#define MAYBE_AddStrokedPaths AddStrokedPaths
2140#endif
2141TEST_F(FPDFEditEmbedderTest, MAYBE_AddStrokedPaths) {
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002142 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -05002143 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002144
2145 // Add a large stroked rectangle (fill color should not affect it).
2146 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
Lei Zhang3475b482019-05-13 18:30:57 +00002147 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 255));
2148 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect, 0, 255, 0, 255));
2149 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(rect, 15.0f));
Miklos Vajna366df7f2018-05-22 14:27:29 +00002150
2151 float width = 0;
2152 EXPECT_TRUE(FPDFPageObj_GetStrokeWidth(rect, &width));
2153 EXPECT_EQ(15.0f, width);
2154
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002155 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
2156 FPDFPage_InsertObject(page, rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002157 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002158 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002159#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2160 static constexpr char kChecksum_1[] = "1469acf60e7647ebeb8e1fb08c5d6c7a";
2161#else
2162 static constexpr char kChecksum_1[] = "64bd31f862a89e0a9e505a5af6efd506";
2163#endif
2164 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_1);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002165 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002166
2167 // Add crossed-checkmark
2168 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
2169 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
2170 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
2171 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
2172 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
Lei Zhang3475b482019-05-13 18:30:57 +00002173 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(check, 128, 128, 128, 180));
2174 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(check, 8.35f));
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002175 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
2176 FPDFPage_InsertObject(page, check);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002177 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002178 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002179#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2180 static constexpr char kChecksum_2[] = "68b3194f74abd9d471695ce1415be43f";
2181#else
2182 static constexpr char kChecksum_2[] = "4b6f3b9d25c4e194821217d5016c3724";
2183#endif
2184 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_2);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002185 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002186
2187 // Add stroked and filled oval-ish path.
2188 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
2189 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
2190 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
2191 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
2192 EXPECT_TRUE(FPDFPath_Close(path));
Lei Zhang3475b482019-05-13 18:30:57 +00002193 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 128, 128, 100));
2194 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(path, 128, 200, 128, 150));
2195 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(path, 10.5f));
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002196 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
2197 FPDFPage_InsertObject(page, path);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002198 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002199 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002200#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2201 static constexpr char kChecksum_3[] = "ea784068651df2b9ba132ce9215e6780";
2202#else
2203 static constexpr char kChecksum_3[] = "ff3e6a22326754944cc6e56609acd73b";
2204#endif
2205 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_3);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002206 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002207 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002208}
Nicolas Pena49058402017-02-14 18:26:20 -05002209
Nicolas Pena4c48b102018-06-13 18:23:46 +00002210// Tests adding text from standard font using FPDFPageObj_NewTextObj.
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002211TEST_F(FPDFEditEmbedderTest, AddStandardFontText) {
Nicolas Pena49058402017-02-14 18:26:20 -05002212 // Start with a blank page
Lei Zhang8496d132021-07-08 04:34:34 +00002213 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
Nicolas Pena49058402017-02-14 18:26:20 -05002214
2215 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -04002216 FPDF_PAGEOBJECT text_object1 =
2217 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2218 EXPECT_TRUE(text_object1);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002219 ScopedFPDFWideString text1 = GetFPDFWideString(kBottomText);
Nicolas Penab3161852017-05-02 14:12:50 -04002220 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
Lei Zhangcfd08172021-06-30 04:11:21 +00002221 static constexpr FS_MATRIX kMatrix1{1, 0, 0, 1, 20, 20};
2222 EXPECT_TRUE(FPDFPageObj_SetMatrix(text_object1, &kMatrix1));
Lei Zhang8496d132021-07-08 04:34:34 +00002223 FPDFPage_InsertObject(page.get(), text_object1);
2224 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002225 {
Lei Zhang8496d132021-07-08 04:34:34 +00002226 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst3b6136a2020-06-09 00:39:33 +00002227 CompareBitmap(page_bitmap.get(), 612, 792, kBottomTextChecksum);
Lei Zhange039bab2019-03-18 19:57:56 +00002228
2229 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Hui Yingst3b6136a2020-06-09 00:39:33 +00002230 VerifySavedDocument(612, 792, kBottomTextChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002231 }
Nicolas Pena49058402017-02-14 18:26:20 -05002232
2233 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -04002234 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -05002235 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -04002236 EXPECT_TRUE(text_object2);
Lei Zhangf0f67682019-04-08 17:03:21 +00002237 ScopedFPDFWideString text2 =
Nicolas Penab3161852017-05-02 14:12:50 -04002238 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
2239 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2240 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
Lei Zhang8496d132021-07-08 04:34:34 +00002241 FPDFPage_InsertObject(page.get(), text_object2);
2242 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002243 {
Lei Zhang8496d132021-07-08 04:34:34 +00002244 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002245#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002246 static constexpr char md5[] = "fa64eb3808b541342496281277fad5f2";
Nicolas Pena49058402017-02-14 18:26:20 -05002247#else
Lei Zhang42d30c22022-01-12 19:24:43 +00002248#if BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002249 static constexpr char md5[] = "983baaa1f688eff7a14b1bf91c171a1a";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002250#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002251 static constexpr char md5[] = "161523e196eb5341604cd73e12c97922";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002252#endif
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002253#endif // defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Lei Zhange039bab2019-03-18 19:57:56 +00002254 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2255
2256 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2257 VerifySavedDocument(612, 792, md5);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002258 }
Nicolas Pena49058402017-02-14 18:26:20 -05002259
2260 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -04002261 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -05002262 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -04002263 EXPECT_TRUE(text_object3);
Lei Zhangf0f67682019-04-08 17:03:21 +00002264 ScopedFPDFWideString text3 = GetFPDFWideString(L"Can you read me? <:)>");
Nicolas Penab3161852017-05-02 14:12:50 -04002265 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
2266 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
Lei Zhang8496d132021-07-08 04:34:34 +00002267 FPDFPage_InsertObject(page.get(), text_object3);
2268 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002269 {
Lei Zhang8496d132021-07-08 04:34:34 +00002270 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002271#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002272 static constexpr char md5[] = "abc65660389911aab95550ca8cd97a2b";
Lei Zhang42d30c22022-01-12 19:24:43 +00002273#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002274 static constexpr char md5[] = "e0b3493c5c16e41d0d892ffb48e63fba";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002275#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002276 static constexpr char md5[] = "1fbf772dca8d82b960631e6683934964";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002277#endif
Lei Zhange039bab2019-03-18 19:57:56 +00002278 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2279
2280 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2281 VerifySavedDocument(612, 792, md5);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002282 }
Nicolas Pena49058402017-02-14 18:26:20 -05002283
Lei Zhang8da98232019-12-11 23:29:33 +00002284 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +00002285 EXPECT_TRUE(FPDFPageObj_GetMatrix(text_object3, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +00002286 EXPECT_FLOAT_EQ(1.0f, matrix.a);
2287 EXPECT_FLOAT_EQ(1.5f, matrix.b);
2288 EXPECT_FLOAT_EQ(2.0f, matrix.c);
2289 EXPECT_FLOAT_EQ(0.5f, matrix.d);
2290 EXPECT_FLOAT_EQ(200.0f, matrix.e);
2291 EXPECT_FLOAT_EQ(200.0f, matrix.f);
Miklos Vajnac765d2a2018-06-19 15:45:42 +00002292
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002293 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, nullptr));
Lei Zhang8496d132021-07-08 04:34:34 +00002294 float size = 55;
2295 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, &size));
2296 EXPECT_EQ(55, size);
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002297 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object3, &size));
2298 EXPECT_EQ(20, size);
Miklos Vajna8625d3b2018-06-26 15:12:48 +00002299
Nicolas Pena49058402017-02-14 18:26:20 -05002300 // TODO(npm): Why are there issues with text rotated by 90 degrees?
2301 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
Nicolas Pena49058402017-02-14 18:26:20 -05002302}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002303
Lei Zhang20c52152021-06-18 20:37:10 +00002304TEST_F(FPDFEditEmbedderTest, AddStandardFontTextOfSizeZero) {
2305 // Start with a blank page
2306 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2307
2308 // Add some text of size 0 to the page.
2309 FPDF_PAGEOBJECT text_object =
2310 FPDFPageObj_NewTextObj(document(), "Arial", 0.0f);
2311 EXPECT_TRUE(text_object);
2312 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
2313 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2314 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2315
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002316 float size = -1; // Make sure 'size' gets changed.
2317 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object, &size));
2318 EXPECT_EQ(0.0f, size);
Lei Zhang20c52152021-06-18 20:37:10 +00002319
2320 FPDFPage_InsertObject(page.get(), text_object);
2321 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2322 {
2323 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2324 CompareBitmap(page_bitmap.get(), 612, 792,
2325 pdfium::kBlankPage612By792Checksum);
2326
2327 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2328 VerifySavedDocument(612, 792, pdfium::kBlankPage612By792Checksum);
2329 }
2330}
2331
Daniel Hosseinian8cb6a652019-12-18 00:50:41 +00002332TEST_F(FPDFEditEmbedderTest, GetTextRenderMode) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002333 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002334 FPDF_PAGE page = LoadPage(0);
2335 ASSERT_TRUE(page);
2336 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2337
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002338 EXPECT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
Daniel Hosseinian8cb6a652019-12-18 00:50:41 +00002339 FPDFTextObj_GetTextRenderMode(nullptr));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002340
2341 FPDF_PAGEOBJECT fill = FPDFPage_GetObject(page, 0);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002342 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFTextObj_GetTextRenderMode(fill));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002343
2344 FPDF_PAGEOBJECT stroke = FPDFPage_GetObject(page, 1);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002345 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE, FPDFTextObj_GetTextRenderMode(stroke));
2346
2347 UnloadPage(page);
2348}
2349
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002350TEST_F(FPDFEditEmbedderTest, SetTextRenderMode) {
Hui Yingst609f7d62020-04-23 23:14:13 +00002351#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002352 const char kOriginalChecksum[] = "bf87e8b36380ebd96ca429213fa23a09";
2353 const char kStrokeChecksum[] = "d16eb1bb4748eeb5fb801594da70d519";
Lei Zhang42d30c22022-01-12 19:24:43 +00002354#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002355 const char kOriginalChecksum[] = "c488514ce0fc949069ff560407edacd2";
2356 const char kStrokeChecksum[] = "e06ee84aeebe926e8c980b7822027e8a";
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002357#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002358 const char kOriginalChecksum[] = "97a4fcf3c9581e19917895631af31d41";
2359 const char kStrokeChecksum[] = "e06ee84aeebe926e8c980b7822027e8a";
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002360#endif
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002361
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002362 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002363 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002364 FPDF_PAGE page = LoadPage(0);
2365 ASSERT_TRUE(page);
2366 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2367
2368 // Check the bitmap
2369 {
2370 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002371 CompareBitmap(page_bitmap.get(), 612, 446, kOriginalChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002372 }
2373
2374 // Cannot set on a null object.
2375 EXPECT_FALSE(
2376 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_UNKNOWN));
2377 EXPECT_FALSE(
2378 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_INVISIBLE));
2379
2380 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2381 ASSERT_TRUE(page_object);
2382 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
2383 FPDFTextObj_GetTextRenderMode(page_object));
2384
2385 // Cannot set UNKNOWN as a render mode.
2386 EXPECT_FALSE(FPDFTextObj_SetTextRenderMode(page_object,
2387 FPDF_TEXTRENDERMODE_UNKNOWN));
2388
2389 EXPECT_TRUE(
2390 FPDFTextObj_SetTextRenderMode(page_object, FPDF_TEXTRENDERMODE_STROKE));
2391 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2392 FPDFTextObj_GetTextRenderMode(page_object));
2393
2394 // Check that bitmap displays changed content
2395 {
2396 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002397 CompareBitmap(page_bitmap.get(), 612, 446, kStrokeChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002398 }
2399
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002400 // Save a copy.
2401 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2402 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2403
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002404 UnloadPage(page);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002405 }
Miklos Vajna1448cc12018-07-03 13:52:33 +00002406
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002407 {
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002408 // Open the saved copy and render it. Check that the changed text render
2409 // mode is kept in the saved copy.
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002410 ASSERT_TRUE(OpenSavedDocument());
2411 FPDF_PAGE saved_page = LoadSavedPage(0);
2412 ASSERT_TRUE(saved_page);
2413
2414 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, 0);
2415 EXPECT_TRUE(page_object);
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002416 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002417 FPDFTextObj_GetTextRenderMode(page_object));
2418
2419 ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002420 CompareBitmap(bitmap.get(), 612, 446, kStrokeChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002421
2422 CloseSavedPage(saved_page);
2423 CloseSavedDocument();
2424 }
Miklos Vajna1448cc12018-07-03 13:52:33 +00002425}
2426
Robert Collyer68a18a02021-09-14 01:48:22 +00002427TEST_F(FPDFEditEmbedderTest, TextFontProperties) {
2428 // bad object tests
2429 EXPECT_FALSE(FPDFTextObj_GetFont(nullptr));
2430 EXPECT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 5));
2431 EXPECT_EQ(-1, FPDFFont_GetFlags(nullptr));
2432 EXPECT_EQ(-1, FPDFFont_GetWeight(nullptr));
2433 EXPECT_FALSE(FPDFFont_GetItalicAngle(nullptr, nullptr));
2434 EXPECT_FALSE(FPDFFont_GetAscent(nullptr, 12.f, nullptr));
2435 EXPECT_FALSE(FPDFFont_GetDescent(nullptr, 12.f, nullptr));
2436 EXPECT_FALSE(FPDFFont_GetGlyphWidth(nullptr, 's', 12.f, nullptr));
2437 EXPECT_FALSE(FPDFFont_GetGlyphPath(nullptr, 's', 12.f));
2438
2439 // good object tests
2440 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2441 FPDF_PAGE page = LoadPage(0);
2442 ASSERT_TRUE(page);
2443 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2444 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2445 ASSERT_TRUE(text);
2446 float font_size;
2447 ASSERT_TRUE(FPDFTextObj_GetFontSize(text, &font_size));
2448 FPDF_FONT font = FPDFTextObj_GetFont(text);
2449 ASSERT_TRUE(font);
2450
2451 // null return pointer tests
2452 EXPECT_FALSE(FPDFFont_GetItalicAngle(font, nullptr));
2453 EXPECT_FALSE(FPDFFont_GetAscent(font, font_size, nullptr));
2454 EXPECT_FALSE(FPDFFont_GetDescent(font, font_size, nullptr));
2455 EXPECT_FALSE(FPDFFont_GetGlyphWidth(font, 's', font_size, nullptr));
2456
2457 // correct property tests
2458 {
2459 EXPECT_EQ(4, FPDFFont_GetFlags(font));
2460 EXPECT_EQ(400, FPDFFont_GetWeight(font));
2461
2462 int angle;
2463 EXPECT_TRUE(FPDFFont_GetItalicAngle(font, &angle));
2464 EXPECT_EQ(0, angle);
2465
2466 float ascent;
2467 EXPECT_TRUE(FPDFFont_GetAscent(font, font_size, &ascent));
2468 EXPECT_FLOAT_EQ(891 * font_size / 1000.0f, ascent);
2469
2470 float descent;
2471 EXPECT_TRUE(FPDFFont_GetDescent(font, font_size, &descent));
2472 EXPECT_FLOAT_EQ(-216 * font_size / 1000.0f, descent);
2473
2474 float a12;
2475 float a24;
2476 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 12.0f, &a12));
2477 EXPECT_FLOAT_EQ(a12, 5.316f);
2478 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 24.0f, &a24));
2479 EXPECT_FLOAT_EQ(a24, 10.632f);
2480 }
2481
2482 {
2483 // FPDFFont_GetFontName() positive testing.
2484 unsigned long size = FPDFFont_GetFontName(font, nullptr, 0);
2485 const char kExpectedFontName[] = "Liberation Serif";
2486 ASSERT_EQ(sizeof(kExpectedFontName), size);
2487 std::vector<char> font_name(size);
2488 ASSERT_EQ(size, FPDFFont_GetFontName(font, font_name.data(), size));
2489 ASSERT_STREQ(kExpectedFontName, font_name.data());
2490
2491 // FPDFFont_GetFontName() negative testing.
2492 ASSERT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 0));
2493
2494 font_name.resize(2);
2495 font_name[0] = 'x';
2496 font_name[1] = '\0';
2497 size = FPDFFont_GetFontName(font, font_name.data(), font_name.size());
2498 ASSERT_EQ(sizeof(kExpectedFontName), size);
2499 ASSERT_STREQ("x", font_name.data());
2500 }
2501
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002502 {
2503 // FPDFFont_GetFontData() positive testing.
2504 constexpr size_t kExpectedSize = 8268;
2505 std::vector<uint8_t> buf;
2506 size_t buf_bytes_required = 123;
2507 ASSERT_TRUE(FPDFFont_GetFontData(font, nullptr, 0, &buf_bytes_required));
2508 ASSERT_EQ(kExpectedSize, buf_bytes_required);
2509
2510 buf.resize(kExpectedSize);
2511 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2512 buf_bytes_required = 234;
2513 // Test with buffer that is too small. Make sure `buf` is unchanged.
2514 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size() - 1,
2515 &buf_bytes_required));
2516 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2517 EXPECT_EQ(kExpectedSize, buf_bytes_required);
2518
2519 // Test with buffer of the correct size.
2520 buf_bytes_required = 234;
2521 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size(),
2522 &buf_bytes_required));
2523 EXPECT_EQ("1a67be75f719b6c476804d85bb9e4844", GenerateMD5Base16(buf));
2524 EXPECT_EQ(kExpectedSize, buf_bytes_required);
2525
2526 // FPDFFont_GetFontData() negative testing.
2527 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, nullptr, 0, nullptr));
2528 EXPECT_FALSE(FPDFFont_GetFontData(font, nullptr, 0, nullptr));
2529
2530 buf_bytes_required = 345;
2531 EXPECT_FALSE(
2532 FPDFFont_GetFontData(nullptr, nullptr, 0, &buf_bytes_required));
2533 EXPECT_EQ(345u, buf_bytes_required);
2534
2535 EXPECT_FALSE(
2536 FPDFFont_GetFontData(nullptr, buf.data(), buf.size(), nullptr));
2537 EXPECT_FALSE(FPDFFont_GetFontData(font, buf.data(), buf.size(), nullptr));
2538
2539 buf_bytes_required = 345;
2540 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, buf.data(), buf.size(),
2541 &buf_bytes_required));
2542 EXPECT_EQ(345u, buf_bytes_required);
2543 }
Lei Zhange617ccd2022-05-11 19:50:35 +00002544 {
2545 ASSERT_EQ(1, FPDFFont_GetIsEmbedded(font));
2546 ASSERT_EQ(-1, FPDFFont_GetIsEmbedded(nullptr));
2547 }
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002548
2549 UnloadPage(page);
2550}
2551
2552TEST_F(FPDFEditEmbedderTest, NoEmbeddedFontData) {
2553 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2554 FPDF_PAGE page = LoadPage(0);
2555 ASSERT_TRUE(page);
2556 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2557
2558 // Since hello_world.pdf does not embed any font data, FPDFFont_GetFontData()
2559 // will return the substitution font data. Since pdfium_embeddertest is
2560 // hermetic, this first object consistently maps to Tinos-Regular.ttf.
2561 constexpr size_t kTinosRegularSize = 469968;
2562 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2563 ASSERT_TRUE(text);
2564 FPDF_FONT font = FPDFTextObj_GetFont(text);
2565 ASSERT_TRUE(font);
2566 std::vector<uint8_t> buf;
2567 buf.resize(kTinosRegularSize);
2568 size_t buf_bytes_required;
2569 ASSERT_TRUE(
2570 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2571 EXPECT_EQ(kTinosRegularSize, buf_bytes_required);
2572 EXPECT_EQ("2b019558f2c2de0b7cbc0a6e64b20599", GenerateMD5Base16(buf));
Lei Zhange617ccd2022-05-11 19:50:35 +00002573 EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002574
2575 // Similarly, the second object consistently maps to Arimo-Regular.ttf.
2576 constexpr size_t kArimoRegularSize = 436180;
2577 text = FPDFPage_GetObject(page, 1);
2578 ASSERT_TRUE(text);
2579 font = FPDFTextObj_GetFont(text);
2580 ASSERT_TRUE(font);
2581 buf.resize(kArimoRegularSize);
2582 ASSERT_TRUE(
2583 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2584 EXPECT_EQ(kArimoRegularSize, buf_bytes_required);
2585 EXPECT_EQ("7ac02a544211773d9636e056e9da6c35", GenerateMD5Base16(buf));
Lei Zhange617ccd2022-05-11 19:50:35 +00002586 EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002587
Robert Collyer68a18a02021-09-14 01:48:22 +00002588 UnloadPage(page);
2589}
2590
2591TEST_F(FPDFEditEmbedderTest, GlyphPaths) {
2592 // bad glyphpath
2593 EXPECT_EQ(-1, FPDFGlyphPath_CountGlyphSegments(nullptr));
2594 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(nullptr, 1));
2595
2596 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2597 FPDF_PAGE page = LoadPage(0);
2598 ASSERT_TRUE(page);
2599 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2600 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2601 ASSERT_TRUE(text);
2602 FPDF_FONT font = FPDFTextObj_GetFont(text);
2603 ASSERT_TRUE(font);
2604
2605 // good glyphpath
2606 FPDF_GLYPHPATH gpath = FPDFFont_GetGlyphPath(font, 's', 12.0f);
2607 ASSERT_TRUE(gpath);
2608
2609 int count = FPDFGlyphPath_CountGlyphSegments(gpath);
2610 ASSERT_GT(count, 0);
2611 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, -1));
2612 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, count));
2613
2614 FPDF_PATHSEGMENT segment = FPDFGlyphPath_GetGlyphPathSegment(gpath, 1);
2615 ASSERT_TRUE(segment);
2616 EXPECT_EQ(FPDF_SEGMENT_BEZIERTO, FPDFPathSegment_GetType(segment));
2617
2618 UnloadPage(page);
2619}
2620
Lei Zhang4363dab2021-06-24 19:23:09 +00002621TEST_F(FPDFEditEmbedderTest, FormGetObjects) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002622 ASSERT_TRUE(OpenDocument("form_object.pdf"));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002623 FPDF_PAGE page = LoadPage(0);
2624 ASSERT_TRUE(page);
2625 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2626
2627 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002628 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002629 ASSERT_EQ(-1, FPDFFormObj_CountObjects(nullptr));
2630 ASSERT_EQ(2, FPDFFormObj_CountObjects(form));
2631
Miklos Vajna1d273f12018-07-16 19:20:36 +00002632 // FPDFFormObj_GetObject() positive testing.
2633 FPDF_PAGEOBJECT text1 = FPDFFormObj_GetObject(form, 0);
2634 ASSERT_TRUE(text1);
2635 float left = 0;
2636 float bottom = 0;
2637 float right = 0;
2638 float top = 0;
2639 ASSERT_TRUE(FPDFPageObj_GetBounds(text1, &left, &bottom, &right, &top));
2640 ASSERT_EQ(271, static_cast<int>(top));
2641
2642 FPDF_PAGEOBJECT text2 = FPDFFormObj_GetObject(form, 1);
2643 ASSERT_TRUE(text2);
2644 ASSERT_TRUE(FPDFPageObj_GetBounds(text2, &left, &bottom, &right, &top));
2645 ASSERT_EQ(221, static_cast<int>(top));
2646
2647 // FPDFFormObj_GetObject() negative testing.
2648 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(nullptr, 0));
2649 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
2650 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
2651
Lei Zhangc8601bf2021-06-29 23:19:27 +00002652 // FPDFPageObj_GetMatrix() positive testing for forms.
Lei Zhang8da98232019-12-11 23:29:33 +00002653 static constexpr FS_MATRIX kMatrix = {1.0f, 1.5f, 2.0f, 2.5f, 100.0f, 200.0f};
Lei Zhang2193da92021-06-30 01:03:07 +00002654 EXPECT_TRUE(FPDFPageObj_SetMatrix(form, &kMatrix));
Miklos Vajna46b43732018-08-14 19:15:43 +00002655
Lei Zhang8da98232019-12-11 23:29:33 +00002656 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +00002657 EXPECT_TRUE(FPDFPageObj_GetMatrix(form, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +00002658 EXPECT_FLOAT_EQ(kMatrix.a, matrix.a);
2659 EXPECT_FLOAT_EQ(kMatrix.b, matrix.b);
2660 EXPECT_FLOAT_EQ(kMatrix.c, matrix.c);
2661 EXPECT_FLOAT_EQ(kMatrix.d, matrix.d);
2662 EXPECT_FLOAT_EQ(kMatrix.e, matrix.e);
2663 EXPECT_FLOAT_EQ(kMatrix.f, matrix.f);
Miklos Vajna46b43732018-08-14 19:15:43 +00002664
Lei Zhangc8601bf2021-06-29 23:19:27 +00002665 // FPDFPageObj_GetMatrix() negative testing for forms.
2666 EXPECT_FALSE(FPDFPageObj_GetMatrix(form, nullptr));
Miklos Vajna46b43732018-08-14 19:15:43 +00002667
Miklos Vajnab66077d2018-07-11 13:25:02 +00002668 UnloadPage(page);
2669}
2670
Lei Zhang4363dab2021-06-24 19:23:09 +00002671TEST_F(FPDFEditEmbedderTest, ModifyFormObject) {
2672#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002673 const char kOrigChecksum[] = "e15086e54078e4d22fa3fb12105c579e";
2674 const char kNewChecksum[] = "7282fe98693c0a7ad2c1b3f3f9563977";
Lei Zhang42d30c22022-01-12 19:24:43 +00002675#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002676 const char kOrigChecksum[] = "a637057185f50aac1aa5490f726aef95";
2677 const char kNewChecksum[] = "8ad9d79b02b609ff734e2a2195c96e2d";
Lei Zhang4363dab2021-06-24 19:23:09 +00002678#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002679 const char kOrigChecksum[] = "34a9ec0a9581a7970e073c0bcc4ca676";
2680 const char kNewChecksum[] = "609b5632a21c886fa93182dbc290bf7a";
2681#endif
Lei Zhang4363dab2021-06-24 19:23:09 +00002682
2683 ASSERT_TRUE(OpenDocument("form_object.pdf"));
2684 FPDF_PAGE page = LoadPage(0);
2685 ASSERT_TRUE(page);
2686 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2687
2688 {
2689 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2690 CompareBitmap(bitmap.get(), 62, 69, kOrigChecksum);
2691 }
2692
2693 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
2694 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
2695
Lei Zhang651113b2021-06-25 20:03:25 +00002696 FPDFPageObj_Transform(form, 0.5, 0, 0, 0.5, 0, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002697 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2698
2699 {
2700 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2701 CompareBitmap(bitmap.get(), 62, 69, kNewChecksum);
2702 }
2703
Lei Zhang4363dab2021-06-24 19:23:09 +00002704 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhangac7f0e12021-06-24 19:38:00 +00002705 VerifySavedDocument(62, 69, kNewChecksum);
Lei Zhang4363dab2021-06-24 19:23:09 +00002706
2707 UnloadPage(page);
2708}
2709
Nicolas Pena4c48b102018-06-13 18:23:46 +00002710// Tests adding text from standard font using FPDFText_LoadStandardFont.
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002711TEST_F(FPDFEditEmbedderTest, AddStandardFontText2) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002712 // Start with a blank page
2713 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2714
2715 // Load a standard font.
Tom Sepezffff6c52019-07-30 21:56:19 +00002716 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002717 ASSERT_TRUE(font);
2718
2719 // Add some text to the page.
2720 FPDF_PAGEOBJECT text_object =
Tom Sepezffff6c52019-07-30 21:56:19 +00002721 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002722 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002723 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002724 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2725 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2726 FPDFPage_InsertObject(page.get(), text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00002727 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst3b6136a2020-06-09 00:39:33 +00002728 CompareBitmap(page_bitmap.get(), 612, 792, kBottomTextChecksum);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002729}
2730
Lei Zhangab41f252018-12-23 03:10:50 +00002731TEST_F(FPDFEditEmbedderTest, LoadStandardFonts) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002732 CreateNewDocument();
Lei Zhang590f4242019-05-15 20:57:26 +00002733 static constexpr const char* kStandardFontNames[] = {
Lei Zhangd72fd582018-07-27 19:37:27 +00002734 "Arial",
2735 "Arial-Bold",
2736 "Arial-BoldItalic",
2737 "Arial-Italic",
2738 "Courier",
2739 "Courier-BoldOblique",
2740 "Courier-Oblique",
2741 "Courier-Bold",
2742 "CourierNew",
2743 "CourierNew-Bold",
2744 "CourierNew-BoldItalic",
2745 "CourierNew-Italic",
2746 "Helvetica",
2747 "Helvetica-Bold",
2748 "Helvetica-BoldOblique",
2749 "Helvetica-Oblique",
2750 "Symbol",
2751 "TimesNewRoman",
2752 "TimesNewRoman-Bold",
2753 "TimesNewRoman-BoldItalic",
2754 "TimesNewRoman-Italic",
2755 "ZapfDingbats"};
Lei Zhang590f4242019-05-15 20:57:26 +00002756 for (const char* font_name : kStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002757 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002758 EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
2759 }
Lei Zhang590f4242019-05-15 20:57:26 +00002760 static constexpr const char* kNotStandardFontNames[] = {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002761 "Abcdefg", "ArialB", "Arial-Style",
2762 "Font Name", "FontArial", "NotAStandardFontName",
2763 "TestFontName", "Quack", "Symbol-Italic",
2764 "Zapf"};
Lei Zhang590f4242019-05-15 20:57:26 +00002765 for (const char* font_name : kNotStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002766 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002767 EXPECT_FALSE(font) << font_name
2768 << " should not be considered a standard font.";
2769 }
2770}
2771
Lei Zhangab41f252018-12-23 03:10:50 +00002772TEST_F(FPDFEditEmbedderTest, GraphicsData) {
Nicolas Pena603a31d2017-06-14 11:41:18 -04002773 // New page
Tom Sepeze08d2b12018-04-25 18:49:32 +00002774 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002775
2776 // Create a rect with nontrivial graphics
2777 FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2778 FPDFPageObj_SetBlendMode(rect1, "Color");
2779 FPDFPage_InsertObject(page.get(), rect1);
2780 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2781
2782 // Check that the ExtGState was created
Lei Zhang107fa7b2018-02-09 21:48:15 +00002783 CPDF_Page* cpage = CPDFPageFromFPDFPage(page.get());
Tom Sepezc8155092021-04-26 23:37:42 +00002784 const CPDF_Dictionary* graphics_dict =
2785 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Pena603a31d2017-06-14 11:41:18 -04002786 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002787 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002788
2789 // Add a text object causing no change to the graphics dictionary
2790 FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2791 // Only alpha, the last component, matters for the graphics dictionary. And
2792 // the default value is 255.
Lei Zhang3475b482019-05-13 18:30:57 +00002793 EXPECT_TRUE(FPDFPageObj_SetFillColor(text1, 100, 100, 100, 255));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002794 FPDFPage_InsertObject(page.get(), text1);
2795 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002796 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002797
2798 // Add a text object increasing the size of the graphics dictionary
2799 FPDF_PAGEOBJECT text2 =
2800 FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
2801 FPDFPage_InsertObject(page.get(), text2);
2802 FPDFPageObj_SetBlendMode(text2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002803 EXPECT_TRUE(FPDFPageObj_SetFillColor(text2, 0, 0, 255, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002804 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002805 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002806
2807 // Add a path that should reuse graphics
Nicolas Penace67be42017-06-14 14:52:49 -04002808 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
Nicolas Pena603a31d2017-06-14 11:41:18 -04002809 FPDFPageObj_SetBlendMode(path, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002810 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 200, 100, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002811 FPDFPage_InsertObject(page.get(), path);
2812 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002813 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002814
2815 // Add a rect increasing the size of the graphics dictionary
2816 FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2817 FPDFPageObj_SetBlendMode(rect2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002818 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect2, 0, 0, 255, 150));
2819 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect2, 0, 0, 0, 200));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002820 FPDFPage_InsertObject(page.get(), rect2);
2821 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002822 EXPECT_EQ(4u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002823}
2824
Lei Zhangab41f252018-12-23 03:10:50 +00002825TEST_F(FPDFEditEmbedderTest, DoubleGenerating) {
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002826 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -05002827 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002828
2829 // Add a red rectangle with some non-default alpha
2830 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
Lei Zhang3475b482019-05-13 18:30:57 +00002831 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 128));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002832 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
2833 FPDFPage_InsertObject(page, rect);
2834 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2835
2836 // Check the ExtGState
Lei Zhang107fa7b2018-02-09 21:48:15 +00002837 CPDF_Page* cpage = CPDFPageFromFPDFPage(page);
Tom Sepezc8155092021-04-26 23:37:42 +00002838 const CPDF_Dictionary* graphics_dict =
2839 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002840 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002841 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002842
2843 // Check the bitmap
Lei Zhang107fa7b2018-02-09 21:48:15 +00002844 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002845 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002846 CompareBitmap(page_bitmap.get(), 612, 792,
2847 "5384da3406d62360ffb5cac4476fff1c");
2848 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002849
2850 // Never mind, my new favorite color is blue, increase alpha
Lei Zhang3475b482019-05-13 18:30:57 +00002851 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 0, 0, 255, 180));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002852 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002853 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002854
2855 // Check that bitmap displays changed content
Lei Zhang107fa7b2018-02-09 21:48:15 +00002856 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002857 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002858 CompareBitmap(page_bitmap.get(), 612, 792,
2859 "2e51656f5073b0bee611d9cd086aa09c");
2860 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002861
2862 // And now generate, without changes
2863 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002864 EXPECT_EQ(3u, graphics_dict->size());
Lei Zhang107fa7b2018-02-09 21:48:15 +00002865 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002866 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002867 CompareBitmap(page_bitmap.get(), 612, 792,
2868 "2e51656f5073b0bee611d9cd086aa09c");
2869 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002870
2871 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -04002872 FPDF_PAGEOBJECT text_object =
2873 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00002874 ScopedFPDFWideString text =
Nicolas Penab3161852017-05-02 14:12:50 -04002875 GetFPDFWideString(L"Something something #text# something");
2876 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2877 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
2878 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002879 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepezc8155092021-04-26 23:37:42 +00002880 const CPDF_Dictionary* font_dict = cpage->GetResources()->GetDictFor("Font");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002881 ASSERT_TRUE(font_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002882 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002883
2884 // Generate yet again, check dicts are reasonably sized
2885 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002886 EXPECT_EQ(3u, graphics_dict->size());
2887 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002888 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002889}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002890
Lei Zhangab41f252018-12-23 03:10:50 +00002891TEST_F(FPDFEditEmbedderTest, LoadSimpleType1Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002892 CreateNewDocument();
2893 // TODO(npm): use other fonts after disallowing loading any font as any type
Tom Sepezffff6c52019-07-30 21:56:19 +00002894 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002895 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Tom Sepez20c41a52018-08-29 23:53:53 +00002896 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2897 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2898 FPDF_FONT_TYPE1, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002899 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002900 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002901 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002902
Lei Zhang710fa992018-05-25 16:24:48 +00002903 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002904 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2905 EXPECT_EQ("Type1", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002906 EXPECT_EQ("Tinos-Bold", font_dict->GetNameFor("BaseFont"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002907 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2908 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2909 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002910 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
2911
Lei Zhangde579ab2018-05-25 21:49:49 +00002912 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002913 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002914 ASSERT_EQ(224u, widths_array->size());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002915 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -05002916 EXPECT_EQ(569, widths_array->GetNumberAt(11));
2917 EXPECT_EQ(500, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002918 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002919}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002920
Lei Zhangab41f252018-12-23 03:10:50 +00002921TEST_F(FPDFEditEmbedderTest, LoadSimpleTrueTypeFont) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002922 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002923 RetainPtr<CPDF_Font> stock_font =
2924 CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Tom Sepez20c41a52018-08-29 23:53:53 +00002925 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2926 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2927 FPDF_FONT_TRUETYPE, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002928 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002929 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002930 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002931
Lei Zhang710fa992018-05-25 16:24:48 +00002932 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002933 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2934 EXPECT_EQ("TrueType", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002935 EXPECT_EQ("Cousine-Regular", font_dict->GetNameFor("BaseFont"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002936 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2937 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2938 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
2939 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002940
Lei Zhangde579ab2018-05-25 21:49:49 +00002941 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002942 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002943 ASSERT_EQ(224u, widths_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002944 EXPECT_EQ(600, widths_array->GetNumberAt(33));
2945 EXPECT_EQ(600, widths_array->GetNumberAt(74));
2946 EXPECT_EQ(600, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002947 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002948}
2949
Lei Zhangab41f252018-12-23 03:10:50 +00002950TEST_F(FPDFEditEmbedderTest, LoadCIDType0Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002951 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002952 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002953 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Tom Sepez20c41a52018-08-29 23:53:53 +00002954 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2955 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2956 FPDF_FONT_TYPE1, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04002957 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002958 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002959 EXPECT_TRUE(typed_font->IsCIDFont());
2960
2961 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00002962 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002963 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2964 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002965 EXPECT_EQ("Tinos-Regular-Identity-H", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00002966 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00002967 const CPDF_Array* descendant_array =
2968 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05002969 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002970 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002971
2972 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00002973 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00002974 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
2975 EXPECT_EQ("CIDFontType0", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002976 EXPECT_EQ("Tinos-Regular", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00002977 const CPDF_Dictionary* cidinfo_dict =
2978 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05002979 ASSERT_TRUE(cidinfo_dict);
Lei Zhang9c950b12019-01-16 19:06:37 +00002980 const CPDF_Object* registry = cidinfo_dict->GetObjectFor("Registry");
2981 ASSERT_TRUE(registry);
KDr28da0e1b2019-01-17 03:44:29 +00002982 EXPECT_EQ(CPDF_Object::kString, registry->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002983 EXPECT_EQ("Adobe", registry->GetString());
2984 const CPDF_Object* ordering = cidinfo_dict->GetObjectFor("Ordering");
2985 ASSERT_TRUE(ordering);
KDr28da0e1b2019-01-17 03:44:29 +00002986 EXPECT_EQ(CPDF_Object::kString, ordering->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002987 EXPECT_EQ("Identity", ordering->GetString());
Nicolas Penad03ca422017-03-06 13:54:33 -05002988 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00002989 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002990
2991 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00002992 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05002993 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002994 EXPECT_GT(widths_array->size(), 1u);
Nicolas Penad03ca422017-03-06 13:54:33 -05002995 CheckCompositeFontWidths(widths_array, typed_font);
2996}
2997
Lei Zhangab41f252018-12-23 03:10:50 +00002998TEST_F(FPDFEditEmbedderTest, LoadCIDType2Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002999 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00003000 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05003001 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Tom Sepez20c41a52018-08-29 23:53:53 +00003002 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3003 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3004 FPDF_FONT_TRUETYPE, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04003005 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00003006 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05003007 EXPECT_TRUE(typed_font->IsCIDFont());
3008
3009 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00003010 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00003011 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3012 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00003013 EXPECT_EQ("Arimo-Italic", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00003014 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00003015 const CPDF_Array* descendant_array =
3016 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05003017 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00003018 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05003019
3020 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00003021 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00003022 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
3023 EXPECT_EQ("CIDFontType2", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00003024 EXPECT_EQ("Arimo-Italic", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00003025 const CPDF_Dictionary* cidinfo_dict =
3026 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05003027 ASSERT_TRUE(cidinfo_dict);
3028 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
3029 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
3030 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00003031 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05003032
3033 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00003034 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05003035 ASSERT_TRUE(widths_array);
3036 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -05003037}
rbpotterce8e51e2017-04-28 12:42:47 -07003038
Lei Zhangab41f252018-12-23 03:10:50 +00003039TEST_F(FPDFEditEmbedderTest, NormalizeNegativeRotation) {
rbpotterce8e51e2017-04-28 12:42:47 -07003040 // Load document with a -90 degree rotation
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003041 ASSERT_TRUE(OpenDocument("bug_713197.pdf"));
rbpotterce8e51e2017-04-28 12:42:47 -07003042 FPDF_PAGE page = LoadPage(0);
3043 EXPECT_NE(nullptr, page);
3044
3045 EXPECT_EQ(3, FPDFPage_GetRotation(page));
3046 UnloadPage(page);
3047}
Nicolas Penab3161852017-05-02 14:12:50 -04003048
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003049TEST_F(FPDFEditEmbedderTest, AddTrueTypeFontText) {
Nicolas Penab3161852017-05-02 14:12:50 -04003050 // Start with a blank page
3051 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3052 {
Tom Sepezffff6c52019-07-30 21:56:19 +00003053 RetainPtr<CPDF_Font> stock_font =
3054 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00003055 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3056 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3057 FPDF_FONT_TRUETYPE, 0));
Nicolas Penab3161852017-05-02 14:12:50 -04003058 ASSERT_TRUE(font.get());
3059
3060 // Add some text to the page
3061 FPDF_PAGEOBJECT text_object =
3062 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3063 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003064 ScopedFPDFWideString text = GetFPDFWideString(kLoadedFontText);
Nicolas Penab3161852017-05-02 14:12:50 -04003065 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3066 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3067 FPDFPage_InsertObject(page, text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00003068 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003069 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003070
3071 // Add some more text, same font
3072 FPDF_PAGEOBJECT text_object2 =
3073 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00003074 ScopedFPDFWideString text2 = GetFPDFWideString(L"Bigger font size");
Nicolas Penab3161852017-05-02 14:12:50 -04003075 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3076 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
3077 FPDFPage_InsertObject(page, text_object2);
Nicolas Penab3161852017-05-02 14:12:50 -04003078 }
Lei Zhang30ff2532019-01-31 21:37:55 +00003079 ScopedFPDFBitmap page_bitmap2 = RenderPage(page);
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003080#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingste1215fc2022-03-26 22:29:08 +00003081 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhang42d30c22022-01-12 19:24:43 +00003082#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00003083 const char kInsertTrueTypeChecksum[] = "c7e2271a7f30e5b919a13ead47cea105";
Nicolas Penab3161852017-05-02 14:12:50 -04003084#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00003085 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhange4cdac52019-04-30 16:45:57 +00003086#endif
Hui Yingst3b6136a2020-06-09 00:39:33 +00003087 CompareBitmap(page_bitmap2.get(), 612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003088
Nicolas Pena207b7272017-05-26 17:37:06 -04003089 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penab3161852017-05-02 14:12:50 -04003090 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3091 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003092
Hui Yingst3b6136a2020-06-09 00:39:33 +00003093 VerifySavedDocument(612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003094}
Nicolas Penaf45ade32017-05-03 10:23:49 -04003095
Lei Zhangab41f252018-12-23 03:10:50 +00003096TEST_F(FPDFEditEmbedderTest, TransformAnnot) {
Jane Liueda65252017-06-07 11:31:27 -04003097 // Open a file with one annotation and load its first page.
3098 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
Lei Zhang75c81712018-02-08 17:22:39 +00003099 FPDF_PAGE page = LoadPage(0);
Jane Liueda65252017-06-07 11:31:27 -04003100 ASSERT_TRUE(page);
3101
Lei Zhanga21d5932018-02-05 18:28:38 +00003102 {
3103 // Add an underline annotation to the page without specifying its rectangle.
Tom Sepeze08d2b12018-04-25 18:49:32 +00003104 ScopedFPDFAnnotation annot(
Lei Zhanga21d5932018-02-05 18:28:38 +00003105 FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
3106 ASSERT_TRUE(annot);
Jane Liueda65252017-06-07 11:31:27 -04003107
Lei Zhanga21d5932018-02-05 18:28:38 +00003108 // FPDFPage_TransformAnnots() should run without errors when modifying
3109 // annotation rectangles.
3110 FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
3111 }
Jane Liueda65252017-06-07 11:31:27 -04003112 UnloadPage(page);
3113}
3114
Nicolas Penaf45ade32017-05-03 10:23:49 -04003115// TODO(npm): Add tests using Japanese fonts in other OS.
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003116#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00003117TEST_F(FPDFEditEmbedderTest, AddCIDFontText) {
Nicolas Penaf45ade32017-05-03 10:23:49 -04003118 // Start with a blank page
3119 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3120 CFX_Font CIDfont;
3121 {
3122 // First, get the data from the font
Anton Bikineev7ac13342022-01-24 21:25:15 +00003123 CIDfont.LoadSubst("Noto Sans CJK JP", true, 0, 400, 0,
3124 FX_CodePage::kShiftJIS, false);
Tom Andersond4fe5f72021-12-03 20:52:52 +00003125 EXPECT_EQ("Noto Sans CJK JP", CIDfont.GetFaceName());
Tom Sepez20c41a52018-08-29 23:53:53 +00003126 pdfium::span<const uint8_t> span = CIDfont.GetFontSpan();
Nicolas Penaf45ade32017-05-03 10:23:49 -04003127
3128 // Load the data into a FPDF_Font.
Tom Sepez20c41a52018-08-29 23:53:53 +00003129 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3130 FPDF_FONT_TRUETYPE, 1));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003131 ASSERT_TRUE(font.get());
3132
3133 // Add some text to the page
3134 FPDF_PAGEOBJECT text_object =
3135 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3136 ASSERT_TRUE(text_object);
3137 std::wstring wstr = L"ABCDEFGhijklmnop.";
Lei Zhangf0f67682019-04-08 17:03:21 +00003138 ScopedFPDFWideString text = GetFPDFWideString(wstr);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003139 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3140 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
3141 FPDFPage_InsertObject(page, text_object);
3142
3143 // And add some Japanese characters
3144 FPDF_PAGEOBJECT text_object2 =
3145 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
3146 ASSERT_TRUE(text_object2);
3147 std::wstring wstr2 =
3148 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
3149 L"\u756A";
Lei Zhangf0f67682019-04-08 17:03:21 +00003150 ScopedFPDFWideString text2 = GetFPDFWideString(wstr2);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003151 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3152 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
3153 FPDFPage_InsertObject(page, text_object2);
3154 }
3155
Nicolas Pena207b7272017-05-26 17:37:06 -04003156 // Check that the text renders properly.
Tom Andersond4fe5f72021-12-03 20:52:52 +00003157 static constexpr char md5[] = "84d31d11b76845423a2cfc1879c0fbb9";
Lei Zhang107fa7b2018-02-09 21:48:15 +00003158 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003159 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00003160 CompareBitmap(page_bitmap.get(), 612, 792, md5);
3161 }
Nicolas Penaf45ade32017-05-03 10:23:49 -04003162
3163 // Save the document, close the page.
Nicolas Pena207b7272017-05-26 17:37:06 -04003164 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003165 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3166 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003167
3168 VerifySavedDocument(612, 792, md5);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003169}
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003170#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003171
Hui Yingst29d377b2021-03-03 20:22:41 +00003172// TODO(crbug.com/pdfium/1651): Fix this issue and enable the test for Skia.
3173#if defined(_SKIA_SUPPORT_)
Lei Zhang03e5e682019-09-16 19:45:55 +00003174#define MAYBE_SaveAndRender DISABLED_SaveAndRender
3175#else
3176#define MAYBE_SaveAndRender SaveAndRender
3177#endif
3178TEST_F(FPDFEditEmbedderTest, MAYBE_SaveAndRender) {
Hui Yingst29d377b2021-03-03 20:22:41 +00003179#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
3180 static constexpr char kChecksum[] = "0e8b079e349e34f64211c495845a3529";
3181#else
3182 static constexpr char kChecksum[] = "3c20472b0552c0c22b88ab1ed8c6202b";
3183#endif
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003184 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003185 ASSERT_TRUE(OpenDocument("bug_779.pdf"));
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003186 FPDF_PAGE page = LoadPage(0);
3187 ASSERT_NE(nullptr, page);
3188
Hui Yingst29d377b2021-03-03 20:22:41 +00003189 // Now add a more complex green path.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003190 FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
Lei Zhang3475b482019-05-13 18:30:57 +00003191 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_path, 0, 255, 0, 200));
Hui Yingst29d377b2021-03-03 20:22:41 +00003192 // TODO(npm): stroking will cause the checksums to differ.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003193 EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
3194 EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
3195 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
3196 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
3197 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
3198 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
3199 EXPECT_TRUE(FPDFPath_Close(green_path));
3200 FPDFPage_InsertObject(page, green_path);
Tom Sepeze08d2b12018-04-25 18:49:32 +00003201 ScopedFPDFBitmap page_bitmap = RenderLoadedPage(page);
Hui Yingst29d377b2021-03-03 20:22:41 +00003202 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003203
3204 // Now save the result, closing the page and document
3205 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3206 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3207 UnloadPage(page);
3208 }
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003209
Hui Yingst29d377b2021-03-03 20:22:41 +00003210 VerifySavedDocument(612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003211}
Jane Liu28fb7ba2017-08-02 21:45:57 -04003212
Lei Zhangab41f252018-12-23 03:10:50 +00003213TEST_F(FPDFEditEmbedderTest, AddMark) {
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003214 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003215 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003216 FPDF_PAGE page = LoadPage(0);
3217 ASSERT_TRUE(page);
3218
Lei Zhang2697cb12019-07-03 18:14:29 +00003219 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003220
3221 // Add to the first page object a "Bounds" mark with "Position": "First".
3222 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3223 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3224 EXPECT_TRUE(mark);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003225 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3226 "Position", "First"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003227
Lei Zhang2697cb12019-07-03 18:14:29 +00003228 CheckMarkCounts(page, 1, 19, 8, 4, 9, 2);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003229
3230 // Save the file
3231 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3232 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3233 UnloadPage(page);
3234
3235 // Re-open the file and check the new mark is present.
Lei Zhang0b494052019-01-31 21:41:15 +00003236 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003237 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003238 ASSERT_TRUE(saved_page);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003239
Lei Zhang2697cb12019-07-03 18:14:29 +00003240 CheckMarkCounts(saved_page, 1, 19, 8, 4, 9, 2);
3241
3242 CloseSavedPage(saved_page);
3243 CloseSavedDocument();
3244}
3245
Hui Yingst04440af2020-07-27 22:39:02 +00003246TEST_F(FPDFEditEmbedderTest, AddMarkCompressedStream) {
Lei Zhang2697cb12019-07-03 18:14:29 +00003247 // Load document with some text in a compressed stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003248 ASSERT_TRUE(OpenDocument("hello_world_compressed_stream.pdf"));
Lei Zhang2697cb12019-07-03 18:14:29 +00003249 FPDF_PAGE page = LoadPage(0);
3250 ASSERT_TRUE(page);
3251
3252 // Render and check there are no marks.
3253 {
3254 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003255 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003256 }
3257 CheckMarkCounts(page, 0, 2, 0, 0, 0, 0);
3258
3259 // Add to the first page object a "Bounds" mark with "Position": "First".
3260 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3261 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3262 EXPECT_TRUE(mark);
3263 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3264 "Position", "First"));
3265
3266 // Render and check there is 1 mark.
3267 {
3268 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003269 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003270 }
3271 CheckMarkCounts(page, 0, 2, 0, 0, 0, 1);
3272
3273 // Save the file.
3274 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3275 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3276 UnloadPage(page);
3277
3278 // Re-open the file and check the new mark is present.
3279 ASSERT_TRUE(OpenSavedDocument());
3280 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003281 ASSERT_TRUE(saved_page);
Lei Zhang2697cb12019-07-03 18:14:29 +00003282
3283 {
3284 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003285 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003286 }
3287 CheckMarkCounts(saved_page, 0, 2, 0, 0, 0, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003288
3289 CloseSavedPage(saved_page);
3290 CloseSavedDocument();
3291}
3292
Lei Zhangab41f252018-12-23 03:10:50 +00003293TEST_F(FPDFEditEmbedderTest, SetMarkParam) {
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003294 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003295 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003296 FPDF_PAGE page = LoadPage(0);
3297 ASSERT_TRUE(page);
3298
3299 constexpr int kExpectedObjectCount = 19;
3300 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3301
3302 // Check the "Bounds" mark's "Position" param is "Last".
3303 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3304 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3305 ASSERT_TRUE(mark);
3306 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003307 unsigned long name_len = 999u;
3308 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3309 EXPECT_EQ((6u + 1u) * 2u, name_len);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003310 ASSERT_EQ(L"Bounds",
3311 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3312 unsigned long out_buffer_len;
3313 ASSERT_TRUE(FPDFPageObjMark_GetParamStringValue(
3314 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3315 ASSERT_EQ(L"Last",
3316 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3317
3318 // Set is to "End".
3319 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3320 "Position", "End"));
3321
3322 // Verify the object passed must correspond to the mark passed.
3323 FPDF_PAGEOBJECT another_page_object = FPDFPage_GetObject(page, 17);
3324 EXPECT_FALSE(FPDFPageObjMark_SetStringParam(document(), another_page_object,
3325 mark, "Position", "End"));
3326
3327 // Verify nothing else changed.
3328 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3329
3330 // Verify "Position" now maps to "End".
3331 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3332 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3333 EXPECT_EQ(L"End",
3334 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3335
3336 // Save the file
3337 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3338 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3339 UnloadPage(page);
3340
3341 // Re-open the file and cerify "Position" still maps to "End".
Lei Zhang0b494052019-01-31 21:41:15 +00003342 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003343 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003344 ASSERT_TRUE(saved_page);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003345
3346 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3347 page_object = FPDFPage_GetObject(saved_page, 18);
3348 mark = FPDFPageObj_GetMark(page_object, 1);
3349 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3350 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3351 EXPECT_EQ(L"End",
3352 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3353
3354 CloseSavedPage(saved_page);
3355 CloseSavedDocument();
3356}
3357
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003358TEST_F(FPDFEditEmbedderTest, AddMarkedText) {
Henrique Nakashima144107d2018-07-10 21:04:05 +00003359 // Start with a blank page.
3360 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3361
Tom Sepezffff6c52019-07-30 21:56:19 +00003362 RetainPtr<CPDF_Font> stock_font =
3363 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00003364 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3365 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3366 FPDF_FONT_TRUETYPE, 0));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003367 ASSERT_TRUE(font.get());
3368
3369 // Add some text to the page.
3370 FPDF_PAGEOBJECT text_object =
3371 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3372
3373 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003374 ScopedFPDFWideString text1 = GetFPDFWideString(kLoadedFontText);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003375 EXPECT_TRUE(FPDFText_SetText(text_object, text1.get()));
3376 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3377 FPDFPage_InsertObject(page, text_object);
3378
3379 // Add a mark with the tag "TestMarkName" to that text.
3380 EXPECT_EQ(0, FPDFPageObj_CountMarks(text_object));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003381 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(text_object, "Test Mark Name");
Henrique Nakashima144107d2018-07-10 21:04:05 +00003382 EXPECT_TRUE(mark);
3383 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3384 EXPECT_EQ(mark, FPDFPageObj_GetMark(text_object, 0));
3385 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003386 unsigned long name_len = 999u;
3387 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3388 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003389 std::wstring name =
3390 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003391 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003392
3393 // Add parameters:
3394 // - int "IntKey" : 42
3395 // - string "StringKey": "StringValue"
Henrique Nakashima07520f62018-07-12 19:45:29 +00003396 // - blob "BlobKey": "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0"
Lei Zhang590f4242019-05-15 20:57:26 +00003397 constexpr size_t kBlobLen = 28;
Lei Zhangd3b028b2018-11-30 22:22:00 +00003398 char block_value[kBlobLen];
3399 memcpy(block_value, "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0", kBlobLen);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003400 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003401 EXPECT_TRUE(
3402 FPDFPageObjMark_SetIntParam(document(), text_object, mark, "IntKey", 42));
3403 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), text_object, mark,
3404 "StringKey", "StringValue"));
3405 EXPECT_TRUE(FPDFPageObjMark_SetBlobParam(document(), text_object, mark,
Lei Zhangd3b028b2018-11-30 22:22:00 +00003406 "BlobKey", block_value, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003407 EXPECT_EQ(3, FPDFPageObjMark_CountParams(mark));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003408
3409 // Check the two parameters can be retrieved.
3410 EXPECT_EQ(FPDF_OBJECT_NUMBER,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003411 FPDFPageObjMark_GetParamValueType(mark, "IntKey"));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003412 int int_value;
Henrique Nakashima94230e52018-07-11 22:02:02 +00003413 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "IntKey", &int_value));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003414 EXPECT_EQ(42, int_value);
3415
3416 EXPECT_EQ(FPDF_OBJECT_STRING,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003417 FPDFPageObjMark_GetParamValueType(mark, "StringKey"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003418 unsigned long out_buffer_len = 999u;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003419 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3420 mark, "StringKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003421 EXPECT_GT(out_buffer_len, 0u);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003422 EXPECT_NE(999u, out_buffer_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003423 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3424 EXPECT_EQ(L"StringValue", name);
3425
Henrique Nakashima07520f62018-07-12 19:45:29 +00003426 EXPECT_EQ(FPDF_OBJECT_STRING,
3427 FPDFPageObjMark_GetParamValueType(mark, "BlobKey"));
3428 out_buffer_len = 0;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003429 EXPECT_TRUE(FPDFPageObjMark_GetParamBlobValue(
3430 mark, "BlobKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003431 EXPECT_EQ(kBlobLen, out_buffer_len);
Lei Zhangd3b028b2018-11-30 22:22:00 +00003432 EXPECT_EQ(0, memcmp(block_value, buffer, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003433
Lei Zhangf16376e2020-06-18 19:19:32 +00003434 // Render and check the bitmap is the expected one.
Henrique Nakashima144107d2018-07-10 21:04:05 +00003435 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003436 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003437 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003438 }
3439
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003440 // Now save the result.
3441 EXPECT_EQ(1, FPDFPage_CountObjects(page));
3442 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3443 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3444
Henrique Nakashima144107d2018-07-10 21:04:05 +00003445 FPDF_ClosePage(page);
3446
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003447 // Re-open the file and check the changes were kept in the saved .pdf.
Lei Zhang0b494052019-01-31 21:41:15 +00003448 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003449 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003450 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003451 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
3452
3453 text_object = FPDFPage_GetObject(saved_page, 0);
3454 EXPECT_TRUE(text_object);
3455 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3456 mark = FPDFPageObj_GetMark(text_object, 0);
3457 EXPECT_TRUE(mark);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003458
3459 name_len = 999u;
3460 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3461 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003462 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003463 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003464
3465 CloseSavedPage(saved_page);
3466 CloseSavedDocument();
Henrique Nakashima144107d2018-07-10 21:04:05 +00003467}
3468
Lei Zhangab41f252018-12-23 03:10:50 +00003469TEST_F(FPDFEditEmbedderTest, MarkGetName) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003470 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003471 FPDF_PAGE page = LoadPage(0);
3472 ASSERT_TRUE(page);
3473 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3474 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3475 ASSERT_TRUE(mark);
3476
3477 char buffer[256];
3478 unsigned long out_len;
3479
3480 // Show the positive cases of FPDFPageObjMark_GetName.
3481 out_len = 999u;
3482 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, nullptr, 0, &out_len));
3483 EXPECT_EQ((6u + 1u) * 2u, out_len);
3484
3485 out_len = 999u;
3486 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &out_len));
3487 EXPECT_EQ(L"Bounds",
3488 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3489 EXPECT_EQ((6u + 1u) * 2u, out_len);
3490
3491 // Show the negative cases of FPDFPageObjMark_GetName.
3492 out_len = 999u;
3493 EXPECT_FALSE(
3494 FPDFPageObjMark_GetName(nullptr, buffer, sizeof(buffer), &out_len));
3495 EXPECT_EQ(999u, out_len);
3496
3497 EXPECT_FALSE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), nullptr));
3498
3499 UnloadPage(page);
3500}
3501
Lei Zhangab41f252018-12-23 03:10:50 +00003502TEST_F(FPDFEditEmbedderTest, MarkGetParamKey) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003503 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003504 FPDF_PAGE page = LoadPage(0);
3505 ASSERT_TRUE(page);
3506 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3507 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3508 ASSERT_TRUE(mark);
3509
3510 char buffer[256];
3511 unsigned long out_len;
3512
3513 // Show the positive cases of FPDFPageObjMark_GetParamKey.
3514 out_len = 999u;
3515 EXPECT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, nullptr, 0, &out_len));
3516 EXPECT_EQ((8u + 1u) * 2u, out_len);
3517
3518 out_len = 999u;
3519 EXPECT_TRUE(
3520 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), &out_len));
3521 EXPECT_EQ(L"Position",
3522 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3523 EXPECT_EQ((8u + 1u) * 2u, out_len);
3524
3525 // Show the negative cases of FPDFPageObjMark_GetParamKey.
3526 out_len = 999u;
3527 EXPECT_FALSE(FPDFPageObjMark_GetParamKey(nullptr, 0, buffer, sizeof(buffer),
3528 &out_len));
3529 EXPECT_EQ(999u, out_len);
3530
3531 out_len = 999u;
3532 EXPECT_FALSE(
3533 FPDFPageObjMark_GetParamKey(mark, 1, buffer, sizeof(buffer), &out_len));
3534 EXPECT_EQ(999u, out_len);
3535
3536 EXPECT_FALSE(
3537 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), nullptr));
3538
3539 UnloadPage(page);
3540}
3541
Lei Zhangab41f252018-12-23 03:10:50 +00003542TEST_F(FPDFEditEmbedderTest, MarkGetIntParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003543 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003544 FPDF_PAGE page = LoadPage(0);
3545 ASSERT_TRUE(page);
3546 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 8);
3547 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 0);
3548 ASSERT_TRUE(mark);
3549
3550 int out_value;
3551
3552 // Show the positive cases of FPDFPageObjMark_GetParamIntValue.
3553 out_value = 999;
3554 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
3555 EXPECT_EQ(3, out_value);
3556
3557 // Show the negative cases of FPDFPageObjMark_GetParamIntValue.
3558 out_value = 999;
3559 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(nullptr, "Factor", &out_value));
3560 EXPECT_EQ(999, out_value);
3561
3562 out_value = 999;
3563 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "ParamThatDoesNotExist",
3564 &out_value));
3565 EXPECT_EQ(999, out_value);
3566
3567 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", nullptr));
3568
3569 page_object = FPDFPage_GetObject(page, 18);
3570 mark = FPDFPageObj_GetMark(page_object, 1);
3571 out_value = 999;
3572 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Position", &out_value));
3573 EXPECT_EQ(999, out_value);
3574
3575 UnloadPage(page);
3576}
3577
Lei Zhangab41f252018-12-23 03:10:50 +00003578TEST_F(FPDFEditEmbedderTest, MarkGetStringParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003579 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003580 FPDF_PAGE page = LoadPage(0);
3581 ASSERT_TRUE(page);
3582 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3583 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3584 ASSERT_TRUE(mark);
3585
3586 char buffer[256];
3587 unsigned long out_len;
3588
3589 // Show the positive cases of FPDFPageObjMark_GetParamStringValue.
3590 out_len = 999u;
3591 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", nullptr, 0,
3592 &out_len));
3593 EXPECT_EQ((4u + 1u) * 2u, out_len);
3594
3595 out_len = 999u;
3596 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3597 sizeof(buffer), &out_len));
3598 EXPECT_EQ(L"Last",
3599 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3600 EXPECT_EQ((4u + 1u) * 2u, out_len);
3601
3602 // Show the negative cases of FPDFPageObjMark_GetParamStringValue.
3603 out_len = 999u;
3604 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(nullptr, "Position", buffer,
3605 sizeof(buffer), &out_len));
3606 EXPECT_EQ(999u, out_len);
3607
3608 out_len = 999u;
3609 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(
3610 mark, "ParamThatDoesNotExist", buffer, sizeof(buffer), &out_len));
3611 EXPECT_EQ(999u, out_len);
3612
3613 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3614 sizeof(buffer), nullptr));
3615
3616 page_object = FPDFPage_GetObject(page, 8);
3617 mark = FPDFPageObj_GetMark(page_object, 0);
3618 out_len = 999u;
3619 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Factor", buffer,
3620 sizeof(buffer), &out_len));
3621 EXPECT_EQ(999u, out_len);
3622
3623 UnloadPage(page);
3624}
3625
Lei Zhang2c57ad82022-02-04 02:21:28 +00003626// See also FPDFStructTreeEmbedderTest.GetMarkedContentID, which traverses the
3627// marked contents using FPDF_StructTree_GetForPage() and related API.
3628TEST_F(FPDFEditEmbedderTest, TraverseMarkedContentID) {
3629 ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
3630 FPDF_PAGE page = LoadPage(0);
3631 ASSERT_TRUE(page);
3632
3633 ASSERT_EQ(2, FPDFPage_CountObjects(page));
3634 FPDF_PAGEOBJECT object1 = FPDFPage_GetObject(page, 0);
3635 ASSERT_TRUE(object1);
3636 ASSERT_EQ(1, FPDFPageObj_CountMarks(object1));
3637
3638 FPDF_PAGEOBJECTMARK mark11 = FPDFPageObj_GetMark(object1, 0);
3639 ASSERT_TRUE(mark11);
3640 unsigned long len = 0;
3641 unsigned short buf[40];
3642 ASSERT_TRUE(FPDFPageObjMark_GetName(mark11, buf, sizeof(buf), &len));
3643 EXPECT_EQ(18u, len);
3644 EXPECT_EQ(L"Artifact", GetPlatformWString(buf));
3645 ASSERT_EQ(2, FPDFPageObjMark_CountParams(mark11));
3646 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 0, buf, sizeof(buf), &len));
3647 EXPECT_EQ(10u, len);
3648 EXPECT_EQ(L"BBox", GetPlatformWString(buf));
3649 EXPECT_EQ(FPDF_OBJECT_ARRAY,
3650 FPDFPageObjMark_GetParamValueType(mark11, "BBox"));
3651 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 1, buf, sizeof(buf), &len));
3652 EXPECT_EQ(10u, len);
3653 EXPECT_EQ(L"Type", GetPlatformWString(buf));
3654 EXPECT_EQ(FPDF_OBJECT_NAME,
3655 FPDFPageObjMark_GetParamValueType(mark11, "Type"));
3656
3657 FPDF_PAGEOBJECT object2 = FPDFPage_GetObject(page, 1);
3658 ASSERT_TRUE(object2);
3659 ASSERT_EQ(2, FPDFPageObj_CountMarks(object2));
3660 EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(object2));
3661
3662 FPDF_PAGEOBJECTMARK mark21 = FPDFPageObj_GetMark(object2, 0);
3663 ASSERT_TRUE(mark21);
3664 ASSERT_TRUE(FPDFPageObjMark_GetName(mark21, buf, sizeof(buf), &len));
3665 EXPECT_EQ(14u, len);
3666 EXPECT_EQ(L"Figure", GetPlatformWString(buf));
3667 ASSERT_EQ(1, FPDFPageObjMark_CountParams(mark21));
3668 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark21, 0, buf, sizeof(buf), &len));
3669 EXPECT_EQ(10u, len);
3670 EXPECT_EQ(L"MCID", GetPlatformWString(buf));
3671 ASSERT_EQ(FPDF_OBJECT_NUMBER,
3672 FPDFPageObjMark_GetParamValueType(mark21, "MCID"));
3673 int mcid = -1;
3674 ASSERT_TRUE(FPDFPageObjMark_GetParamIntValue(mark21, "MCID", &mcid));
3675 EXPECT_EQ(0, mcid);
3676
3677 FPDF_PAGEOBJECTMARK mark22 = FPDFPageObj_GetMark(object2, 1);
3678 ASSERT_TRUE(mark22);
3679 ASSERT_TRUE(FPDFPageObjMark_GetName(mark22, buf, sizeof(buf), &len));
3680 EXPECT_EQ(18u, len);
3681 EXPECT_EQ(L"ClipSpan", GetPlatformWString(buf));
3682 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark22));
3683
3684 UnloadPage(page);
3685}
3686
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003687TEST_F(FPDFEditEmbedderTest, GetBitmap) {
Jane Liu28fb7ba2017-08-02 21:45:57 -04003688 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3689 FPDF_PAGE page = LoadPage(0);
3690 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003691 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu28fb7ba2017-08-02 21:45:57 -04003692
3693 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3694 EXPECT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3695 EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
3696
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003697 {
3698 obj = FPDFPage_GetObject(page, 33);
3699 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3700 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3701 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
Lei Zhang85166512020-07-14 23:28:56 +00003702 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003703 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003704
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003705 {
3706 obj = FPDFPage_GetObject(page, 34);
3707 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3708 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3709 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3710 CompareBitmap(bitmap.get(), 103, 75, "c8d51fa6821ceb2a67f08446ff236c40");
3711 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003712
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003713 {
3714 obj = FPDFPage_GetObject(page, 35);
3715 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3716 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3717 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3718 CompareBitmap(bitmap.get(), 92, 68, "9c6d76cb1e37ef8514f9455d759391f3");
3719 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003720
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003721 {
3722 obj = FPDFPage_GetObject(page, 36);
3723 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3724 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3725 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3726 CompareBitmap(bitmap.get(), 79, 60, "f4e72fb783a01c7b4614cdc25eaa98ac");
3727 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003728
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003729 {
3730 obj = FPDFPage_GetObject(page, 37);
3731 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3732 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3733 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3734 CompareBitmap(bitmap.get(), 126, 106, "2cf9e66414c72461f4ccbf9cdebdfa1b");
3735 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003736
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003737 {
3738 obj = FPDFPage_GetObject(page, 38);
3739 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3740 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3741 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3742 CompareBitmap(bitmap.get(), 194, 119, "a8f3a126cec274dab8242fd2ccdc1b8b");
3743 }
3744
Jane Liu28fb7ba2017-08-02 21:45:57 -04003745 UnloadPage(page);
3746}
Jane Liu548334e2017-08-03 16:33:40 -04003747
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003748TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSetMatrix) {
Lei Zhang85166512020-07-14 23:28:56 +00003749 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3750 FPDF_PAGE page = LoadPage(0);
3751 ASSERT_TRUE(page);
3752 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3753
3754 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3755 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3756
3757 {
3758 // Render |obj| as is.
3759 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3760 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3761 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3762 }
3763
3764 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003765 FS_MATRIX matrix;
3766 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3767 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3768 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3769 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3770 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3771 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3772 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003773
3774 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003775 matrix.a = 120.0;
3776 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang85166512020-07-14 23:28:56 +00003777
3778 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003779 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3780 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3781 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3782 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3783 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3784 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3785 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003786
3787 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003788 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has no
Lei Zhang85166512020-07-14 23:28:56 +00003789 // effect.
3790 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3791 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3792 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3793 }
3794
3795 UnloadPage(page);
3796}
3797
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003798TEST_F(FPDFEditEmbedderTest, GetBitmapForJBigImage) {
Lei Zhang53341dd2018-03-01 15:42:47 +00003799 ASSERT_TRUE(OpenDocument("bug_631912.pdf"));
3800 FPDF_PAGE page = LoadPage(0);
3801 ASSERT_TRUE(page);
3802 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3803
3804 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
3805 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3806 {
Tom Sepeze08d2b12018-04-25 18:49:32 +00003807 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
Lei Zhang1330ebb2018-03-05 15:16:37 +00003808 ASSERT_TRUE(bitmap);
3809 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3810 CompareBitmap(bitmap.get(), 1152, 720, "3f6a48e2b3e91b799bf34567f55cb4de");
Lei Zhang53341dd2018-03-01 15:42:47 +00003811 }
3812
3813 UnloadPage(page);
3814}
3815
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003816TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSMask) {
Lei Zhang2e1b4f22020-07-08 23:40:18 +00003817 ASSERT_TRUE(OpenDocument("matte.pdf"));
3818 FPDF_PAGE page = LoadPage(0);
3819 ASSERT_TRUE(page);
3820
3821 constexpr int kExpectedObjects = 4;
3822 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3823
3824 for (int i = 0; i < kExpectedObjects; ++i) {
3825 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3826 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3827 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3828 ASSERT_TRUE(bitmap);
3829 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3830 CompareBitmap(bitmap.get(), 50, 50, "46c9a1dbe0b44765ce46017ad629a2fe");
3831 }
3832
3833 UnloadPage(page);
3834}
3835
Hui Yingst822fb8d2020-10-05 22:10:35 +00003836// TODO(crbug.com/pdfium/11): Fix this test and enable.
3837#if defined(_SKIA_SUPPORT_)
3838#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3839 DISABLED_GetRenderedBitmapHandlesSetMatrix
3840#else
3841#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3842 GetRenderedBitmapHandlesSetMatrix
3843#endif
3844TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSetMatrix) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003845 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3846 FPDF_PAGE page = LoadPage(0);
3847 ASSERT_TRUE(page);
3848 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3849
3850 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3851 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3852
3853 {
3854 // Render |obj| as is.
3855 ScopedFPDFBitmap bitmap(
3856 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3857 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003858 CompareBitmap(bitmap.get(), 53, 43, "582ca300e003f512d7b552c7b5b45d2e");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003859 }
3860
3861 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003862 FS_MATRIX matrix;
3863 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3864 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3865 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3866 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3867 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3868 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3869 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003870
3871 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003872 matrix.a = 120.0;
3873 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003874
3875 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003876 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3877 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3878 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3879 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3880 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3881 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3882 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003883
3884 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003885 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has an
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003886 // effect.
3887 ScopedFPDFBitmap bitmap(
3888 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3889 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003890 CompareBitmap(bitmap.get(), 120, 43, "0824c16dcf2dfcef44b45d88db1fddce");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003891 }
3892
3893 UnloadPage(page);
3894}
3895
Hui Yingst822fb8d2020-10-05 22:10:35 +00003896// TODO(crbug.com/pdfium/11): Fix this test and enable.
3897#if defined(_SKIA_SUPPORT_)
3898#define MAYBE_GetRenderedBitmapHandlesSMask \
3899 DISABLED_GetRenderedBitmapHandlesSMask
3900#else
3901#define MAYBE_GetRenderedBitmapHandlesSMask GetRenderedBitmapHandlesSMask
3902#endif
3903TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSMask) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003904 ASSERT_TRUE(OpenDocument("matte.pdf"));
3905 FPDF_PAGE page = LoadPage(0);
3906 ASSERT_TRUE(page);
3907
3908 constexpr int kExpectedObjects = 4;
3909 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3910
3911 for (int i = 0; i < kExpectedObjects; ++i) {
3912 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3913 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3914 ScopedFPDFBitmap bitmap(
3915 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3916 ASSERT_TRUE(bitmap);
3917 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
3918 if (i == 0)
3919 CompareBitmap(bitmap.get(), 40, 60, "5a3ae4a660ce919e29c42ec2258142f1");
3920 else
3921 CompareBitmap(bitmap.get(), 40, 60, "67504e83f5d78214ea00efc19082c5c1");
3922 }
3923
3924 UnloadPage(page);
3925}
3926
3927TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapBadParams) {
3928 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3929 FPDF_PAGE page = LoadPage(0);
3930 ASSERT_TRUE(page);
3931
3932 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3933 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3934
3935 // Test various null parameters.
3936 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, nullptr));
3937 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), nullptr, nullptr));
3938 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, nullptr));
3939 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, obj));
3940 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), page, nullptr));
3941 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, obj));
3942
3943 // Test mismatch between document and page parameters.
3944 ScopedFPDFDocument new_document(FPDF_CreateNewDocument());
3945 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(new_document.get(), page, obj));
3946
3947 UnloadPage(page);
3948}
3949
Lei Zhangab41f252018-12-23 03:10:50 +00003950TEST_F(FPDFEditEmbedderTest, GetImageData) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003951 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liu548334e2017-08-03 16:33:40 -04003952 FPDF_PAGE page = LoadPage(0);
3953 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003954 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu548334e2017-08-03 16:33:40 -04003955
3956 // Retrieve an image object with flate-encoded data stream.
3957 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3958 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3959
3960 // Check that the raw image data has the correct length and hash value.
3961 unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
Lei Zhang0bd11f72022-05-11 00:10:54 +00003962 std::vector<uint8_t> buf(len);
Jane Liu548334e2017-08-03 16:33:40 -04003963 EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003964 EXPECT_EQ("f73802327d2e88e890f653961bcda81a", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003965
3966 // Check that the decoded image data has the correct length and hash value.
3967 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3968 buf.clear();
3969 buf.resize(len);
3970 EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003971 EXPECT_EQ(kEmbeddedImage33Checksum, GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003972
Lei Zhang351e8b02018-12-20 01:10:06 +00003973 // Retrieve an image object with DCTDecode-encoded data stream.
Jane Liu548334e2017-08-03 16:33:40 -04003974 obj = FPDFPage_GetObject(page, 37);
3975 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3976
3977 // Check that the raw image data has the correct length and hash value.
3978 len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
3979 buf.clear();
3980 buf.resize(len);
3981 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003982 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003983
3984 // Check that the decoded image data has the correct length and hash value,
3985 // which should be the same as those of the raw data, since this image is
3986 // encoded by a single DCTDecode filter and decoding is a noop.
3987 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3988 buf.clear();
3989 buf.resize(len);
3990 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003991 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003992
3993 UnloadPage(page);
3994}
Jane Liu2e5f0ae2017-08-08 15:23:27 -04003995
Lei Zhangab41f252018-12-23 03:10:50 +00003996TEST_F(FPDFEditEmbedderTest, GetImageMatrix) {
Lei Zhang866d6882018-10-24 17:31:01 +00003997 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3998 FPDF_PAGE page = LoadPage(0);
3999 ASSERT_TRUE(page);
4000 ASSERT_EQ(39, FPDFPage_CountObjects(page));
4001
4002 FPDF_PAGEOBJECT obj;
Lei Zhangc8601bf2021-06-29 23:19:27 +00004003 FS_MATRIX matrix;
Lei Zhang866d6882018-10-24 17:31:01 +00004004
4005 obj = FPDFPage_GetObject(page, 33);
4006 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004007 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4008 EXPECT_FLOAT_EQ(53.0f, matrix.a);
4009 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4010 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4011 EXPECT_FLOAT_EQ(43.0f, matrix.d);
4012 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4013 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004014
4015 obj = FPDFPage_GetObject(page, 34);
4016 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004017 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4018 EXPECT_FLOAT_EQ(70.0f, matrix.a);
4019 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4020 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4021 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4022 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4023 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004024
4025 obj = FPDFPage_GetObject(page, 35);
4026 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004027 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4028 EXPECT_FLOAT_EQ(69.0f, matrix.a);
4029 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4030 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4031 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4032 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4033 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004034
4035 obj = FPDFPage_GetObject(page, 36);
4036 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004037 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4038 EXPECT_FLOAT_EQ(59.0f, matrix.a);
4039 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4040 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4041 EXPECT_FLOAT_EQ(45.0f, matrix.d);
4042 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4043 EXPECT_FLOAT_EQ(553.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004044
4045 obj = FPDFPage_GetObject(page, 37);
4046 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004047 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4048 EXPECT_FLOAT_EQ(55.94000244140625f, matrix.a);
4049 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4050 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4051 EXPECT_FLOAT_EQ(46.950000762939453f, matrix.d);
4052 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4053 EXPECT_FLOAT_EQ(552.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004054
4055 obj = FPDFPage_GetObject(page, 38);
4056 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004057 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4058 EXPECT_FLOAT_EQ(70.528999328613281f, matrix.a);
4059 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4060 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4061 EXPECT_FLOAT_EQ(43.149997711181641f, matrix.d);
4062 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4063 EXPECT_FLOAT_EQ(553.3599853515625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004064
4065 UnloadPage(page);
4066}
4067
Lei Zhangab41f252018-12-23 03:10:50 +00004068TEST_F(FPDFEditEmbedderTest, DestroyPageObject) {
Jane Liu2e5f0ae2017-08-08 15:23:27 -04004069 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
4070 ASSERT_TRUE(rect);
4071
4072 // There should be no memory leaks with a call to FPDFPageObj_Destroy().
4073 FPDFPageObj_Destroy(rect);
4074}
Jane Liube63ab92017-08-09 14:09:34 -04004075
Lei Zhangab41f252018-12-23 03:10:50 +00004076TEST_F(FPDFEditEmbedderTest, GetImageFilters) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00004077 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liube63ab92017-08-09 14:09:34 -04004078 FPDF_PAGE page = LoadPage(0);
4079 ASSERT_TRUE(page);
4080
4081 // Verify that retrieving the filter of a non-image object would fail.
4082 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
4083 ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4084 ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
4085 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
4086
4087 // Verify the returned filter string for an image object with a single filter.
4088 obj = FPDFPage_GetObject(page, 33);
4089 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4090 ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
4091 unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4092 std::vector<char> buf(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004093 static constexpr char kFlateDecode[] = "FlateDecode";
4094 EXPECT_EQ(sizeof(kFlateDecode),
4095 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4096 EXPECT_STREQ(kFlateDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004097 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
4098
4099 // Verify all the filters for an image object with a list of filters.
4100 obj = FPDFPage_GetObject(page, 38);
4101 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4102 ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
4103 len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4104 buf.clear();
4105 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004106 static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
4107 EXPECT_EQ(sizeof(kASCIIHexDecode),
4108 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4109 EXPECT_STREQ(kASCIIHexDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004110
4111 len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
4112 buf.clear();
4113 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004114 static constexpr char kDCTDecode[] = "DCTDecode";
4115 EXPECT_EQ(sizeof(kDCTDecode),
4116 FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
4117 EXPECT_STREQ(kDCTDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004118
4119 UnloadPage(page);
4120}
Jane Liuca898292017-08-16 11:25:35 -04004121
Lei Zhangab41f252018-12-23 03:10:50 +00004122TEST_F(FPDFEditEmbedderTest, GetImageMetadata) {
Jane Liuca898292017-08-16 11:25:35 -04004123 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4124 FPDF_PAGE page = LoadPage(0);
4125 ASSERT_TRUE(page);
4126
4127 // Check that getting the metadata of a null object would fail.
4128 FPDF_IMAGEOBJ_METADATA metadata;
4129 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
4130
4131 // Check that receiving the metadata with a null metadata object would fail.
4132 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4133 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
4134
4135 // Check that when retrieving an image object's metadata without passing in
4136 // |page|, all values are correct, with the last two being default values.
4137 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4138 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004139 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004140 EXPECT_EQ(92u, metadata.width);
4141 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004142 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4143 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004144 EXPECT_EQ(0u, metadata.bits_per_pixel);
4145 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4146
4147 // Verify the metadata of a bitmap image with indexed colorspace.
4148 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004149 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004150 EXPECT_EQ(92u, metadata.width);
4151 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004152 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4153 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004154 EXPECT_EQ(1u, metadata.bits_per_pixel);
4155 EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
4156
4157 // Verify the metadata of an image with RGB colorspace.
4158 obj = FPDFPage_GetObject(page, 37);
4159 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4160 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004161 EXPECT_EQ(9, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004162 EXPECT_EQ(126u, metadata.width);
4163 EXPECT_EQ(106u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004164 EXPECT_FLOAT_EQ(162.173752f, metadata.horizontal_dpi);
4165 EXPECT_FLOAT_EQ(162.555878f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004166 EXPECT_EQ(24u, metadata.bits_per_pixel);
4167 EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
4168
4169 UnloadPage(page);
4170}
Lei Zhangdc1b7392020-05-14 21:15:53 +00004171
4172TEST_F(FPDFEditEmbedderTest, GetImageMetadataJpxLzw) {
4173 ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
4174 FPDF_PAGE page = LoadPage(0);
4175 ASSERT_TRUE(page);
4176
4177 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4178 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4179
4180 FPDF_IMAGEOBJ_METADATA metadata;
4181 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4182 EXPECT_EQ(-1, metadata.marked_content_id);
4183 EXPECT_EQ(612u, metadata.width);
4184 EXPECT_EQ(792u, metadata.height);
4185 EXPECT_FLOAT_EQ(72.0f, metadata.horizontal_dpi);
4186 EXPECT_FLOAT_EQ(72.0f, metadata.vertical_dpi);
4187 EXPECT_EQ(24u, metadata.bits_per_pixel);
4188 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4189
4190 UnloadPage(page);
4191}