blob: e819ffc292fa723b203c3e9c728e14c84facd9ab [file] [log] [blame]
Tom Sepezd483eb42016-01-06 10:03:59 -08001// Copyright 2016 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05005#include <memory>
6#include <string>
Nicolas Penad03ca422017-03-06 13:54:33 -05007#include <utility>
Jane Liu548334e2017-08-03 16:33:40 -04008#include <vector>
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05009
Lei Zhange4cdac52019-04-30 16:45:57 +000010#include "build/build_config.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050011#include "core/fpdfapi/font/cpdf_font.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050012#include "core/fpdfapi/page/cpdf_page.h"
Henrique Nakashima6eb79392018-06-12 20:27:35 +000013#include "core/fpdfapi/page/cpdf_pageobject.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050014#include "core/fpdfapi/parser/cpdf_array.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050015#include "core/fpdfapi/parser/cpdf_dictionary.h"
Nicolas Penad03ca422017-03-06 13:54:33 -050016#include "core/fpdfapi/parser/cpdf_number.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050017#include "core/fpdfapi/parser/cpdf_stream.h"
Artem Strygineababa12018-06-06 12:31:18 +000018#include "core/fpdfapi/parser/cpdf_stream_acc.h"
Tom Sepez6c57cda2021-07-23 19:41:57 +000019#include "core/fxcrt/fx_codepage.h"
Nicolas Pena0fc185e2017-02-08 12:13:20 -050020#include "core/fxcrt/fx_system.h"
Lei Zhang0dcb8fd2019-02-07 00:46:04 +000021#include "core/fxge/fx_font.h"
Dan Sinclair00d47a62018-03-28 18:39:04 +000022#include "fpdfsdk/cpdfsdk_helpers.h"
Tom Sepeze08d2b12018-04-25 18:49:32 +000023#include "public/cpp/fpdf_scopers.h"
Jane Liueda65252017-06-07 11:31:27 -040024#include "public/fpdf_annot.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080025#include "public/fpdf_edit.h"
26#include "public/fpdfview.h"
27#include "testing/embedder_test.h"
Hui Yingstb4baceb2020-04-28 23:46:10 +000028#include "testing/embedder_test_constants.h"
Lei Zhangb6992dd2019-02-05 23:30:20 +000029#include "testing/fx_string_testhelpers.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080030#include "testing/gmock/include/gmock/gmock-matchers.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080031#include "testing/gtest/include/gtest/gtest.h"
Hui Yingst8e88e382020-11-02 18:19:56 +000032#include "testing/utils/file_util.h"
Lei Zhang4c64e962019-02-05 19:24:12 +000033#include "testing/utils/hash.h"
Hui Yingst8e88e382020-11-02 18:19:56 +000034#include "testing/utils/path_service.h"
Tom Sepez9c78c0d2021-01-27 20:13:14 +000035#include "third_party/base/check.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080036
Hui Yingstb4baceb2020-04-28 23:46:10 +000037using pdfium::kHelloWorldChecksum;
38
39namespace {
40
Hui Yingst3b6136a2020-06-09 00:39:33 +000041const char kAllRemovedChecksum[] = "eee4600ac08b458ac7ac2320e225674c";
42
43const wchar_t kBottomText[] = L"I'm at the bottom of the page";
44
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000045#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
46static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000047 "84461cd5d952b6ae3d57a5070da84e19";
Lei Zhang42d30c22022-01-12 19:24:43 +000048#elif BUILDFLAG(IS_APPLE)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000049static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000050 "81636489006a31fcb00cf29efcdf7909";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000051#else
52static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000053 "891dcb6e914c8360998055f1f47c9727";
Hui Yingst3b6136a2020-06-09 00:39:33 +000054#endif
Hui Yingstb4baceb2020-04-28 23:46:10 +000055
Hui Yingst08c40712020-04-29 01:37:35 +000056#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +000057const char kFirstRemovedChecksum[] = "f46cbf12eb4e9bbdc3a5d8e1f2103446";
Lei Zhang42d30c22022-01-12 19:24:43 +000058#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +000059const char kFirstRemovedChecksum[] = "a1dc2812692fcc7ee4f01ca77435df9d";
Hui Yingstb4baceb2020-04-28 23:46:10 +000060#else
Tom Andersond4fe5f72021-12-03 20:52:52 +000061const char kFirstRemovedChecksum[] = "e1477dc3b5b3b9c560814c4d1135a02b";
Hui Yingstb4baceb2020-04-28 23:46:10 +000062#endif
63
Hui Yingst3b6136a2020-06-09 00:39:33 +000064const wchar_t kLoadedFontText[] = L"I am testing my loaded font, WEE.";
65
Hui Yingst9d6ec8f2020-11-05 23:35:38 +000066#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingste1215fc2022-03-26 22:29:08 +000067const char kLoadedFontTextChecksum[] = "d58570cc045dfb818b92cbabbd1a364c";
Lei Zhang42d30c22022-01-12 19:24:43 +000068#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +000069const char kLoadedFontTextChecksum[] = "0f3e4a7d71f9e7eb8a1a0d69403b9848";
Hui Yingst3b6136a2020-06-09 00:39:33 +000070#else
Tom Andersond4fe5f72021-12-03 20:52:52 +000071const char kLoadedFontTextChecksum[] = "d58570cc045dfb818b92cbabbd1a364c";
Hui Yingst3b6136a2020-06-09 00:39:33 +000072#endif
73
74const char kRedRectangleChecksum[] = "66d02eaa6181e2c069ce2ea99beda497";
75
Lei Zhang85166512020-07-14 23:28:56 +000076// In embedded_images.pdf.
77const char kEmbeddedImage33Checksum[] = "cb3637934bb3b95a6e4ae1ea9eb9e56e";
78
Hui Yingstb4baceb2020-04-28 23:46:10 +000079} // namespace
80
Lei Zhangab41f252018-12-23 03:10:50 +000081class FPDFEditEmbedderTest : public EmbedderTest {
Nicolas Penad03ca422017-03-06 13:54:33 -050082 protected:
83 FPDF_DOCUMENT CreateNewDocument() {
Lei Zhang935fb862021-11-05 00:15:05 +000084 CreateEmptyDocumentWithoutFormFillEnvironment();
Lei Zhang38e2b0e2021-11-05 00:28:05 +000085 cpdf_doc_ = CPDFDocumentFromFPDFDocument(document());
86 return document();
Nicolas Penad03ca422017-03-06 13:54:33 -050087 }
88
Lei Zhang710fa992018-05-25 16:24:48 +000089 void CheckFontDescriptor(const CPDF_Dictionary* font_dict,
Nicolas Penad03ca422017-03-06 13:54:33 -050090 int font_type,
91 bool bold,
92 bool italic,
Tom Sepez20c41a52018-08-29 23:53:53 +000093 pdfium::span<const uint8_t> span) {
Lei Zhangb1ec2802018-05-25 21:55:24 +000094 const CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
Nicolas Penad03ca422017-03-06 13:54:33 -050095 ASSERT_TRUE(font_desc);
Lei Zhanga228ff32020-06-24 17:39:33 +000096 EXPECT_EQ("FontDescriptor", font_desc->GetNameFor("Type"));
97 ByteString font_name = font_desc->GetNameFor("FontName");
98 EXPECT_FALSE(font_name.IsEmpty());
99 EXPECT_EQ(font_dict->GetNameFor("BaseFont"), font_name);
Nicolas Penad03ca422017-03-06 13:54:33 -0500100
101 // Check that the font descriptor has the required keys according to spec
102 // 1.7 Table 5.19
103 ASSERT_TRUE(font_desc->KeyExist("Flags"));
Dan Sinclair10e1f052017-09-28 15:59:42 -0400104
Nicolas Penad03ca422017-03-06 13:54:33 -0500105 int font_flags = font_desc->GetIntegerFor("Flags");
Lei Zhang44d03832019-10-18 18:45:31 +0000106 EXPECT_EQ(bold, FontStyleIsForceBold(font_flags));
Dan Sinclair10e1f052017-09-28 15:59:42 -0400107 EXPECT_EQ(italic, FontStyleIsItalic(font_flags));
108 EXPECT_TRUE(FontStyleIsNonSymbolic(font_flags));
Nicolas Penad03ca422017-03-06 13:54:33 -0500109 ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
Nicolás Peña5f95f362017-09-28 13:00:45 +0900110
Lei Zhangb1ec2802018-05-25 21:55:24 +0000111 const CPDF_Array* fontBBox = font_desc->GetArrayFor("FontBBox");
Nicolás Peña5f95f362017-09-28 13:00:45 +0900112 ASSERT_TRUE(fontBBox);
Lei Zhangf40380f2018-10-12 18:31:51 +0000113 EXPECT_EQ(4u, fontBBox->size());
Nicolás Peña5f95f362017-09-28 13:00:45 +0900114 // Check that the coordinates are in the preferred order according to spec
115 // 1.7 Section 3.8.4
116 EXPECT_TRUE(fontBBox->GetIntegerAt(0) < fontBBox->GetIntegerAt(2));
117 EXPECT_TRUE(fontBBox->GetIntegerAt(1) < fontBBox->GetIntegerAt(3));
118
Nicolas Penad03ca422017-03-06 13:54:33 -0500119 EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
120 EXPECT_TRUE(font_desc->KeyExist("Ascent"));
121 EXPECT_TRUE(font_desc->KeyExist("Descent"));
122 EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
123 EXPECT_TRUE(font_desc->KeyExist("StemV"));
Ryan Harrison275e2602017-09-18 14:23:18 -0400124 ByteString present("FontFile");
125 ByteString absent("FontFile2");
Nicolas Penad03ca422017-03-06 13:54:33 -0500126 if (font_type == FPDF_FONT_TRUETYPE)
127 std::swap(present, absent);
128 EXPECT_TRUE(font_desc->KeyExist(present));
129 EXPECT_FALSE(font_desc->KeyExist(absent));
130
Artem Strygineababa12018-06-06 12:31:18 +0000131 auto streamAcc =
132 pdfium::MakeRetain<CPDF_StreamAcc>(font_desc->GetStreamFor(present));
133 streamAcc->LoadAllDataRaw();
134
Nicolas Penad03ca422017-03-06 13:54:33 -0500135 // Check that the font stream is the one that was provided
Tom Sepez20c41a52018-08-29 23:53:53 +0000136 ASSERT_EQ(span.size(), streamAcc->GetSize());
Nicolás Peña79eab232017-09-28 13:29:05 +0900137 if (font_type == FPDF_FONT_TRUETYPE) {
Tom Sepez20c41a52018-08-29 23:53:53 +0000138 ASSERT_EQ(static_cast<int>(span.size()),
Artem Strygineababa12018-06-06 12:31:18 +0000139 streamAcc->GetDict()->GetIntegerFor("Length1"));
Nicolás Peña79eab232017-09-28 13:29:05 +0900140 }
Artem Strygineababa12018-06-06 12:31:18 +0000141
142 const uint8_t* stream_data = streamAcc->GetData();
Tom Sepez20c41a52018-08-29 23:53:53 +0000143 for (size_t j = 0; j < span.size(); j++)
144 EXPECT_EQ(span[j], stream_data[j]) << " at byte " << j;
Nicolas Penad03ca422017-03-06 13:54:33 -0500145 }
146
Lei Zhangde579ab2018-05-25 21:49:49 +0000147 void CheckCompositeFontWidths(const CPDF_Array* widths_array,
Nicolas Penad03ca422017-03-06 13:54:33 -0500148 CPDF_Font* typed_font) {
149 // Check that W array is in a format that conforms to PDF spec 1.7 section
150 // "Glyph Metrics in CIDFonts" (these checks are not
151 // implementation-specific).
Lei Zhangf40380f2018-10-12 18:31:51 +0000152 EXPECT_GT(widths_array->size(), 1u);
Nicolas Penad03ca422017-03-06 13:54:33 -0500153 int num_cids_checked = 0;
154 int cur_cid = 0;
Lei Zhangf40380f2018-10-12 18:31:51 +0000155 for (size_t idx = 0; idx < widths_array->size(); idx++) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500156 int cid = widths_array->GetNumberAt(idx);
157 EXPECT_GE(cid, cur_cid);
Lei Zhangf40380f2018-10-12 18:31:51 +0000158 ASSERT_FALSE(++idx == widths_array->size());
Lei Zhangde579ab2018-05-25 21:49:49 +0000159 const CPDF_Object* next = widths_array->GetObjectAt(idx);
Nicolas Penad03ca422017-03-06 13:54:33 -0500160 if (next->IsArray()) {
161 // We are in the c [w1 w2 ...] case
Lei Zhangde579ab2018-05-25 21:49:49 +0000162 const CPDF_Array* arr = next->AsArray();
Lei Zhangf40380f2018-10-12 18:31:51 +0000163 int cnt = static_cast<int>(arr->size());
Nicolas Penad03ca422017-03-06 13:54:33 -0500164 size_t inner_idx = 0;
165 for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
Lei Zhang70e66192020-09-18 20:50:51 +0000166 int width = arr->GetNumberAt(inner_idx++);
Dan Sinclair971a6742018-03-28 19:23:25 +0000167 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
168 << " at cid " << cur_cid;
Nicolas Penad03ca422017-03-06 13:54:33 -0500169 }
170 num_cids_checked += cnt;
171 continue;
172 }
173 // Otherwise, are in the c_first c_last w case.
174 ASSERT_TRUE(next->IsNumber());
175 int last_cid = next->AsNumber()->GetInteger();
Lei Zhangf40380f2018-10-12 18:31:51 +0000176 ASSERT_FALSE(++idx == widths_array->size());
Lei Zhang70e66192020-09-18 20:50:51 +0000177 int width = widths_array->GetNumberAt(idx);
Nicolas Penad03ca422017-03-06 13:54:33 -0500178 for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
Dan Sinclair971a6742018-03-28 19:23:25 +0000179 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
180 << " at cid " << cur_cid;
Nicolas Penad03ca422017-03-06 13:54:33 -0500181 }
182 num_cids_checked += last_cid - cid + 1;
183 }
184 // Make sure we have a good amount of cids described
Tom Andersond4fe5f72021-12-03 20:52:52 +0000185 EXPECT_GT(num_cids_checked, 200);
Nicolas Penad03ca422017-03-06 13:54:33 -0500186 }
187 CPDF_Document* cpdf_doc() { return cpdf_doc_; }
188
189 private:
190 CPDF_Document* cpdf_doc_;
191};
Tom Sepezd483eb42016-01-06 10:03:59 -0800192
etienneb7712c262016-04-26 08:13:45 -0700193namespace {
thestigdc7ec032016-11-21 15:32:52 -0800194
etienneb7712c262016-04-26 08:13:45 -0700195const char kExpectedPDF[] =
196 "%PDF-1.7\r\n"
197 "%\xA1\xB3\xC5\xD7\r\n"
198 "1 0 obj\r\n"
199 "<</Pages 2 0 R /Type/Catalog>>\r\n"
200 "endobj\r\n"
201 "2 0 obj\r\n"
202 "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
203 "endobj\r\n"
204 "3 0 obj\r\n"
205 "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
206 "endobj\r\n"
207 "4 0 obj\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400208 "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R "
209 "/Resources<</ExtGState<</FXE1 5 0 R >>>>"
Nicolas Penad9d6c292017-06-06 16:12:10 -0400210 "/Rotate 0/Type/Page"
etienneb7712c262016-04-26 08:13:45 -0700211 ">>\r\n"
212 "endobj\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400213 "5 0 obj\r\n"
214 "<</BM/Normal/CA 1/ca 1>>\r\n"
215 "endobj\r\n"
etienneb7712c262016-04-26 08:13:45 -0700216 "xref\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400217 "0 6\r\n"
etienneb7712c262016-04-26 08:13:45 -0700218 "0000000000 65535 f\r\n"
219 "0000000017 00000 n\r\n"
220 "0000000066 00000 n\r\n"
221 "0000000122 00000 n\r\n"
222 "0000000192 00000 n\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400223 "0000000311 00000 n\r\n"
etienneb7712c262016-04-26 08:13:45 -0700224 "trailer\r\n"
225 "<<\r\n"
226 "/Root 1 0 R\r\n"
227 "/Info 3 0 R\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400228 "/Size 6/ID\\[<.*><.*>\\]>>\r\n"
etienneb7712c262016-04-26 08:13:45 -0700229 "startxref\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400230 "354\r\n"
etienneb7712c262016-04-26 08:13:45 -0700231 "%%EOF\r\n";
thestigdc7ec032016-11-21 15:32:52 -0800232
etienneb7712c262016-04-26 08:13:45 -0700233} // namespace
234
Hui Yingst8e88e382020-11-02 18:19:56 +0000235TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFont) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000236 CreateEmptyDocument();
Hui Yingst8e88e382020-11-02 18:19:56 +0000237 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
238 std::string font_path;
Hui Yingst8532ef02020-11-04 19:17:17 +0000239 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
240 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
Hui Yingst8e88e382020-11-02 18:19:56 +0000241
242 size_t file_length = 0;
243 std::unique_ptr<char, pdfium::FreeDeleter> font_data =
244 GetFileContents(font_path.c_str(), &file_length);
Lei Zhang786544d2021-07-27 21:25:24 +0000245 ASSERT_TRUE(font_data);
Hui Yingst8e88e382020-11-02 18:19:56 +0000246
247 ScopedFPDFFont font(FPDFText_LoadFont(
248 document(), reinterpret_cast<const uint8_t*>(font_data.get()),
249 file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
250 FPDF_PAGEOBJECT text_object =
251 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
252 EXPECT_TRUE(text_object);
253
254 // Test the characters which are either mapped to one single unicode or
255 // multiple unicodes in the embedded font.
256 ScopedFPDFWideString text = GetFPDFWideString(L"这是第一句。 这是第二行。");
257 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
258
259 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
260 FPDFPage_InsertObject(page.get(), text_object);
261 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
262
Hui Yingst8e88e382020-11-02 18:19:56 +0000263 const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
Hui Yingst8e88e382020-11-02 18:19:56 +0000264 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
265 CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
266
Lei Zhang786544d2021-07-27 21:25:24 +0000267 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
268 VerifySavedDocument(400, 400, kChecksum);
269}
270
271TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFontWithCharcodes) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000272 CreateEmptyDocument();
Lei Zhang786544d2021-07-27 21:25:24 +0000273 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
274 std::string font_path;
275 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
276 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
277
278 size_t file_length = 0;
279 std::unique_ptr<char, pdfium::FreeDeleter> font_data =
280 GetFileContents(font_path.c_str(), &file_length);
281 ASSERT_TRUE(font_data);
282
283 ScopedFPDFFont font(FPDFText_LoadFont(
284 document(), reinterpret_cast<const uint8_t*>(font_data.get()),
285 file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
286 FPDF_PAGEOBJECT text_object =
287 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
288 EXPECT_TRUE(text_object);
289
290 // Same as `text` in the EmbedNotoSansSCFont test case above.
291 const std::vector<uint32_t> charcodes = {9, 6, 7, 3, 5, 2, 1,
292 9, 6, 7, 4, 8, 2};
293 EXPECT_TRUE(
294 FPDFText_SetCharcodes(text_object, charcodes.data(), charcodes.size()));
295
296 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
297 FPDFPage_InsertObject(page.get(), text_object);
298 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
299
Lei Zhang786544d2021-07-27 21:25:24 +0000300 const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
Lei Zhang786544d2021-07-27 21:25:24 +0000301 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
302 CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
303
304 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Hui Yingst8e88e382020-11-02 18:19:56 +0000305 VerifySavedDocument(400, 400, kChecksum);
306}
307
Lei Zhangab41f252018-12-23 03:10:50 +0000308TEST_F(FPDFEditEmbedderTest, EmptyCreation) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000309 CreateEmptyDocument();
weili9b777de2016-08-19 16:19:46 -0700310 FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
Tom Sepezd483eb42016-01-06 10:03:59 -0800311 EXPECT_NE(nullptr, page);
Nicolas Penad9d6c292017-06-06 16:12:10 -0400312 // The FPDFPage_GenerateContent call should do nothing.
Tom Sepezd483eb42016-01-06 10:03:59 -0800313 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepez0aec19b2016-01-07 12:22:44 -0800314 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
etienneb7712c262016-04-26 08:13:45 -0700315
Nicolas Penad9d6c292017-06-06 16:12:10 -0400316 EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
317 kExpectedPDF, sizeof(kExpectedPDF))));
weili9b777de2016-08-19 16:19:46 -0700318 FPDF_ClosePage(page);
Tom Sepezd483eb42016-01-06 10:03:59 -0800319}
thestigdc7ec032016-11-21 15:32:52 -0800320
321// Regression test for https://crbug.com/667012
Lei Zhangab41f252018-12-23 03:10:50 +0000322TEST_F(FPDFEditEmbedderTest, RasterizePDF) {
thestigdc7ec032016-11-21 15:32:52 -0800323 const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
324
Lei Zhangf0542892019-01-17 18:46:27 +0000325 // Get the bitmap for the original document.
Tom Sepeze08d2b12018-04-25 18:49:32 +0000326 ScopedFPDFBitmap orig_bitmap;
thestigdc7ec032016-11-21 15:32:52 -0800327 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000328 ASSERT_TRUE(OpenDocument("black.pdf"));
thestigdc7ec032016-11-21 15:32:52 -0800329 FPDF_PAGE orig_page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000330 ASSERT_TRUE(orig_page);
331 orig_bitmap = RenderLoadedPage(orig_page);
332 CompareBitmap(orig_bitmap.get(), 612, 792, kAllBlackMd5sum);
thestigdc7ec032016-11-21 15:32:52 -0800333 UnloadPage(orig_page);
334 }
335
336 // Create a new document from |orig_bitmap| and save it.
337 {
338 FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
339 FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
340
341 // Add the bitmap to an image object and add the image object to the output
342 // page.
Lei Zhangcbd89572017-03-15 17:35:47 -0700343 FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000344 EXPECT_TRUE(
345 FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap.get()));
Lei Zhangc8601bf2021-06-29 23:19:27 +0000346 static constexpr FS_MATRIX kLetterScaleMatrix{612, 0, 0, 792, 0, 0};
347 EXPECT_TRUE(FPDFPageObj_SetMatrix(temp_img, &kLetterScaleMatrix));
thestigdc7ec032016-11-21 15:32:52 -0800348 FPDFPage_InsertObject(temp_page, temp_img);
349 EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
350 EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
351 FPDF_ClosePage(temp_page);
352 FPDF_CloseDocument(temp_doc);
353 }
thestigdc7ec032016-11-21 15:32:52 -0800354
355 // Get the generated content. Make sure it is at least as big as the original
356 // PDF.
Lei Zhangd72fd582018-07-27 19:37:27 +0000357 EXPECT_GT(GetString().size(), 923u);
Dan Sinclair04e4dc82017-10-18 12:17:14 -0400358 VerifySavedDocument(612, 792, kAllBlackMd5sum);
thestigdc7ec032016-11-21 15:32:52 -0800359}
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500360
Hui Yingsta929df72021-02-26 23:56:18 +0000361TEST_F(FPDFEditEmbedderTest, AddPaths) {
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500362 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500363 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000364 ASSERT_TRUE(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500365
366 // We will first add a red rectangle
367 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000368 ASSERT_TRUE(red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500369 // Expect false when trying to set colors out of range
Lei Zhang3475b482019-05-13 18:30:57 +0000370 EXPECT_FALSE(FPDFPageObj_SetStrokeColor(red_rect, 100, 100, 100, 300));
371 EXPECT_FALSE(FPDFPageObj_SetFillColor(red_rect, 200, 256, 200, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500372
373 // Fill rectangle with red and insert to the page
Lei Zhang3475b482019-05-13 18:30:57 +0000374 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500375 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
Miklos Vajna491112b2018-05-30 13:30:10 +0000376
377 int fillmode = FPDF_FILLMODE_NONE;
378 FPDF_BOOL stroke = true;
379 EXPECT_TRUE(FPDFPath_GetDrawMode(red_rect, &fillmode, &stroke));
380 EXPECT_EQ(FPDF_FILLMODE_ALTERNATE, fillmode);
381 EXPECT_FALSE(stroke);
382
Lei Zhangc8601bf2021-06-29 23:19:27 +0000383 static constexpr FS_MATRIX kMatrix = {1, 2, 3, 4, 5, 6};
384 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &kMatrix));
Lei Zhang8da98232019-12-11 23:29:33 +0000385
386 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +0000387 EXPECT_TRUE(FPDFPageObj_GetMatrix(red_rect, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +0000388 EXPECT_FLOAT_EQ(1.0f, matrix.a);
389 EXPECT_FLOAT_EQ(2.0f, matrix.b);
390 EXPECT_FLOAT_EQ(3.0f, matrix.c);
391 EXPECT_FLOAT_EQ(4.0f, matrix.d);
392 EXPECT_FLOAT_EQ(5.0f, matrix.e);
393 EXPECT_FLOAT_EQ(6.0f, matrix.f);
394
395 // Set back the identity matrix.
396 matrix = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
Lei Zhangc8601bf2021-06-29 23:19:27 +0000397 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &matrix));
Miklos Vajna97f4d672018-06-04 14:47:17 +0000398
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500399 FPDFPage_InsertObject(page, red_rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000400 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000401 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000402 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000403 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500404
405 // Now add to that a green rectangle with some medium alpha
406 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
Lei Zhang3475b482019-05-13 18:30:57 +0000407 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 128));
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200408
Miklos Vajna1ef04c92017-05-08 18:14:19 +0200409 // Make sure the type of the rectangle is a path.
410 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
411
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200412 // Make sure we get back the same color we set previously.
413 unsigned int R;
414 unsigned int G;
415 unsigned int B;
416 unsigned int A;
Lei Zhang3475b482019-05-13 18:30:57 +0000417 EXPECT_TRUE(FPDFPageObj_GetFillColor(green_rect, &R, &G, &B, &A));
Lei Zhangd72fd582018-07-27 19:37:27 +0000418 EXPECT_EQ(0u, R);
419 EXPECT_EQ(255u, G);
420 EXPECT_EQ(0u, B);
421 EXPECT_EQ(128u, A);
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200422
Lei Zhang9b4b8df2021-06-12 06:38:48 +0000423 // Make sure the path has 5 points (1 CFX_Path::Point::Type::kMove and 4
424 // CFX_Path::Point::Type::kLine).
Miklos Vajna0150a542017-09-21 21:46:56 +0200425 ASSERT_EQ(5, FPDFPath_CountSegments(green_rect));
Miklos Vajna36eed872017-09-20 22:52:43 +0200426 // Verify actual coordinates.
427 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0);
428 float x;
429 float y;
430 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
431 EXPECT_EQ(100, x);
432 EXPECT_EQ(100, y);
433 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
434 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
435 segment = FPDFPath_GetPathSegment(green_rect, 1);
436 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
437 EXPECT_EQ(100, x);
438 EXPECT_EQ(140, y);
439 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
440 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
441 segment = FPDFPath_GetPathSegment(green_rect, 2);
442 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
443 EXPECT_EQ(140, x);
444 EXPECT_EQ(140, y);
445 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
446 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
447 segment = FPDFPath_GetPathSegment(green_rect, 3);
448 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
449 EXPECT_EQ(140, x);
450 EXPECT_EQ(100, y);
451 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
452 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
453 segment = FPDFPath_GetPathSegment(green_rect, 4);
454 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
455 EXPECT_EQ(100, x);
456 EXPECT_EQ(100, y);
457 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
458 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200459
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500460 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
461 FPDFPage_InsertObject(page, green_rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000462 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000463 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000464 CompareBitmap(page_bitmap.get(), 612, 792,
465 "7b0b87604594e773add528fae567a558");
466 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500467
468 // Add a black triangle.
469 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
Lei Zhang3475b482019-05-13 18:30:57 +0000470 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 200));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500471 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
472 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
473 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
474 EXPECT_TRUE(FPDFPath_Close(black_path));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200475
Lei Zhang9b4b8df2021-06-12 06:38:48 +0000476 // Make sure the path has 3 points (1 CFX_Path::Point::Type::kMove and 2
477 // CFX_Path::Point::Type::kLine).
Miklos Vajna0150a542017-09-21 21:46:56 +0200478 ASSERT_EQ(3, FPDFPath_CountSegments(black_path));
Miklos Vajna36eed872017-09-20 22:52:43 +0200479 // Verify actual coordinates.
480 segment = FPDFPath_GetPathSegment(black_path, 0);
481 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
482 EXPECT_EQ(400, x);
483 EXPECT_EQ(100, y);
484 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
485 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
486 segment = FPDFPath_GetPathSegment(black_path, 1);
487 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
488 EXPECT_EQ(400, x);
489 EXPECT_EQ(200, y);
490 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
491 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
492 segment = FPDFPath_GetPathSegment(black_path, 2);
493 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
494 EXPECT_EQ(300, x);
495 EXPECT_EQ(100, y);
496 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
497 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
498 // Make sure out of bounds index access fails properly.
499 EXPECT_EQ(nullptr, FPDFPath_GetPathSegment(black_path, 3));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200500
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500501 FPDFPage_InsertObject(page, black_path);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000502 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000503 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000504 CompareBitmap(page_bitmap.get(), 612, 792,
505 "eadc8020a14dfcf091da2688733d8806");
506 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500507
508 // Now add a more complex blue path.
509 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
Lei Zhang3475b482019-05-13 18:30:57 +0000510 EXPECT_TRUE(FPDFPageObj_SetFillColor(blue_path, 0, 0, 255, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500511 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
512 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
513 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
514 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
515 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
516 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
517 EXPECT_TRUE(FPDFPath_Close(blue_path));
518 FPDFPage_InsertObject(page, blue_path);
Hui Yingsta929df72021-02-26 23:56:18 +0000519#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
520 static constexpr char kLastChecksum[] = "ed14c60702b1489c597c7d46ece7f86d";
521#else
522 static constexpr char kLastChecksum[] = "9823e1a21bd9b72b6a442ba4f12af946";
523#endif
Lei Zhang107fa7b2018-02-09 21:48:15 +0000524 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000525 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingsta929df72021-02-26 23:56:18 +0000526 CompareBitmap(page_bitmap.get(), 612, 792, kLastChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000527 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500528
529 // Now save the result, closing the page and document
Nicolas Pena207b7272017-05-26 17:37:06 -0400530 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penad03ca422017-03-06 13:54:33 -0500531 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500532 FPDF_ClosePage(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500533
534 // Render the saved result
Hui Yingsta929df72021-02-26 23:56:18 +0000535 VerifySavedDocument(612, 792, kLastChecksum);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500536}
537
Miklos Vajna45501f32019-07-30 07:41:02 +0000538TEST_F(FPDFEditEmbedderTest, ClipPath) {
539 // Load document with a clipped rectangle.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000540 ASSERT_TRUE(OpenDocument("clip_path.pdf"));
Miklos Vajna45501f32019-07-30 07:41:02 +0000541 FPDF_PAGE page = LoadPage(0);
542 ASSERT_TRUE(page);
543
544 ASSERT_EQ(1, FPDFPage_CountObjects(page));
545
546 FPDF_PAGEOBJECT triangle = FPDFPage_GetObject(page, 0);
547 ASSERT_TRUE(triangle);
548
549 // Test that we got the expected triangle.
550 ASSERT_EQ(4, FPDFPath_CountSegments(triangle));
551
552 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(triangle, 0);
553 float x;
554 float y;
555 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
556 EXPECT_EQ(10, x);
557 EXPECT_EQ(10, y);
558 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
559 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
560
561 segment = FPDFPath_GetPathSegment(triangle, 1);
562 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
563 EXPECT_EQ(25, x);
564 EXPECT_EQ(40, y);
565 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
566 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
567
568 segment = FPDFPath_GetPathSegment(triangle, 2);
569 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
570 EXPECT_EQ(40, x);
571 EXPECT_EQ(10, y);
572 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
573 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
574
575 segment = FPDFPath_GetPathSegment(triangle, 3);
576 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
577 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
578
579 // Test FPDFPageObj_GetClipPath().
580 ASSERT_EQ(nullptr, FPDFPageObj_GetClipPath(nullptr));
581
582 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(triangle);
583 ASSERT_TRUE(clip_path);
584
585 // Test FPDFClipPath_CountPaths().
586 ASSERT_EQ(-1, FPDFClipPath_CountPaths(nullptr));
587 ASSERT_EQ(1, FPDFClipPath_CountPaths(clip_path));
588
589 // Test FPDFClipPath_CountPathSegments().
590 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(nullptr, 0));
591 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, -1));
592 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 1));
593 ASSERT_EQ(4, FPDFClipPath_CountPathSegments(clip_path, 0));
594
595 // FPDFClipPath_GetPathSegment() negative testing.
596 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(nullptr, 0, 0));
597 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, -1, 0));
598 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 1, 0));
599 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, -1));
600 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, 4));
601
602 // FPDFClipPath_GetPathSegment() positive testing.
603 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 0);
604 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
605 EXPECT_EQ(10, x);
606 EXPECT_EQ(15, y);
607 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
608 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
609
610 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 1);
611 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
612 EXPECT_EQ(40, x);
613 EXPECT_EQ(15, y);
614 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
615 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
616
617 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 2);
618 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
619 EXPECT_EQ(40, x);
620 EXPECT_EQ(35, y);
621 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
622 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
623
624 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 3);
625 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
626 EXPECT_EQ(10, x);
627 EXPECT_EQ(35, y);
628 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
629 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
630
631 UnloadPage(page);
632}
633
Lei Zhang571f9322019-09-25 12:40:25 +0000634TEST_F(FPDFEditEmbedderTest, BUG_1399) {
635 // Load document with a clipped rectangle.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000636 ASSERT_TRUE(OpenDocument("bug_1399.pdf"));
Lei Zhang571f9322019-09-25 12:40:25 +0000637 FPDF_PAGE page = LoadPage(0);
638 ASSERT_TRUE(page);
639
640 ASSERT_EQ(7, FPDFPage_CountObjects(page));
641
642 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
643 ASSERT_TRUE(obj);
644
645 ASSERT_EQ(2, FPDFPath_CountSegments(obj));
646
647 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(obj, 0);
648 float x;
649 float y;
650 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
651 EXPECT_FLOAT_EQ(107.718f, x);
652 EXPECT_FLOAT_EQ(719.922f, y);
653 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
654 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
655
656 segment = FPDFPath_GetPathSegment(obj, 1);
657 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
658 EXPECT_FLOAT_EQ(394.718f, x);
659 EXPECT_FLOAT_EQ(719.922f, y);
660 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
661 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
662
663 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(obj);
664 ASSERT_TRUE(clip_path);
665
666 EXPECT_EQ(-1, FPDFClipPath_CountPaths(clip_path));
667 EXPECT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 0));
668 EXPECT_FALSE(FPDFClipPath_GetPathSegment(clip_path, 0, 0));
669
670 UnloadPage(page);
671}
672
Lei Zhangfcf7e7f2021-07-02 18:46:54 +0000673TEST_F(FPDFEditEmbedderTest, BUG_1549) {
674 static const char kOriginalChecksum[] = "126366fb95e6caf8ea196780075b22b2";
675 static const char kRemovedChecksum[] = "6ec2f27531927882624b37bc7d8e12f4";
676
677 ASSERT_TRUE(OpenDocument("bug_1549.pdf"));
678 FPDF_PAGE page = LoadPage(0);
679
680 {
681 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
682 CompareBitmap(bitmap.get(), 100, 150, kOriginalChecksum);
683
684 ScopedFPDFPageObject obj(FPDFPage_GetObject(page, 0));
685 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj.get()));
686 ASSERT_TRUE(FPDFPage_RemoveObject(page, obj.get()));
687 }
688
689 ASSERT_TRUE(FPDFPage_GenerateContent(page));
690
691 {
692 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
693 CompareBitmap(bitmap.get(), 100, 150, kRemovedChecksum);
694 }
695
696 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
697 UnloadPage(page);
698
699 // TODO(crbug.com/pdfium/1549): Should be `kRemovedChecksum`.
700 VerifySavedDocument(100, 150, "4f9889cd5993db20f1ab37d677ac8d26");
701}
702
Hui Yingstcb4203d2020-06-09 01:48:47 +0000703TEST_F(FPDFEditEmbedderTest, SetText) {
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000704 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000705 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000706 FPDF_PAGE page = LoadPage(0);
707 ASSERT_TRUE(page);
708
709 // Get the "Hello, world!" text object and change it.
710 ASSERT_EQ(2, FPDFPage_CountObjects(page));
711 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
712 ASSERT_TRUE(page_object);
Lei Zhangf0f67682019-04-08 17:03:21 +0000713 ScopedFPDFWideString text1 = GetFPDFWideString(L"Changed for SetText test");
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000714 EXPECT_TRUE(FPDFText_SetText(page_object, text1.get()));
715
716 // Verify the "Hello, world!" text is gone and "Changed for SetText test" is
717 // now displayed.
718 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Hui Yingstcb4203d2020-06-09 01:48:47 +0000719
720#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +0000721 const char kChangedChecksum[] = "49c8602cb60508009a34d0caaac63bb4";
Lei Zhang42d30c22022-01-12 19:24:43 +0000722#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +0000723 const char kChangedChecksum[] = "b720e83476fd6819d47c533f1f43c728";
Hui Yingstcb4203d2020-06-09 01:48:47 +0000724#else
Tom Andersond4fe5f72021-12-03 20:52:52 +0000725 const char kChangedChecksum[] = "9a85b9354a69c61772ed24151c140f46";
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000726#endif
727 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000728 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstcb4203d2020-06-09 01:48:47 +0000729 CompareBitmap(page_bitmap.get(), 200, 200, kChangedChecksum);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000730 }
731
732 // Now save the result.
733 EXPECT_TRUE(FPDFPage_GenerateContent(page));
734 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
735
736 UnloadPage(page);
737
738 // Re-open the file and check the changes were kept in the saved .pdf.
Lei Zhang0b494052019-01-31 21:41:15 +0000739 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000740 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +0000741 ASSERT_TRUE(saved_page);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000742 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
743 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000744 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstcb4203d2020-06-09 01:48:47 +0000745 CompareBitmap(page_bitmap.get(), 200, 200, kChangedChecksum);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000746 }
747
748 CloseSavedPage(saved_page);
749 CloseSavedDocument();
750}
751
Lei Zhang786544d2021-07-27 21:25:24 +0000752TEST_F(FPDFEditEmbedderTest, SetCharcodesBadParams) {
753 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
754 FPDF_PAGE page = LoadPage(0);
755 ASSERT_TRUE(page);
756
757 ASSERT_EQ(2, FPDFPage_CountObjects(page));
758 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
759 ASSERT_TRUE(page_object);
760
761 const uint32_t kDummyValue = 42;
762 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 0));
763 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 1));
764 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 0));
765 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 1));
766 EXPECT_FALSE(FPDFText_SetCharcodes(page_object, nullptr, 1));
767
768 UnloadPage(page);
769}
770
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000771TEST_F(FPDFEditEmbedderTest, SetTextKeepClippingPath) {
Daniel Hosseinianda651442020-07-17 23:30:22 +0000772 // Load document with some text, with parts clipped.
773 ASSERT_TRUE(OpenDocument("bug_1558.pdf"));
774 FPDF_PAGE page = LoadPage(0);
775 ASSERT_TRUE(page);
776
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000777#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Daniel Hosseinianda651442020-07-17 23:30:22 +0000778 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000779 "92ff84385a0f986eacfa4bbecf8d7a7a";
Lei Zhang42d30c22022-01-12 19:24:43 +0000780#elif BUILDFLAG(IS_APPLE)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000781 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000782 "ae7a25c85e0e2dd0c5cb9dd5cd37f6df";
Daniel Hosseinianda651442020-07-17 23:30:22 +0000783#else
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000784 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000785 "7af7fe5b281298261eb66ac2d22f5054";
Daniel Hosseinianda651442020-07-17 23:30:22 +0000786#endif
787 {
788 // When opened before any editing and saving, the clipping path is rendered.
789 ScopedFPDFBitmap original_bitmap = RenderPage(page);
790 CompareBitmap(original_bitmap.get(), 200, 200, kOriginalChecksum);
791 }
792
793 // "Change" the text in the objects to their current values to force them to
794 // regenerate when saving.
795 {
796 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
797 ASSERT_TRUE(text_page);
798 const int obj_count = FPDFPage_CountObjects(page);
799 ASSERT_EQ(2, obj_count);
800 for (int i = 0; i < obj_count; ++i) {
801 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, i);
802 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
803 unsigned long size =
804 FPDFTextObj_GetText(text_obj, text_page.get(),
805 /*buffer=*/nullptr, /*length=*/0);
806 ASSERT_GT(size, 0u);
807 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
808 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
809 buffer.data(), size));
810 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
811 }
812 }
813
814 {
815 // After editing but before saving, the clipping path is retained.
816 ScopedFPDFBitmap edited_bitmap = RenderPage(page);
817 CompareBitmap(edited_bitmap.get(), 200, 200, kOriginalChecksum);
818 }
819
820 // Save the file.
821 EXPECT_TRUE(FPDFPage_GenerateContent(page));
822 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
823 UnloadPage(page);
824
825 // Open the saved copy and render it.
826 ASSERT_TRUE(OpenSavedDocument());
827 FPDF_PAGE saved_page = LoadSavedPage(0);
828 ASSERT_TRUE(saved_page);
829
830 {
Daniel Hosseinianda651442020-07-17 23:30:22 +0000831 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
Daniel Hosseinian75efd912020-07-21 08:07:28 +0000832 CompareBitmap(saved_bitmap.get(), 200, 200, kOriginalChecksum);
Daniel Hosseinianda651442020-07-17 23:30:22 +0000833 }
834
835 CloseSavedPage(saved_page);
836 CloseSavedDocument();
837}
838
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000839TEST_F(FPDFEditEmbedderTest, BUG_1574) {
840 // Load document with some text within a clipping path.
841 ASSERT_TRUE(OpenDocument("bug_1574.pdf"));
842 FPDF_PAGE page = LoadPage(0);
843 ASSERT_TRUE(page);
844
845#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
846 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000847 "1e022a0360f053ecb41cc431a36834a6";
Lei Zhang42d30c22022-01-12 19:24:43 +0000848#elif BUILDFLAG(IS_APPLE)
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000849 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000850 "1226bc2b8072622eb28f52321876e814";
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000851#else
852 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000853 "c5241eef60b9eac68ed1f2a5fd002703";
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000854#endif
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000855 {
856 // When opened before any editing and saving, the text object is rendered.
857 ScopedFPDFBitmap original_bitmap = RenderPage(page);
858 CompareBitmap(original_bitmap.get(), 200, 300, kOriginalChecksum);
859 }
860
861 // "Change" the text in the objects to their current values to force them to
862 // regenerate when saving.
863 {
864 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
865 ASSERT_TRUE(text_page);
866
867 ASSERT_EQ(2, FPDFPage_CountObjects(page));
868 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, 1);
869 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
870
871 unsigned long size = FPDFTextObj_GetText(text_obj, text_page.get(),
872 /*buffer=*/nullptr, /*length=*/0);
873 ASSERT_GT(size, 0u);
874 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
875 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
876 buffer.data(), size));
877 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
878 }
879
880 // Save the file.
881 EXPECT_TRUE(FPDFPage_GenerateContent(page));
882 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
883 UnloadPage(page);
884
885 // Open the saved copy and render it.
886 ASSERT_TRUE(OpenSavedDocument());
887 FPDF_PAGE saved_page = LoadSavedPage(0);
888 ASSERT_TRUE(saved_page);
889
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000890 {
891 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
Daniel Hosseinian91eeeb92021-01-27 19:53:24 +0000892 CompareBitmap(saved_bitmap.get(), 200, 300, kOriginalChecksum);
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000893 }
894
895 CloseSavedPage(saved_page);
896 CloseSavedDocument();
897}
898
Hui Yingst08c40712020-04-29 01:37:35 +0000899TEST_F(FPDFEditEmbedderTest, RemovePageObject) {
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000900 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000901 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000902 FPDF_PAGE page = LoadPage(0);
903 ASSERT_TRUE(page);
904
Henrique Nakashimac90adc52018-03-27 16:26:44 +0000905 // Show what the original file looks like.
906 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000907 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000908 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000909 }
910
911 // Get the "Hello, world!" text object and remove it.
912 ASSERT_EQ(2, FPDFPage_CountObjects(page));
913 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
914 ASSERT_TRUE(page_object);
915 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
916
Henrique Nakashimac90adc52018-03-27 16:26:44 +0000917 // Verify the "Hello, world!" text is gone.
918 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000919 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000920 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000921 }
922 ASSERT_EQ(1, FPDFPage_CountObjects(page));
923
924 UnloadPage(page);
925 FPDFPageObj_Destroy(page_object);
926}
927
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000928void CheckMarkCounts(FPDF_PAGE page,
929 int start_from,
930 int expected_object_count,
931 size_t expected_prime_count,
932 size_t expected_square_count,
933 size_t expected_greater_than_ten_count,
934 size_t expected_bounds_count) {
935 int object_count = FPDFPage_CountObjects(page);
936 ASSERT_EQ(expected_object_count, object_count);
937
938 size_t prime_count = 0;
939 size_t square_count = 0;
940 size_t greater_than_ten_count = 0;
941 size_t bounds_count = 0;
942 for (int i = 0; i < object_count; ++i) {
943 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
944
945 int mark_count = FPDFPageObj_CountMarks(page_object);
946 for (int j = 0; j < mark_count; ++j) {
947 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
948
949 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000950 unsigned long name_len = 999u;
951 ASSERT_TRUE(
952 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
953 EXPECT_GT(name_len, 0u);
954 EXPECT_NE(999u, name_len);
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000955 std::wstring name =
956 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
957 if (name == L"Prime") {
958 prime_count++;
959 } else if (name == L"Square") {
960 square_count++;
961 int expected_square = start_from + i;
962 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
963
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000964 unsigned long get_param_key_return = 999u;
965 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
966 &get_param_key_return));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000967 EXPECT_EQ((6u + 1u) * 2u, get_param_key_return);
968 std::wstring key =
969 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
970 EXPECT_EQ(L"Factor", key);
971
972 EXPECT_EQ(FPDF_OBJECT_NUMBER,
Henrique Nakashima94230e52018-07-11 22:02:02 +0000973 FPDFPageObjMark_GetParamValueType(mark, "Factor"));
Henrique Nakashima140dead2018-07-11 21:40:03 +0000974 int square_root;
Henrique Nakashima94230e52018-07-11 22:02:02 +0000975 EXPECT_TRUE(
976 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &square_root));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000977 EXPECT_EQ(expected_square, square_root * square_root);
978 } else if (name == L"GreaterThanTen") {
979 greater_than_ten_count++;
980 } else if (name == L"Bounds") {
981 bounds_count++;
982 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
983
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000984 unsigned long get_param_key_return = 999u;
985 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
986 &get_param_key_return));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000987 EXPECT_EQ((8u + 1u) * 2u, get_param_key_return);
988 std::wstring key =
989 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
990 EXPECT_EQ(L"Position", key);
991
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000992 EXPECT_EQ(FPDF_OBJECT_STRING,
Henrique Nakashima94230e52018-07-11 22:02:02 +0000993 FPDFPageObjMark_GetParamValueType(mark, "Position"));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000994 unsigned long length;
Henrique Nakashimaa3406772018-07-13 19:10:53 +0000995 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
996 mark, "Position", buffer, sizeof(buffer), &length));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000997 ASSERT_GT(length, 0u);
Henrique Nakashima140dead2018-07-11 21:40:03 +0000998 std::wstring value =
999 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00001000
Henrique Nakashimaa3406772018-07-13 19:10:53 +00001001 // "Position" can be "First", "Last", or "End".
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00001002 if (i == 0) {
1003 EXPECT_EQ((5u + 1u) * 2u, length);
1004 EXPECT_EQ(L"First", value);
1005 } else if (i == object_count - 1) {
Henrique Nakashimaa3406772018-07-13 19:10:53 +00001006 if (length == (4u + 1u) * 2u) {
1007 EXPECT_EQ(L"Last", value);
1008 } else if (length == (3u + 1u) * 2u) {
1009 EXPECT_EQ(L"End", value);
1010 } else {
1011 FAIL();
1012 }
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00001013 } else {
1014 FAIL();
1015 }
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001016 } else {
1017 FAIL();
1018 }
1019 }
1020 }
1021
1022 // Expect certain number of tagged objects. The test file contains strings
1023 // from 1 to 19.
1024 EXPECT_EQ(expected_prime_count, prime_count);
1025 EXPECT_EQ(expected_square_count, square_count);
1026 EXPECT_EQ(expected_greater_than_ten_count, greater_than_ten_count);
1027 EXPECT_EQ(expected_bounds_count, bounds_count);
1028}
1029
Lei Zhangab41f252018-12-23 03:10:50 +00001030TEST_F(FPDFEditEmbedderTest, ReadMarkedObjectsIndirectDict) {
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001031 // Load document with some text marked with an indirect property.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001032 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001033 FPDF_PAGE page = LoadPage(0);
1034 ASSERT_TRUE(page);
1035
1036 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1037
1038 UnloadPage(page);
1039}
1040
Hui Yingstf26b5f82020-11-17 05:26:03 +00001041TEST_F(FPDFEditEmbedderTest, RemoveMarkedObjectsPrime) {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001042 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001043 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001044 FPDF_PAGE page = LoadPage(0);
1045 ASSERT_TRUE(page);
1046
1047 // Show what the original file looks like.
1048 {
Hui Yingstf26b5f82020-11-17 05:26:03 +00001049#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1050 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001051 "8a8bed7820764522955f422e27f4292f";
Lei Zhang42d30c22022-01-12 19:24:43 +00001052#elif BUILDFLAG(IS_APPLE)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001053 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001054 "966579fb98206858ce2f0a1f94a74d05";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001055#else
1056 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001057 "3d5a3de53d5866044c2b6bf339742c97";
1058#endif
Lei Zhang30ff2532019-01-31 21:37:55 +00001059 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001060 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalChecksum);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001061 }
1062
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001063 constexpr int expected_object_count = 19;
1064 CheckMarkCounts(page, 1, expected_object_count, 8, 4, 9, 1);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001065
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001066 // Get all objects marked with "Prime"
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001067 std::vector<FPDF_PAGEOBJECT> primes;
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001068 for (int i = 0; i < expected_object_count; ++i) {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001069 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1070
1071 int mark_count = FPDFPageObj_CountMarks(page_object);
1072 for (int j = 0; j < mark_count; ++j) {
1073 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1074
1075 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001076 unsigned long name_len = 999u;
1077 ASSERT_TRUE(
1078 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1079 EXPECT_GT(name_len, 0u);
1080 EXPECT_NE(999u, name_len);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001081 std::wstring name =
1082 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1083 if (name == L"Prime") {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001084 primes.push_back(page_object);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001085 }
1086 }
1087 }
1088
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001089 // Remove all objects marked with "Prime".
1090 for (FPDF_PAGEOBJECT page_object : primes) {
1091 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1092 FPDFPageObj_Destroy(page_object);
1093 }
1094
1095 EXPECT_EQ(11, FPDFPage_CountObjects(page));
Hui Yingstf26b5f82020-11-17 05:26:03 +00001096#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1097 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001098 "1573b85dd9a2c59401c1c30abbee3b25";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001099 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001100 "1573b85dd9a2c59401c1c30abbee3b25";
Lei Zhang42d30c22022-01-12 19:24:43 +00001101#elif BUILDFLAG(IS_APPLE)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001102 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001103 "6e19a4dd674b522cd39cf41956559bd6";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001104 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001105 "3cb35c681f8fb5a43a49146ac7caa818";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001106#else
1107 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001108 "bc8623c052f12376c3d8dd09a6cd27df";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001109 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001110 "bc8623c052f12376c3d8dd09a6cd27df";
1111#endif
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001112 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001113 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001114 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesChecksum);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001115 }
1116
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001117 // Save the file.
1118 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1119 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001120 UnloadPage(page);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001121
1122 // Re-open the file and check the prime marks are not there anymore.
Lei Zhang0b494052019-01-31 21:41:15 +00001123 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001124 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001125 ASSERT_TRUE(saved_page);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001126 EXPECT_EQ(11, FPDFPage_CountObjects(saved_page));
1127
1128 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001129 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001130 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesAfterSaveChecksum);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001131 }
1132
1133 CloseSavedPage(saved_page);
1134 CloseSavedDocument();
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001135}
1136
Lei Zhangab41f252018-12-23 03:10:50 +00001137TEST_F(FPDFEditEmbedderTest, RemoveMarks) {
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001138 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001139 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001140 FPDF_PAGE page = LoadPage(0);
1141 ASSERT_TRUE(page);
1142
1143 constexpr int kExpectedObjectCount = 19;
1144 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1145
1146 // Remove all "Prime" content marks.
1147 for (int i = 0; i < kExpectedObjectCount; ++i) {
1148 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1149
1150 int mark_count = FPDFPageObj_CountMarks(page_object);
1151 for (int j = mark_count - 1; j >= 0; --j) {
1152 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1153
1154 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001155 unsigned long name_len = 999u;
1156 ASSERT_TRUE(
1157 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1158 EXPECT_GT(name_len, 0u);
1159 EXPECT_NE(999u, name_len);
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001160 std::wstring name =
1161 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1162 if (name == L"Prime") {
1163 // Remove mark.
1164 EXPECT_TRUE(FPDFPageObj_RemoveMark(page_object, mark));
1165
1166 // Verify there is now one fewer mark in the page object.
1167 EXPECT_EQ(mark_count - 1, FPDFPageObj_CountMarks(page_object));
1168 }
1169 }
1170 }
1171
1172 // Verify there are 0 "Prime" content marks now.
1173 CheckMarkCounts(page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1174
1175 // Save the file.
1176 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1177 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1178 UnloadPage(page);
1179
1180 // Re-open the file and check the prime marks are not there anymore.
Lei Zhang0b494052019-01-31 21:41:15 +00001181 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001182 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001183 ASSERT_TRUE(saved_page);
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001184
1185 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1186
1187 CloseSavedPage(saved_page);
1188 CloseSavedDocument();
1189}
1190
Lei Zhangab41f252018-12-23 03:10:50 +00001191TEST_F(FPDFEditEmbedderTest, RemoveMarkParam) {
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001192 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001193 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001194 FPDF_PAGE page = LoadPage(0);
1195 ASSERT_TRUE(page);
1196
1197 constexpr int kExpectedObjectCount = 19;
1198 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1199
1200 // Remove all "Square" content marks parameters.
1201 for (int i = 0; i < kExpectedObjectCount; ++i) {
1202 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1203
1204 int mark_count = FPDFPageObj_CountMarks(page_object);
1205 for (int j = 0; j < mark_count; ++j) {
1206 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1207
1208 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001209 unsigned long name_len = 999u;
1210 ASSERT_TRUE(
1211 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1212 EXPECT_GT(name_len, 0u);
1213 EXPECT_NE(999u, name_len);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001214 std::wstring name =
1215 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1216 if (name == L"Square") {
1217 // Show the mark has a "Factor" parameter.
1218 int out_value;
1219 EXPECT_TRUE(
1220 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1221
1222 // Remove parameter.
1223 EXPECT_TRUE(FPDFPageObjMark_RemoveParam(page_object, mark, "Factor"));
1224
1225 // Verify the "Factor" parameter is gone.
1226 EXPECT_FALSE(
1227 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1228 }
1229 }
1230 }
1231
1232 // Save the file.
1233 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1234 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1235 UnloadPage(page);
1236
1237 // Re-open the file and check the "Factor" parameters are still gone.
Lei Zhang0b494052019-01-31 21:41:15 +00001238 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001239 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001240 ASSERT_TRUE(saved_page);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001241
1242 size_t square_count = 0;
1243 for (int i = 0; i < kExpectedObjectCount; ++i) {
1244 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1245
1246 int mark_count = FPDFPageObj_CountMarks(page_object);
1247 for (int j = 0; j < mark_count; ++j) {
1248 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1249
1250 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001251 unsigned long name_len = 999u;
1252 ASSERT_TRUE(
1253 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1254 EXPECT_GT(name_len, 0u);
1255 EXPECT_NE(999u, name_len);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001256 std::wstring name =
1257 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1258 if (name == L"Square") {
1259 // Verify the "Factor" parameter is still gone.
1260 int out_value;
1261 EXPECT_FALSE(
1262 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1263
1264 ++square_count;
1265 }
1266 }
1267 }
1268
1269 // Verify the parameters are gone, but the marks are not.
1270 EXPECT_EQ(4u, square_count);
1271
1272 CloseSavedPage(saved_page);
1273 CloseSavedDocument();
1274}
1275
Lei Zhangab41f252018-12-23 03:10:50 +00001276TEST_F(FPDFEditEmbedderTest, MaintainMarkedObjects) {
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001277 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001278 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001279 FPDF_PAGE page = LoadPage(0);
1280 ASSERT_TRUE(page);
1281
1282 // Iterate over all objects, counting the number of times each content mark
1283 // name appears.
1284 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1285
1286 // Remove first page object.
1287 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1288 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1289 FPDFPageObj_Destroy(page_object);
1290
1291 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1292
1293 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1294 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1295
1296 UnloadPage(page);
1297
Lei Zhang0b494052019-01-31 21:41:15 +00001298 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001299 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001300 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001301
1302 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1303
1304 CloseSavedPage(saved_page);
1305 CloseSavedDocument();
1306}
1307
Lei Zhangab41f252018-12-23 03:10:50 +00001308TEST_F(FPDFEditEmbedderTest, MaintainIndirectMarkedObjects) {
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001309 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001310 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001311 FPDF_PAGE page = LoadPage(0);
1312 ASSERT_TRUE(page);
1313
1314 // Iterate over all objects, counting the number of times each content mark
1315 // name appears.
1316 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1317
1318 // Remove first page object.
1319 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1320 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1321 FPDFPageObj_Destroy(page_object);
1322
1323 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1324
1325 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1326 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1327
1328 UnloadPage(page);
1329
Lei Zhang0b494052019-01-31 21:41:15 +00001330 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001331 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001332 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001333
1334 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1335
1336 CloseSavedPage(saved_page);
1337 CloseSavedDocument();
1338}
1339
Lei Zhangab41f252018-12-23 03:10:50 +00001340TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObject) {
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001341 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001342 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001343 FPDF_PAGE page = LoadPage(0);
1344 ASSERT_TRUE(page);
1345
1346 // Get the "Hello, world!" text object and remove it.
1347 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1348 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1349 ASSERT_TRUE(page_object);
1350 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1351
1352 // Verify the "Hello, world!" text is gone.
1353 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1354
1355 // Save the file
1356 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1357 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1358 UnloadPage(page);
1359 FPDFPageObj_Destroy(page_object);
1360
1361 // Re-open the file and check the page object count is still 1.
Lei Zhang0b494052019-01-31 21:41:15 +00001362 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001363 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001364 ASSERT_TRUE(saved_page);
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001365 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
1366 CloseSavedPage(saved_page);
1367 CloseSavedDocument();
1368}
1369
Hui Yingstcb4203d2020-06-09 01:48:47 +00001370TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsNotLonely) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001371 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001372 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001373 FPDF_PAGE page = LoadPage(0);
1374 ASSERT_TRUE(page);
1375
1376 // Get the "Hello, world!" text object and remove it. There is another object
1377 // in the same stream that says "Goodbye, world!"
1378 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1379 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1380 ASSERT_TRUE(page_object);
1381 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1382
1383 // Verify the "Hello, world!" text is gone.
1384 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Hui Yingstcb4203d2020-06-09 01:48:47 +00001385#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001386 const char kHelloRemovedChecksum[] = "fc2a40a3d1edfe6e972be104b5ae87ad";
Lei Zhang42d30c22022-01-12 19:24:43 +00001387#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001388 const char kHelloRemovedChecksum[] = "5508c2f06d104050f74f655693e38c2c";
Hui Yingstcb4203d2020-06-09 01:48:47 +00001389#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00001390 const char kHelloRemovedChecksum[] = "a8cd82499cf744e0862ca468c9d4ceb8";
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001391#endif
1392 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001393 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstcb4203d2020-06-09 01:48:47 +00001394 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001395 }
1396
1397 // Save the file
1398 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1399 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1400 UnloadPage(page);
1401 FPDFPageObj_Destroy(page_object);
1402
1403 // Re-open the file and check the page object count is still 2.
Lei Zhang0b494052019-01-31 21:41:15 +00001404 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001405 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001406 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001407
1408 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1409 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001410 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstcb4203d2020-06-09 01:48:47 +00001411 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001412 }
1413
1414 CloseSavedPage(saved_page);
1415 CloseSavedDocument();
1416}
1417
Hui Yingst08c40712020-04-29 01:37:35 +00001418TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsLonely) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001419 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001420 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001421 FPDF_PAGE page = LoadPage(0);
1422 ASSERT_TRUE(page);
1423
1424 // Get the "Greetings, world!" text object and remove it. This is the only
1425 // object in the stream.
1426 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1427 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 2);
1428 ASSERT_TRUE(page_object);
1429 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1430
1431 // Verify the "Greetings, world!" text is gone.
1432 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001433 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001434 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001435 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001436 }
1437
1438 // Save the file
1439 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1440 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1441 UnloadPage(page);
1442 FPDFPageObj_Destroy(page_object);
1443
1444 // Re-open the file and check the page object count is still 2.
Lei Zhang0b494052019-01-31 21:41:15 +00001445 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001446 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001447 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001448
1449 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1450 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001451 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001452 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001453 }
1454
1455 CloseSavedPage(saved_page);
1456 CloseSavedDocument();
1457}
1458
Lei Zhangab41f252018-12-23 03:10:50 +00001459TEST_F(FPDFEditEmbedderTest, GetContentStream) {
Henrique Nakashima6eb79392018-06-12 20:27:35 +00001460 // Load document with some text split across streams.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001461 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
Henrique Nakashima6eb79392018-06-12 20:27:35 +00001462 FPDF_PAGE page = LoadPage(0);
1463 ASSERT_TRUE(page);
1464
1465 // Content stream 0: page objects 0-14.
1466 // Content stream 1: page objects 15-17.
1467 // Content stream 2: page object 18.
1468 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1469 for (int i = 0; i < 19; i++) {
1470 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1471 ASSERT_TRUE(page_object);
1472 CPDF_PageObject* cpdf_page_object =
1473 CPDFPageObjectFromFPDFPageObject(page_object);
1474 if (i < 15)
1475 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1476 else if (i < 18)
1477 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1478 else
1479 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1480 }
1481
1482 UnloadPage(page);
1483}
1484
Hui Yingst0d692fe2020-11-06 17:32:50 +00001485TEST_F(FPDFEditEmbedderTest, RemoveAllFromStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001486 // Load document with some text split across streams.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001487 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001488 FPDF_PAGE page = LoadPage(0);
1489 ASSERT_TRUE(page);
1490
1491 // Content stream 0: page objects 0-14.
1492 // Content stream 1: page objects 15-17.
1493 // Content stream 2: page object 18.
1494 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1495
1496 // Loop backwards because objects will being removed, which shifts the indexes
1497 // after the removed position.
1498 for (int i = 18; i >= 0; i--) {
1499 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1500 ASSERT_TRUE(page_object);
1501 CPDF_PageObject* cpdf_page_object =
1502 CPDFPageObjectFromFPDFPageObject(page_object);
1503
1504 // Empty content stream 1.
1505 if (cpdf_page_object->GetContentStream() == 1) {
1506 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1507 FPDFPageObj_Destroy(page_object);
1508 }
1509 }
1510
1511 // Content stream 0: page objects 0-14.
1512 // Content stream 2: page object 15.
1513 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1514 for (int i = 0; i < 16; i++) {
1515 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1516 ASSERT_TRUE(page_object);
1517 CPDF_PageObject* cpdf_page_object =
1518 CPDFPageObjectFromFPDFPageObject(page_object);
1519 if (i < 15)
1520 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1521 else
1522 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1523 }
1524
1525 // Generate contents should remove the empty stream and update the page
1526 // objects' contents stream indexes.
1527 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1528
1529 // Content stream 0: page objects 0-14.
1530 // Content stream 1: page object 15.
1531 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1532 for (int i = 0; i < 16; i++) {
1533 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1534 ASSERT_TRUE(page_object);
1535 CPDF_PageObject* cpdf_page_object =
1536 CPDFPageObjectFromFPDFPageObject(page_object);
1537 if (i < 15)
1538 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1539 else
1540 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1541 }
1542
Hui Yingst0d692fe2020-11-06 17:32:50 +00001543#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001544 const char kStream1RemovedChecksum[] = "7fe07f182b37d40afc6ae36a4e89fe73";
Lei Zhang42d30c22022-01-12 19:24:43 +00001545#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001546 const char kStream1RemovedChecksum[] = "3cdc75af44c15bed80998facd6e674c9";
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001547#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00001548 const char kStream1RemovedChecksum[] = "b474826df1acedb05c7b82e1e49e64a6";
1549#endif
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001550 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001551 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst0d692fe2020-11-06 17:32:50 +00001552 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001553 }
1554
1555 // Save the file
1556 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1557 UnloadPage(page);
1558
1559 // Re-open the file and check the page object count is still 16, and that
1560 // content stream 1 was removed.
Lei Zhang0b494052019-01-31 21:41:15 +00001561 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001562 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001563 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001564
1565 // Content stream 0: page objects 0-14.
1566 // Content stream 1: page object 15.
1567 EXPECT_EQ(16, FPDFPage_CountObjects(saved_page));
1568 for (int i = 0; i < 16; i++) {
1569 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1570 ASSERT_TRUE(page_object);
1571 CPDF_PageObject* cpdf_page_object =
1572 CPDFPageObjectFromFPDFPageObject(page_object);
1573 if (i < 15)
1574 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1575 else
1576 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1577 }
1578
1579 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001580 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst0d692fe2020-11-06 17:32:50 +00001581 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001582 }
1583
1584 CloseSavedPage(saved_page);
1585 CloseSavedDocument();
1586}
1587
Lei Zhangab41f252018-12-23 03:10:50 +00001588TEST_F(FPDFEditEmbedderTest, RemoveAllFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001589 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001590 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001591 FPDF_PAGE page = LoadPage(0);
1592 ASSERT_TRUE(page);
1593
1594 // Content stream 0: page objects 0-1.
1595 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1596
1597 // Loop backwards because objects will being removed, which shifts the indexes
1598 // after the removed position.
1599 for (int i = 1; i >= 0; i--) {
1600 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1601 ASSERT_TRUE(page_object);
1602 CPDF_PageObject* cpdf_page_object =
1603 CPDFPageObjectFromFPDFPageObject(page_object);
1604 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1605 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1606 FPDFPageObj_Destroy(page_object);
1607 }
1608
1609 // No more objects in the stream
1610 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1611
1612 // Generate contents should remove the empty stream and update the page
1613 // objects' contents stream indexes.
1614 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1615
1616 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1617
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001618 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001619 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001620 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001621 }
1622
1623 // Save the file
1624 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1625 UnloadPage(page);
1626
1627 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001628 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001629 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001630 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001631
1632 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1633 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001634 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001635 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001636 }
1637
1638 CloseSavedPage(saved_page);
1639 CloseSavedDocument();
1640}
1641
Hui Yingst08c40712020-04-29 01:37:35 +00001642TEST_F(FPDFEditEmbedderTest, RemoveFirstFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001643 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001644 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001645 FPDF_PAGE page = LoadPage(0);
1646 ASSERT_TRUE(page);
1647
1648 // Content stream 0: page objects 0-1.
1649 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1650
1651 // Remove first object.
1652 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1653 ASSERT_TRUE(page_object);
1654 CPDF_PageObject* cpdf_page_object =
1655 CPDFPageObjectFromFPDFPageObject(page_object);
1656 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1657 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1658 FPDFPageObj_Destroy(page_object);
1659
1660 // One object left in the stream.
1661 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1662 page_object = FPDFPage_GetObject(page, 0);
1663 ASSERT_TRUE(page_object);
1664 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1665 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1666
1667 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1668
1669 // Still one object left in the stream.
1670 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1671 page_object = FPDFPage_GetObject(page, 0);
1672 ASSERT_TRUE(page_object);
1673 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1674 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1675
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001676 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001677 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001678 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001679 }
1680
1681 // Save the file
1682 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1683 UnloadPage(page);
1684
1685 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001686 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001687 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001688 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001689
1690 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1691 page_object = FPDFPage_GetObject(saved_page, 0);
1692 ASSERT_TRUE(page_object);
1693 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1694 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1695 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001696 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001697 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001698 }
1699
1700 CloseSavedPage(saved_page);
1701 CloseSavedDocument();
1702}
1703
Hui Yingst08c40712020-04-29 01:37:35 +00001704TEST_F(FPDFEditEmbedderTest, RemoveLastFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001705 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001706 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001707 FPDF_PAGE page = LoadPage(0);
1708 ASSERT_TRUE(page);
1709
1710 // Content stream 0: page objects 0-1.
1711 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1712
1713 // Remove last object
1714 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 1);
1715 ASSERT_TRUE(page_object);
1716 CPDF_PageObject* cpdf_page_object =
1717 CPDFPageObjectFromFPDFPageObject(page_object);
1718 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1719 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1720 FPDFPageObj_Destroy(page_object);
1721
1722 // One object left in the stream.
1723 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1724 page_object = FPDFPage_GetObject(page, 0);
1725 ASSERT_TRUE(page_object);
1726 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1727 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1728
1729 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1730
1731 // Still one object left in the stream.
1732 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1733 page_object = FPDFPage_GetObject(page, 0);
1734 ASSERT_TRUE(page_object);
1735 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1736 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1737
Hui Yingstb4baceb2020-04-28 23:46:10 +00001738 using pdfium::kHelloWorldRemovedChecksum;
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001739 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001740 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001741 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001742 }
1743
1744 // Save the file
1745 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1746 UnloadPage(page);
1747
1748 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001749 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001750 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001751 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001752
1753 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1754 page_object = FPDFPage_GetObject(saved_page, 0);
1755 ASSERT_TRUE(page_object);
1756 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1757 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1758 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001759 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001760 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001761 }
1762
1763 CloseSavedPage(saved_page);
1764 CloseSavedDocument();
1765}
1766
Lei Zhangab41f252018-12-23 03:10:50 +00001767TEST_F(FPDFEditEmbedderTest, RemoveAllFromMultipleStreams) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001768 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001769 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001770 FPDF_PAGE page = LoadPage(0);
1771 ASSERT_TRUE(page);
1772
1773 // Content stream 0: page objects 0-1.
1774 // Content stream 1: page object 2.
1775 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1776
1777 // Loop backwards because objects will being removed, which shifts the indexes
1778 // after the removed position.
1779 for (int i = 2; i >= 0; i--) {
1780 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1781 ASSERT_TRUE(page_object);
1782 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1783 FPDFPageObj_Destroy(page_object);
1784 }
1785
1786 // No more objects in the page.
1787 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1788
1789 // Generate contents should remove the empty streams and update the page
1790 // objects' contents stream indexes.
1791 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1792
1793 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1794
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001795 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001796 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001797 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001798 }
1799
1800 // Save the file
1801 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1802 UnloadPage(page);
1803
1804 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001805 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001806 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001807 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001808
1809 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1810 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001811 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001812 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001813 }
1814
1815 CloseSavedPage(saved_page);
1816 CloseSavedDocument();
1817}
1818
Lei Zhangab41f252018-12-23 03:10:50 +00001819TEST_F(FPDFEditEmbedderTest, InsertPageObjectAndSave) {
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001820 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001821 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001822 FPDF_PAGE page = LoadPage(0);
1823 ASSERT_TRUE(page);
1824
1825 // Add a red rectangle.
1826 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1827 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001828 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001829 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1830 FPDFPage_InsertObject(page, red_rect);
1831
1832 // Verify the red rectangle was added.
1833 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1834
1835 // Save the file
1836 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1837 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1838 UnloadPage(page);
1839
1840 // Re-open the file and check the page object count is still 3.
Lei Zhang0b494052019-01-31 21:41:15 +00001841 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001842 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001843 ASSERT_TRUE(saved_page);
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001844 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1845 CloseSavedPage(saved_page);
1846 CloseSavedDocument();
1847}
1848
Lei Zhangab41f252018-12-23 03:10:50 +00001849TEST_F(FPDFEditEmbedderTest, InsertPageObjectEditAndSave) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001850 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001851 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001852 FPDF_PAGE page = LoadPage(0);
1853 ASSERT_TRUE(page);
1854
1855 // Add a red rectangle.
1856 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1857 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001858 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 100, 100, 255));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001859 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1860 FPDFPage_InsertObject(page, red_rect);
1861
1862 // Verify the red rectangle was added.
1863 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1864
1865 // Generate content but change it again
1866 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhang3475b482019-05-13 18:30:57 +00001867 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001868
1869 // Save the file
1870 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1871 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1872 UnloadPage(page);
1873
1874 // Re-open the file and check the page object count is still 3.
Lei Zhang0b494052019-01-31 21:41:15 +00001875 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001876 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001877 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001878 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1879 CloseSavedPage(saved_page);
1880 CloseSavedDocument();
1881}
1882
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001883TEST_F(FPDFEditEmbedderTest, InsertAndRemoveLargeFile) {
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001884 const int kOriginalObjectCount = 600;
1885
1886 // Load document with many objects.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001887 ASSERT_TRUE(OpenDocument("many_rectangles.pdf"));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001888 FPDF_PAGE page = LoadPage(0);
1889 ASSERT_TRUE(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001890
1891 using pdfium::kManyRectanglesChecksum;
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001892 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001893 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001894 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001895 }
1896
1897 // Add a black rectangle.
1898 ASSERT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(page));
1899 FPDF_PAGEOBJECT black_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001900 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_rect, 0, 0, 0, 255));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001901 EXPECT_TRUE(FPDFPath_SetDrawMode(black_rect, FPDF_FILLMODE_ALTERNATE, 0));
1902 FPDFPage_InsertObject(page, black_rect);
1903
1904 // Verify the black rectangle was added.
1905 ASSERT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(page));
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001906#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1907 const char kPlusRectangleMD5[] = "0d3715fcfb9bd0dd25dcce60800bff47";
1908#else
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001909 const char kPlusRectangleMD5[] = "6b9396ab570754b32b04ca629e902f77";
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001910#endif
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001911 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001912 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001913 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1914 }
1915
1916 // Save the file.
1917 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1918 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1919 UnloadPage(page);
1920
1921 // Re-open the file and check the rectangle added is still there.
Lei Zhang0b494052019-01-31 21:41:15 +00001922 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001923 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001924 ASSERT_TRUE(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001925 EXPECT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(saved_page));
1926 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001927 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001928 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1929 }
1930
1931 // Remove the added rectangle.
1932 FPDF_PAGEOBJECT added_object =
1933 FPDFPage_GetObject(saved_page, kOriginalObjectCount);
1934 EXPECT_TRUE(FPDFPage_RemoveObject(saved_page, added_object));
1935 FPDFPageObj_Destroy(added_object);
1936 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001937 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001938 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001939 }
1940 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1941
1942 // Save the file again.
1943 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
Lei Zhang38e2b0e2021-11-05 00:28:05 +00001944 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001945
1946 CloseSavedPage(saved_page);
1947 CloseSavedDocument();
1948
1949 // Re-open the file (again) and check the black rectangle was removed and the
1950 // rest is intact.
Lei Zhang0b494052019-01-31 21:41:15 +00001951 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001952 saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001953 ASSERT_TRUE(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001954 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1955 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001956 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001957 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001958 }
1959
1960 CloseSavedPage(saved_page);
1961 CloseSavedDocument();
1962}
1963
Lei Zhangab41f252018-12-23 03:10:50 +00001964TEST_F(FPDFEditEmbedderTest, AddAndRemovePaths) {
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001965 // Start with a blank page.
1966 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
1967 ASSERT_TRUE(page);
1968
1969 // Render the blank page and verify it's a blank bitmap.
Hui Yingstb4baceb2020-04-28 23:46:10 +00001970 using pdfium::kBlankPage612By792Checksum;
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001971 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001972 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001973 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001974 }
1975 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1976
1977 // Add a red rectangle.
1978 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
1979 ASSERT_TRUE(red_rect);
Lei Zhang3475b482019-05-13 18:30:57 +00001980 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001981 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1982 FPDFPage_InsertObject(page, red_rect);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001983 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001984 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001985 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001986 }
1987 EXPECT_EQ(1, FPDFPage_CountObjects(page));
1988
1989 // Remove rectangle and verify it does not render anymore and the bitmap is
1990 // back to a blank one.
1991 EXPECT_TRUE(FPDFPage_RemoveObject(page, red_rect));
1992 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001993 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001994 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001995 }
1996 EXPECT_EQ(0, FPDFPage_CountObjects(page));
1997
1998 // Trying to remove an object not in the page should return false.
1999 EXPECT_FALSE(FPDFPage_RemoveObject(page, red_rect));
2000
2001 FPDF_ClosePage(page);
2002 FPDFPageObj_Destroy(red_rect);
2003}
2004
Lei Zhangab41f252018-12-23 03:10:50 +00002005TEST_F(FPDFEditEmbedderTest, PathsPoints) {
Miklos Vajna12abfd02017-09-15 07:49:03 +02002006 CreateNewDocument();
Lei Zhang38e2b0e2021-11-05 00:28:05 +00002007 FPDF_PAGEOBJECT img = FPDFPageObj_NewImageObj(document());
Miklos Vajna12abfd02017-09-15 07:49:03 +02002008 // This should fail gracefully, even if img is not a path.
Miklos Vajna0150a542017-09-21 21:46:56 +02002009 ASSERT_EQ(-1, FPDFPath_CountSegments(img));
Miklos Vajna12abfd02017-09-15 07:49:03 +02002010
2011 // This should fail gracefully, even if path is NULL.
Miklos Vajna0150a542017-09-21 21:46:56 +02002012 ASSERT_EQ(-1, FPDFPath_CountSegments(nullptr));
Miklos Vajna12abfd02017-09-15 07:49:03 +02002013
Miklos Vajna36eed872017-09-20 22:52:43 +02002014 // FPDFPath_GetPathSegment() with a non-path.
2015 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0));
2016 // FPDFPath_GetPathSegment() with a NULL path.
2017 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0));
2018 float x;
2019 float y;
2020 // FPDFPathSegment_GetPoint() with a NULL segment.
2021 EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y));
2022
2023 // FPDFPathSegment_GetType() with a NULL segment.
2024 ASSERT_EQ(FPDF_SEGMENT_UNKNOWN, FPDFPathSegment_GetType(nullptr));
2025
2026 // FPDFPathSegment_GetClose() with a NULL segment.
2027 EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr));
2028
Miklos Vajna12abfd02017-09-15 07:49:03 +02002029 FPDFPageObj_Destroy(img);
2030}
2031
Hui Yingste95d5772020-08-24 23:58:26 +00002032TEST_F(FPDFEditEmbedderTest, PathOnTopOfText) {
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002033 // Load document with some text
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002034 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002035 FPDF_PAGE page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002036 ASSERT_TRUE(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002037
2038 // Add an opaque rectangle on top of some of the text.
2039 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002040 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002041 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2042 FPDFPage_InsertObject(page, red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002043
2044 // Add a transparent triangle on top of other part of the text.
2045 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002046 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 100));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002047 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
2048 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
2049 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
2050 EXPECT_TRUE(FPDFPath_Close(black_path));
2051 FPDFPage_InsertObject(page, black_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002052
Hui Yingste95d5772020-08-24 23:58:26 +00002053 // Render and check the result.
Tom Sepeze08d2b12018-04-25 18:49:32 +00002054 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
Hui Yingste95d5772020-08-24 23:58:26 +00002055#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002056 const char kChecksum[] = "3490f699d894351a554d79e1fcdf7981";
Lei Zhang42d30c22022-01-12 19:24:43 +00002057#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002058 const char kChecksum[] = "279693baca9f48da2d75a8e289aed58e";
Hui Yingste95d5772020-08-24 23:58:26 +00002059#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002060 const char kChecksum[] = "fe415d47945c10b9cc8e9ca08887369e";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002061#endif
Hui Yingste95d5772020-08-24 23:58:26 +00002062 CompareBitmap(bitmap.get(), 200, 200, kChecksum);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002063 UnloadPage(page);
2064}
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002065
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002066TEST_F(FPDFEditEmbedderTest, EditOverExistingContent) {
wileyryae858aa42017-05-31 14:49:05 -05002067 // Load document with existing content
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002068 ASSERT_TRUE(OpenDocument("bug_717.pdf"));
wileyryae858aa42017-05-31 14:49:05 -05002069 FPDF_PAGE page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002070 ASSERT_TRUE(page);
wileyryae858aa42017-05-31 14:49:05 -05002071
2072 // Add a transparent rectangle on top of the existing content
2073 FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002074 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect2, 255, 0, 0, 100));
wileyryae858aa42017-05-31 14:49:05 -05002075 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
2076 FPDFPage_InsertObject(page, red_rect2);
2077
2078 // Add an opaque rectangle on top of the existing content
2079 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002080 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
wileyryae858aa42017-05-31 14:49:05 -05002081 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2082 FPDFPage_InsertObject(page, red_rect);
2083
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002084#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2085 const char kOriginalChecksum[] = "1e82fbdd21490cee9d3479fe6125af67";
2086#else
2087 const char kOriginalChecksum[] = "ad04e5bd0f471a9a564fb034bd0fb073";
2088#endif
Tom Sepeze08d2b12018-04-25 18:49:32 +00002089 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002090 CompareBitmap(bitmap.get(), 612, 792, kOriginalChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002091 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2092
2093 // Now save the result, closing the page and document
2094 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena3ff54002017-07-05 11:55:35 -04002095 UnloadPage(page);
wileyryae858aa42017-05-31 14:49:05 -05002096
Lei Zhang0b494052019-01-31 21:41:15 +00002097 ASSERT_TRUE(OpenSavedDocument());
Lei Zhang107fa7b2018-02-09 21:48:15 +00002098 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00002099 ASSERT_TRUE(saved_page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002100 VerifySavedRendering(saved_page, 612, 792, kOriginalChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002101
2102 ClearString();
2103 // Add another opaque rectangle on top of the existing content
2104 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002105 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 255));
wileyryae858aa42017-05-31 14:49:05 -05002106 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002107 FPDFPage_InsertObject(saved_page, green_rect);
wileyryae858aa42017-05-31 14:49:05 -05002108
2109 // Add another transparent rectangle on top of existing content
2110 FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002111 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect2, 0, 255, 0, 100));
wileyryae858aa42017-05-31 14:49:05 -05002112 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002113 FPDFPage_InsertObject(saved_page, green_rect2);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002114#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2115 const char kLastChecksum[] = "8705d023e5fec3499d1e30cf2bcc5dc1";
2116#else
2117 const char kLastChecksum[] = "4b5b00f824620f8c9b8801ebb98e1cdd";
2118#endif
Lei Zhangc113c7a2018-02-12 14:58:44 +00002119 {
Tom Sepeze08d2b12018-04-25 18:49:32 +00002120 ScopedFPDFBitmap new_bitmap = RenderSavedPage(saved_page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002121 CompareBitmap(new_bitmap.get(), 612, 792, kLastChecksum);
Lei Zhangc113c7a2018-02-12 14:58:44 +00002122 }
Lei Zhang107fa7b2018-02-09 21:48:15 +00002123 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
wileyryae858aa42017-05-31 14:49:05 -05002124
2125 // Now save the result, closing the page and document
Lei Zhang38e2b0e2021-11-05 00:28:05 +00002126 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
Dan Sinclair04e4dc82017-10-18 12:17:14 -04002127
Lei Zhang107fa7b2018-02-09 21:48:15 +00002128 CloseSavedPage(saved_page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04002129 CloseSavedDocument();
wileyryae858aa42017-05-31 14:49:05 -05002130
2131 // Render the saved result
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002132 VerifySavedDocument(612, 792, kLastChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002133}
2134
Hui Yingst041116e2021-03-01 21:27:50 +00002135// TODO(crbug.com/pdfium/1651): Fix this issue and enable the test for Skia.
2136#if defined(_SKIA_SUPPORT_)
Lei Zhang03e5e682019-09-16 19:45:55 +00002137#define MAYBE_AddStrokedPaths DISABLED_AddStrokedPaths
2138#else
2139#define MAYBE_AddStrokedPaths AddStrokedPaths
2140#endif
2141TEST_F(FPDFEditEmbedderTest, MAYBE_AddStrokedPaths) {
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002142 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -05002143 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002144
2145 // Add a large stroked rectangle (fill color should not affect it).
2146 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
Lei Zhang3475b482019-05-13 18:30:57 +00002147 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 255));
2148 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect, 0, 255, 0, 255));
2149 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(rect, 15.0f));
Miklos Vajna366df7f2018-05-22 14:27:29 +00002150
2151 float width = 0;
2152 EXPECT_TRUE(FPDFPageObj_GetStrokeWidth(rect, &width));
2153 EXPECT_EQ(15.0f, width);
2154
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002155 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
2156 FPDFPage_InsertObject(page, rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002157 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002158 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002159#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2160 static constexpr char kChecksum_1[] = "1469acf60e7647ebeb8e1fb08c5d6c7a";
2161#else
2162 static constexpr char kChecksum_1[] = "64bd31f862a89e0a9e505a5af6efd506";
2163#endif
2164 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_1);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002165 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002166
2167 // Add crossed-checkmark
2168 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
2169 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
2170 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
2171 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
2172 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
Lei Zhang3475b482019-05-13 18:30:57 +00002173 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(check, 128, 128, 128, 180));
2174 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(check, 8.35f));
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002175 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
2176 FPDFPage_InsertObject(page, check);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002177 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002178 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002179#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2180 static constexpr char kChecksum_2[] = "68b3194f74abd9d471695ce1415be43f";
2181#else
2182 static constexpr char kChecksum_2[] = "4b6f3b9d25c4e194821217d5016c3724";
2183#endif
2184 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_2);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002185 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002186
2187 // Add stroked and filled oval-ish path.
2188 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
2189 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
2190 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
2191 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
2192 EXPECT_TRUE(FPDFPath_Close(path));
Lei Zhang3475b482019-05-13 18:30:57 +00002193 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 128, 128, 100));
2194 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(path, 128, 200, 128, 150));
2195 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(path, 10.5f));
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002196 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
2197 FPDFPage_InsertObject(page, path);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002198 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002199 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002200#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2201 static constexpr char kChecksum_3[] = "ea784068651df2b9ba132ce9215e6780";
2202#else
2203 static constexpr char kChecksum_3[] = "ff3e6a22326754944cc6e56609acd73b";
2204#endif
2205 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_3);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002206 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002207 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002208}
Nicolas Pena49058402017-02-14 18:26:20 -05002209
Nicolas Pena4c48b102018-06-13 18:23:46 +00002210// Tests adding text from standard font using FPDFPageObj_NewTextObj.
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002211TEST_F(FPDFEditEmbedderTest, AddStandardFontText) {
Nicolas Pena49058402017-02-14 18:26:20 -05002212 // Start with a blank page
Lei Zhang8496d132021-07-08 04:34:34 +00002213 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
Nicolas Pena49058402017-02-14 18:26:20 -05002214
2215 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -04002216 FPDF_PAGEOBJECT text_object1 =
2217 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2218 EXPECT_TRUE(text_object1);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002219 ScopedFPDFWideString text1 = GetFPDFWideString(kBottomText);
Nicolas Penab3161852017-05-02 14:12:50 -04002220 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
Lei Zhangcfd08172021-06-30 04:11:21 +00002221 static constexpr FS_MATRIX kMatrix1{1, 0, 0, 1, 20, 20};
2222 EXPECT_TRUE(FPDFPageObj_SetMatrix(text_object1, &kMatrix1));
Lei Zhang8496d132021-07-08 04:34:34 +00002223 FPDFPage_InsertObject(page.get(), text_object1);
2224 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002225 {
Lei Zhang8496d132021-07-08 04:34:34 +00002226 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst3b6136a2020-06-09 00:39:33 +00002227 CompareBitmap(page_bitmap.get(), 612, 792, kBottomTextChecksum);
Lei Zhange039bab2019-03-18 19:57:56 +00002228
2229 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Hui Yingst3b6136a2020-06-09 00:39:33 +00002230 VerifySavedDocument(612, 792, kBottomTextChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002231 }
Nicolas Pena49058402017-02-14 18:26:20 -05002232
2233 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -04002234 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -05002235 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -04002236 EXPECT_TRUE(text_object2);
Lei Zhangf0f67682019-04-08 17:03:21 +00002237 ScopedFPDFWideString text2 =
Nicolas Penab3161852017-05-02 14:12:50 -04002238 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
2239 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2240 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
Lei Zhang8496d132021-07-08 04:34:34 +00002241 FPDFPage_InsertObject(page.get(), text_object2);
2242 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002243 {
Lei Zhang8496d132021-07-08 04:34:34 +00002244 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002245#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002246 static constexpr char md5[] = "fa64eb3808b541342496281277fad5f2";
Nicolas Pena49058402017-02-14 18:26:20 -05002247#else
Lei Zhang42d30c22022-01-12 19:24:43 +00002248#if BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002249 static constexpr char md5[] = "983baaa1f688eff7a14b1bf91c171a1a";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002250#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002251 static constexpr char md5[] = "161523e196eb5341604cd73e12c97922";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002252#endif
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002253#endif // defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Lei Zhange039bab2019-03-18 19:57:56 +00002254 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2255
2256 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2257 VerifySavedDocument(612, 792, md5);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002258 }
Nicolas Pena49058402017-02-14 18:26:20 -05002259
2260 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -04002261 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -05002262 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -04002263 EXPECT_TRUE(text_object3);
Lei Zhangf0f67682019-04-08 17:03:21 +00002264 ScopedFPDFWideString text3 = GetFPDFWideString(L"Can you read me? <:)>");
Nicolas Penab3161852017-05-02 14:12:50 -04002265 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
2266 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
Lei Zhang8496d132021-07-08 04:34:34 +00002267 FPDFPage_InsertObject(page.get(), text_object3);
2268 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002269 {
Lei Zhang8496d132021-07-08 04:34:34 +00002270 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002271#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002272 static constexpr char md5[] = "abc65660389911aab95550ca8cd97a2b";
Lei Zhang42d30c22022-01-12 19:24:43 +00002273#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002274 static constexpr char md5[] = "e0b3493c5c16e41d0d892ffb48e63fba";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002275#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002276 static constexpr char md5[] = "1fbf772dca8d82b960631e6683934964";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002277#endif
Lei Zhange039bab2019-03-18 19:57:56 +00002278 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2279
2280 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2281 VerifySavedDocument(612, 792, md5);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002282 }
Nicolas Pena49058402017-02-14 18:26:20 -05002283
Lei Zhang8da98232019-12-11 23:29:33 +00002284 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +00002285 EXPECT_TRUE(FPDFPageObj_GetMatrix(text_object3, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +00002286 EXPECT_FLOAT_EQ(1.0f, matrix.a);
2287 EXPECT_FLOAT_EQ(1.5f, matrix.b);
2288 EXPECT_FLOAT_EQ(2.0f, matrix.c);
2289 EXPECT_FLOAT_EQ(0.5f, matrix.d);
2290 EXPECT_FLOAT_EQ(200.0f, matrix.e);
2291 EXPECT_FLOAT_EQ(200.0f, matrix.f);
Miklos Vajnac765d2a2018-06-19 15:45:42 +00002292
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002293 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, nullptr));
Lei Zhang8496d132021-07-08 04:34:34 +00002294 float size = 55;
2295 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, &size));
2296 EXPECT_EQ(55, size);
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002297 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object3, &size));
2298 EXPECT_EQ(20, size);
Miklos Vajna8625d3b2018-06-26 15:12:48 +00002299
Nicolas Pena49058402017-02-14 18:26:20 -05002300 // TODO(npm): Why are there issues with text rotated by 90 degrees?
2301 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
Nicolas Pena49058402017-02-14 18:26:20 -05002302}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002303
Lei Zhang20c52152021-06-18 20:37:10 +00002304TEST_F(FPDFEditEmbedderTest, AddStandardFontTextOfSizeZero) {
2305 // Start with a blank page
2306 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2307
2308 // Add some text of size 0 to the page.
2309 FPDF_PAGEOBJECT text_object =
2310 FPDFPageObj_NewTextObj(document(), "Arial", 0.0f);
2311 EXPECT_TRUE(text_object);
2312 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
2313 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2314 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2315
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002316 float size = -1; // Make sure 'size' gets changed.
2317 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object, &size));
2318 EXPECT_EQ(0.0f, size);
Lei Zhang20c52152021-06-18 20:37:10 +00002319
2320 FPDFPage_InsertObject(page.get(), text_object);
2321 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2322 {
2323 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2324 CompareBitmap(page_bitmap.get(), 612, 792,
2325 pdfium::kBlankPage612By792Checksum);
2326
2327 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2328 VerifySavedDocument(612, 792, pdfium::kBlankPage612By792Checksum);
2329 }
2330}
2331
Daniel Hosseinian8cb6a652019-12-18 00:50:41 +00002332TEST_F(FPDFEditEmbedderTest, GetTextRenderMode) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002333 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002334 FPDF_PAGE page = LoadPage(0);
2335 ASSERT_TRUE(page);
2336 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2337
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002338 EXPECT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
Daniel Hosseinian8cb6a652019-12-18 00:50:41 +00002339 FPDFTextObj_GetTextRenderMode(nullptr));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002340
2341 FPDF_PAGEOBJECT fill = FPDFPage_GetObject(page, 0);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002342 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFTextObj_GetTextRenderMode(fill));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002343
2344 FPDF_PAGEOBJECT stroke = FPDFPage_GetObject(page, 1);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002345 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE, FPDFTextObj_GetTextRenderMode(stroke));
2346
2347 UnloadPage(page);
2348}
2349
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002350TEST_F(FPDFEditEmbedderTest, SetTextRenderMode) {
Hui Yingst609f7d62020-04-23 23:14:13 +00002351#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002352 const char kOriginalChecksum[] = "bf87e8b36380ebd96ca429213fa23a09";
2353 const char kStrokeChecksum[] = "d16eb1bb4748eeb5fb801594da70d519";
Lei Zhang42d30c22022-01-12 19:24:43 +00002354#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002355 const char kOriginalChecksum[] = "c488514ce0fc949069ff560407edacd2";
2356 const char kStrokeChecksum[] = "e06ee84aeebe926e8c980b7822027e8a";
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002357#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002358 const char kOriginalChecksum[] = "97a4fcf3c9581e19917895631af31d41";
2359 const char kStrokeChecksum[] = "e06ee84aeebe926e8c980b7822027e8a";
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002360#endif
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002361
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002362 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002363 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002364 FPDF_PAGE page = LoadPage(0);
2365 ASSERT_TRUE(page);
2366 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2367
2368 // Check the bitmap
2369 {
2370 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002371 CompareBitmap(page_bitmap.get(), 612, 446, kOriginalChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002372 }
2373
2374 // Cannot set on a null object.
2375 EXPECT_FALSE(
2376 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_UNKNOWN));
2377 EXPECT_FALSE(
2378 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_INVISIBLE));
2379
2380 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2381 ASSERT_TRUE(page_object);
2382 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
2383 FPDFTextObj_GetTextRenderMode(page_object));
2384
2385 // Cannot set UNKNOWN as a render mode.
2386 EXPECT_FALSE(FPDFTextObj_SetTextRenderMode(page_object,
2387 FPDF_TEXTRENDERMODE_UNKNOWN));
2388
2389 EXPECT_TRUE(
2390 FPDFTextObj_SetTextRenderMode(page_object, FPDF_TEXTRENDERMODE_STROKE));
2391 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2392 FPDFTextObj_GetTextRenderMode(page_object));
2393
2394 // Check that bitmap displays changed content
2395 {
2396 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002397 CompareBitmap(page_bitmap.get(), 612, 446, kStrokeChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002398 }
2399
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002400 // Save a copy.
2401 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2402 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2403
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002404 UnloadPage(page);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002405 }
Miklos Vajna1448cc12018-07-03 13:52:33 +00002406
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002407 {
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002408 // Open the saved copy and render it. Check that the changed text render
2409 // mode is kept in the saved copy.
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002410 ASSERT_TRUE(OpenSavedDocument());
2411 FPDF_PAGE saved_page = LoadSavedPage(0);
2412 ASSERT_TRUE(saved_page);
2413
2414 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, 0);
2415 EXPECT_TRUE(page_object);
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002416 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002417 FPDFTextObj_GetTextRenderMode(page_object));
2418
2419 ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002420 CompareBitmap(bitmap.get(), 612, 446, kStrokeChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002421
2422 CloseSavedPage(saved_page);
2423 CloseSavedDocument();
2424 }
Miklos Vajna1448cc12018-07-03 13:52:33 +00002425}
2426
Robert Collyer68a18a02021-09-14 01:48:22 +00002427TEST_F(FPDFEditEmbedderTest, TextFontProperties) {
2428 // bad object tests
2429 EXPECT_FALSE(FPDFTextObj_GetFont(nullptr));
2430 EXPECT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 5));
2431 EXPECT_EQ(-1, FPDFFont_GetFlags(nullptr));
2432 EXPECT_EQ(-1, FPDFFont_GetWeight(nullptr));
2433 EXPECT_FALSE(FPDFFont_GetItalicAngle(nullptr, nullptr));
2434 EXPECT_FALSE(FPDFFont_GetAscent(nullptr, 12.f, nullptr));
2435 EXPECT_FALSE(FPDFFont_GetDescent(nullptr, 12.f, nullptr));
2436 EXPECT_FALSE(FPDFFont_GetGlyphWidth(nullptr, 's', 12.f, nullptr));
2437 EXPECT_FALSE(FPDFFont_GetGlyphPath(nullptr, 's', 12.f));
2438
2439 // good object tests
2440 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2441 FPDF_PAGE page = LoadPage(0);
2442 ASSERT_TRUE(page);
2443 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2444 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2445 ASSERT_TRUE(text);
2446 float font_size;
2447 ASSERT_TRUE(FPDFTextObj_GetFontSize(text, &font_size));
2448 FPDF_FONT font = FPDFTextObj_GetFont(text);
2449 ASSERT_TRUE(font);
2450
2451 // null return pointer tests
2452 EXPECT_FALSE(FPDFFont_GetItalicAngle(font, nullptr));
2453 EXPECT_FALSE(FPDFFont_GetAscent(font, font_size, nullptr));
2454 EXPECT_FALSE(FPDFFont_GetDescent(font, font_size, nullptr));
2455 EXPECT_FALSE(FPDFFont_GetGlyphWidth(font, 's', font_size, nullptr));
2456
2457 // correct property tests
2458 {
2459 EXPECT_EQ(4, FPDFFont_GetFlags(font));
2460 EXPECT_EQ(400, FPDFFont_GetWeight(font));
2461
2462 int angle;
2463 EXPECT_TRUE(FPDFFont_GetItalicAngle(font, &angle));
2464 EXPECT_EQ(0, angle);
2465
2466 float ascent;
2467 EXPECT_TRUE(FPDFFont_GetAscent(font, font_size, &ascent));
2468 EXPECT_FLOAT_EQ(891 * font_size / 1000.0f, ascent);
2469
2470 float descent;
2471 EXPECT_TRUE(FPDFFont_GetDescent(font, font_size, &descent));
2472 EXPECT_FLOAT_EQ(-216 * font_size / 1000.0f, descent);
2473
2474 float a12;
2475 float a24;
2476 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 12.0f, &a12));
2477 EXPECT_FLOAT_EQ(a12, 5.316f);
2478 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 24.0f, &a24));
2479 EXPECT_FLOAT_EQ(a24, 10.632f);
2480 }
2481
2482 {
2483 // FPDFFont_GetFontName() positive testing.
2484 unsigned long size = FPDFFont_GetFontName(font, nullptr, 0);
2485 const char kExpectedFontName[] = "Liberation Serif";
2486 ASSERT_EQ(sizeof(kExpectedFontName), size);
2487 std::vector<char> font_name(size);
2488 ASSERT_EQ(size, FPDFFont_GetFontName(font, font_name.data(), size));
2489 ASSERT_STREQ(kExpectedFontName, font_name.data());
2490
2491 // FPDFFont_GetFontName() negative testing.
2492 ASSERT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 0));
2493
2494 font_name.resize(2);
2495 font_name[0] = 'x';
2496 font_name[1] = '\0';
2497 size = FPDFFont_GetFontName(font, font_name.data(), font_name.size());
2498 ASSERT_EQ(sizeof(kExpectedFontName), size);
2499 ASSERT_STREQ("x", font_name.data());
2500 }
2501
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002502 {
2503 // FPDFFont_GetFontData() positive testing.
2504 constexpr size_t kExpectedSize = 8268;
2505 std::vector<uint8_t> buf;
2506 size_t buf_bytes_required = 123;
2507 ASSERT_TRUE(FPDFFont_GetFontData(font, nullptr, 0, &buf_bytes_required));
2508 ASSERT_EQ(kExpectedSize, buf_bytes_required);
2509
2510 buf.resize(kExpectedSize);
2511 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2512 buf_bytes_required = 234;
2513 // Test with buffer that is too small. Make sure `buf` is unchanged.
2514 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size() - 1,
2515 &buf_bytes_required));
2516 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2517 EXPECT_EQ(kExpectedSize, buf_bytes_required);
2518
2519 // Test with buffer of the correct size.
2520 buf_bytes_required = 234;
2521 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size(),
2522 &buf_bytes_required));
2523 EXPECT_EQ("1a67be75f719b6c476804d85bb9e4844", GenerateMD5Base16(buf));
2524 EXPECT_EQ(kExpectedSize, buf_bytes_required);
2525
2526 // FPDFFont_GetFontData() negative testing.
2527 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, nullptr, 0, nullptr));
2528 EXPECT_FALSE(FPDFFont_GetFontData(font, nullptr, 0, nullptr));
2529
2530 buf_bytes_required = 345;
2531 EXPECT_FALSE(
2532 FPDFFont_GetFontData(nullptr, nullptr, 0, &buf_bytes_required));
2533 EXPECT_EQ(345u, buf_bytes_required);
2534
2535 EXPECT_FALSE(
2536 FPDFFont_GetFontData(nullptr, buf.data(), buf.size(), nullptr));
2537 EXPECT_FALSE(FPDFFont_GetFontData(font, buf.data(), buf.size(), nullptr));
2538
2539 buf_bytes_required = 345;
2540 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, buf.data(), buf.size(),
2541 &buf_bytes_required));
2542 EXPECT_EQ(345u, buf_bytes_required);
2543 }
2544
2545 UnloadPage(page);
2546}
2547
2548TEST_F(FPDFEditEmbedderTest, NoEmbeddedFontData) {
2549 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2550 FPDF_PAGE page = LoadPage(0);
2551 ASSERT_TRUE(page);
2552 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2553
2554 // Since hello_world.pdf does not embed any font data, FPDFFont_GetFontData()
2555 // will return the substitution font data. Since pdfium_embeddertest is
2556 // hermetic, this first object consistently maps to Tinos-Regular.ttf.
2557 constexpr size_t kTinosRegularSize = 469968;
2558 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2559 ASSERT_TRUE(text);
2560 FPDF_FONT font = FPDFTextObj_GetFont(text);
2561 ASSERT_TRUE(font);
2562 std::vector<uint8_t> buf;
2563 buf.resize(kTinosRegularSize);
2564 size_t buf_bytes_required;
2565 ASSERT_TRUE(
2566 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2567 EXPECT_EQ(kTinosRegularSize, buf_bytes_required);
2568 EXPECT_EQ("2b019558f2c2de0b7cbc0a6e64b20599", GenerateMD5Base16(buf));
2569
2570 // Similarly, the second object consistently maps to Arimo-Regular.ttf.
2571 constexpr size_t kArimoRegularSize = 436180;
2572 text = FPDFPage_GetObject(page, 1);
2573 ASSERT_TRUE(text);
2574 font = FPDFTextObj_GetFont(text);
2575 ASSERT_TRUE(font);
2576 buf.resize(kArimoRegularSize);
2577 ASSERT_TRUE(
2578 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2579 EXPECT_EQ(kArimoRegularSize, buf_bytes_required);
2580 EXPECT_EQ("7ac02a544211773d9636e056e9da6c35", GenerateMD5Base16(buf));
2581
Robert Collyer68a18a02021-09-14 01:48:22 +00002582 UnloadPage(page);
2583}
2584
2585TEST_F(FPDFEditEmbedderTest, GlyphPaths) {
2586 // bad glyphpath
2587 EXPECT_EQ(-1, FPDFGlyphPath_CountGlyphSegments(nullptr));
2588 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(nullptr, 1));
2589
2590 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2591 FPDF_PAGE page = LoadPage(0);
2592 ASSERT_TRUE(page);
2593 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2594 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2595 ASSERT_TRUE(text);
2596 FPDF_FONT font = FPDFTextObj_GetFont(text);
2597 ASSERT_TRUE(font);
2598
2599 // good glyphpath
2600 FPDF_GLYPHPATH gpath = FPDFFont_GetGlyphPath(font, 's', 12.0f);
2601 ASSERT_TRUE(gpath);
2602
2603 int count = FPDFGlyphPath_CountGlyphSegments(gpath);
2604 ASSERT_GT(count, 0);
2605 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, -1));
2606 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, count));
2607
2608 FPDF_PATHSEGMENT segment = FPDFGlyphPath_GetGlyphPathSegment(gpath, 1);
2609 ASSERT_TRUE(segment);
2610 EXPECT_EQ(FPDF_SEGMENT_BEZIERTO, FPDFPathSegment_GetType(segment));
2611
2612 UnloadPage(page);
2613}
2614
Lei Zhang4363dab2021-06-24 19:23:09 +00002615TEST_F(FPDFEditEmbedderTest, FormGetObjects) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002616 ASSERT_TRUE(OpenDocument("form_object.pdf"));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002617 FPDF_PAGE page = LoadPage(0);
2618 ASSERT_TRUE(page);
2619 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2620
2621 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002622 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002623 ASSERT_EQ(-1, FPDFFormObj_CountObjects(nullptr));
2624 ASSERT_EQ(2, FPDFFormObj_CountObjects(form));
2625
Miklos Vajna1d273f12018-07-16 19:20:36 +00002626 // FPDFFormObj_GetObject() positive testing.
2627 FPDF_PAGEOBJECT text1 = FPDFFormObj_GetObject(form, 0);
2628 ASSERT_TRUE(text1);
2629 float left = 0;
2630 float bottom = 0;
2631 float right = 0;
2632 float top = 0;
2633 ASSERT_TRUE(FPDFPageObj_GetBounds(text1, &left, &bottom, &right, &top));
2634 ASSERT_EQ(271, static_cast<int>(top));
2635
2636 FPDF_PAGEOBJECT text2 = FPDFFormObj_GetObject(form, 1);
2637 ASSERT_TRUE(text2);
2638 ASSERT_TRUE(FPDFPageObj_GetBounds(text2, &left, &bottom, &right, &top));
2639 ASSERT_EQ(221, static_cast<int>(top));
2640
2641 // FPDFFormObj_GetObject() negative testing.
2642 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(nullptr, 0));
2643 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
2644 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
2645
Lei Zhangc8601bf2021-06-29 23:19:27 +00002646 // FPDFPageObj_GetMatrix() positive testing for forms.
Lei Zhang8da98232019-12-11 23:29:33 +00002647 static constexpr FS_MATRIX kMatrix = {1.0f, 1.5f, 2.0f, 2.5f, 100.0f, 200.0f};
Lei Zhang2193da92021-06-30 01:03:07 +00002648 EXPECT_TRUE(FPDFPageObj_SetMatrix(form, &kMatrix));
Miklos Vajna46b43732018-08-14 19:15:43 +00002649
Lei Zhang8da98232019-12-11 23:29:33 +00002650 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +00002651 EXPECT_TRUE(FPDFPageObj_GetMatrix(form, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +00002652 EXPECT_FLOAT_EQ(kMatrix.a, matrix.a);
2653 EXPECT_FLOAT_EQ(kMatrix.b, matrix.b);
2654 EXPECT_FLOAT_EQ(kMatrix.c, matrix.c);
2655 EXPECT_FLOAT_EQ(kMatrix.d, matrix.d);
2656 EXPECT_FLOAT_EQ(kMatrix.e, matrix.e);
2657 EXPECT_FLOAT_EQ(kMatrix.f, matrix.f);
Miklos Vajna46b43732018-08-14 19:15:43 +00002658
Lei Zhangc8601bf2021-06-29 23:19:27 +00002659 // FPDFPageObj_GetMatrix() negative testing for forms.
2660 EXPECT_FALSE(FPDFPageObj_GetMatrix(form, nullptr));
Miklos Vajna46b43732018-08-14 19:15:43 +00002661
Miklos Vajnab66077d2018-07-11 13:25:02 +00002662 UnloadPage(page);
2663}
2664
Lei Zhang4363dab2021-06-24 19:23:09 +00002665TEST_F(FPDFEditEmbedderTest, ModifyFormObject) {
2666#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002667 const char kOrigChecksum[] = "e15086e54078e4d22fa3fb12105c579e";
2668 const char kNewChecksum[] = "7282fe98693c0a7ad2c1b3f3f9563977";
Lei Zhang42d30c22022-01-12 19:24:43 +00002669#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002670 const char kOrigChecksum[] = "a637057185f50aac1aa5490f726aef95";
2671 const char kNewChecksum[] = "8ad9d79b02b609ff734e2a2195c96e2d";
Lei Zhang4363dab2021-06-24 19:23:09 +00002672#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002673 const char kOrigChecksum[] = "34a9ec0a9581a7970e073c0bcc4ca676";
2674 const char kNewChecksum[] = "609b5632a21c886fa93182dbc290bf7a";
2675#endif
Lei Zhang4363dab2021-06-24 19:23:09 +00002676
2677 ASSERT_TRUE(OpenDocument("form_object.pdf"));
2678 FPDF_PAGE page = LoadPage(0);
2679 ASSERT_TRUE(page);
2680 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2681
2682 {
2683 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2684 CompareBitmap(bitmap.get(), 62, 69, kOrigChecksum);
2685 }
2686
2687 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
2688 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
2689
Lei Zhang651113b2021-06-25 20:03:25 +00002690 FPDFPageObj_Transform(form, 0.5, 0, 0, 0.5, 0, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002691 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2692
2693 {
2694 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2695 CompareBitmap(bitmap.get(), 62, 69, kNewChecksum);
2696 }
2697
Lei Zhang4363dab2021-06-24 19:23:09 +00002698 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhangac7f0e12021-06-24 19:38:00 +00002699 VerifySavedDocument(62, 69, kNewChecksum);
Lei Zhang4363dab2021-06-24 19:23:09 +00002700
2701 UnloadPage(page);
2702}
2703
Nicolas Pena4c48b102018-06-13 18:23:46 +00002704// Tests adding text from standard font using FPDFText_LoadStandardFont.
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002705TEST_F(FPDFEditEmbedderTest, AddStandardFontText2) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002706 // Start with a blank page
2707 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2708
2709 // Load a standard font.
Tom Sepezffff6c52019-07-30 21:56:19 +00002710 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002711 ASSERT_TRUE(font);
2712
2713 // Add some text to the page.
2714 FPDF_PAGEOBJECT text_object =
Tom Sepezffff6c52019-07-30 21:56:19 +00002715 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002716 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002717 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002718 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2719 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2720 FPDFPage_InsertObject(page.get(), text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00002721 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst3b6136a2020-06-09 00:39:33 +00002722 CompareBitmap(page_bitmap.get(), 612, 792, kBottomTextChecksum);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002723}
2724
Lei Zhangab41f252018-12-23 03:10:50 +00002725TEST_F(FPDFEditEmbedderTest, LoadStandardFonts) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002726 CreateNewDocument();
Lei Zhang590f4242019-05-15 20:57:26 +00002727 static constexpr const char* kStandardFontNames[] = {
Lei Zhangd72fd582018-07-27 19:37:27 +00002728 "Arial",
2729 "Arial-Bold",
2730 "Arial-BoldItalic",
2731 "Arial-Italic",
2732 "Courier",
2733 "Courier-BoldOblique",
2734 "Courier-Oblique",
2735 "Courier-Bold",
2736 "CourierNew",
2737 "CourierNew-Bold",
2738 "CourierNew-BoldItalic",
2739 "CourierNew-Italic",
2740 "Helvetica",
2741 "Helvetica-Bold",
2742 "Helvetica-BoldOblique",
2743 "Helvetica-Oblique",
2744 "Symbol",
2745 "TimesNewRoman",
2746 "TimesNewRoman-Bold",
2747 "TimesNewRoman-BoldItalic",
2748 "TimesNewRoman-Italic",
2749 "ZapfDingbats"};
Lei Zhang590f4242019-05-15 20:57:26 +00002750 for (const char* font_name : kStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002751 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002752 EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
2753 }
Lei Zhang590f4242019-05-15 20:57:26 +00002754 static constexpr const char* kNotStandardFontNames[] = {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002755 "Abcdefg", "ArialB", "Arial-Style",
2756 "Font Name", "FontArial", "NotAStandardFontName",
2757 "TestFontName", "Quack", "Symbol-Italic",
2758 "Zapf"};
Lei Zhang590f4242019-05-15 20:57:26 +00002759 for (const char* font_name : kNotStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002760 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002761 EXPECT_FALSE(font) << font_name
2762 << " should not be considered a standard font.";
2763 }
2764}
2765
Lei Zhangab41f252018-12-23 03:10:50 +00002766TEST_F(FPDFEditEmbedderTest, GraphicsData) {
Nicolas Pena603a31d2017-06-14 11:41:18 -04002767 // New page
Tom Sepeze08d2b12018-04-25 18:49:32 +00002768 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002769
2770 // Create a rect with nontrivial graphics
2771 FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2772 FPDFPageObj_SetBlendMode(rect1, "Color");
2773 FPDFPage_InsertObject(page.get(), rect1);
2774 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2775
2776 // Check that the ExtGState was created
Lei Zhang107fa7b2018-02-09 21:48:15 +00002777 CPDF_Page* cpage = CPDFPageFromFPDFPage(page.get());
Tom Sepezc8155092021-04-26 23:37:42 +00002778 const CPDF_Dictionary* graphics_dict =
2779 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Pena603a31d2017-06-14 11:41:18 -04002780 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002781 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002782
2783 // Add a text object causing no change to the graphics dictionary
2784 FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2785 // Only alpha, the last component, matters for the graphics dictionary. And
2786 // the default value is 255.
Lei Zhang3475b482019-05-13 18:30:57 +00002787 EXPECT_TRUE(FPDFPageObj_SetFillColor(text1, 100, 100, 100, 255));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002788 FPDFPage_InsertObject(page.get(), text1);
2789 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002790 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002791
2792 // Add a text object increasing the size of the graphics dictionary
2793 FPDF_PAGEOBJECT text2 =
2794 FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
2795 FPDFPage_InsertObject(page.get(), text2);
2796 FPDFPageObj_SetBlendMode(text2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002797 EXPECT_TRUE(FPDFPageObj_SetFillColor(text2, 0, 0, 255, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002798 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002799 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002800
2801 // Add a path that should reuse graphics
Nicolas Penace67be42017-06-14 14:52:49 -04002802 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
Nicolas Pena603a31d2017-06-14 11:41:18 -04002803 FPDFPageObj_SetBlendMode(path, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002804 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 200, 100, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002805 FPDFPage_InsertObject(page.get(), path);
2806 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002807 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002808
2809 // Add a rect increasing the size of the graphics dictionary
2810 FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2811 FPDFPageObj_SetBlendMode(rect2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002812 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect2, 0, 0, 255, 150));
2813 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect2, 0, 0, 0, 200));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002814 FPDFPage_InsertObject(page.get(), rect2);
2815 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002816 EXPECT_EQ(4u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002817}
2818
Lei Zhangab41f252018-12-23 03:10:50 +00002819TEST_F(FPDFEditEmbedderTest, DoubleGenerating) {
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002820 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -05002821 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002822
2823 // Add a red rectangle with some non-default alpha
2824 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
Lei Zhang3475b482019-05-13 18:30:57 +00002825 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 128));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002826 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
2827 FPDFPage_InsertObject(page, rect);
2828 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2829
2830 // Check the ExtGState
Lei Zhang107fa7b2018-02-09 21:48:15 +00002831 CPDF_Page* cpage = CPDFPageFromFPDFPage(page);
Tom Sepezc8155092021-04-26 23:37:42 +00002832 const CPDF_Dictionary* graphics_dict =
2833 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002834 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002835 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002836
2837 // Check the bitmap
Lei Zhang107fa7b2018-02-09 21:48:15 +00002838 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002839 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002840 CompareBitmap(page_bitmap.get(), 612, 792,
2841 "5384da3406d62360ffb5cac4476fff1c");
2842 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002843
2844 // Never mind, my new favorite color is blue, increase alpha
Lei Zhang3475b482019-05-13 18:30:57 +00002845 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 0, 0, 255, 180));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002846 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002847 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002848
2849 // Check that bitmap displays changed content
Lei Zhang107fa7b2018-02-09 21:48:15 +00002850 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002851 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002852 CompareBitmap(page_bitmap.get(), 612, 792,
2853 "2e51656f5073b0bee611d9cd086aa09c");
2854 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002855
2856 // And now generate, without changes
2857 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002858 EXPECT_EQ(3u, graphics_dict->size());
Lei Zhang107fa7b2018-02-09 21:48:15 +00002859 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002860 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002861 CompareBitmap(page_bitmap.get(), 612, 792,
2862 "2e51656f5073b0bee611d9cd086aa09c");
2863 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002864
2865 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -04002866 FPDF_PAGEOBJECT text_object =
2867 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00002868 ScopedFPDFWideString text =
Nicolas Penab3161852017-05-02 14:12:50 -04002869 GetFPDFWideString(L"Something something #text# something");
2870 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2871 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
2872 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002873 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepezc8155092021-04-26 23:37:42 +00002874 const CPDF_Dictionary* font_dict = cpage->GetResources()->GetDictFor("Font");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002875 ASSERT_TRUE(font_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002876 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002877
2878 // Generate yet again, check dicts are reasonably sized
2879 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002880 EXPECT_EQ(3u, graphics_dict->size());
2881 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002882 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002883}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002884
Lei Zhangab41f252018-12-23 03:10:50 +00002885TEST_F(FPDFEditEmbedderTest, LoadSimpleType1Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002886 CreateNewDocument();
2887 // TODO(npm): use other fonts after disallowing loading any font as any type
Tom Sepezffff6c52019-07-30 21:56:19 +00002888 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002889 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Tom Sepez20c41a52018-08-29 23:53:53 +00002890 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2891 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2892 FPDF_FONT_TYPE1, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002893 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002894 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002895 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002896
Lei Zhang710fa992018-05-25 16:24:48 +00002897 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002898 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2899 EXPECT_EQ("Type1", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002900 EXPECT_EQ("Tinos-Bold", font_dict->GetNameFor("BaseFont"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002901 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2902 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2903 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002904 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
2905
Lei Zhangde579ab2018-05-25 21:49:49 +00002906 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002907 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002908 ASSERT_EQ(224u, widths_array->size());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002909 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -05002910 EXPECT_EQ(569, widths_array->GetNumberAt(11));
2911 EXPECT_EQ(500, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002912 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002913}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002914
Lei Zhangab41f252018-12-23 03:10:50 +00002915TEST_F(FPDFEditEmbedderTest, LoadSimpleTrueTypeFont) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002916 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002917 RetainPtr<CPDF_Font> stock_font =
2918 CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Tom Sepez20c41a52018-08-29 23:53:53 +00002919 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2920 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2921 FPDF_FONT_TRUETYPE, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002922 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002923 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002924 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002925
Lei Zhang710fa992018-05-25 16:24:48 +00002926 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002927 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2928 EXPECT_EQ("TrueType", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002929 EXPECT_EQ("Cousine-Regular", font_dict->GetNameFor("BaseFont"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002930 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2931 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2932 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
2933 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002934
Lei Zhangde579ab2018-05-25 21:49:49 +00002935 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002936 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002937 ASSERT_EQ(224u, widths_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002938 EXPECT_EQ(600, widths_array->GetNumberAt(33));
2939 EXPECT_EQ(600, widths_array->GetNumberAt(74));
2940 EXPECT_EQ(600, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002941 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002942}
2943
Lei Zhangab41f252018-12-23 03:10:50 +00002944TEST_F(FPDFEditEmbedderTest, LoadCIDType0Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002945 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002946 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002947 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Tom Sepez20c41a52018-08-29 23:53:53 +00002948 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2949 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2950 FPDF_FONT_TYPE1, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04002951 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002952 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002953 EXPECT_TRUE(typed_font->IsCIDFont());
2954
2955 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00002956 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002957 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2958 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002959 EXPECT_EQ("Tinos-Regular-Identity-H", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00002960 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00002961 const CPDF_Array* descendant_array =
2962 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05002963 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002964 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002965
2966 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00002967 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00002968 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
2969 EXPECT_EQ("CIDFontType0", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002970 EXPECT_EQ("Tinos-Regular", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00002971 const CPDF_Dictionary* cidinfo_dict =
2972 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05002973 ASSERT_TRUE(cidinfo_dict);
Lei Zhang9c950b12019-01-16 19:06:37 +00002974 const CPDF_Object* registry = cidinfo_dict->GetObjectFor("Registry");
2975 ASSERT_TRUE(registry);
KDr28da0e1b2019-01-17 03:44:29 +00002976 EXPECT_EQ(CPDF_Object::kString, registry->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002977 EXPECT_EQ("Adobe", registry->GetString());
2978 const CPDF_Object* ordering = cidinfo_dict->GetObjectFor("Ordering");
2979 ASSERT_TRUE(ordering);
KDr28da0e1b2019-01-17 03:44:29 +00002980 EXPECT_EQ(CPDF_Object::kString, ordering->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002981 EXPECT_EQ("Identity", ordering->GetString());
Nicolas Penad03ca422017-03-06 13:54:33 -05002982 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00002983 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002984
2985 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00002986 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05002987 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002988 EXPECT_GT(widths_array->size(), 1u);
Nicolas Penad03ca422017-03-06 13:54:33 -05002989 CheckCompositeFontWidths(widths_array, typed_font);
2990}
2991
Lei Zhangab41f252018-12-23 03:10:50 +00002992TEST_F(FPDFEditEmbedderTest, LoadCIDType2Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002993 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002994 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002995 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Tom Sepez20c41a52018-08-29 23:53:53 +00002996 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2997 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2998 FPDF_FONT_TRUETYPE, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04002999 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00003000 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05003001 EXPECT_TRUE(typed_font->IsCIDFont());
3002
3003 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00003004 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00003005 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3006 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00003007 EXPECT_EQ("Arimo-Italic", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00003008 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00003009 const CPDF_Array* descendant_array =
3010 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05003011 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00003012 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05003013
3014 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00003015 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00003016 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
3017 EXPECT_EQ("CIDFontType2", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00003018 EXPECT_EQ("Arimo-Italic", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00003019 const CPDF_Dictionary* cidinfo_dict =
3020 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05003021 ASSERT_TRUE(cidinfo_dict);
3022 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
3023 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
3024 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00003025 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05003026
3027 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00003028 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05003029 ASSERT_TRUE(widths_array);
3030 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -05003031}
rbpotterce8e51e2017-04-28 12:42:47 -07003032
Lei Zhangab41f252018-12-23 03:10:50 +00003033TEST_F(FPDFEditEmbedderTest, NormalizeNegativeRotation) {
rbpotterce8e51e2017-04-28 12:42:47 -07003034 // Load document with a -90 degree rotation
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003035 ASSERT_TRUE(OpenDocument("bug_713197.pdf"));
rbpotterce8e51e2017-04-28 12:42:47 -07003036 FPDF_PAGE page = LoadPage(0);
3037 EXPECT_NE(nullptr, page);
3038
3039 EXPECT_EQ(3, FPDFPage_GetRotation(page));
3040 UnloadPage(page);
3041}
Nicolas Penab3161852017-05-02 14:12:50 -04003042
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003043TEST_F(FPDFEditEmbedderTest, AddTrueTypeFontText) {
Nicolas Penab3161852017-05-02 14:12:50 -04003044 // Start with a blank page
3045 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3046 {
Tom Sepezffff6c52019-07-30 21:56:19 +00003047 RetainPtr<CPDF_Font> stock_font =
3048 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00003049 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3050 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3051 FPDF_FONT_TRUETYPE, 0));
Nicolas Penab3161852017-05-02 14:12:50 -04003052 ASSERT_TRUE(font.get());
3053
3054 // Add some text to the page
3055 FPDF_PAGEOBJECT text_object =
3056 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3057 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003058 ScopedFPDFWideString text = GetFPDFWideString(kLoadedFontText);
Nicolas Penab3161852017-05-02 14:12:50 -04003059 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3060 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3061 FPDFPage_InsertObject(page, text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00003062 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003063 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003064
3065 // Add some more text, same font
3066 FPDF_PAGEOBJECT text_object2 =
3067 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00003068 ScopedFPDFWideString text2 = GetFPDFWideString(L"Bigger font size");
Nicolas Penab3161852017-05-02 14:12:50 -04003069 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3070 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
3071 FPDFPage_InsertObject(page, text_object2);
Nicolas Penab3161852017-05-02 14:12:50 -04003072 }
Lei Zhang30ff2532019-01-31 21:37:55 +00003073 ScopedFPDFBitmap page_bitmap2 = RenderPage(page);
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003074#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingste1215fc2022-03-26 22:29:08 +00003075 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhang42d30c22022-01-12 19:24:43 +00003076#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00003077 const char kInsertTrueTypeChecksum[] = "c7e2271a7f30e5b919a13ead47cea105";
Nicolas Penab3161852017-05-02 14:12:50 -04003078#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00003079 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhange4cdac52019-04-30 16:45:57 +00003080#endif
Hui Yingst3b6136a2020-06-09 00:39:33 +00003081 CompareBitmap(page_bitmap2.get(), 612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003082
Nicolas Pena207b7272017-05-26 17:37:06 -04003083 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penab3161852017-05-02 14:12:50 -04003084 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3085 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003086
Hui Yingst3b6136a2020-06-09 00:39:33 +00003087 VerifySavedDocument(612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003088}
Nicolas Penaf45ade32017-05-03 10:23:49 -04003089
Lei Zhangab41f252018-12-23 03:10:50 +00003090TEST_F(FPDFEditEmbedderTest, TransformAnnot) {
Jane Liueda65252017-06-07 11:31:27 -04003091 // Open a file with one annotation and load its first page.
3092 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
Lei Zhang75c81712018-02-08 17:22:39 +00003093 FPDF_PAGE page = LoadPage(0);
Jane Liueda65252017-06-07 11:31:27 -04003094 ASSERT_TRUE(page);
3095
Lei Zhanga21d5932018-02-05 18:28:38 +00003096 {
3097 // Add an underline annotation to the page without specifying its rectangle.
Tom Sepeze08d2b12018-04-25 18:49:32 +00003098 ScopedFPDFAnnotation annot(
Lei Zhanga21d5932018-02-05 18:28:38 +00003099 FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
3100 ASSERT_TRUE(annot);
Jane Liueda65252017-06-07 11:31:27 -04003101
Lei Zhanga21d5932018-02-05 18:28:38 +00003102 // FPDFPage_TransformAnnots() should run without errors when modifying
3103 // annotation rectangles.
3104 FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
3105 }
Jane Liueda65252017-06-07 11:31:27 -04003106 UnloadPage(page);
3107}
3108
Nicolas Penaf45ade32017-05-03 10:23:49 -04003109// TODO(npm): Add tests using Japanese fonts in other OS.
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003110#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00003111TEST_F(FPDFEditEmbedderTest, AddCIDFontText) {
Nicolas Penaf45ade32017-05-03 10:23:49 -04003112 // Start with a blank page
3113 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3114 CFX_Font CIDfont;
3115 {
3116 // First, get the data from the font
Anton Bikineev7ac13342022-01-24 21:25:15 +00003117 CIDfont.LoadSubst("Noto Sans CJK JP", true, 0, 400, 0,
3118 FX_CodePage::kShiftJIS, false);
Tom Andersond4fe5f72021-12-03 20:52:52 +00003119 EXPECT_EQ("Noto Sans CJK JP", CIDfont.GetFaceName());
Tom Sepez20c41a52018-08-29 23:53:53 +00003120 pdfium::span<const uint8_t> span = CIDfont.GetFontSpan();
Nicolas Penaf45ade32017-05-03 10:23:49 -04003121
3122 // Load the data into a FPDF_Font.
Tom Sepez20c41a52018-08-29 23:53:53 +00003123 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3124 FPDF_FONT_TRUETYPE, 1));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003125 ASSERT_TRUE(font.get());
3126
3127 // Add some text to the page
3128 FPDF_PAGEOBJECT text_object =
3129 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3130 ASSERT_TRUE(text_object);
3131 std::wstring wstr = L"ABCDEFGhijklmnop.";
Lei Zhangf0f67682019-04-08 17:03:21 +00003132 ScopedFPDFWideString text = GetFPDFWideString(wstr);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003133 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3134 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
3135 FPDFPage_InsertObject(page, text_object);
3136
3137 // And add some Japanese characters
3138 FPDF_PAGEOBJECT text_object2 =
3139 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
3140 ASSERT_TRUE(text_object2);
3141 std::wstring wstr2 =
3142 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
3143 L"\u756A";
Lei Zhangf0f67682019-04-08 17:03:21 +00003144 ScopedFPDFWideString text2 = GetFPDFWideString(wstr2);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003145 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3146 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
3147 FPDFPage_InsertObject(page, text_object2);
3148 }
3149
Nicolas Pena207b7272017-05-26 17:37:06 -04003150 // Check that the text renders properly.
Tom Andersond4fe5f72021-12-03 20:52:52 +00003151 static constexpr char md5[] = "84d31d11b76845423a2cfc1879c0fbb9";
Lei Zhang107fa7b2018-02-09 21:48:15 +00003152 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003153 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00003154 CompareBitmap(page_bitmap.get(), 612, 792, md5);
3155 }
Nicolas Penaf45ade32017-05-03 10:23:49 -04003156
3157 // Save the document, close the page.
Nicolas Pena207b7272017-05-26 17:37:06 -04003158 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003159 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3160 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003161
3162 VerifySavedDocument(612, 792, md5);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003163}
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003164#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003165
Hui Yingst29d377b2021-03-03 20:22:41 +00003166// TODO(crbug.com/pdfium/1651): Fix this issue and enable the test for Skia.
3167#if defined(_SKIA_SUPPORT_)
Lei Zhang03e5e682019-09-16 19:45:55 +00003168#define MAYBE_SaveAndRender DISABLED_SaveAndRender
3169#else
3170#define MAYBE_SaveAndRender SaveAndRender
3171#endif
3172TEST_F(FPDFEditEmbedderTest, MAYBE_SaveAndRender) {
Hui Yingst29d377b2021-03-03 20:22:41 +00003173#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
3174 static constexpr char kChecksum[] = "0e8b079e349e34f64211c495845a3529";
3175#else
3176 static constexpr char kChecksum[] = "3c20472b0552c0c22b88ab1ed8c6202b";
3177#endif
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003178 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003179 ASSERT_TRUE(OpenDocument("bug_779.pdf"));
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003180 FPDF_PAGE page = LoadPage(0);
3181 ASSERT_NE(nullptr, page);
3182
Hui Yingst29d377b2021-03-03 20:22:41 +00003183 // Now add a more complex green path.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003184 FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
Lei Zhang3475b482019-05-13 18:30:57 +00003185 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_path, 0, 255, 0, 200));
Hui Yingst29d377b2021-03-03 20:22:41 +00003186 // TODO(npm): stroking will cause the checksums to differ.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003187 EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
3188 EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
3189 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
3190 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
3191 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
3192 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
3193 EXPECT_TRUE(FPDFPath_Close(green_path));
3194 FPDFPage_InsertObject(page, green_path);
Tom Sepeze08d2b12018-04-25 18:49:32 +00003195 ScopedFPDFBitmap page_bitmap = RenderLoadedPage(page);
Hui Yingst29d377b2021-03-03 20:22:41 +00003196 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003197
3198 // Now save the result, closing the page and document
3199 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3200 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3201 UnloadPage(page);
3202 }
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003203
Hui Yingst29d377b2021-03-03 20:22:41 +00003204 VerifySavedDocument(612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003205}
Jane Liu28fb7ba2017-08-02 21:45:57 -04003206
Lei Zhangab41f252018-12-23 03:10:50 +00003207TEST_F(FPDFEditEmbedderTest, AddMark) {
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003208 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003209 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003210 FPDF_PAGE page = LoadPage(0);
3211 ASSERT_TRUE(page);
3212
Lei Zhang2697cb12019-07-03 18:14:29 +00003213 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003214
3215 // Add to the first page object a "Bounds" mark with "Position": "First".
3216 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3217 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3218 EXPECT_TRUE(mark);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003219 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3220 "Position", "First"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003221
Lei Zhang2697cb12019-07-03 18:14:29 +00003222 CheckMarkCounts(page, 1, 19, 8, 4, 9, 2);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003223
3224 // Save the file
3225 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3226 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3227 UnloadPage(page);
3228
3229 // Re-open the file and check the new mark is present.
Lei Zhang0b494052019-01-31 21:41:15 +00003230 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003231 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003232 ASSERT_TRUE(saved_page);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003233
Lei Zhang2697cb12019-07-03 18:14:29 +00003234 CheckMarkCounts(saved_page, 1, 19, 8, 4, 9, 2);
3235
3236 CloseSavedPage(saved_page);
3237 CloseSavedDocument();
3238}
3239
Hui Yingst04440af2020-07-27 22:39:02 +00003240TEST_F(FPDFEditEmbedderTest, AddMarkCompressedStream) {
Lei Zhang2697cb12019-07-03 18:14:29 +00003241 // Load document with some text in a compressed stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003242 ASSERT_TRUE(OpenDocument("hello_world_compressed_stream.pdf"));
Lei Zhang2697cb12019-07-03 18:14:29 +00003243 FPDF_PAGE page = LoadPage(0);
3244 ASSERT_TRUE(page);
3245
3246 // Render and check there are no marks.
3247 {
3248 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003249 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003250 }
3251 CheckMarkCounts(page, 0, 2, 0, 0, 0, 0);
3252
3253 // Add to the first page object a "Bounds" mark with "Position": "First".
3254 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3255 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3256 EXPECT_TRUE(mark);
3257 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3258 "Position", "First"));
3259
3260 // Render and check there is 1 mark.
3261 {
3262 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003263 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003264 }
3265 CheckMarkCounts(page, 0, 2, 0, 0, 0, 1);
3266
3267 // Save the file.
3268 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3269 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3270 UnloadPage(page);
3271
3272 // Re-open the file and check the new mark is present.
3273 ASSERT_TRUE(OpenSavedDocument());
3274 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003275 ASSERT_TRUE(saved_page);
Lei Zhang2697cb12019-07-03 18:14:29 +00003276
3277 {
3278 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003279 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003280 }
3281 CheckMarkCounts(saved_page, 0, 2, 0, 0, 0, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003282
3283 CloseSavedPage(saved_page);
3284 CloseSavedDocument();
3285}
3286
Lei Zhangab41f252018-12-23 03:10:50 +00003287TEST_F(FPDFEditEmbedderTest, SetMarkParam) {
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003288 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003289 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003290 FPDF_PAGE page = LoadPage(0);
3291 ASSERT_TRUE(page);
3292
3293 constexpr int kExpectedObjectCount = 19;
3294 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3295
3296 // Check the "Bounds" mark's "Position" param is "Last".
3297 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3298 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3299 ASSERT_TRUE(mark);
3300 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003301 unsigned long name_len = 999u;
3302 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3303 EXPECT_EQ((6u + 1u) * 2u, name_len);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003304 ASSERT_EQ(L"Bounds",
3305 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3306 unsigned long out_buffer_len;
3307 ASSERT_TRUE(FPDFPageObjMark_GetParamStringValue(
3308 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3309 ASSERT_EQ(L"Last",
3310 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3311
3312 // Set is to "End".
3313 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3314 "Position", "End"));
3315
3316 // Verify the object passed must correspond to the mark passed.
3317 FPDF_PAGEOBJECT another_page_object = FPDFPage_GetObject(page, 17);
3318 EXPECT_FALSE(FPDFPageObjMark_SetStringParam(document(), another_page_object,
3319 mark, "Position", "End"));
3320
3321 // Verify nothing else changed.
3322 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3323
3324 // Verify "Position" now maps to "End".
3325 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3326 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3327 EXPECT_EQ(L"End",
3328 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3329
3330 // Save the file
3331 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3332 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3333 UnloadPage(page);
3334
3335 // Re-open the file and cerify "Position" still maps to "End".
Lei Zhang0b494052019-01-31 21:41:15 +00003336 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003337 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003338 ASSERT_TRUE(saved_page);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003339
3340 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3341 page_object = FPDFPage_GetObject(saved_page, 18);
3342 mark = FPDFPageObj_GetMark(page_object, 1);
3343 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3344 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3345 EXPECT_EQ(L"End",
3346 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3347
3348 CloseSavedPage(saved_page);
3349 CloseSavedDocument();
3350}
3351
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003352TEST_F(FPDFEditEmbedderTest, AddMarkedText) {
Henrique Nakashima144107d2018-07-10 21:04:05 +00003353 // Start with a blank page.
3354 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3355
Tom Sepezffff6c52019-07-30 21:56:19 +00003356 RetainPtr<CPDF_Font> stock_font =
3357 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00003358 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3359 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3360 FPDF_FONT_TRUETYPE, 0));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003361 ASSERT_TRUE(font.get());
3362
3363 // Add some text to the page.
3364 FPDF_PAGEOBJECT text_object =
3365 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3366
3367 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003368 ScopedFPDFWideString text1 = GetFPDFWideString(kLoadedFontText);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003369 EXPECT_TRUE(FPDFText_SetText(text_object, text1.get()));
3370 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3371 FPDFPage_InsertObject(page, text_object);
3372
3373 // Add a mark with the tag "TestMarkName" to that text.
3374 EXPECT_EQ(0, FPDFPageObj_CountMarks(text_object));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003375 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(text_object, "Test Mark Name");
Henrique Nakashima144107d2018-07-10 21:04:05 +00003376 EXPECT_TRUE(mark);
3377 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3378 EXPECT_EQ(mark, FPDFPageObj_GetMark(text_object, 0));
3379 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003380 unsigned long name_len = 999u;
3381 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3382 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003383 std::wstring name =
3384 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003385 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003386
3387 // Add parameters:
3388 // - int "IntKey" : 42
3389 // - string "StringKey": "StringValue"
Henrique Nakashima07520f62018-07-12 19:45:29 +00003390 // - blob "BlobKey": "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0"
Lei Zhang590f4242019-05-15 20:57:26 +00003391 constexpr size_t kBlobLen = 28;
Lei Zhangd3b028b2018-11-30 22:22:00 +00003392 char block_value[kBlobLen];
3393 memcpy(block_value, "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0", kBlobLen);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003394 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003395 EXPECT_TRUE(
3396 FPDFPageObjMark_SetIntParam(document(), text_object, mark, "IntKey", 42));
3397 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), text_object, mark,
3398 "StringKey", "StringValue"));
3399 EXPECT_TRUE(FPDFPageObjMark_SetBlobParam(document(), text_object, mark,
Lei Zhangd3b028b2018-11-30 22:22:00 +00003400 "BlobKey", block_value, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003401 EXPECT_EQ(3, FPDFPageObjMark_CountParams(mark));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003402
3403 // Check the two parameters can be retrieved.
3404 EXPECT_EQ(FPDF_OBJECT_NUMBER,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003405 FPDFPageObjMark_GetParamValueType(mark, "IntKey"));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003406 int int_value;
Henrique Nakashima94230e52018-07-11 22:02:02 +00003407 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "IntKey", &int_value));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003408 EXPECT_EQ(42, int_value);
3409
3410 EXPECT_EQ(FPDF_OBJECT_STRING,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003411 FPDFPageObjMark_GetParamValueType(mark, "StringKey"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003412 unsigned long out_buffer_len = 999u;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003413 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3414 mark, "StringKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003415 EXPECT_GT(out_buffer_len, 0u);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003416 EXPECT_NE(999u, out_buffer_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003417 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3418 EXPECT_EQ(L"StringValue", name);
3419
Henrique Nakashima07520f62018-07-12 19:45:29 +00003420 EXPECT_EQ(FPDF_OBJECT_STRING,
3421 FPDFPageObjMark_GetParamValueType(mark, "BlobKey"));
3422 out_buffer_len = 0;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003423 EXPECT_TRUE(FPDFPageObjMark_GetParamBlobValue(
3424 mark, "BlobKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003425 EXPECT_EQ(kBlobLen, out_buffer_len);
Lei Zhangd3b028b2018-11-30 22:22:00 +00003426 EXPECT_EQ(0, memcmp(block_value, buffer, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003427
Lei Zhangf16376e2020-06-18 19:19:32 +00003428 // Render and check the bitmap is the expected one.
Henrique Nakashima144107d2018-07-10 21:04:05 +00003429 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003430 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003431 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003432 }
3433
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003434 // Now save the result.
3435 EXPECT_EQ(1, FPDFPage_CountObjects(page));
3436 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3437 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3438
Henrique Nakashima144107d2018-07-10 21:04:05 +00003439 FPDF_ClosePage(page);
3440
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003441 // Re-open the file and check the changes were kept in the saved .pdf.
Lei Zhang0b494052019-01-31 21:41:15 +00003442 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003443 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003444 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003445 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
3446
3447 text_object = FPDFPage_GetObject(saved_page, 0);
3448 EXPECT_TRUE(text_object);
3449 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3450 mark = FPDFPageObj_GetMark(text_object, 0);
3451 EXPECT_TRUE(mark);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003452
3453 name_len = 999u;
3454 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3455 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003456 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003457 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003458
3459 CloseSavedPage(saved_page);
3460 CloseSavedDocument();
Henrique Nakashima144107d2018-07-10 21:04:05 +00003461}
3462
Lei Zhangab41f252018-12-23 03:10:50 +00003463TEST_F(FPDFEditEmbedderTest, MarkGetName) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003464 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003465 FPDF_PAGE page = LoadPage(0);
3466 ASSERT_TRUE(page);
3467 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3468 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3469 ASSERT_TRUE(mark);
3470
3471 char buffer[256];
3472 unsigned long out_len;
3473
3474 // Show the positive cases of FPDFPageObjMark_GetName.
3475 out_len = 999u;
3476 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, nullptr, 0, &out_len));
3477 EXPECT_EQ((6u + 1u) * 2u, out_len);
3478
3479 out_len = 999u;
3480 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &out_len));
3481 EXPECT_EQ(L"Bounds",
3482 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3483 EXPECT_EQ((6u + 1u) * 2u, out_len);
3484
3485 // Show the negative cases of FPDFPageObjMark_GetName.
3486 out_len = 999u;
3487 EXPECT_FALSE(
3488 FPDFPageObjMark_GetName(nullptr, buffer, sizeof(buffer), &out_len));
3489 EXPECT_EQ(999u, out_len);
3490
3491 EXPECT_FALSE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), nullptr));
3492
3493 UnloadPage(page);
3494}
3495
Lei Zhangab41f252018-12-23 03:10:50 +00003496TEST_F(FPDFEditEmbedderTest, MarkGetParamKey) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003497 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003498 FPDF_PAGE page = LoadPage(0);
3499 ASSERT_TRUE(page);
3500 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3501 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3502 ASSERT_TRUE(mark);
3503
3504 char buffer[256];
3505 unsigned long out_len;
3506
3507 // Show the positive cases of FPDFPageObjMark_GetParamKey.
3508 out_len = 999u;
3509 EXPECT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, nullptr, 0, &out_len));
3510 EXPECT_EQ((8u + 1u) * 2u, out_len);
3511
3512 out_len = 999u;
3513 EXPECT_TRUE(
3514 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), &out_len));
3515 EXPECT_EQ(L"Position",
3516 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3517 EXPECT_EQ((8u + 1u) * 2u, out_len);
3518
3519 // Show the negative cases of FPDFPageObjMark_GetParamKey.
3520 out_len = 999u;
3521 EXPECT_FALSE(FPDFPageObjMark_GetParamKey(nullptr, 0, buffer, sizeof(buffer),
3522 &out_len));
3523 EXPECT_EQ(999u, out_len);
3524
3525 out_len = 999u;
3526 EXPECT_FALSE(
3527 FPDFPageObjMark_GetParamKey(mark, 1, buffer, sizeof(buffer), &out_len));
3528 EXPECT_EQ(999u, out_len);
3529
3530 EXPECT_FALSE(
3531 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), nullptr));
3532
3533 UnloadPage(page);
3534}
3535
Lei Zhangab41f252018-12-23 03:10:50 +00003536TEST_F(FPDFEditEmbedderTest, MarkGetIntParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003537 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003538 FPDF_PAGE page = LoadPage(0);
3539 ASSERT_TRUE(page);
3540 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 8);
3541 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 0);
3542 ASSERT_TRUE(mark);
3543
3544 int out_value;
3545
3546 // Show the positive cases of FPDFPageObjMark_GetParamIntValue.
3547 out_value = 999;
3548 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
3549 EXPECT_EQ(3, out_value);
3550
3551 // Show the negative cases of FPDFPageObjMark_GetParamIntValue.
3552 out_value = 999;
3553 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(nullptr, "Factor", &out_value));
3554 EXPECT_EQ(999, out_value);
3555
3556 out_value = 999;
3557 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "ParamThatDoesNotExist",
3558 &out_value));
3559 EXPECT_EQ(999, out_value);
3560
3561 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", nullptr));
3562
3563 page_object = FPDFPage_GetObject(page, 18);
3564 mark = FPDFPageObj_GetMark(page_object, 1);
3565 out_value = 999;
3566 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Position", &out_value));
3567 EXPECT_EQ(999, out_value);
3568
3569 UnloadPage(page);
3570}
3571
Lei Zhangab41f252018-12-23 03:10:50 +00003572TEST_F(FPDFEditEmbedderTest, MarkGetStringParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003573 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003574 FPDF_PAGE page = LoadPage(0);
3575 ASSERT_TRUE(page);
3576 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3577 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3578 ASSERT_TRUE(mark);
3579
3580 char buffer[256];
3581 unsigned long out_len;
3582
3583 // Show the positive cases of FPDFPageObjMark_GetParamStringValue.
3584 out_len = 999u;
3585 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", nullptr, 0,
3586 &out_len));
3587 EXPECT_EQ((4u + 1u) * 2u, out_len);
3588
3589 out_len = 999u;
3590 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3591 sizeof(buffer), &out_len));
3592 EXPECT_EQ(L"Last",
3593 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3594 EXPECT_EQ((4u + 1u) * 2u, out_len);
3595
3596 // Show the negative cases of FPDFPageObjMark_GetParamStringValue.
3597 out_len = 999u;
3598 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(nullptr, "Position", buffer,
3599 sizeof(buffer), &out_len));
3600 EXPECT_EQ(999u, out_len);
3601
3602 out_len = 999u;
3603 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(
3604 mark, "ParamThatDoesNotExist", buffer, sizeof(buffer), &out_len));
3605 EXPECT_EQ(999u, out_len);
3606
3607 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3608 sizeof(buffer), nullptr));
3609
3610 page_object = FPDFPage_GetObject(page, 8);
3611 mark = FPDFPageObj_GetMark(page_object, 0);
3612 out_len = 999u;
3613 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Factor", buffer,
3614 sizeof(buffer), &out_len));
3615 EXPECT_EQ(999u, out_len);
3616
3617 UnloadPage(page);
3618}
3619
Lei Zhang2c57ad82022-02-04 02:21:28 +00003620// See also FPDFStructTreeEmbedderTest.GetMarkedContentID, which traverses the
3621// marked contents using FPDF_StructTree_GetForPage() and related API.
3622TEST_F(FPDFEditEmbedderTest, TraverseMarkedContentID) {
3623 ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
3624 FPDF_PAGE page = LoadPage(0);
3625 ASSERT_TRUE(page);
3626
3627 ASSERT_EQ(2, FPDFPage_CountObjects(page));
3628 FPDF_PAGEOBJECT object1 = FPDFPage_GetObject(page, 0);
3629 ASSERT_TRUE(object1);
3630 ASSERT_EQ(1, FPDFPageObj_CountMarks(object1));
3631
3632 FPDF_PAGEOBJECTMARK mark11 = FPDFPageObj_GetMark(object1, 0);
3633 ASSERT_TRUE(mark11);
3634 unsigned long len = 0;
3635 unsigned short buf[40];
3636 ASSERT_TRUE(FPDFPageObjMark_GetName(mark11, buf, sizeof(buf), &len));
3637 EXPECT_EQ(18u, len);
3638 EXPECT_EQ(L"Artifact", GetPlatformWString(buf));
3639 ASSERT_EQ(2, FPDFPageObjMark_CountParams(mark11));
3640 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 0, buf, sizeof(buf), &len));
3641 EXPECT_EQ(10u, len);
3642 EXPECT_EQ(L"BBox", GetPlatformWString(buf));
3643 EXPECT_EQ(FPDF_OBJECT_ARRAY,
3644 FPDFPageObjMark_GetParamValueType(mark11, "BBox"));
3645 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 1, buf, sizeof(buf), &len));
3646 EXPECT_EQ(10u, len);
3647 EXPECT_EQ(L"Type", GetPlatformWString(buf));
3648 EXPECT_EQ(FPDF_OBJECT_NAME,
3649 FPDFPageObjMark_GetParamValueType(mark11, "Type"));
3650
3651 FPDF_PAGEOBJECT object2 = FPDFPage_GetObject(page, 1);
3652 ASSERT_TRUE(object2);
3653 ASSERT_EQ(2, FPDFPageObj_CountMarks(object2));
3654 EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(object2));
3655
3656 FPDF_PAGEOBJECTMARK mark21 = FPDFPageObj_GetMark(object2, 0);
3657 ASSERT_TRUE(mark21);
3658 ASSERT_TRUE(FPDFPageObjMark_GetName(mark21, buf, sizeof(buf), &len));
3659 EXPECT_EQ(14u, len);
3660 EXPECT_EQ(L"Figure", GetPlatformWString(buf));
3661 ASSERT_EQ(1, FPDFPageObjMark_CountParams(mark21));
3662 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark21, 0, buf, sizeof(buf), &len));
3663 EXPECT_EQ(10u, len);
3664 EXPECT_EQ(L"MCID", GetPlatformWString(buf));
3665 ASSERT_EQ(FPDF_OBJECT_NUMBER,
3666 FPDFPageObjMark_GetParamValueType(mark21, "MCID"));
3667 int mcid = -1;
3668 ASSERT_TRUE(FPDFPageObjMark_GetParamIntValue(mark21, "MCID", &mcid));
3669 EXPECT_EQ(0, mcid);
3670
3671 FPDF_PAGEOBJECTMARK mark22 = FPDFPageObj_GetMark(object2, 1);
3672 ASSERT_TRUE(mark22);
3673 ASSERT_TRUE(FPDFPageObjMark_GetName(mark22, buf, sizeof(buf), &len));
3674 EXPECT_EQ(18u, len);
3675 EXPECT_EQ(L"ClipSpan", GetPlatformWString(buf));
3676 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark22));
3677
3678 UnloadPage(page);
3679}
3680
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003681TEST_F(FPDFEditEmbedderTest, GetBitmap) {
Jane Liu28fb7ba2017-08-02 21:45:57 -04003682 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3683 FPDF_PAGE page = LoadPage(0);
3684 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003685 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu28fb7ba2017-08-02 21:45:57 -04003686
3687 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3688 EXPECT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3689 EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
3690
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003691 {
3692 obj = FPDFPage_GetObject(page, 33);
3693 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3694 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3695 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
Lei Zhang85166512020-07-14 23:28:56 +00003696 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003697 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003698
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003699 {
3700 obj = FPDFPage_GetObject(page, 34);
3701 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3702 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3703 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3704 CompareBitmap(bitmap.get(), 103, 75, "c8d51fa6821ceb2a67f08446ff236c40");
3705 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003706
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003707 {
3708 obj = FPDFPage_GetObject(page, 35);
3709 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3710 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3711 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3712 CompareBitmap(bitmap.get(), 92, 68, "9c6d76cb1e37ef8514f9455d759391f3");
3713 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003714
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003715 {
3716 obj = FPDFPage_GetObject(page, 36);
3717 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3718 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3719 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3720 CompareBitmap(bitmap.get(), 79, 60, "f4e72fb783a01c7b4614cdc25eaa98ac");
3721 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003722
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003723 {
3724 obj = FPDFPage_GetObject(page, 37);
3725 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3726 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3727 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3728 CompareBitmap(bitmap.get(), 126, 106, "2cf9e66414c72461f4ccbf9cdebdfa1b");
3729 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003730
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003731 {
3732 obj = FPDFPage_GetObject(page, 38);
3733 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3734 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3735 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3736 CompareBitmap(bitmap.get(), 194, 119, "a8f3a126cec274dab8242fd2ccdc1b8b");
3737 }
3738
Jane Liu28fb7ba2017-08-02 21:45:57 -04003739 UnloadPage(page);
3740}
Jane Liu548334e2017-08-03 16:33:40 -04003741
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003742TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSetMatrix) {
Lei Zhang85166512020-07-14 23:28:56 +00003743 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3744 FPDF_PAGE page = LoadPage(0);
3745 ASSERT_TRUE(page);
3746 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3747
3748 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3749 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3750
3751 {
3752 // Render |obj| as is.
3753 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3754 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3755 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3756 }
3757
3758 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003759 FS_MATRIX matrix;
3760 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3761 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3762 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3763 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3764 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3765 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3766 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003767
3768 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003769 matrix.a = 120.0;
3770 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang85166512020-07-14 23:28:56 +00003771
3772 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003773 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3774 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3775 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3776 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3777 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3778 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3779 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003780
3781 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003782 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has no
Lei Zhang85166512020-07-14 23:28:56 +00003783 // effect.
3784 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3785 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3786 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3787 }
3788
3789 UnloadPage(page);
3790}
3791
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003792TEST_F(FPDFEditEmbedderTest, GetBitmapForJBigImage) {
Lei Zhang53341dd2018-03-01 15:42:47 +00003793 ASSERT_TRUE(OpenDocument("bug_631912.pdf"));
3794 FPDF_PAGE page = LoadPage(0);
3795 ASSERT_TRUE(page);
3796 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3797
3798 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
3799 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3800 {
Tom Sepeze08d2b12018-04-25 18:49:32 +00003801 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
Lei Zhang1330ebb2018-03-05 15:16:37 +00003802 ASSERT_TRUE(bitmap);
3803 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3804 CompareBitmap(bitmap.get(), 1152, 720, "3f6a48e2b3e91b799bf34567f55cb4de");
Lei Zhang53341dd2018-03-01 15:42:47 +00003805 }
3806
3807 UnloadPage(page);
3808}
3809
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003810TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSMask) {
Lei Zhang2e1b4f22020-07-08 23:40:18 +00003811 ASSERT_TRUE(OpenDocument("matte.pdf"));
3812 FPDF_PAGE page = LoadPage(0);
3813 ASSERT_TRUE(page);
3814
3815 constexpr int kExpectedObjects = 4;
3816 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3817
3818 for (int i = 0; i < kExpectedObjects; ++i) {
3819 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3820 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3821 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3822 ASSERT_TRUE(bitmap);
3823 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3824 CompareBitmap(bitmap.get(), 50, 50, "46c9a1dbe0b44765ce46017ad629a2fe");
3825 }
3826
3827 UnloadPage(page);
3828}
3829
Hui Yingst822fb8d2020-10-05 22:10:35 +00003830// TODO(crbug.com/pdfium/11): Fix this test and enable.
3831#if defined(_SKIA_SUPPORT_)
3832#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3833 DISABLED_GetRenderedBitmapHandlesSetMatrix
3834#else
3835#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3836 GetRenderedBitmapHandlesSetMatrix
3837#endif
3838TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSetMatrix) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003839 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3840 FPDF_PAGE page = LoadPage(0);
3841 ASSERT_TRUE(page);
3842 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3843
3844 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3845 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3846
3847 {
3848 // Render |obj| as is.
3849 ScopedFPDFBitmap bitmap(
3850 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3851 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003852 CompareBitmap(bitmap.get(), 53, 43, "582ca300e003f512d7b552c7b5b45d2e");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003853 }
3854
3855 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003856 FS_MATRIX matrix;
3857 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3858 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3859 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3860 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3861 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3862 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3863 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003864
3865 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003866 matrix.a = 120.0;
3867 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003868
3869 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003870 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3871 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3872 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3873 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3874 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3875 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3876 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003877
3878 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003879 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has an
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003880 // effect.
3881 ScopedFPDFBitmap bitmap(
3882 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3883 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003884 CompareBitmap(bitmap.get(), 120, 43, "0824c16dcf2dfcef44b45d88db1fddce");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003885 }
3886
3887 UnloadPage(page);
3888}
3889
Hui Yingst822fb8d2020-10-05 22:10:35 +00003890// TODO(crbug.com/pdfium/11): Fix this test and enable.
3891#if defined(_SKIA_SUPPORT_)
3892#define MAYBE_GetRenderedBitmapHandlesSMask \
3893 DISABLED_GetRenderedBitmapHandlesSMask
3894#else
3895#define MAYBE_GetRenderedBitmapHandlesSMask GetRenderedBitmapHandlesSMask
3896#endif
3897TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSMask) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003898 ASSERT_TRUE(OpenDocument("matte.pdf"));
3899 FPDF_PAGE page = LoadPage(0);
3900 ASSERT_TRUE(page);
3901
3902 constexpr int kExpectedObjects = 4;
3903 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3904
3905 for (int i = 0; i < kExpectedObjects; ++i) {
3906 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3907 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3908 ScopedFPDFBitmap bitmap(
3909 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3910 ASSERT_TRUE(bitmap);
3911 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
3912 if (i == 0)
3913 CompareBitmap(bitmap.get(), 40, 60, "5a3ae4a660ce919e29c42ec2258142f1");
3914 else
3915 CompareBitmap(bitmap.get(), 40, 60, "67504e83f5d78214ea00efc19082c5c1");
3916 }
3917
3918 UnloadPage(page);
3919}
3920
3921TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapBadParams) {
3922 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3923 FPDF_PAGE page = LoadPage(0);
3924 ASSERT_TRUE(page);
3925
3926 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3927 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3928
3929 // Test various null parameters.
3930 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, nullptr));
3931 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), nullptr, nullptr));
3932 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, nullptr));
3933 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, obj));
3934 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), page, nullptr));
3935 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, obj));
3936
3937 // Test mismatch between document and page parameters.
3938 ScopedFPDFDocument new_document(FPDF_CreateNewDocument());
3939 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(new_document.get(), page, obj));
3940
3941 UnloadPage(page);
3942}
3943
Lei Zhangab41f252018-12-23 03:10:50 +00003944TEST_F(FPDFEditEmbedderTest, GetImageData) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003945 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liu548334e2017-08-03 16:33:40 -04003946 FPDF_PAGE page = LoadPage(0);
3947 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003948 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu548334e2017-08-03 16:33:40 -04003949
3950 // Retrieve an image object with flate-encoded data stream.
3951 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3952 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3953
3954 // Check that the raw image data has the correct length and hash value.
3955 unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
Lei Zhang0bd11f72022-05-11 00:10:54 +00003956 std::vector<uint8_t> buf(len);
Jane Liu548334e2017-08-03 16:33:40 -04003957 EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003958 EXPECT_EQ("f73802327d2e88e890f653961bcda81a", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003959
3960 // Check that the decoded image data has the correct length and hash value.
3961 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3962 buf.clear();
3963 buf.resize(len);
3964 EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003965 EXPECT_EQ(kEmbeddedImage33Checksum, GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003966
Lei Zhang351e8b02018-12-20 01:10:06 +00003967 // Retrieve an image object with DCTDecode-encoded data stream.
Jane Liu548334e2017-08-03 16:33:40 -04003968 obj = FPDFPage_GetObject(page, 37);
3969 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3970
3971 // Check that the raw image data has the correct length and hash value.
3972 len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
3973 buf.clear();
3974 buf.resize(len);
3975 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003976 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003977
3978 // Check that the decoded image data has the correct length and hash value,
3979 // which should be the same as those of the raw data, since this image is
3980 // encoded by a single DCTDecode filter and decoding is a noop.
3981 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3982 buf.clear();
3983 buf.resize(len);
3984 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003985 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003986
3987 UnloadPage(page);
3988}
Jane Liu2e5f0ae2017-08-08 15:23:27 -04003989
Lei Zhangab41f252018-12-23 03:10:50 +00003990TEST_F(FPDFEditEmbedderTest, GetImageMatrix) {
Lei Zhang866d6882018-10-24 17:31:01 +00003991 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3992 FPDF_PAGE page = LoadPage(0);
3993 ASSERT_TRUE(page);
3994 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3995
3996 FPDF_PAGEOBJECT obj;
Lei Zhangc8601bf2021-06-29 23:19:27 +00003997 FS_MATRIX matrix;
Lei Zhang866d6882018-10-24 17:31:01 +00003998
3999 obj = FPDFPage_GetObject(page, 33);
4000 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004001 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4002 EXPECT_FLOAT_EQ(53.0f, matrix.a);
4003 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4004 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4005 EXPECT_FLOAT_EQ(43.0f, matrix.d);
4006 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4007 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004008
4009 obj = FPDFPage_GetObject(page, 34);
4010 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004011 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4012 EXPECT_FLOAT_EQ(70.0f, matrix.a);
4013 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4014 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4015 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4016 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4017 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004018
4019 obj = FPDFPage_GetObject(page, 35);
4020 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004021 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4022 EXPECT_FLOAT_EQ(69.0f, matrix.a);
4023 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4024 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4025 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4026 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4027 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004028
4029 obj = FPDFPage_GetObject(page, 36);
4030 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004031 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4032 EXPECT_FLOAT_EQ(59.0f, matrix.a);
4033 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4034 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4035 EXPECT_FLOAT_EQ(45.0f, matrix.d);
4036 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4037 EXPECT_FLOAT_EQ(553.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004038
4039 obj = FPDFPage_GetObject(page, 37);
4040 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004041 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4042 EXPECT_FLOAT_EQ(55.94000244140625f, matrix.a);
4043 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4044 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4045 EXPECT_FLOAT_EQ(46.950000762939453f, matrix.d);
4046 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4047 EXPECT_FLOAT_EQ(552.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004048
4049 obj = FPDFPage_GetObject(page, 38);
4050 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004051 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4052 EXPECT_FLOAT_EQ(70.528999328613281f, matrix.a);
4053 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4054 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4055 EXPECT_FLOAT_EQ(43.149997711181641f, matrix.d);
4056 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4057 EXPECT_FLOAT_EQ(553.3599853515625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004058
4059 UnloadPage(page);
4060}
4061
Lei Zhangab41f252018-12-23 03:10:50 +00004062TEST_F(FPDFEditEmbedderTest, DestroyPageObject) {
Jane Liu2e5f0ae2017-08-08 15:23:27 -04004063 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
4064 ASSERT_TRUE(rect);
4065
4066 // There should be no memory leaks with a call to FPDFPageObj_Destroy().
4067 FPDFPageObj_Destroy(rect);
4068}
Jane Liube63ab92017-08-09 14:09:34 -04004069
Lei Zhangab41f252018-12-23 03:10:50 +00004070TEST_F(FPDFEditEmbedderTest, GetImageFilters) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00004071 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liube63ab92017-08-09 14:09:34 -04004072 FPDF_PAGE page = LoadPage(0);
4073 ASSERT_TRUE(page);
4074
4075 // Verify that retrieving the filter of a non-image object would fail.
4076 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
4077 ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4078 ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
4079 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
4080
4081 // Verify the returned filter string for an image object with a single filter.
4082 obj = FPDFPage_GetObject(page, 33);
4083 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4084 ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
4085 unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4086 std::vector<char> buf(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004087 static constexpr char kFlateDecode[] = "FlateDecode";
4088 EXPECT_EQ(sizeof(kFlateDecode),
4089 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4090 EXPECT_STREQ(kFlateDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004091 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
4092
4093 // Verify all the filters for an image object with a list of filters.
4094 obj = FPDFPage_GetObject(page, 38);
4095 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4096 ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
4097 len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4098 buf.clear();
4099 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004100 static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
4101 EXPECT_EQ(sizeof(kASCIIHexDecode),
4102 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4103 EXPECT_STREQ(kASCIIHexDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004104
4105 len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
4106 buf.clear();
4107 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004108 static constexpr char kDCTDecode[] = "DCTDecode";
4109 EXPECT_EQ(sizeof(kDCTDecode),
4110 FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
4111 EXPECT_STREQ(kDCTDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004112
4113 UnloadPage(page);
4114}
Jane Liuca898292017-08-16 11:25:35 -04004115
Lei Zhangab41f252018-12-23 03:10:50 +00004116TEST_F(FPDFEditEmbedderTest, GetImageMetadata) {
Jane Liuca898292017-08-16 11:25:35 -04004117 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4118 FPDF_PAGE page = LoadPage(0);
4119 ASSERT_TRUE(page);
4120
4121 // Check that getting the metadata of a null object would fail.
4122 FPDF_IMAGEOBJ_METADATA metadata;
4123 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
4124
4125 // Check that receiving the metadata with a null metadata object would fail.
4126 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4127 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
4128
4129 // Check that when retrieving an image object's metadata without passing in
4130 // |page|, all values are correct, with the last two being default values.
4131 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4132 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004133 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004134 EXPECT_EQ(92u, metadata.width);
4135 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004136 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4137 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004138 EXPECT_EQ(0u, metadata.bits_per_pixel);
4139 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4140
4141 // Verify the metadata of a bitmap image with indexed colorspace.
4142 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004143 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004144 EXPECT_EQ(92u, metadata.width);
4145 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004146 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4147 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004148 EXPECT_EQ(1u, metadata.bits_per_pixel);
4149 EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
4150
4151 // Verify the metadata of an image with RGB colorspace.
4152 obj = FPDFPage_GetObject(page, 37);
4153 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4154 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004155 EXPECT_EQ(9, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004156 EXPECT_EQ(126u, metadata.width);
4157 EXPECT_EQ(106u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004158 EXPECT_FLOAT_EQ(162.173752f, metadata.horizontal_dpi);
4159 EXPECT_FLOAT_EQ(162.555878f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004160 EXPECT_EQ(24u, metadata.bits_per_pixel);
4161 EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
4162
4163 UnloadPage(page);
4164}
Lei Zhangdc1b7392020-05-14 21:15:53 +00004165
4166TEST_F(FPDFEditEmbedderTest, GetImageMetadataJpxLzw) {
4167 ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
4168 FPDF_PAGE page = LoadPage(0);
4169 ASSERT_TRUE(page);
4170
4171 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4172 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4173
4174 FPDF_IMAGEOBJ_METADATA metadata;
4175 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4176 EXPECT_EQ(-1, metadata.marked_content_id);
4177 EXPECT_EQ(612u, metadata.width);
4178 EXPECT_EQ(792u, metadata.height);
4179 EXPECT_FLOAT_EQ(72.0f, metadata.horizontal_dpi);
4180 EXPECT_FLOAT_EQ(72.0f, metadata.vertical_dpi);
4181 EXPECT_EQ(24u, metadata.bits_per_pixel);
4182 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4183
4184 UnloadPage(page);
4185}