blob: 8942c28dd9fd07be7c5604b76c853a1e59cf659f [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
2502 UnloadPage(page);
2503}
2504
2505TEST_F(FPDFEditEmbedderTest, GlyphPaths) {
2506 // bad glyphpath
2507 EXPECT_EQ(-1, FPDFGlyphPath_CountGlyphSegments(nullptr));
2508 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(nullptr, 1));
2509
2510 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2511 FPDF_PAGE page = LoadPage(0);
2512 ASSERT_TRUE(page);
2513 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2514 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2515 ASSERT_TRUE(text);
2516 FPDF_FONT font = FPDFTextObj_GetFont(text);
2517 ASSERT_TRUE(font);
2518
2519 // good glyphpath
2520 FPDF_GLYPHPATH gpath = FPDFFont_GetGlyphPath(font, 's', 12.0f);
2521 ASSERT_TRUE(gpath);
2522
2523 int count = FPDFGlyphPath_CountGlyphSegments(gpath);
2524 ASSERT_GT(count, 0);
2525 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, -1));
2526 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, count));
2527
2528 FPDF_PATHSEGMENT segment = FPDFGlyphPath_GetGlyphPathSegment(gpath, 1);
2529 ASSERT_TRUE(segment);
2530 EXPECT_EQ(FPDF_SEGMENT_BEZIERTO, FPDFPathSegment_GetType(segment));
2531
2532 UnloadPage(page);
2533}
2534
Lei Zhang4363dab2021-06-24 19:23:09 +00002535TEST_F(FPDFEditEmbedderTest, FormGetObjects) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002536 ASSERT_TRUE(OpenDocument("form_object.pdf"));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002537 FPDF_PAGE page = LoadPage(0);
2538 ASSERT_TRUE(page);
2539 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2540
2541 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002542 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002543 ASSERT_EQ(-1, FPDFFormObj_CountObjects(nullptr));
2544 ASSERT_EQ(2, FPDFFormObj_CountObjects(form));
2545
Miklos Vajna1d273f12018-07-16 19:20:36 +00002546 // FPDFFormObj_GetObject() positive testing.
2547 FPDF_PAGEOBJECT text1 = FPDFFormObj_GetObject(form, 0);
2548 ASSERT_TRUE(text1);
2549 float left = 0;
2550 float bottom = 0;
2551 float right = 0;
2552 float top = 0;
2553 ASSERT_TRUE(FPDFPageObj_GetBounds(text1, &left, &bottom, &right, &top));
2554 ASSERT_EQ(271, static_cast<int>(top));
2555
2556 FPDF_PAGEOBJECT text2 = FPDFFormObj_GetObject(form, 1);
2557 ASSERT_TRUE(text2);
2558 ASSERT_TRUE(FPDFPageObj_GetBounds(text2, &left, &bottom, &right, &top));
2559 ASSERT_EQ(221, static_cast<int>(top));
2560
2561 // FPDFFormObj_GetObject() negative testing.
2562 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(nullptr, 0));
2563 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
2564 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
2565
Lei Zhangc8601bf2021-06-29 23:19:27 +00002566 // FPDFPageObj_GetMatrix() positive testing for forms.
Lei Zhang8da98232019-12-11 23:29:33 +00002567 static constexpr FS_MATRIX kMatrix = {1.0f, 1.5f, 2.0f, 2.5f, 100.0f, 200.0f};
Lei Zhang2193da92021-06-30 01:03:07 +00002568 EXPECT_TRUE(FPDFPageObj_SetMatrix(form, &kMatrix));
Miklos Vajna46b43732018-08-14 19:15:43 +00002569
Lei Zhang8da98232019-12-11 23:29:33 +00002570 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +00002571 EXPECT_TRUE(FPDFPageObj_GetMatrix(form, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +00002572 EXPECT_FLOAT_EQ(kMatrix.a, matrix.a);
2573 EXPECT_FLOAT_EQ(kMatrix.b, matrix.b);
2574 EXPECT_FLOAT_EQ(kMatrix.c, matrix.c);
2575 EXPECT_FLOAT_EQ(kMatrix.d, matrix.d);
2576 EXPECT_FLOAT_EQ(kMatrix.e, matrix.e);
2577 EXPECT_FLOAT_EQ(kMatrix.f, matrix.f);
Miklos Vajna46b43732018-08-14 19:15:43 +00002578
Lei Zhangc8601bf2021-06-29 23:19:27 +00002579 // FPDFPageObj_GetMatrix() negative testing for forms.
2580 EXPECT_FALSE(FPDFPageObj_GetMatrix(form, nullptr));
Miklos Vajna46b43732018-08-14 19:15:43 +00002581
Miklos Vajnab66077d2018-07-11 13:25:02 +00002582 UnloadPage(page);
2583}
2584
Lei Zhang4363dab2021-06-24 19:23:09 +00002585TEST_F(FPDFEditEmbedderTest, ModifyFormObject) {
2586#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002587 const char kOrigChecksum[] = "e15086e54078e4d22fa3fb12105c579e";
2588 const char kNewChecksum[] = "7282fe98693c0a7ad2c1b3f3f9563977";
Lei Zhang42d30c22022-01-12 19:24:43 +00002589#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002590 const char kOrigChecksum[] = "a637057185f50aac1aa5490f726aef95";
2591 const char kNewChecksum[] = "8ad9d79b02b609ff734e2a2195c96e2d";
Lei Zhang4363dab2021-06-24 19:23:09 +00002592#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002593 const char kOrigChecksum[] = "34a9ec0a9581a7970e073c0bcc4ca676";
2594 const char kNewChecksum[] = "609b5632a21c886fa93182dbc290bf7a";
2595#endif
Lei Zhang4363dab2021-06-24 19:23:09 +00002596
2597 ASSERT_TRUE(OpenDocument("form_object.pdf"));
2598 FPDF_PAGE page = LoadPage(0);
2599 ASSERT_TRUE(page);
2600 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2601
2602 {
2603 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2604 CompareBitmap(bitmap.get(), 62, 69, kOrigChecksum);
2605 }
2606
2607 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
2608 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
2609
Lei Zhang651113b2021-06-25 20:03:25 +00002610 FPDFPageObj_Transform(form, 0.5, 0, 0, 0.5, 0, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002611 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2612
2613 {
2614 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2615 CompareBitmap(bitmap.get(), 62, 69, kNewChecksum);
2616 }
2617
Lei Zhang4363dab2021-06-24 19:23:09 +00002618 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhangac7f0e12021-06-24 19:38:00 +00002619 VerifySavedDocument(62, 69, kNewChecksum);
Lei Zhang4363dab2021-06-24 19:23:09 +00002620
2621 UnloadPage(page);
2622}
2623
Nicolas Pena4c48b102018-06-13 18:23:46 +00002624// Tests adding text from standard font using FPDFText_LoadStandardFont.
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002625TEST_F(FPDFEditEmbedderTest, AddStandardFontText2) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002626 // Start with a blank page
2627 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2628
2629 // Load a standard font.
Tom Sepezffff6c52019-07-30 21:56:19 +00002630 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002631 ASSERT_TRUE(font);
2632
2633 // Add some text to the page.
2634 FPDF_PAGEOBJECT text_object =
Tom Sepezffff6c52019-07-30 21:56:19 +00002635 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002636 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002637 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002638 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2639 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2640 FPDFPage_InsertObject(page.get(), text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00002641 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst3b6136a2020-06-09 00:39:33 +00002642 CompareBitmap(page_bitmap.get(), 612, 792, kBottomTextChecksum);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002643}
2644
Lei Zhangab41f252018-12-23 03:10:50 +00002645TEST_F(FPDFEditEmbedderTest, LoadStandardFonts) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002646 CreateNewDocument();
Lei Zhang590f4242019-05-15 20:57:26 +00002647 static constexpr const char* kStandardFontNames[] = {
Lei Zhangd72fd582018-07-27 19:37:27 +00002648 "Arial",
2649 "Arial-Bold",
2650 "Arial-BoldItalic",
2651 "Arial-Italic",
2652 "Courier",
2653 "Courier-BoldOblique",
2654 "Courier-Oblique",
2655 "Courier-Bold",
2656 "CourierNew",
2657 "CourierNew-Bold",
2658 "CourierNew-BoldItalic",
2659 "CourierNew-Italic",
2660 "Helvetica",
2661 "Helvetica-Bold",
2662 "Helvetica-BoldOblique",
2663 "Helvetica-Oblique",
2664 "Symbol",
2665 "TimesNewRoman",
2666 "TimesNewRoman-Bold",
2667 "TimesNewRoman-BoldItalic",
2668 "TimesNewRoman-Italic",
2669 "ZapfDingbats"};
Lei Zhang590f4242019-05-15 20:57:26 +00002670 for (const char* font_name : kStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002671 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002672 EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
2673 }
Lei Zhang590f4242019-05-15 20:57:26 +00002674 static constexpr const char* kNotStandardFontNames[] = {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002675 "Abcdefg", "ArialB", "Arial-Style",
2676 "Font Name", "FontArial", "NotAStandardFontName",
2677 "TestFontName", "Quack", "Symbol-Italic",
2678 "Zapf"};
Lei Zhang590f4242019-05-15 20:57:26 +00002679 for (const char* font_name : kNotStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002680 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002681 EXPECT_FALSE(font) << font_name
2682 << " should not be considered a standard font.";
2683 }
2684}
2685
Lei Zhangab41f252018-12-23 03:10:50 +00002686TEST_F(FPDFEditEmbedderTest, GraphicsData) {
Nicolas Pena603a31d2017-06-14 11:41:18 -04002687 // New page
Tom Sepeze08d2b12018-04-25 18:49:32 +00002688 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002689
2690 // Create a rect with nontrivial graphics
2691 FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2692 FPDFPageObj_SetBlendMode(rect1, "Color");
2693 FPDFPage_InsertObject(page.get(), rect1);
2694 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2695
2696 // Check that the ExtGState was created
Lei Zhang107fa7b2018-02-09 21:48:15 +00002697 CPDF_Page* cpage = CPDFPageFromFPDFPage(page.get());
Tom Sepezc8155092021-04-26 23:37:42 +00002698 const CPDF_Dictionary* graphics_dict =
2699 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Pena603a31d2017-06-14 11:41:18 -04002700 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002701 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002702
2703 // Add a text object causing no change to the graphics dictionary
2704 FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2705 // Only alpha, the last component, matters for the graphics dictionary. And
2706 // the default value is 255.
Lei Zhang3475b482019-05-13 18:30:57 +00002707 EXPECT_TRUE(FPDFPageObj_SetFillColor(text1, 100, 100, 100, 255));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002708 FPDFPage_InsertObject(page.get(), text1);
2709 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002710 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002711
2712 // Add a text object increasing the size of the graphics dictionary
2713 FPDF_PAGEOBJECT text2 =
2714 FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
2715 FPDFPage_InsertObject(page.get(), text2);
2716 FPDFPageObj_SetBlendMode(text2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002717 EXPECT_TRUE(FPDFPageObj_SetFillColor(text2, 0, 0, 255, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002718 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002719 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002720
2721 // Add a path that should reuse graphics
Nicolas Penace67be42017-06-14 14:52:49 -04002722 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
Nicolas Pena603a31d2017-06-14 11:41:18 -04002723 FPDFPageObj_SetBlendMode(path, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002724 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 200, 100, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002725 FPDFPage_InsertObject(page.get(), path);
2726 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002727 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002728
2729 // Add a rect increasing the size of the graphics dictionary
2730 FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2731 FPDFPageObj_SetBlendMode(rect2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002732 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect2, 0, 0, 255, 150));
2733 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect2, 0, 0, 0, 200));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002734 FPDFPage_InsertObject(page.get(), rect2);
2735 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002736 EXPECT_EQ(4u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002737}
2738
Lei Zhangab41f252018-12-23 03:10:50 +00002739TEST_F(FPDFEditEmbedderTest, DoubleGenerating) {
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002740 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -05002741 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002742
2743 // Add a red rectangle with some non-default alpha
2744 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
Lei Zhang3475b482019-05-13 18:30:57 +00002745 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 128));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002746 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
2747 FPDFPage_InsertObject(page, rect);
2748 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2749
2750 // Check the ExtGState
Lei Zhang107fa7b2018-02-09 21:48:15 +00002751 CPDF_Page* cpage = CPDFPageFromFPDFPage(page);
Tom Sepezc8155092021-04-26 23:37:42 +00002752 const CPDF_Dictionary* graphics_dict =
2753 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002754 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002755 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002756
2757 // Check the bitmap
Lei Zhang107fa7b2018-02-09 21:48:15 +00002758 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002759 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002760 CompareBitmap(page_bitmap.get(), 612, 792,
2761 "5384da3406d62360ffb5cac4476fff1c");
2762 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002763
2764 // Never mind, my new favorite color is blue, increase alpha
Lei Zhang3475b482019-05-13 18:30:57 +00002765 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 0, 0, 255, 180));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002766 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002767 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002768
2769 // Check that bitmap displays changed content
Lei Zhang107fa7b2018-02-09 21:48:15 +00002770 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002771 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002772 CompareBitmap(page_bitmap.get(), 612, 792,
2773 "2e51656f5073b0bee611d9cd086aa09c");
2774 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002775
2776 // And now generate, without changes
2777 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002778 EXPECT_EQ(3u, graphics_dict->size());
Lei Zhang107fa7b2018-02-09 21:48:15 +00002779 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002780 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002781 CompareBitmap(page_bitmap.get(), 612, 792,
2782 "2e51656f5073b0bee611d9cd086aa09c");
2783 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002784
2785 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -04002786 FPDF_PAGEOBJECT text_object =
2787 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00002788 ScopedFPDFWideString text =
Nicolas Penab3161852017-05-02 14:12:50 -04002789 GetFPDFWideString(L"Something something #text# something");
2790 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2791 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
2792 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002793 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepezc8155092021-04-26 23:37:42 +00002794 const CPDF_Dictionary* font_dict = cpage->GetResources()->GetDictFor("Font");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002795 ASSERT_TRUE(font_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002796 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002797
2798 // Generate yet again, check dicts are reasonably sized
2799 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002800 EXPECT_EQ(3u, graphics_dict->size());
2801 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002802 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002803}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002804
Lei Zhangab41f252018-12-23 03:10:50 +00002805TEST_F(FPDFEditEmbedderTest, LoadSimpleType1Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002806 CreateNewDocument();
2807 // TODO(npm): use other fonts after disallowing loading any font as any type
Tom Sepezffff6c52019-07-30 21:56:19 +00002808 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002809 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Tom Sepez20c41a52018-08-29 23:53:53 +00002810 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2811 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2812 FPDF_FONT_TYPE1, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002813 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002814 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002815 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002816
Lei Zhang710fa992018-05-25 16:24:48 +00002817 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002818 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2819 EXPECT_EQ("Type1", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002820 EXPECT_EQ("Tinos-Bold", font_dict->GetNameFor("BaseFont"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002821 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2822 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2823 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002824 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
2825
Lei Zhangde579ab2018-05-25 21:49:49 +00002826 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002827 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002828 ASSERT_EQ(224u, widths_array->size());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002829 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -05002830 EXPECT_EQ(569, widths_array->GetNumberAt(11));
2831 EXPECT_EQ(500, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002832 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002833}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002834
Lei Zhangab41f252018-12-23 03:10:50 +00002835TEST_F(FPDFEditEmbedderTest, LoadSimpleTrueTypeFont) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002836 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002837 RetainPtr<CPDF_Font> stock_font =
2838 CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Tom Sepez20c41a52018-08-29 23:53:53 +00002839 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2840 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2841 FPDF_FONT_TRUETYPE, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002842 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002843 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002844 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002845
Lei Zhang710fa992018-05-25 16:24:48 +00002846 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002847 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2848 EXPECT_EQ("TrueType", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002849 EXPECT_EQ("Cousine-Regular", font_dict->GetNameFor("BaseFont"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002850 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2851 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2852 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
2853 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002854
Lei Zhangde579ab2018-05-25 21:49:49 +00002855 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002856 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002857 ASSERT_EQ(224u, widths_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002858 EXPECT_EQ(600, widths_array->GetNumberAt(33));
2859 EXPECT_EQ(600, widths_array->GetNumberAt(74));
2860 EXPECT_EQ(600, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002861 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002862}
2863
Lei Zhangab41f252018-12-23 03:10:50 +00002864TEST_F(FPDFEditEmbedderTest, LoadCIDType0Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002865 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002866 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002867 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Tom Sepez20c41a52018-08-29 23:53:53 +00002868 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2869 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2870 FPDF_FONT_TYPE1, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04002871 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002872 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002873 EXPECT_TRUE(typed_font->IsCIDFont());
2874
2875 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00002876 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002877 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2878 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002879 EXPECT_EQ("Tinos-Regular-Identity-H", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00002880 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00002881 const CPDF_Array* descendant_array =
2882 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05002883 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002884 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002885
2886 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00002887 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00002888 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
2889 EXPECT_EQ("CIDFontType0", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002890 EXPECT_EQ("Tinos-Regular", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00002891 const CPDF_Dictionary* cidinfo_dict =
2892 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05002893 ASSERT_TRUE(cidinfo_dict);
Lei Zhang9c950b12019-01-16 19:06:37 +00002894 const CPDF_Object* registry = cidinfo_dict->GetObjectFor("Registry");
2895 ASSERT_TRUE(registry);
KDr28da0e1b2019-01-17 03:44:29 +00002896 EXPECT_EQ(CPDF_Object::kString, registry->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002897 EXPECT_EQ("Adobe", registry->GetString());
2898 const CPDF_Object* ordering = cidinfo_dict->GetObjectFor("Ordering");
2899 ASSERT_TRUE(ordering);
KDr28da0e1b2019-01-17 03:44:29 +00002900 EXPECT_EQ(CPDF_Object::kString, ordering->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002901 EXPECT_EQ("Identity", ordering->GetString());
Nicolas Penad03ca422017-03-06 13:54:33 -05002902 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00002903 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002904
2905 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00002906 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05002907 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002908 EXPECT_GT(widths_array->size(), 1u);
Nicolas Penad03ca422017-03-06 13:54:33 -05002909 CheckCompositeFontWidths(widths_array, typed_font);
2910}
2911
Lei Zhangab41f252018-12-23 03:10:50 +00002912TEST_F(FPDFEditEmbedderTest, LoadCIDType2Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002913 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002914 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002915 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Tom Sepez20c41a52018-08-29 23:53:53 +00002916 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2917 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2918 FPDF_FONT_TRUETYPE, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04002919 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002920 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002921 EXPECT_TRUE(typed_font->IsCIDFont());
2922
2923 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00002924 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002925 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2926 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002927 EXPECT_EQ("Arimo-Italic", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00002928 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00002929 const CPDF_Array* descendant_array =
2930 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05002931 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002932 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002933
2934 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00002935 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00002936 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
2937 EXPECT_EQ("CIDFontType2", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002938 EXPECT_EQ("Arimo-Italic", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00002939 const CPDF_Dictionary* cidinfo_dict =
2940 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05002941 ASSERT_TRUE(cidinfo_dict);
2942 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
2943 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
2944 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00002945 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002946
2947 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00002948 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05002949 ASSERT_TRUE(widths_array);
2950 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -05002951}
rbpotterce8e51e2017-04-28 12:42:47 -07002952
Lei Zhangab41f252018-12-23 03:10:50 +00002953TEST_F(FPDFEditEmbedderTest, NormalizeNegativeRotation) {
rbpotterce8e51e2017-04-28 12:42:47 -07002954 // Load document with a -90 degree rotation
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002955 ASSERT_TRUE(OpenDocument("bug_713197.pdf"));
rbpotterce8e51e2017-04-28 12:42:47 -07002956 FPDF_PAGE page = LoadPage(0);
2957 EXPECT_NE(nullptr, page);
2958
2959 EXPECT_EQ(3, FPDFPage_GetRotation(page));
2960 UnloadPage(page);
2961}
Nicolas Penab3161852017-05-02 14:12:50 -04002962
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00002963TEST_F(FPDFEditEmbedderTest, AddTrueTypeFontText) {
Nicolas Penab3161852017-05-02 14:12:50 -04002964 // Start with a blank page
2965 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2966 {
Tom Sepezffff6c52019-07-30 21:56:19 +00002967 RetainPtr<CPDF_Font> stock_font =
2968 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00002969 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2970 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2971 FPDF_FONT_TRUETYPE, 0));
Nicolas Penab3161852017-05-02 14:12:50 -04002972 ASSERT_TRUE(font.get());
2973
2974 // Add some text to the page
2975 FPDF_PAGEOBJECT text_object =
2976 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
2977 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002978 ScopedFPDFWideString text = GetFPDFWideString(kLoadedFontText);
Nicolas Penab3161852017-05-02 14:12:50 -04002979 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2980 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
2981 FPDFPage_InsertObject(page, text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00002982 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002983 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04002984
2985 // Add some more text, same font
2986 FPDF_PAGEOBJECT text_object2 =
2987 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00002988 ScopedFPDFWideString text2 = GetFPDFWideString(L"Bigger font size");
Nicolas Penab3161852017-05-02 14:12:50 -04002989 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2990 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
2991 FPDFPage_InsertObject(page, text_object2);
Nicolas Penab3161852017-05-02 14:12:50 -04002992 }
Lei Zhang30ff2532019-01-31 21:37:55 +00002993 ScopedFPDFBitmap page_bitmap2 = RenderPage(page);
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00002994#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingste1215fc2022-03-26 22:29:08 +00002995 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhang42d30c22022-01-12 19:24:43 +00002996#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002997 const char kInsertTrueTypeChecksum[] = "c7e2271a7f30e5b919a13ead47cea105";
Nicolas Penab3161852017-05-02 14:12:50 -04002998#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002999 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhange4cdac52019-04-30 16:45:57 +00003000#endif
Hui Yingst3b6136a2020-06-09 00:39:33 +00003001 CompareBitmap(page_bitmap2.get(), 612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003002
Nicolas Pena207b7272017-05-26 17:37:06 -04003003 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penab3161852017-05-02 14:12:50 -04003004 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3005 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003006
Hui Yingst3b6136a2020-06-09 00:39:33 +00003007 VerifySavedDocument(612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003008}
Nicolas Penaf45ade32017-05-03 10:23:49 -04003009
Lei Zhangab41f252018-12-23 03:10:50 +00003010TEST_F(FPDFEditEmbedderTest, TransformAnnot) {
Jane Liueda65252017-06-07 11:31:27 -04003011 // Open a file with one annotation and load its first page.
3012 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
Lei Zhang75c81712018-02-08 17:22:39 +00003013 FPDF_PAGE page = LoadPage(0);
Jane Liueda65252017-06-07 11:31:27 -04003014 ASSERT_TRUE(page);
3015
Lei Zhanga21d5932018-02-05 18:28:38 +00003016 {
3017 // Add an underline annotation to the page without specifying its rectangle.
Tom Sepeze08d2b12018-04-25 18:49:32 +00003018 ScopedFPDFAnnotation annot(
Lei Zhanga21d5932018-02-05 18:28:38 +00003019 FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
3020 ASSERT_TRUE(annot);
Jane Liueda65252017-06-07 11:31:27 -04003021
Lei Zhanga21d5932018-02-05 18:28:38 +00003022 // FPDFPage_TransformAnnots() should run without errors when modifying
3023 // annotation rectangles.
3024 FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
3025 }
Jane Liueda65252017-06-07 11:31:27 -04003026 UnloadPage(page);
3027}
3028
Nicolas Penaf45ade32017-05-03 10:23:49 -04003029// TODO(npm): Add tests using Japanese fonts in other OS.
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003030#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00003031TEST_F(FPDFEditEmbedderTest, AddCIDFontText) {
Nicolas Penaf45ade32017-05-03 10:23:49 -04003032 // Start with a blank page
3033 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3034 CFX_Font CIDfont;
3035 {
3036 // First, get the data from the font
Anton Bikineev7ac13342022-01-24 21:25:15 +00003037 CIDfont.LoadSubst("Noto Sans CJK JP", true, 0, 400, 0,
3038 FX_CodePage::kShiftJIS, false);
Tom Andersond4fe5f72021-12-03 20:52:52 +00003039 EXPECT_EQ("Noto Sans CJK JP", CIDfont.GetFaceName());
Tom Sepez20c41a52018-08-29 23:53:53 +00003040 pdfium::span<const uint8_t> span = CIDfont.GetFontSpan();
Nicolas Penaf45ade32017-05-03 10:23:49 -04003041
3042 // Load the data into a FPDF_Font.
Tom Sepez20c41a52018-08-29 23:53:53 +00003043 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3044 FPDF_FONT_TRUETYPE, 1));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003045 ASSERT_TRUE(font.get());
3046
3047 // Add some text to the page
3048 FPDF_PAGEOBJECT text_object =
3049 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3050 ASSERT_TRUE(text_object);
3051 std::wstring wstr = L"ABCDEFGhijklmnop.";
Lei Zhangf0f67682019-04-08 17:03:21 +00003052 ScopedFPDFWideString text = GetFPDFWideString(wstr);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003053 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3054 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
3055 FPDFPage_InsertObject(page, text_object);
3056
3057 // And add some Japanese characters
3058 FPDF_PAGEOBJECT text_object2 =
3059 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
3060 ASSERT_TRUE(text_object2);
3061 std::wstring wstr2 =
3062 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
3063 L"\u756A";
Lei Zhangf0f67682019-04-08 17:03:21 +00003064 ScopedFPDFWideString text2 = GetFPDFWideString(wstr2);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003065 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3066 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
3067 FPDFPage_InsertObject(page, text_object2);
3068 }
3069
Nicolas Pena207b7272017-05-26 17:37:06 -04003070 // Check that the text renders properly.
Tom Andersond4fe5f72021-12-03 20:52:52 +00003071 static constexpr char md5[] = "84d31d11b76845423a2cfc1879c0fbb9";
Lei Zhang107fa7b2018-02-09 21:48:15 +00003072 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003073 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00003074 CompareBitmap(page_bitmap.get(), 612, 792, md5);
3075 }
Nicolas Penaf45ade32017-05-03 10:23:49 -04003076
3077 // Save the document, close the page.
Nicolas Pena207b7272017-05-26 17:37:06 -04003078 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003079 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3080 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003081
3082 VerifySavedDocument(612, 792, md5);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003083}
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003084#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003085
Hui Yingst29d377b2021-03-03 20:22:41 +00003086// TODO(crbug.com/pdfium/1651): Fix this issue and enable the test for Skia.
3087#if defined(_SKIA_SUPPORT_)
Lei Zhang03e5e682019-09-16 19:45:55 +00003088#define MAYBE_SaveAndRender DISABLED_SaveAndRender
3089#else
3090#define MAYBE_SaveAndRender SaveAndRender
3091#endif
3092TEST_F(FPDFEditEmbedderTest, MAYBE_SaveAndRender) {
Hui Yingst29d377b2021-03-03 20:22:41 +00003093#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
3094 static constexpr char kChecksum[] = "0e8b079e349e34f64211c495845a3529";
3095#else
3096 static constexpr char kChecksum[] = "3c20472b0552c0c22b88ab1ed8c6202b";
3097#endif
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003098 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003099 ASSERT_TRUE(OpenDocument("bug_779.pdf"));
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003100 FPDF_PAGE page = LoadPage(0);
3101 ASSERT_NE(nullptr, page);
3102
Hui Yingst29d377b2021-03-03 20:22:41 +00003103 // Now add a more complex green path.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003104 FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
Lei Zhang3475b482019-05-13 18:30:57 +00003105 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_path, 0, 255, 0, 200));
Hui Yingst29d377b2021-03-03 20:22:41 +00003106 // TODO(npm): stroking will cause the checksums to differ.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003107 EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
3108 EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
3109 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
3110 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
3111 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
3112 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
3113 EXPECT_TRUE(FPDFPath_Close(green_path));
3114 FPDFPage_InsertObject(page, green_path);
Tom Sepeze08d2b12018-04-25 18:49:32 +00003115 ScopedFPDFBitmap page_bitmap = RenderLoadedPage(page);
Hui Yingst29d377b2021-03-03 20:22:41 +00003116 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003117
3118 // Now save the result, closing the page and document
3119 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3120 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3121 UnloadPage(page);
3122 }
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003123
Hui Yingst29d377b2021-03-03 20:22:41 +00003124 VerifySavedDocument(612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003125}
Jane Liu28fb7ba2017-08-02 21:45:57 -04003126
Lei Zhangab41f252018-12-23 03:10:50 +00003127TEST_F(FPDFEditEmbedderTest, AddMark) {
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003128 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003129 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003130 FPDF_PAGE page = LoadPage(0);
3131 ASSERT_TRUE(page);
3132
Lei Zhang2697cb12019-07-03 18:14:29 +00003133 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003134
3135 // Add to the first page object a "Bounds" mark with "Position": "First".
3136 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3137 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3138 EXPECT_TRUE(mark);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003139 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3140 "Position", "First"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003141
Lei Zhang2697cb12019-07-03 18:14:29 +00003142 CheckMarkCounts(page, 1, 19, 8, 4, 9, 2);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003143
3144 // Save the file
3145 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3146 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3147 UnloadPage(page);
3148
3149 // Re-open the file and check the new mark is present.
Lei Zhang0b494052019-01-31 21:41:15 +00003150 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003151 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003152 ASSERT_TRUE(saved_page);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003153
Lei Zhang2697cb12019-07-03 18:14:29 +00003154 CheckMarkCounts(saved_page, 1, 19, 8, 4, 9, 2);
3155
3156 CloseSavedPage(saved_page);
3157 CloseSavedDocument();
3158}
3159
Hui Yingst04440af2020-07-27 22:39:02 +00003160TEST_F(FPDFEditEmbedderTest, AddMarkCompressedStream) {
Lei Zhang2697cb12019-07-03 18:14:29 +00003161 // Load document with some text in a compressed stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003162 ASSERT_TRUE(OpenDocument("hello_world_compressed_stream.pdf"));
Lei Zhang2697cb12019-07-03 18:14:29 +00003163 FPDF_PAGE page = LoadPage(0);
3164 ASSERT_TRUE(page);
3165
3166 // Render and check there are no marks.
3167 {
3168 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003169 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003170 }
3171 CheckMarkCounts(page, 0, 2, 0, 0, 0, 0);
3172
3173 // Add to the first page object a "Bounds" mark with "Position": "First".
3174 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3175 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3176 EXPECT_TRUE(mark);
3177 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3178 "Position", "First"));
3179
3180 // Render and check there is 1 mark.
3181 {
3182 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003183 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003184 }
3185 CheckMarkCounts(page, 0, 2, 0, 0, 0, 1);
3186
3187 // Save the file.
3188 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3189 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3190 UnloadPage(page);
3191
3192 // Re-open the file and check the new mark is present.
3193 ASSERT_TRUE(OpenSavedDocument());
3194 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003195 ASSERT_TRUE(saved_page);
Lei Zhang2697cb12019-07-03 18:14:29 +00003196
3197 {
3198 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003199 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003200 }
3201 CheckMarkCounts(saved_page, 0, 2, 0, 0, 0, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003202
3203 CloseSavedPage(saved_page);
3204 CloseSavedDocument();
3205}
3206
Lei Zhangab41f252018-12-23 03:10:50 +00003207TEST_F(FPDFEditEmbedderTest, SetMarkParam) {
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003208 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003209 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003210 FPDF_PAGE page = LoadPage(0);
3211 ASSERT_TRUE(page);
3212
3213 constexpr int kExpectedObjectCount = 19;
3214 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3215
3216 // Check the "Bounds" mark's "Position" param is "Last".
3217 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3218 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3219 ASSERT_TRUE(mark);
3220 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003221 unsigned long name_len = 999u;
3222 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3223 EXPECT_EQ((6u + 1u) * 2u, name_len);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003224 ASSERT_EQ(L"Bounds",
3225 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3226 unsigned long out_buffer_len;
3227 ASSERT_TRUE(FPDFPageObjMark_GetParamStringValue(
3228 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3229 ASSERT_EQ(L"Last",
3230 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3231
3232 // Set is to "End".
3233 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3234 "Position", "End"));
3235
3236 // Verify the object passed must correspond to the mark passed.
3237 FPDF_PAGEOBJECT another_page_object = FPDFPage_GetObject(page, 17);
3238 EXPECT_FALSE(FPDFPageObjMark_SetStringParam(document(), another_page_object,
3239 mark, "Position", "End"));
3240
3241 // Verify nothing else changed.
3242 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3243
3244 // Verify "Position" now maps to "End".
3245 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3246 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3247 EXPECT_EQ(L"End",
3248 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3249
3250 // Save the file
3251 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3252 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3253 UnloadPage(page);
3254
3255 // Re-open the file and cerify "Position" still maps to "End".
Lei Zhang0b494052019-01-31 21:41:15 +00003256 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003257 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003258 ASSERT_TRUE(saved_page);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003259
3260 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3261 page_object = FPDFPage_GetObject(saved_page, 18);
3262 mark = FPDFPageObj_GetMark(page_object, 1);
3263 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3264 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3265 EXPECT_EQ(L"End",
3266 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3267
3268 CloseSavedPage(saved_page);
3269 CloseSavedDocument();
3270}
3271
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003272TEST_F(FPDFEditEmbedderTest, AddMarkedText) {
Henrique Nakashima144107d2018-07-10 21:04:05 +00003273 // Start with a blank page.
3274 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3275
Tom Sepezffff6c52019-07-30 21:56:19 +00003276 RetainPtr<CPDF_Font> stock_font =
3277 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00003278 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3279 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3280 FPDF_FONT_TRUETYPE, 0));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003281 ASSERT_TRUE(font.get());
3282
3283 // Add some text to the page.
3284 FPDF_PAGEOBJECT text_object =
3285 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3286
3287 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003288 ScopedFPDFWideString text1 = GetFPDFWideString(kLoadedFontText);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003289 EXPECT_TRUE(FPDFText_SetText(text_object, text1.get()));
3290 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3291 FPDFPage_InsertObject(page, text_object);
3292
3293 // Add a mark with the tag "TestMarkName" to that text.
3294 EXPECT_EQ(0, FPDFPageObj_CountMarks(text_object));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003295 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(text_object, "Test Mark Name");
Henrique Nakashima144107d2018-07-10 21:04:05 +00003296 EXPECT_TRUE(mark);
3297 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3298 EXPECT_EQ(mark, FPDFPageObj_GetMark(text_object, 0));
3299 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003300 unsigned long name_len = 999u;
3301 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3302 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003303 std::wstring name =
3304 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003305 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003306
3307 // Add parameters:
3308 // - int "IntKey" : 42
3309 // - string "StringKey": "StringValue"
Henrique Nakashima07520f62018-07-12 19:45:29 +00003310 // - blob "BlobKey": "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0"
Lei Zhang590f4242019-05-15 20:57:26 +00003311 constexpr size_t kBlobLen = 28;
Lei Zhangd3b028b2018-11-30 22:22:00 +00003312 char block_value[kBlobLen];
3313 memcpy(block_value, "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0", kBlobLen);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003314 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003315 EXPECT_TRUE(
3316 FPDFPageObjMark_SetIntParam(document(), text_object, mark, "IntKey", 42));
3317 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), text_object, mark,
3318 "StringKey", "StringValue"));
3319 EXPECT_TRUE(FPDFPageObjMark_SetBlobParam(document(), text_object, mark,
Lei Zhangd3b028b2018-11-30 22:22:00 +00003320 "BlobKey", block_value, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003321 EXPECT_EQ(3, FPDFPageObjMark_CountParams(mark));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003322
3323 // Check the two parameters can be retrieved.
3324 EXPECT_EQ(FPDF_OBJECT_NUMBER,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003325 FPDFPageObjMark_GetParamValueType(mark, "IntKey"));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003326 int int_value;
Henrique Nakashima94230e52018-07-11 22:02:02 +00003327 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "IntKey", &int_value));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003328 EXPECT_EQ(42, int_value);
3329
3330 EXPECT_EQ(FPDF_OBJECT_STRING,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003331 FPDFPageObjMark_GetParamValueType(mark, "StringKey"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003332 unsigned long out_buffer_len = 999u;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003333 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3334 mark, "StringKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003335 EXPECT_GT(out_buffer_len, 0u);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003336 EXPECT_NE(999u, out_buffer_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003337 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3338 EXPECT_EQ(L"StringValue", name);
3339
Henrique Nakashima07520f62018-07-12 19:45:29 +00003340 EXPECT_EQ(FPDF_OBJECT_STRING,
3341 FPDFPageObjMark_GetParamValueType(mark, "BlobKey"));
3342 out_buffer_len = 0;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003343 EXPECT_TRUE(FPDFPageObjMark_GetParamBlobValue(
3344 mark, "BlobKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003345 EXPECT_EQ(kBlobLen, out_buffer_len);
Lei Zhangd3b028b2018-11-30 22:22:00 +00003346 EXPECT_EQ(0, memcmp(block_value, buffer, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003347
Lei Zhangf16376e2020-06-18 19:19:32 +00003348 // Render and check the bitmap is the expected one.
Henrique Nakashima144107d2018-07-10 21:04:05 +00003349 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003350 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003351 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003352 }
3353
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003354 // Now save the result.
3355 EXPECT_EQ(1, FPDFPage_CountObjects(page));
3356 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3357 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3358
Henrique Nakashima144107d2018-07-10 21:04:05 +00003359 FPDF_ClosePage(page);
3360
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003361 // Re-open the file and check the changes were kept in the saved .pdf.
Lei Zhang0b494052019-01-31 21:41:15 +00003362 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003363 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003364 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003365 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
3366
3367 text_object = FPDFPage_GetObject(saved_page, 0);
3368 EXPECT_TRUE(text_object);
3369 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3370 mark = FPDFPageObj_GetMark(text_object, 0);
3371 EXPECT_TRUE(mark);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003372
3373 name_len = 999u;
3374 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3375 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003376 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003377 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003378
3379 CloseSavedPage(saved_page);
3380 CloseSavedDocument();
Henrique Nakashima144107d2018-07-10 21:04:05 +00003381}
3382
Lei Zhangab41f252018-12-23 03:10:50 +00003383TEST_F(FPDFEditEmbedderTest, MarkGetName) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003384 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003385 FPDF_PAGE page = LoadPage(0);
3386 ASSERT_TRUE(page);
3387 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3388 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3389 ASSERT_TRUE(mark);
3390
3391 char buffer[256];
3392 unsigned long out_len;
3393
3394 // Show the positive cases of FPDFPageObjMark_GetName.
3395 out_len = 999u;
3396 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, nullptr, 0, &out_len));
3397 EXPECT_EQ((6u + 1u) * 2u, out_len);
3398
3399 out_len = 999u;
3400 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &out_len));
3401 EXPECT_EQ(L"Bounds",
3402 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3403 EXPECT_EQ((6u + 1u) * 2u, out_len);
3404
3405 // Show the negative cases of FPDFPageObjMark_GetName.
3406 out_len = 999u;
3407 EXPECT_FALSE(
3408 FPDFPageObjMark_GetName(nullptr, buffer, sizeof(buffer), &out_len));
3409 EXPECT_EQ(999u, out_len);
3410
3411 EXPECT_FALSE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), nullptr));
3412
3413 UnloadPage(page);
3414}
3415
Lei Zhangab41f252018-12-23 03:10:50 +00003416TEST_F(FPDFEditEmbedderTest, MarkGetParamKey) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003417 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003418 FPDF_PAGE page = LoadPage(0);
3419 ASSERT_TRUE(page);
3420 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3421 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3422 ASSERT_TRUE(mark);
3423
3424 char buffer[256];
3425 unsigned long out_len;
3426
3427 // Show the positive cases of FPDFPageObjMark_GetParamKey.
3428 out_len = 999u;
3429 EXPECT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, nullptr, 0, &out_len));
3430 EXPECT_EQ((8u + 1u) * 2u, out_len);
3431
3432 out_len = 999u;
3433 EXPECT_TRUE(
3434 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), &out_len));
3435 EXPECT_EQ(L"Position",
3436 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3437 EXPECT_EQ((8u + 1u) * 2u, out_len);
3438
3439 // Show the negative cases of FPDFPageObjMark_GetParamKey.
3440 out_len = 999u;
3441 EXPECT_FALSE(FPDFPageObjMark_GetParamKey(nullptr, 0, buffer, sizeof(buffer),
3442 &out_len));
3443 EXPECT_EQ(999u, out_len);
3444
3445 out_len = 999u;
3446 EXPECT_FALSE(
3447 FPDFPageObjMark_GetParamKey(mark, 1, buffer, sizeof(buffer), &out_len));
3448 EXPECT_EQ(999u, out_len);
3449
3450 EXPECT_FALSE(
3451 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), nullptr));
3452
3453 UnloadPage(page);
3454}
3455
Lei Zhangab41f252018-12-23 03:10:50 +00003456TEST_F(FPDFEditEmbedderTest, MarkGetIntParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003457 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003458 FPDF_PAGE page = LoadPage(0);
3459 ASSERT_TRUE(page);
3460 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 8);
3461 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 0);
3462 ASSERT_TRUE(mark);
3463
3464 int out_value;
3465
3466 // Show the positive cases of FPDFPageObjMark_GetParamIntValue.
3467 out_value = 999;
3468 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
3469 EXPECT_EQ(3, out_value);
3470
3471 // Show the negative cases of FPDFPageObjMark_GetParamIntValue.
3472 out_value = 999;
3473 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(nullptr, "Factor", &out_value));
3474 EXPECT_EQ(999, out_value);
3475
3476 out_value = 999;
3477 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "ParamThatDoesNotExist",
3478 &out_value));
3479 EXPECT_EQ(999, out_value);
3480
3481 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", nullptr));
3482
3483 page_object = FPDFPage_GetObject(page, 18);
3484 mark = FPDFPageObj_GetMark(page_object, 1);
3485 out_value = 999;
3486 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Position", &out_value));
3487 EXPECT_EQ(999, out_value);
3488
3489 UnloadPage(page);
3490}
3491
Lei Zhangab41f252018-12-23 03:10:50 +00003492TEST_F(FPDFEditEmbedderTest, MarkGetStringParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003493 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003494 FPDF_PAGE page = LoadPage(0);
3495 ASSERT_TRUE(page);
3496 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3497 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3498 ASSERT_TRUE(mark);
3499
3500 char buffer[256];
3501 unsigned long out_len;
3502
3503 // Show the positive cases of FPDFPageObjMark_GetParamStringValue.
3504 out_len = 999u;
3505 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", nullptr, 0,
3506 &out_len));
3507 EXPECT_EQ((4u + 1u) * 2u, out_len);
3508
3509 out_len = 999u;
3510 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3511 sizeof(buffer), &out_len));
3512 EXPECT_EQ(L"Last",
3513 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3514 EXPECT_EQ((4u + 1u) * 2u, out_len);
3515
3516 // Show the negative cases of FPDFPageObjMark_GetParamStringValue.
3517 out_len = 999u;
3518 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(nullptr, "Position", buffer,
3519 sizeof(buffer), &out_len));
3520 EXPECT_EQ(999u, out_len);
3521
3522 out_len = 999u;
3523 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(
3524 mark, "ParamThatDoesNotExist", buffer, sizeof(buffer), &out_len));
3525 EXPECT_EQ(999u, out_len);
3526
3527 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3528 sizeof(buffer), nullptr));
3529
3530 page_object = FPDFPage_GetObject(page, 8);
3531 mark = FPDFPageObj_GetMark(page_object, 0);
3532 out_len = 999u;
3533 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Factor", buffer,
3534 sizeof(buffer), &out_len));
3535 EXPECT_EQ(999u, out_len);
3536
3537 UnloadPage(page);
3538}
3539
Lei Zhang2c57ad82022-02-04 02:21:28 +00003540// See also FPDFStructTreeEmbedderTest.GetMarkedContentID, which traverses the
3541// marked contents using FPDF_StructTree_GetForPage() and related API.
3542TEST_F(FPDFEditEmbedderTest, TraverseMarkedContentID) {
3543 ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
3544 FPDF_PAGE page = LoadPage(0);
3545 ASSERT_TRUE(page);
3546
3547 ASSERT_EQ(2, FPDFPage_CountObjects(page));
3548 FPDF_PAGEOBJECT object1 = FPDFPage_GetObject(page, 0);
3549 ASSERT_TRUE(object1);
3550 ASSERT_EQ(1, FPDFPageObj_CountMarks(object1));
3551
3552 FPDF_PAGEOBJECTMARK mark11 = FPDFPageObj_GetMark(object1, 0);
3553 ASSERT_TRUE(mark11);
3554 unsigned long len = 0;
3555 unsigned short buf[40];
3556 ASSERT_TRUE(FPDFPageObjMark_GetName(mark11, buf, sizeof(buf), &len));
3557 EXPECT_EQ(18u, len);
3558 EXPECT_EQ(L"Artifact", GetPlatformWString(buf));
3559 ASSERT_EQ(2, FPDFPageObjMark_CountParams(mark11));
3560 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 0, buf, sizeof(buf), &len));
3561 EXPECT_EQ(10u, len);
3562 EXPECT_EQ(L"BBox", GetPlatformWString(buf));
3563 EXPECT_EQ(FPDF_OBJECT_ARRAY,
3564 FPDFPageObjMark_GetParamValueType(mark11, "BBox"));
3565 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 1, buf, sizeof(buf), &len));
3566 EXPECT_EQ(10u, len);
3567 EXPECT_EQ(L"Type", GetPlatformWString(buf));
3568 EXPECT_EQ(FPDF_OBJECT_NAME,
3569 FPDFPageObjMark_GetParamValueType(mark11, "Type"));
3570
3571 FPDF_PAGEOBJECT object2 = FPDFPage_GetObject(page, 1);
3572 ASSERT_TRUE(object2);
3573 ASSERT_EQ(2, FPDFPageObj_CountMarks(object2));
3574 EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(object2));
3575
3576 FPDF_PAGEOBJECTMARK mark21 = FPDFPageObj_GetMark(object2, 0);
3577 ASSERT_TRUE(mark21);
3578 ASSERT_TRUE(FPDFPageObjMark_GetName(mark21, buf, sizeof(buf), &len));
3579 EXPECT_EQ(14u, len);
3580 EXPECT_EQ(L"Figure", GetPlatformWString(buf));
3581 ASSERT_EQ(1, FPDFPageObjMark_CountParams(mark21));
3582 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark21, 0, buf, sizeof(buf), &len));
3583 EXPECT_EQ(10u, len);
3584 EXPECT_EQ(L"MCID", GetPlatformWString(buf));
3585 ASSERT_EQ(FPDF_OBJECT_NUMBER,
3586 FPDFPageObjMark_GetParamValueType(mark21, "MCID"));
3587 int mcid = -1;
3588 ASSERT_TRUE(FPDFPageObjMark_GetParamIntValue(mark21, "MCID", &mcid));
3589 EXPECT_EQ(0, mcid);
3590
3591 FPDF_PAGEOBJECTMARK mark22 = FPDFPageObj_GetMark(object2, 1);
3592 ASSERT_TRUE(mark22);
3593 ASSERT_TRUE(FPDFPageObjMark_GetName(mark22, buf, sizeof(buf), &len));
3594 EXPECT_EQ(18u, len);
3595 EXPECT_EQ(L"ClipSpan", GetPlatformWString(buf));
3596 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark22));
3597
3598 UnloadPage(page);
3599}
3600
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003601TEST_F(FPDFEditEmbedderTest, GetBitmap) {
Jane Liu28fb7ba2017-08-02 21:45:57 -04003602 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3603 FPDF_PAGE page = LoadPage(0);
3604 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003605 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu28fb7ba2017-08-02 21:45:57 -04003606
3607 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3608 EXPECT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3609 EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
3610
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003611 {
3612 obj = FPDFPage_GetObject(page, 33);
3613 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3614 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3615 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
Lei Zhang85166512020-07-14 23:28:56 +00003616 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003617 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003618
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003619 {
3620 obj = FPDFPage_GetObject(page, 34);
3621 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3622 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3623 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3624 CompareBitmap(bitmap.get(), 103, 75, "c8d51fa6821ceb2a67f08446ff236c40");
3625 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003626
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003627 {
3628 obj = FPDFPage_GetObject(page, 35);
3629 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3630 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3631 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3632 CompareBitmap(bitmap.get(), 92, 68, "9c6d76cb1e37ef8514f9455d759391f3");
3633 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003634
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003635 {
3636 obj = FPDFPage_GetObject(page, 36);
3637 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3638 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3639 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3640 CompareBitmap(bitmap.get(), 79, 60, "f4e72fb783a01c7b4614cdc25eaa98ac");
3641 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003642
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003643 {
3644 obj = FPDFPage_GetObject(page, 37);
3645 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3646 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3647 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3648 CompareBitmap(bitmap.get(), 126, 106, "2cf9e66414c72461f4ccbf9cdebdfa1b");
3649 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003650
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003651 {
3652 obj = FPDFPage_GetObject(page, 38);
3653 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3654 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3655 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3656 CompareBitmap(bitmap.get(), 194, 119, "a8f3a126cec274dab8242fd2ccdc1b8b");
3657 }
3658
Jane Liu28fb7ba2017-08-02 21:45:57 -04003659 UnloadPage(page);
3660}
Jane Liu548334e2017-08-03 16:33:40 -04003661
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003662TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSetMatrix) {
Lei Zhang85166512020-07-14 23:28:56 +00003663 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3664 FPDF_PAGE page = LoadPage(0);
3665 ASSERT_TRUE(page);
3666 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3667
3668 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3669 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3670
3671 {
3672 // Render |obj| as is.
3673 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3674 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3675 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3676 }
3677
3678 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003679 FS_MATRIX matrix;
3680 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3681 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3682 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3683 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3684 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3685 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3686 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003687
3688 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003689 matrix.a = 120.0;
3690 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang85166512020-07-14 23:28:56 +00003691
3692 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003693 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3694 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3695 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3696 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3697 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3698 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3699 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003700
3701 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003702 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has no
Lei Zhang85166512020-07-14 23:28:56 +00003703 // effect.
3704 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3705 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3706 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3707 }
3708
3709 UnloadPage(page);
3710}
3711
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003712TEST_F(FPDFEditEmbedderTest, GetBitmapForJBigImage) {
Lei Zhang53341dd2018-03-01 15:42:47 +00003713 ASSERT_TRUE(OpenDocument("bug_631912.pdf"));
3714 FPDF_PAGE page = LoadPage(0);
3715 ASSERT_TRUE(page);
3716 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3717
3718 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
3719 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3720 {
Tom Sepeze08d2b12018-04-25 18:49:32 +00003721 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
Lei Zhang1330ebb2018-03-05 15:16:37 +00003722 ASSERT_TRUE(bitmap);
3723 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3724 CompareBitmap(bitmap.get(), 1152, 720, "3f6a48e2b3e91b799bf34567f55cb4de");
Lei Zhang53341dd2018-03-01 15:42:47 +00003725 }
3726
3727 UnloadPage(page);
3728}
3729
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003730TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSMask) {
Lei Zhang2e1b4f22020-07-08 23:40:18 +00003731 ASSERT_TRUE(OpenDocument("matte.pdf"));
3732 FPDF_PAGE page = LoadPage(0);
3733 ASSERT_TRUE(page);
3734
3735 constexpr int kExpectedObjects = 4;
3736 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3737
3738 for (int i = 0; i < kExpectedObjects; ++i) {
3739 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3740 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3741 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3742 ASSERT_TRUE(bitmap);
3743 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3744 CompareBitmap(bitmap.get(), 50, 50, "46c9a1dbe0b44765ce46017ad629a2fe");
3745 }
3746
3747 UnloadPage(page);
3748}
3749
Hui Yingst822fb8d2020-10-05 22:10:35 +00003750// TODO(crbug.com/pdfium/11): Fix this test and enable.
3751#if defined(_SKIA_SUPPORT_)
3752#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3753 DISABLED_GetRenderedBitmapHandlesSetMatrix
3754#else
3755#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3756 GetRenderedBitmapHandlesSetMatrix
3757#endif
3758TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSetMatrix) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003759 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3760 FPDF_PAGE page = LoadPage(0);
3761 ASSERT_TRUE(page);
3762 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3763
3764 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3765 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3766
3767 {
3768 // Render |obj| as is.
3769 ScopedFPDFBitmap bitmap(
3770 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3771 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003772 CompareBitmap(bitmap.get(), 53, 43, "582ca300e003f512d7b552c7b5b45d2e");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003773 }
3774
3775 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003776 FS_MATRIX matrix;
3777 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3778 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3779 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3780 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3781 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3782 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3783 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003784
3785 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003786 matrix.a = 120.0;
3787 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003788
3789 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003790 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3791 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3792 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3793 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3794 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3795 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3796 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003797
3798 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003799 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has an
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003800 // effect.
3801 ScopedFPDFBitmap bitmap(
3802 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3803 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003804 CompareBitmap(bitmap.get(), 120, 43, "0824c16dcf2dfcef44b45d88db1fddce");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003805 }
3806
3807 UnloadPage(page);
3808}
3809
Hui Yingst822fb8d2020-10-05 22:10:35 +00003810// TODO(crbug.com/pdfium/11): Fix this test and enable.
3811#if defined(_SKIA_SUPPORT_)
3812#define MAYBE_GetRenderedBitmapHandlesSMask \
3813 DISABLED_GetRenderedBitmapHandlesSMask
3814#else
3815#define MAYBE_GetRenderedBitmapHandlesSMask GetRenderedBitmapHandlesSMask
3816#endif
3817TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSMask) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003818 ASSERT_TRUE(OpenDocument("matte.pdf"));
3819 FPDF_PAGE page = LoadPage(0);
3820 ASSERT_TRUE(page);
3821
3822 constexpr int kExpectedObjects = 4;
3823 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3824
3825 for (int i = 0; i < kExpectedObjects; ++i) {
3826 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3827 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3828 ScopedFPDFBitmap bitmap(
3829 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3830 ASSERT_TRUE(bitmap);
3831 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
3832 if (i == 0)
3833 CompareBitmap(bitmap.get(), 40, 60, "5a3ae4a660ce919e29c42ec2258142f1");
3834 else
3835 CompareBitmap(bitmap.get(), 40, 60, "67504e83f5d78214ea00efc19082c5c1");
3836 }
3837
3838 UnloadPage(page);
3839}
3840
3841TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapBadParams) {
3842 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3843 FPDF_PAGE page = LoadPage(0);
3844 ASSERT_TRUE(page);
3845
3846 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3847 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3848
3849 // Test various null parameters.
3850 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, nullptr));
3851 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), nullptr, nullptr));
3852 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, nullptr));
3853 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, obj));
3854 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), page, nullptr));
3855 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, obj));
3856
3857 // Test mismatch between document and page parameters.
3858 ScopedFPDFDocument new_document(FPDF_CreateNewDocument());
3859 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(new_document.get(), page, obj));
3860
3861 UnloadPage(page);
3862}
3863
Lei Zhangab41f252018-12-23 03:10:50 +00003864TEST_F(FPDFEditEmbedderTest, GetImageData) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003865 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liu548334e2017-08-03 16:33:40 -04003866 FPDF_PAGE page = LoadPage(0);
3867 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003868 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu548334e2017-08-03 16:33:40 -04003869
3870 // Retrieve an image object with flate-encoded data stream.
3871 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3872 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3873
3874 // Check that the raw image data has the correct length and hash value.
3875 unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
Lei Zhang0bd11f72022-05-11 00:10:54 +00003876 std::vector<uint8_t> buf(len);
Jane Liu548334e2017-08-03 16:33:40 -04003877 EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003878 EXPECT_EQ("f73802327d2e88e890f653961bcda81a", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003879
3880 // Check that the decoded image data has the correct length and hash value.
3881 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3882 buf.clear();
3883 buf.resize(len);
3884 EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003885 EXPECT_EQ(kEmbeddedImage33Checksum, GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003886
Lei Zhang351e8b02018-12-20 01:10:06 +00003887 // Retrieve an image object with DCTDecode-encoded data stream.
Jane Liu548334e2017-08-03 16:33:40 -04003888 obj = FPDFPage_GetObject(page, 37);
3889 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3890
3891 // Check that the raw image data has the correct length and hash value.
3892 len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
3893 buf.clear();
3894 buf.resize(len);
3895 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003896 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003897
3898 // Check that the decoded image data has the correct length and hash value,
3899 // which should be the same as those of the raw data, since this image is
3900 // encoded by a single DCTDecode filter and decoding is a noop.
3901 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3902 buf.clear();
3903 buf.resize(len);
3904 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003905 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003906
3907 UnloadPage(page);
3908}
Jane Liu2e5f0ae2017-08-08 15:23:27 -04003909
Lei Zhangab41f252018-12-23 03:10:50 +00003910TEST_F(FPDFEditEmbedderTest, GetImageMatrix) {
Lei Zhang866d6882018-10-24 17:31:01 +00003911 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3912 FPDF_PAGE page = LoadPage(0);
3913 ASSERT_TRUE(page);
3914 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3915
3916 FPDF_PAGEOBJECT obj;
Lei Zhangc8601bf2021-06-29 23:19:27 +00003917 FS_MATRIX matrix;
Lei Zhang866d6882018-10-24 17:31:01 +00003918
3919 obj = FPDFPage_GetObject(page, 33);
3920 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00003921 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3922 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3923 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3924 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3925 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3926 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3927 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00003928
3929 obj = FPDFPage_GetObject(page, 34);
3930 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00003931 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3932 EXPECT_FLOAT_EQ(70.0f, matrix.a);
3933 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3934 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3935 EXPECT_FLOAT_EQ(51.0f, matrix.d);
3936 EXPECT_FLOAT_EQ(216.0f, matrix.e);
3937 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00003938
3939 obj = FPDFPage_GetObject(page, 35);
3940 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00003941 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3942 EXPECT_FLOAT_EQ(69.0f, matrix.a);
3943 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3944 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3945 EXPECT_FLOAT_EQ(51.0f, matrix.d);
3946 EXPECT_FLOAT_EQ(360.0f, matrix.e);
3947 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00003948
3949 obj = FPDFPage_GetObject(page, 36);
3950 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00003951 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3952 EXPECT_FLOAT_EQ(59.0f, matrix.a);
3953 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3954 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3955 EXPECT_FLOAT_EQ(45.0f, matrix.d);
3956 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3957 EXPECT_FLOAT_EQ(553.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00003958
3959 obj = FPDFPage_GetObject(page, 37);
3960 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00003961 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3962 EXPECT_FLOAT_EQ(55.94000244140625f, matrix.a);
3963 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3964 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3965 EXPECT_FLOAT_EQ(46.950000762939453f, matrix.d);
3966 EXPECT_FLOAT_EQ(216.0f, matrix.e);
3967 EXPECT_FLOAT_EQ(552.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00003968
3969 obj = FPDFPage_GetObject(page, 38);
3970 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00003971 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3972 EXPECT_FLOAT_EQ(70.528999328613281f, matrix.a);
3973 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3974 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3975 EXPECT_FLOAT_EQ(43.149997711181641f, matrix.d);
3976 EXPECT_FLOAT_EQ(360.0f, matrix.e);
3977 EXPECT_FLOAT_EQ(553.3599853515625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00003978
3979 UnloadPage(page);
3980}
3981
Lei Zhangab41f252018-12-23 03:10:50 +00003982TEST_F(FPDFEditEmbedderTest, DestroyPageObject) {
Jane Liu2e5f0ae2017-08-08 15:23:27 -04003983 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
3984 ASSERT_TRUE(rect);
3985
3986 // There should be no memory leaks with a call to FPDFPageObj_Destroy().
3987 FPDFPageObj_Destroy(rect);
3988}
Jane Liube63ab92017-08-09 14:09:34 -04003989
Lei Zhangab41f252018-12-23 03:10:50 +00003990TEST_F(FPDFEditEmbedderTest, GetImageFilters) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003991 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liube63ab92017-08-09 14:09:34 -04003992 FPDF_PAGE page = LoadPage(0);
3993 ASSERT_TRUE(page);
3994
3995 // Verify that retrieving the filter of a non-image object would fail.
3996 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3997 ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3998 ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
3999 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
4000
4001 // Verify the returned filter string for an image object with a single filter.
4002 obj = FPDFPage_GetObject(page, 33);
4003 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4004 ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
4005 unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4006 std::vector<char> buf(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004007 static constexpr char kFlateDecode[] = "FlateDecode";
4008 EXPECT_EQ(sizeof(kFlateDecode),
4009 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4010 EXPECT_STREQ(kFlateDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004011 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
4012
4013 // Verify all the filters for an image object with a list of filters.
4014 obj = FPDFPage_GetObject(page, 38);
4015 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4016 ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
4017 len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4018 buf.clear();
4019 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004020 static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
4021 EXPECT_EQ(sizeof(kASCIIHexDecode),
4022 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4023 EXPECT_STREQ(kASCIIHexDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004024
4025 len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
4026 buf.clear();
4027 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004028 static constexpr char kDCTDecode[] = "DCTDecode";
4029 EXPECT_EQ(sizeof(kDCTDecode),
4030 FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
4031 EXPECT_STREQ(kDCTDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004032
4033 UnloadPage(page);
4034}
Jane Liuca898292017-08-16 11:25:35 -04004035
Lei Zhangab41f252018-12-23 03:10:50 +00004036TEST_F(FPDFEditEmbedderTest, GetImageMetadata) {
Jane Liuca898292017-08-16 11:25:35 -04004037 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4038 FPDF_PAGE page = LoadPage(0);
4039 ASSERT_TRUE(page);
4040
4041 // Check that getting the metadata of a null object would fail.
4042 FPDF_IMAGEOBJ_METADATA metadata;
4043 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
4044
4045 // Check that receiving the metadata with a null metadata object would fail.
4046 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4047 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
4048
4049 // Check that when retrieving an image object's metadata without passing in
4050 // |page|, all values are correct, with the last two being default values.
4051 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4052 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004053 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004054 EXPECT_EQ(92u, metadata.width);
4055 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004056 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4057 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004058 EXPECT_EQ(0u, metadata.bits_per_pixel);
4059 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4060
4061 // Verify the metadata of a bitmap image with indexed colorspace.
4062 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004063 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004064 EXPECT_EQ(92u, metadata.width);
4065 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004066 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4067 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004068 EXPECT_EQ(1u, metadata.bits_per_pixel);
4069 EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
4070
4071 // Verify the metadata of an image with RGB colorspace.
4072 obj = FPDFPage_GetObject(page, 37);
4073 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4074 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004075 EXPECT_EQ(9, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004076 EXPECT_EQ(126u, metadata.width);
4077 EXPECT_EQ(106u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004078 EXPECT_FLOAT_EQ(162.173752f, metadata.horizontal_dpi);
4079 EXPECT_FLOAT_EQ(162.555878f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004080 EXPECT_EQ(24u, metadata.bits_per_pixel);
4081 EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
4082
4083 UnloadPage(page);
4084}
Lei Zhangdc1b7392020-05-14 21:15:53 +00004085
4086TEST_F(FPDFEditEmbedderTest, GetImageMetadataJpxLzw) {
4087 ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
4088 FPDF_PAGE page = LoadPage(0);
4089 ASSERT_TRUE(page);
4090
4091 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4092 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4093
4094 FPDF_IMAGEOBJ_METADATA metadata;
4095 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4096 EXPECT_EQ(-1, metadata.marked_content_id);
4097 EXPECT_EQ(612u, metadata.width);
4098 EXPECT_EQ(792u, metadata.height);
4099 EXPECT_FLOAT_EQ(72.0f, metadata.horizontal_dpi);
4100 EXPECT_FLOAT_EQ(72.0f, metadata.vertical_dpi);
4101 EXPECT_EQ(24u, metadata.bits_per_pixel);
4102 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4103
4104 UnloadPage(page);
4105}