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