1 // Copyright 2018 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
6
7 #include <iterator>
8 #include <memory>
9 #include <utility>
10
11 #include "core/fpdfapi/page/cpdf_transferfunc.h"
12 #include "core/fpdfapi/parser/cpdf_array.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_indirect_object_holder.h"
15 #include "core/fpdfapi/parser/cpdf_number.h"
16 #include "core/fpdfapi/parser/cpdf_reference.h"
17 #include "core/fpdfapi/parser/cpdf_stream.h"
18 #include "core/fxcrt/data_vector.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 using ::testing::ElementsAreArray;
23
24 namespace {
25
26 constexpr uint8_t kExpectedType0FunctionSamples[] = {
27 0, 3, 6, 9, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43,
28 46, 49, 52, 55, 58, 60, 63, 66, 68, 71, 74, 76, 79, 81, 84,
29 86, 88, 90, 93, 95, 97, 99, 101, 103, 105, 106, 108, 110, 111, 113,
30 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 125, 126, 126, 127,
31 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123,
32 123, 122, 121, 120, 119, 117, 116, 115, 113, 112, 110, 109, 107, 105, 104,
33 102, 100, 98, 96, 94, 92, 89, 87, 85, 82, 80, 77, 75, 72, 70,
34 67, 64, 62, 59, 56, 53, 50, 48, 45, 42, 39, 36, 33, 30, 27,
35 23, 20, 17, 14, 11, 8, 5, 2, 254, 251, 248, 245, 242, 239, 236,
36 233, 229, 226, 223, 220, 217, 214, 211, 208, 206, 203, 200, 197, 194, 192,
37 189, 186, 184, 181, 179, 176, 174, 171, 169, 167, 164, 162, 160, 158, 156,
38 154, 152, 151, 149, 147, 146, 144, 143, 141, 140, 139, 137, 136, 135, 134,
39 133, 133, 132, 131, 131, 130, 130, 129, 129, 129, 129, 129, 129, 129, 129,
40 129, 129, 130, 130, 131, 131, 132, 133, 134, 135, 136, 137, 138, 139, 141,
41 142, 143, 145, 146, 148, 150, 151, 153, 155, 157, 159, 161, 163, 166, 168,
42 170, 172, 175, 177, 180, 182, 185, 188, 190, 193, 196, 198, 201, 204, 207,
43 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 243, 247, 250, 253,
44 0};
45
46 constexpr uint8_t kExpectedType2FunctionSamples[] = {
47 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
48 25, 25, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
49 24, 24, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
50 23, 23, 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
51 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
52 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
53 20, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
54 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
55 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
56 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
57 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15,
58 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14,
59 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13,
60 13, 13, 13, 13, 13, 13, 13, 13, 13};
61
62 constexpr uint8_t kExpectedType4FunctionSamples[] = {
63 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
64 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
65 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
66 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
67 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
68 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
69 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
70 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
71 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26,
72 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
73 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
74 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
75 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
76 26, 26, 26, 26, 26, 26, 26, 26, 26};
77
CreateType0FunctionStreamReference(CPDF_IndirectObjectHolder & holder)78 RetainPtr<CPDF_Reference> CreateType0FunctionStreamReference(
79 CPDF_IndirectObjectHolder& holder) {
80 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
81 func_dict->SetNewFor<CPDF_Number>("FunctionType", 0);
82 func_dict->SetNewFor<CPDF_Number>("BitsPerSample", 8);
83
84 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
85 domain_array->AppendNew<CPDF_Number>(0);
86 domain_array->AppendNew<CPDF_Number>(1);
87
88 auto range_array = func_dict->SetNewFor<CPDF_Array>("Range");
89 range_array->AppendNew<CPDF_Number>(0);
90 range_array->AppendNew<CPDF_Number>(0.5f);
91
92 auto size_array = func_dict->SetNewFor<CPDF_Array>("Size");
93 size_array->AppendNew<CPDF_Number>(4);
94
95 static constexpr uint8_t kContents[] = "1234";
96 auto stream = holder.NewIndirect<CPDF_Stream>(
97 DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
98 std::move(func_dict));
99 return pdfium::MakeRetain<CPDF_Reference>(&holder, stream->GetObjNum());
100 }
101
CreateType2FunctionDict()102 RetainPtr<CPDF_Dictionary> CreateType2FunctionDict() {
103 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
104 func_dict->SetNewFor<CPDF_Number>("FunctionType", 2);
105 func_dict->SetNewFor<CPDF_Number>("N", 1);
106
107 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
108 domain_array->AppendNew<CPDF_Number>(0);
109 domain_array->AppendNew<CPDF_Number>(1);
110
111 auto c0_array = func_dict->SetNewFor<CPDF_Array>("C0");
112 c0_array->AppendNew<CPDF_Number>(0.1f);
113 c0_array->AppendNew<CPDF_Number>(0.2f);
114 c0_array->AppendNew<CPDF_Number>(0.8f);
115
116 auto c1_array = func_dict->SetNewFor<CPDF_Array>("C1");
117 c1_array->AppendNew<CPDF_Number>(0.05f);
118 c1_array->AppendNew<CPDF_Number>(0.01f);
119 c1_array->AppendNew<CPDF_Number>(0.4f);
120
121 return func_dict;
122 }
123
CreateType4FunctionStreamReference(CPDF_IndirectObjectHolder & holder)124 RetainPtr<CPDF_Reference> CreateType4FunctionStreamReference(
125 CPDF_IndirectObjectHolder& holder) {
126 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
127 func_dict->SetNewFor<CPDF_Number>("FunctionType", 4);
128
129 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
130 domain_array->AppendNew<CPDF_Number>(0);
131 domain_array->AppendNew<CPDF_Number>(1);
132
133 auto range_array = func_dict->SetNewFor<CPDF_Array>("Range");
134 range_array->AppendNew<CPDF_Number>(-1);
135 range_array->AppendNew<CPDF_Number>(1);
136
137 static constexpr uint8_t kContents[] = "{ 360 mul sin 2 div }";
138 auto stream = holder.NewIndirect<CPDF_Stream>(
139 DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
140 std::move(func_dict));
141 return pdfium::MakeRetain<CPDF_Reference>(&holder, stream->GetObjNum());
142 }
143
CreateBadType4FunctionStream()144 RetainPtr<CPDF_Stream> CreateBadType4FunctionStream() {
145 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
146 func_dict->SetNewFor<CPDF_Number>("FunctionType", 4);
147
148 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
149 domain_array->AppendNew<CPDF_Number>(0);
150 domain_array->AppendNew<CPDF_Number>(1);
151
152 auto range_array = func_dict->SetNewFor<CPDF_Array>("Range");
153 range_array->AppendNew<CPDF_Number>(-1);
154 range_array->AppendNew<CPDF_Number>(1);
155
156 static constexpr uint8_t kContents[] = "garbage";
157 return pdfium::MakeRetain<CPDF_Stream>(
158 DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
159 std::move(func_dict));
160 }
161
162 class TestDocRenderData : public CPDF_DocRenderData {
163 public:
164 TestDocRenderData() = default;
165
CreateTransferFuncForTesting(RetainPtr<const CPDF_Object> pObj) const166 RetainPtr<CPDF_TransferFunc> CreateTransferFuncForTesting(
167 RetainPtr<const CPDF_Object> pObj) const {
168 return CreateTransferFunc(std::move(pObj));
169 }
170 };
171
TEST(CPDFDocRenderDataTest,TransferFunctionOne)172 TEST(CPDFDocRenderDataTest, TransferFunctionOne) {
173 RetainPtr<CPDF_Dictionary> func_dict = CreateType2FunctionDict();
174
175 TestDocRenderData render_data;
176 auto func = render_data.CreateTransferFuncForTesting(func_dict);
177 ASSERT_TRUE(func);
178 EXPECT_FALSE(func->GetIdentity());
179 EXPECT_THAT(func->GetSamplesR(),
180 ElementsAreArray(kExpectedType2FunctionSamples));
181 EXPECT_THAT(func->GetSamplesG(),
182 ElementsAreArray(kExpectedType2FunctionSamples));
183 EXPECT_THAT(func->GetSamplesB(),
184 ElementsAreArray(kExpectedType2FunctionSamples));
185 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0x00ffffff));
186 EXPECT_EQ(0x000d1a1au, func->TranslateColor(0x00ff0000));
187 EXPECT_EQ(0x001a0d1au, func->TranslateColor(0x0000ff00));
188 EXPECT_EQ(0x001a1a0du, func->TranslateColor(0x000000ff));
189 EXPECT_EQ(0x000f0f0fu, func->TranslateColor(0x00cccccc));
190 EXPECT_EQ(0x00191715u, func->TranslateColor(0x00123456));
191 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0xffffffff));
192 EXPECT_EQ(0x001a1a1au, func->TranslateColor(0xff000000));
193 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0xccffffff));
194 EXPECT_EQ(0x001a1a1au, func->TranslateColor(0x99000000));
195 }
196
TEST(CPDFDocRenderDataTest,TransferFunctionArray)197 TEST(CPDFDocRenderDataTest, TransferFunctionArray) {
198 CPDF_IndirectObjectHolder holder;
199 auto func_array = pdfium::MakeRetain<CPDF_Array>();
200 func_array->Append(CreateType0FunctionStreamReference(holder));
201 func_array->Append(CreateType2FunctionDict());
202 func_array->Append(CreateType4FunctionStreamReference(holder));
203
204 TestDocRenderData render_data;
205 auto func = render_data.CreateTransferFuncForTesting(func_array);
206 ASSERT_TRUE(func);
207 EXPECT_FALSE(func->GetIdentity());
208 EXPECT_THAT(func->GetSamplesR(),
209 ElementsAreArray(kExpectedType0FunctionSamples));
210 EXPECT_THAT(func->GetSamplesG(),
211 ElementsAreArray(kExpectedType2FunctionSamples));
212 EXPECT_THAT(func->GetSamplesB(),
213 ElementsAreArray(kExpectedType4FunctionSamples));
214 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0x00ffffff));
215 EXPECT_EQ(0x001a1a00u, func->TranslateColor(0x00ff0000));
216 EXPECT_EQ(0x00190d00u, func->TranslateColor(0x0000ff00));
217 EXPECT_EQ(0x00191a00u, func->TranslateColor(0x000000ff));
218 EXPECT_EQ(0x001a0f87u, func->TranslateColor(0x00cccccc));
219 EXPECT_EQ(0x0019176du, func->TranslateColor(0x00123456));
220 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0xffffffff));
221 EXPECT_EQ(0x00191a00u, func->TranslateColor(0xff000000));
222 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0xccffffff));
223 EXPECT_EQ(0x00191a00u, func->TranslateColor(0x99000000));
224 }
225
TEST(CPDFDocRenderDataTest,BadTransferFunctions)226 TEST(CPDFDocRenderDataTest, BadTransferFunctions) {
227 {
228 auto func_stream = CreateBadType4FunctionStream();
229
230 TestDocRenderData render_data;
231 auto func = render_data.CreateTransferFuncForTesting(func_stream);
232 EXPECT_FALSE(func);
233 }
234
235 {
236 auto func_array = pdfium::MakeRetain<CPDF_Array>();
237
238 TestDocRenderData render_data;
239 auto func = render_data.CreateTransferFuncForTesting(func_array);
240 EXPECT_FALSE(func);
241 }
242
243 {
244 CPDF_IndirectObjectHolder holder;
245 auto func_array = pdfium::MakeRetain<CPDF_Array>();
246 func_array->Append(CreateType0FunctionStreamReference(holder));
247 func_array->Append(CreateType2FunctionDict());
248 auto func_stream = CreateBadType4FunctionStream();
249 const int func_stream_object_number =
250 holder.AddIndirectObject(std::move(func_stream));
251 func_array->Append(
252 pdfium::MakeRetain<CPDF_Reference>(&holder, func_stream_object_number));
253
254 TestDocRenderData render_data;
255 auto func = render_data.CreateTransferFuncForTesting(func_array);
256 EXPECT_FALSE(func);
257 }
258 }
259
260 } // namespace
261