Use override in more classes in core/
[pdfium.git] / core / src / fpdfapi / fpdf_page / fpdf_page_func.cpp
1 // Copyright 2014 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 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include <limits.h>
8
9 #include "../../../include/fpdfapi/fpdf_module.h"
10 #include "../../../include/fpdfapi/fpdf_page.h"
11 #include "../../../include/fxcrt/fx_safe_types.h"
12 #include "../../../third_party/base/numerics/safe_conversions_impl.h"
13 #include "pageint.h"
14
15 class CPDF_PSEngine;
16 typedef enum {
17   PSOP_ADD,
18   PSOP_SUB,
19   PSOP_MUL,
20   PSOP_DIV,
21   PSOP_IDIV,
22   PSOP_MOD,
23   PSOP_NEG,
24   PSOP_ABS,
25   PSOP_CEILING,
26   PSOP_FLOOR,
27   PSOP_ROUND,
28   PSOP_TRUNCATE,
29   PSOP_SQRT,
30   PSOP_SIN,
31   PSOP_COS,
32   PSOP_ATAN,
33   PSOP_EXP,
34   PSOP_LN,
35   PSOP_LOG,
36   PSOP_CVI,
37   PSOP_CVR,
38   PSOP_EQ,
39   PSOP_NE,
40   PSOP_GT,
41   PSOP_GE,
42   PSOP_LT,
43   PSOP_LE,
44   PSOP_AND,
45   PSOP_OR,
46   PSOP_XOR,
47   PSOP_NOT,
48   PSOP_BITSHIFT,
49   PSOP_TRUE,
50   PSOP_FALSE,
51   PSOP_IF,
52   PSOP_IFELSE,
53   PSOP_POP,
54   PSOP_EXCH,
55   PSOP_DUP,
56   PSOP_COPY,
57   PSOP_INDEX,
58   PSOP_ROLL,
59   PSOP_PROC,
60   PSOP_CONST
61 } PDF_PSOP;
62 class CPDF_PSProc {
63  public:
64   ~CPDF_PSProc();
65   FX_BOOL Parse(CPDF_SimpleParser& parser);
66   FX_BOOL Execute(CPDF_PSEngine* pEngine);
67   CFX_PtrArray m_Operators;
68 };
69 #define PSENGINE_STACKSIZE 100
70 class CPDF_PSEngine {
71  public:
72   CPDF_PSEngine();
73   ~CPDF_PSEngine();
74   FX_BOOL Parse(const FX_CHAR* string, int size);
75   FX_BOOL Execute() { return m_MainProc.Execute(this); }
76   FX_BOOL DoOperator(PDF_PSOP op);
77   void Reset() { m_StackCount = 0; }
78   void Push(FX_FLOAT value);
79   void Push(int value) { Push((FX_FLOAT)value); }
80   FX_FLOAT Pop();
81   int GetStackSize() { return m_StackCount; }
82
83  private:
84   FX_FLOAT m_Stack[PSENGINE_STACKSIZE];
85   int m_StackCount;
86   CPDF_PSProc m_MainProc;
87 };
88 CPDF_PSProc::~CPDF_PSProc() {
89   int size = m_Operators.GetSize();
90   for (int i = 0; i < size; i++) {
91     if (m_Operators[i] == (void*)PSOP_PROC) {
92       delete (CPDF_PSProc*)m_Operators[i + 1];
93       i++;
94     } else if (m_Operators[i] == (void*)PSOP_CONST) {
95       FX_Free((FX_FLOAT*)m_Operators[i + 1]);
96       i++;
97     }
98   }
99 }
100 FX_BOOL CPDF_PSProc::Execute(CPDF_PSEngine* pEngine) {
101   int size = m_Operators.GetSize();
102   for (int i = 0; i < size; i++) {
103     PDF_PSOP op = (PDF_PSOP)(uintptr_t)m_Operators[i];
104     if (op == PSOP_PROC) {
105       i++;
106     } else if (op == PSOP_CONST) {
107       pEngine->Push(*(FX_FLOAT*)m_Operators[i + 1]);
108       i++;
109     } else if (op == PSOP_IF) {
110       if (i < 2 || m_Operators[i - 2] != (void*)PSOP_PROC) {
111         return FALSE;
112       }
113       if ((int)pEngine->Pop()) {
114         ((CPDF_PSProc*)m_Operators[i - 1])->Execute(pEngine);
115       }
116     } else if (op == PSOP_IFELSE) {
117       if (i < 4 || m_Operators[i - 2] != (void*)PSOP_PROC ||
118           m_Operators[i - 4] != (void*)PSOP_PROC) {
119         return FALSE;
120       }
121       if ((int)pEngine->Pop()) {
122         ((CPDF_PSProc*)m_Operators[i - 3])->Execute(pEngine);
123       } else {
124         ((CPDF_PSProc*)m_Operators[i - 1])->Execute(pEngine);
125       }
126     } else {
127       pEngine->DoOperator(op);
128     }
129   }
130   return TRUE;
131 }
132 CPDF_PSEngine::CPDF_PSEngine() {
133   m_StackCount = 0;
134 }
135 CPDF_PSEngine::~CPDF_PSEngine() {}
136 void CPDF_PSEngine::Push(FX_FLOAT v) {
137   if (m_StackCount == 100) {
138     return;
139   }
140   m_Stack[m_StackCount++] = v;
141 }
142 FX_FLOAT CPDF_PSEngine::Pop() {
143   if (m_StackCount == 0) {
144     return 0;
145   }
146   return m_Stack[--m_StackCount];
147 }
148 const struct _PDF_PSOpName {
149   const FX_CHAR* name;
150   PDF_PSOP op;
151 } _PDF_PSOpNames[] = {{"add", PSOP_ADD},         {"sub", PSOP_SUB},
152                       {"mul", PSOP_MUL},         {"div", PSOP_DIV},
153                       {"idiv", PSOP_IDIV},       {"mod", PSOP_MOD},
154                       {"neg", PSOP_NEG},         {"abs", PSOP_ABS},
155                       {"ceiling", PSOP_CEILING}, {"floor", PSOP_FLOOR},
156                       {"round", PSOP_ROUND},     {"truncate", PSOP_TRUNCATE},
157                       {"sqrt", PSOP_SQRT},       {"sin", PSOP_SIN},
158                       {"cos", PSOP_COS},         {"atan", PSOP_ATAN},
159                       {"exp", PSOP_EXP},         {"ln", PSOP_LN},
160                       {"log", PSOP_LOG},         {"cvi", PSOP_CVI},
161                       {"cvr", PSOP_CVR},         {"eq", PSOP_EQ},
162                       {"ne", PSOP_NE},           {"gt", PSOP_GT},
163                       {"ge", PSOP_GE},           {"lt", PSOP_LT},
164                       {"le", PSOP_LE},           {"and", PSOP_AND},
165                       {"or", PSOP_OR},           {"xor", PSOP_XOR},
166                       {"not", PSOP_NOT},         {"bitshift", PSOP_BITSHIFT},
167                       {"true", PSOP_TRUE},       {"false", PSOP_FALSE},
168                       {"if", PSOP_IF},           {"ifelse", PSOP_IFELSE},
169                       {"pop", PSOP_POP},         {"exch", PSOP_EXCH},
170                       {"dup", PSOP_DUP},         {"copy", PSOP_COPY},
171                       {"index", PSOP_INDEX},     {"roll", PSOP_ROLL},
172                       {NULL, PSOP_PROC}};
173 FX_BOOL CPDF_PSEngine::Parse(const FX_CHAR* string, int size) {
174   CPDF_SimpleParser parser((uint8_t*)string, size);
175   CFX_ByteStringC word = parser.GetWord();
176   if (word != FX_BSTRC("{")) {
177     return FALSE;
178   }
179   return m_MainProc.Parse(parser);
180 }
181 FX_BOOL CPDF_PSProc::Parse(CPDF_SimpleParser& parser) {
182   while (1) {
183     CFX_ByteStringC word = parser.GetWord();
184     if (word.IsEmpty()) {
185       return FALSE;
186     }
187     if (word == FX_BSTRC("}")) {
188       return TRUE;
189     }
190     if (word == FX_BSTRC("{")) {
191       CPDF_PSProc* pProc = new CPDF_PSProc;
192       m_Operators.Add((void*)PSOP_PROC);
193       m_Operators.Add(pProc);
194       if (!pProc->Parse(parser)) {
195         return FALSE;
196       }
197     } else {
198       int i = 0;
199       while (_PDF_PSOpNames[i].name) {
200         if (word == CFX_ByteStringC(_PDF_PSOpNames[i].name)) {
201           m_Operators.Add((void*)_PDF_PSOpNames[i].op);
202           break;
203         }
204         i++;
205       }
206       if (_PDF_PSOpNames[i].name == NULL) {
207         FX_FLOAT* pd = FX_Alloc(FX_FLOAT, 1);
208         *pd = FX_atof(word);
209         m_Operators.Add((void*)PSOP_CONST);
210         m_Operators.Add(pd);
211       }
212     }
213   }
214 }
215 #define PI 3.1415926535897932384626433832795f
216 FX_BOOL CPDF_PSEngine::DoOperator(PDF_PSOP op) {
217   int i1, i2;
218   FX_FLOAT d1, d2;
219   switch (op) {
220     case PSOP_ADD:
221       d1 = Pop();
222       d2 = Pop();
223       Push(d1 + d2);
224       break;
225     case PSOP_SUB:
226       d2 = Pop();
227       d1 = Pop();
228       Push(d1 - d2);
229       break;
230     case PSOP_MUL:
231       d1 = Pop();
232       d2 = Pop();
233       Push(d1 * d2);
234       break;
235     case PSOP_DIV:
236       d2 = Pop();
237       d1 = Pop();
238       Push(d1 / d2);
239       break;
240     case PSOP_IDIV:
241       i2 = (int)Pop();
242       i1 = (int)Pop();
243       Push(i1 / i2);
244       break;
245     case PSOP_MOD:
246       i2 = (int)Pop();
247       i1 = (int)Pop();
248       Push(i1 % i2);
249       break;
250     case PSOP_NEG:
251       d1 = Pop();
252       Push(-d1);
253       break;
254     case PSOP_ABS:
255       d1 = Pop();
256       Push((FX_FLOAT)FXSYS_fabs(d1));
257       break;
258     case PSOP_CEILING:
259       d1 = Pop();
260       Push((FX_FLOAT)FXSYS_ceil(d1));
261       break;
262     case PSOP_FLOOR:
263       d1 = Pop();
264       Push((FX_FLOAT)FXSYS_floor(d1));
265       break;
266     case PSOP_ROUND:
267       d1 = Pop();
268       Push(FXSYS_round(d1));
269       break;
270     case PSOP_TRUNCATE:
271       i1 = (int)Pop();
272       Push(i1);
273       break;
274     case PSOP_SQRT:
275       d1 = Pop();
276       Push((FX_FLOAT)FXSYS_sqrt(d1));
277       break;
278     case PSOP_SIN:
279       d1 = Pop();
280       Push((FX_FLOAT)FXSYS_sin(d1 * PI / 180.0f));
281       break;
282     case PSOP_COS:
283       d1 = Pop();
284       Push((FX_FLOAT)FXSYS_cos(d1 * PI / 180.0f));
285       break;
286     case PSOP_ATAN:
287       d2 = Pop();
288       d1 = Pop();
289       d1 = (FX_FLOAT)(FXSYS_atan2(d1, d2) * 180.0 / PI);
290       if (d1 < 0) {
291         d1 += 360;
292       }
293       Push(d1);
294       break;
295     case PSOP_EXP:
296       d2 = Pop();
297       d1 = Pop();
298       Push((FX_FLOAT)FXSYS_pow(d1, d2));
299       break;
300     case PSOP_LN:
301       d1 = Pop();
302       Push((FX_FLOAT)FXSYS_log(d1));
303       break;
304     case PSOP_LOG:
305       d1 = Pop();
306       Push((FX_FLOAT)FXSYS_log10(d1));
307       break;
308     case PSOP_CVI:
309       i1 = (int)Pop();
310       Push(i1);
311       break;
312     case PSOP_CVR:
313       break;
314     case PSOP_EQ:
315       d2 = Pop();
316       d1 = Pop();
317       Push((int)(d1 == d2));
318       break;
319     case PSOP_NE:
320       d2 = Pop();
321       d1 = Pop();
322       Push((int)(d1 != d2));
323       break;
324     case PSOP_GT:
325       d2 = Pop();
326       d1 = Pop();
327       Push((int)(d1 > d2));
328       break;
329     case PSOP_GE:
330       d2 = Pop();
331       d1 = Pop();
332       Push((int)(d1 >= d2));
333       break;
334     case PSOP_LT:
335       d2 = Pop();
336       d1 = Pop();
337       Push((int)(d1 < d2));
338       break;
339     case PSOP_LE:
340       d2 = Pop();
341       d1 = Pop();
342       Push((int)(d1 <= d2));
343       break;
344     case PSOP_AND:
345       i1 = (int)Pop();
346       i2 = (int)Pop();
347       Push(i1 & i2);
348       break;
349     case PSOP_OR:
350       i1 = (int)Pop();
351       i2 = (int)Pop();
352       Push(i1 | i2);
353       break;
354     case PSOP_XOR:
355       i1 = (int)Pop();
356       i2 = (int)Pop();
357       Push(i1 ^ i2);
358       break;
359     case PSOP_NOT:
360       i1 = (int)Pop();
361       Push((int)!i1);
362       break;
363     case PSOP_BITSHIFT: {
364       int shift = (int)Pop();
365       int i = (int)Pop();
366       if (shift > 0) {
367         Push(i << shift);
368       } else {
369         Push(i >> -shift);
370       }
371       break;
372     }
373     case PSOP_TRUE:
374       Push(1);
375       break;
376     case PSOP_FALSE:
377       Push(0);
378       break;
379     case PSOP_POP:
380       Pop();
381       break;
382     case PSOP_EXCH:
383       d2 = Pop();
384       d1 = Pop();
385       Push(d2);
386       Push(d1);
387       break;
388     case PSOP_DUP:
389       d1 = Pop();
390       Push(d1);
391       Push(d1);
392       break;
393     case PSOP_COPY: {
394       int n = (int)Pop();
395       if (n < 0 || n > PSENGINE_STACKSIZE ||
396           m_StackCount + n > PSENGINE_STACKSIZE || n > m_StackCount) {
397         break;
398       }
399       for (int i = 0; i < n; i++) {
400         m_Stack[m_StackCount + i] = m_Stack[m_StackCount + i - n];
401       }
402       m_StackCount += n;
403       break;
404     }
405     case PSOP_INDEX: {
406       int n = (int)Pop();
407       if (n < 0 || n >= m_StackCount) {
408         break;
409       }
410       Push(m_Stack[m_StackCount - n - 1]);
411       break;
412     }
413     case PSOP_ROLL: {
414       int j = (int)Pop();
415       int n = (int)Pop();
416       if (m_StackCount == 0) {
417         break;
418       }
419       if (n < 0 || n > m_StackCount) {
420         break;
421       }
422       if (j < 0)
423         for (int i = 0; i < -j; i++) {
424           FX_FLOAT first = m_Stack[m_StackCount - n];
425           for (int ii = 0; ii < n - 1; ii++) {
426             m_Stack[m_StackCount - n + ii] = m_Stack[m_StackCount - n + ii + 1];
427           }
428           m_Stack[m_StackCount - 1] = first;
429         }
430       else
431         for (int i = 0; i < j; i++) {
432           FX_FLOAT last = m_Stack[m_StackCount - 1];
433           int ii;
434           for (ii = 0; ii < n - 1; ii++) {
435             m_Stack[m_StackCount - ii - 1] = m_Stack[m_StackCount - ii - 2];
436           }
437           m_Stack[m_StackCount - ii - 1] = last;
438         }
439       break;
440     }
441     default:
442       break;
443   }
444   return TRUE;
445 }
446 static FX_FLOAT PDF_Interpolate(FX_FLOAT x,
447                                 FX_FLOAT xmin,
448                                 FX_FLOAT xmax,
449                                 FX_FLOAT ymin,
450                                 FX_FLOAT ymax) {
451   return ((x - xmin) * (ymax - ymin) / (xmax - xmin)) + ymin;
452 }
453 static FX_DWORD _GetBits32(const uint8_t* pData, int bitpos, int nbits) {
454   int result = 0;
455   for (int i = 0; i < nbits; i++)
456     if (pData[(bitpos + i) / 8] & (1 << (7 - (bitpos + i) % 8))) {
457       result |= 1 << (nbits - i - 1);
458     }
459   return result;
460 }
461 typedef struct {
462   FX_FLOAT encode_max, encode_min;
463   int sizes;
464 } SampleEncodeInfo;
465 typedef struct { FX_FLOAT decode_max, decode_min; } SampleDecodeInfo;
466
467 class CPDF_SampledFunc : public CPDF_Function {
468  public:
469   CPDF_SampledFunc();
470   ~CPDF_SampledFunc() override;
471
472   // CPDF_Function
473   FX_BOOL v_Init(CPDF_Object* pObj) override;
474   FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
475
476   SampleEncodeInfo* m_pEncodeInfo;
477   SampleDecodeInfo* m_pDecodeInfo;
478   FX_DWORD m_nBitsPerSample;
479   FX_DWORD m_SampleMax;
480   CPDF_StreamAcc* m_pSampleStream;
481 };
482
483 CPDF_SampledFunc::CPDF_SampledFunc() {
484   m_pSampleStream = NULL;
485   m_pEncodeInfo = NULL;
486   m_pDecodeInfo = NULL;
487 }
488 CPDF_SampledFunc::~CPDF_SampledFunc() {
489   delete m_pSampleStream;
490   if (m_pEncodeInfo) {
491     FX_Free(m_pEncodeInfo);
492   }
493   if (m_pDecodeInfo) {
494     FX_Free(m_pDecodeInfo);
495   }
496 }
497 FX_BOOL CPDF_SampledFunc::v_Init(CPDF_Object* pObj) {
498   if (pObj->GetType() != PDFOBJ_STREAM) {
499     return FALSE;
500   }
501   CPDF_Stream* pStream = (CPDF_Stream*)pObj;
502   CPDF_Dictionary* pDict = pStream->GetDict();
503   CPDF_Array* pSize = pDict->GetArray(FX_BSTRC("Size"));
504   CPDF_Array* pEncode = pDict->GetArray(FX_BSTRC("Encode"));
505   CPDF_Array* pDecode = pDict->GetArray(FX_BSTRC("Decode"));
506   m_nBitsPerSample = pDict->GetInteger(FX_BSTRC("BitsPerSample"));
507   if (m_nBitsPerSample > 32) {
508     return FALSE;
509   }
510   m_SampleMax = 0xffffffff >> (32 - m_nBitsPerSample);
511   m_pSampleStream = new CPDF_StreamAcc;
512   m_pSampleStream->LoadAllData(pStream, FALSE);
513   m_pEncodeInfo = FX_Alloc(SampleEncodeInfo, m_nInputs);
514   FX_SAFE_DWORD nTotalSampleBits = 1;
515   for (int i = 0; i < m_nInputs; i++) {
516     m_pEncodeInfo[i].sizes = pSize ? pSize->GetInteger(i) : 0;
517     if (!pSize && i == 0) {
518       m_pEncodeInfo[i].sizes = pDict->GetInteger(FX_BSTRC("Size"));
519     }
520     nTotalSampleBits *= m_pEncodeInfo[i].sizes;
521     if (pEncode) {
522       m_pEncodeInfo[i].encode_min = pEncode->GetFloat(i * 2);
523       m_pEncodeInfo[i].encode_max = pEncode->GetFloat(i * 2 + 1);
524     } else {
525       m_pEncodeInfo[i].encode_min = 0;
526       if (m_pEncodeInfo[i].sizes == 1) {
527         m_pEncodeInfo[i].encode_max = 1;
528       } else {
529         m_pEncodeInfo[i].encode_max = (FX_FLOAT)m_pEncodeInfo[i].sizes - 1;
530       }
531     }
532   }
533   nTotalSampleBits *= m_nBitsPerSample;
534   nTotalSampleBits *= m_nOutputs;
535   FX_SAFE_DWORD nTotalSampleBytes = nTotalSampleBits;
536   nTotalSampleBytes += 7;
537   nTotalSampleBytes /= 8;
538   if (!nTotalSampleBytes.IsValid() || nTotalSampleBytes.ValueOrDie() == 0 ||
539       nTotalSampleBytes.ValueOrDie() > m_pSampleStream->GetSize()) {
540     return FALSE;
541   }
542   m_pDecodeInfo = FX_Alloc(SampleDecodeInfo, m_nOutputs);
543   for (int i = 0; i < m_nOutputs; i++) {
544     if (pDecode) {
545       m_pDecodeInfo[i].decode_min = pDecode->GetFloat(2 * i);
546       m_pDecodeInfo[i].decode_max = pDecode->GetFloat(2 * i + 1);
547     } else {
548       m_pDecodeInfo[i].decode_min = m_pRanges[i * 2];
549       m_pDecodeInfo[i].decode_max = m_pRanges[i * 2 + 1];
550     }
551   }
552   return TRUE;
553 }
554 FX_BOOL CPDF_SampledFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
555   int pos = 0;
556   CFX_FixedBufGrow<FX_FLOAT, 16> encoded_input_buf(m_nInputs);
557   FX_FLOAT* encoded_input = encoded_input_buf;
558   CFX_FixedBufGrow<int, 32> int_buf(m_nInputs * 2);
559   int* index = int_buf;
560   int* blocksize = index + m_nInputs;
561   for (int i = 0; i < m_nInputs; i++) {
562     if (i == 0) {
563       blocksize[i] = 1;
564     } else {
565       blocksize[i] = blocksize[i - 1] * m_pEncodeInfo[i - 1].sizes;
566     }
567     encoded_input[i] = PDF_Interpolate(
568         inputs[i], m_pDomains[i * 2], m_pDomains[i * 2 + 1],
569         m_pEncodeInfo[i].encode_min, m_pEncodeInfo[i].encode_max);
570     index[i] = (int)encoded_input[i];
571     if (index[i] < 0) {
572       index[i] = 0;
573     } else if (index[i] > m_pEncodeInfo[i].sizes - 1) {
574       index[i] = m_pEncodeInfo[i].sizes - 1;
575     }
576     pos += index[i] * blocksize[i];
577   }
578   FX_SAFE_INT32 bits_to_output = m_nOutputs;
579   bits_to_output *= m_nBitsPerSample;
580   if (!bits_to_output.IsValid()) {
581     return FALSE;
582   }
583   FX_SAFE_INT32 bitpos = pos;
584   bitpos *= bits_to_output.ValueOrDie();
585   if (!bitpos.IsValid()) {
586     return FALSE;
587   }
588   FX_SAFE_INT32 range_check = bitpos;
589   range_check += bits_to_output.ValueOrDie();
590   if (!range_check.IsValid()) {
591     return FALSE;
592   }
593   const uint8_t* pSampleData = m_pSampleStream->GetData();
594   if (!pSampleData) {
595     return FALSE;
596   }
597   for (int j = 0; j < m_nOutputs; j++) {
598     FX_DWORD sample =
599         _GetBits32(pSampleData, bitpos.ValueOrDie() + j * m_nBitsPerSample,
600                    m_nBitsPerSample);
601     FX_FLOAT encoded = (FX_FLOAT)sample;
602     for (int i = 0; i < m_nInputs; i++) {
603       if (index[i] == m_pEncodeInfo[i].sizes - 1) {
604         if (index[i] == 0) {
605           encoded = encoded_input[i] * (FX_FLOAT)sample;
606         }
607       } else {
608         FX_SAFE_INT32 bitpos2 = blocksize[i];
609         bitpos2 += pos;
610         bitpos2 *= m_nOutputs;
611         bitpos2 += j;
612         bitpos2 *= m_nBitsPerSample;
613         if (!bitpos2.IsValid()) {
614           return FALSE;
615         }
616         FX_DWORD sample1 =
617             _GetBits32(pSampleData, bitpos2.ValueOrDie(), m_nBitsPerSample);
618         encoded += (encoded_input[i] - index[i]) *
619                    ((FX_FLOAT)sample1 - (FX_FLOAT)sample);
620       }
621     }
622     results[j] = PDF_Interpolate(encoded, 0, (FX_FLOAT)m_SampleMax,
623                                  m_pDecodeInfo[j].decode_min,
624                                  m_pDecodeInfo[j].decode_max);
625   }
626   return TRUE;
627 }
628
629 class CPDF_PSFunc : public CPDF_Function {
630  public:
631   // CPDF_Function
632   FX_BOOL v_Init(CPDF_Object* pObj) override;
633   FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
634
635   CPDF_PSEngine m_PS;
636 };
637
638 FX_BOOL CPDF_PSFunc::v_Init(CPDF_Object* pObj) {
639   CPDF_Stream* pStream = (CPDF_Stream*)pObj;
640   CPDF_StreamAcc acc;
641   acc.LoadAllData(pStream, FALSE);
642   return m_PS.Parse((const FX_CHAR*)acc.GetData(), acc.GetSize());
643 }
644 FX_BOOL CPDF_PSFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
645   CPDF_PSEngine& PS = (CPDF_PSEngine&)m_PS;
646   PS.Reset();
647   int i;
648   for (i = 0; i < m_nInputs; i++) {
649     PS.Push(inputs[i]);
650   }
651   PS.Execute();
652   if (PS.GetStackSize() < m_nOutputs) {
653     return FALSE;
654   }
655   for (i = 0; i < m_nOutputs; i++) {
656     results[m_nOutputs - i - 1] = PS.Pop();
657   }
658   return TRUE;
659 }
660
661 class CPDF_ExpIntFunc : public CPDF_Function {
662  public:
663   CPDF_ExpIntFunc();
664   ~CPDF_ExpIntFunc() override;
665
666   // CPDF_Function
667   FX_BOOL v_Init(CPDF_Object* pObj) override;
668   FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
669
670   FX_FLOAT m_Exponent;
671   FX_FLOAT* m_pBeginValues;
672   FX_FLOAT* m_pEndValues;
673   int m_nOrigOutputs;
674 };
675
676 CPDF_ExpIntFunc::CPDF_ExpIntFunc() {
677   m_pBeginValues = NULL;
678   m_pEndValues = NULL;
679 }
680 CPDF_ExpIntFunc::~CPDF_ExpIntFunc() {
681   if (m_pBeginValues) {
682     FX_Free(m_pBeginValues);
683   }
684   if (m_pEndValues) {
685     FX_Free(m_pEndValues);
686   }
687 }
688 FX_BOOL CPDF_ExpIntFunc::v_Init(CPDF_Object* pObj) {
689   CPDF_Dictionary* pDict = pObj->GetDict();
690   if (pDict == NULL) {
691     return FALSE;
692   }
693   CPDF_Array* pArray0 = pDict->GetArray(FX_BSTRC("C0"));
694   if (m_nOutputs == 0) {
695     m_nOutputs = 1;
696     if (pArray0) {
697       m_nOutputs = pArray0->GetCount();
698     }
699   }
700   CPDF_Array* pArray1 = pDict->GetArray(FX_BSTRC("C1"));
701   m_pBeginValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
702   m_pEndValues = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
703   for (int i = 0; i < m_nOutputs; i++) {
704     m_pBeginValues[i] = pArray0 ? pArray0->GetFloat(i) : 0.0f;
705     m_pEndValues[i] = pArray1 ? pArray1->GetFloat(i) : 1.0f;
706   }
707   m_Exponent = pDict->GetFloat(FX_BSTRC("N"));
708   m_nOrigOutputs = m_nOutputs;
709   if (m_nOutputs && m_nInputs > INT_MAX / m_nOutputs) {
710     return FALSE;
711   }
712   m_nOutputs *= m_nInputs;
713   return TRUE;
714 }
715 FX_BOOL CPDF_ExpIntFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const {
716   for (int i = 0; i < m_nInputs; i++)
717     for (int j = 0; j < m_nOrigOutputs; j++) {
718       results[i * m_nOrigOutputs + j] =
719           m_pBeginValues[j] +
720           (FX_FLOAT)FXSYS_pow(inputs[i], m_Exponent) *
721               (m_pEndValues[j] - m_pBeginValues[j]);
722     }
723   return TRUE;
724 }
725
726 class CPDF_StitchFunc : public CPDF_Function {
727  public:
728   CPDF_StitchFunc();
729   ~CPDF_StitchFunc() override;
730
731   // CPDF_Function
732   FX_BOOL v_Init(CPDF_Object* pObj) override;
733   FX_BOOL v_Call(FX_FLOAT* inputs, FX_FLOAT* results) const override;
734
735   int m_nSubs;
736   CPDF_Function** m_pSubFunctions;
737   FX_FLOAT* m_pBounds;
738   FX_FLOAT* m_pEncode;
739 };
740
741 CPDF_StitchFunc::CPDF_StitchFunc() {
742   m_nSubs = 0;
743   m_pSubFunctions = NULL;
744   m_pBounds = NULL;
745   m_pEncode = NULL;
746 }
747 CPDF_StitchFunc::~CPDF_StitchFunc() {
748   for (int i = 0; i < m_nSubs; i++)
749     delete m_pSubFunctions[i];
750   if (m_pSubFunctions) {
751     FX_Free(m_pSubFunctions);
752   }
753   if (m_pBounds) {
754     FX_Free(m_pBounds);
755   }
756   if (m_pEncode) {
757     FX_Free(m_pEncode);
758   }
759 }
760 FX_BOOL CPDF_StitchFunc::v_Init(CPDF_Object* pObj) {
761   CPDF_Dictionary* pDict = pObj->GetDict();
762   if (pDict == NULL) {
763     return FALSE;
764   }
765   CPDF_Array* pArray = pDict->GetArray(FX_BSTRC("Functions"));
766   if (pArray == NULL) {
767     return FALSE;
768   }
769   m_nSubs = pArray->GetCount();
770   if (m_nSubs == 0) {
771     return FALSE;
772   }
773   m_pSubFunctions = FX_Alloc(CPDF_Function*, m_nSubs);
774   m_nOutputs = 0;
775   int i;
776   for (i = 0; i < m_nSubs; i++) {
777     CPDF_Object* pSub = pArray->GetElementValue(i);
778     if (pSub == pObj) {
779       return FALSE;
780     }
781     m_pSubFunctions[i] = CPDF_Function::Load(pSub);
782     if (m_pSubFunctions[i] == NULL) {
783       return FALSE;
784     }
785     if (m_pSubFunctions[i]->CountOutputs() > m_nOutputs) {
786       m_nOutputs = m_pSubFunctions[i]->CountOutputs();
787     }
788   }
789   m_pBounds = FX_Alloc(FX_FLOAT, m_nSubs + 1);
790   m_pBounds[0] = m_pDomains[0];
791   pArray = pDict->GetArray(FX_BSTRC("Bounds"));
792   if (pArray == NULL) {
793     return FALSE;
794   }
795   for (i = 0; i < m_nSubs - 1; i++) {
796     m_pBounds[i + 1] = pArray->GetFloat(i);
797   }
798   m_pBounds[m_nSubs] = m_pDomains[1];
799   m_pEncode = FX_Alloc2D(FX_FLOAT, m_nSubs, 2);
800   pArray = pDict->GetArray(FX_BSTRC("Encode"));
801   if (pArray == NULL) {
802     return FALSE;
803   }
804   for (i = 0; i < m_nSubs * 2; i++) {
805     m_pEncode[i] = pArray->GetFloat(i);
806   }
807   return TRUE;
808 }
809 FX_BOOL CPDF_StitchFunc::v_Call(FX_FLOAT* inputs, FX_FLOAT* outputs) const {
810   FX_FLOAT input = inputs[0];
811   int i;
812   for (i = 0; i < m_nSubs - 1; i++)
813     if (input < m_pBounds[i + 1]) {
814       break;
815     }
816   if (m_pSubFunctions[i] == NULL) {
817     return FALSE;
818   }
819   input = PDF_Interpolate(input, m_pBounds[i], m_pBounds[i + 1],
820                           m_pEncode[i * 2], m_pEncode[i * 2 + 1]);
821   int nresults;
822   m_pSubFunctions[i]->Call(&input, m_nInputs, outputs, nresults);
823   return TRUE;
824 }
825 CPDF_Function* CPDF_Function::Load(CPDF_Object* pFuncObj) {
826   if (pFuncObj == NULL) {
827     return NULL;
828   }
829   CPDF_Function* pFunc = NULL;
830   int type;
831   if (pFuncObj->GetType() == PDFOBJ_STREAM) {
832     type = ((CPDF_Stream*)pFuncObj)
833                ->GetDict()
834                ->GetInteger(FX_BSTRC("FunctionType"));
835   } else if (pFuncObj->GetType() == PDFOBJ_DICTIONARY) {
836     type = ((CPDF_Dictionary*)pFuncObj)->GetInteger(FX_BSTRC("FunctionType"));
837   } else {
838     return NULL;
839   }
840   if (type == 0) {
841     pFunc = new CPDF_SampledFunc;
842   } else if (type == 2) {
843     pFunc = new CPDF_ExpIntFunc;
844   } else if (type == 3) {
845     pFunc = new CPDF_StitchFunc;
846   } else if (type == 4) {
847     pFunc = new CPDF_PSFunc;
848   } else {
849     return NULL;
850   }
851   if (!pFunc->Init(pFuncObj)) {
852     delete pFunc;
853     return NULL;
854   }
855   return pFunc;
856 }
857 CPDF_Function::CPDF_Function() {
858   m_pDomains = NULL;
859   m_pRanges = NULL;
860 }
861 CPDF_Function::~CPDF_Function() {
862   if (m_pDomains) {
863     FX_Free(m_pDomains);
864     m_pDomains = NULL;
865   }
866   if (m_pRanges) {
867     FX_Free(m_pRanges);
868     m_pRanges = NULL;
869   }
870 }
871 FX_BOOL CPDF_Function::Init(CPDF_Object* pObj) {
872   CPDF_Dictionary* pDict;
873   if (pObj->GetType() == PDFOBJ_STREAM) {
874     pDict = ((CPDF_Stream*)pObj)->GetDict();
875   } else {
876     pDict = (CPDF_Dictionary*)pObj;
877   }
878   CPDF_Array* pDomains = pDict->GetArray(FX_BSTRC("Domain"));
879   if (pDomains == NULL) {
880     return FALSE;
881   }
882   m_nInputs = pDomains->GetCount() / 2;
883   if (m_nInputs == 0) {
884     return FALSE;
885   }
886   m_pDomains = FX_Alloc2D(FX_FLOAT, m_nInputs, 2);
887   for (int i = 0; i < m_nInputs * 2; i++) {
888     m_pDomains[i] = pDomains->GetFloat(i);
889   }
890   CPDF_Array* pRanges = pDict->GetArray(FX_BSTRC("Range"));
891   m_nOutputs = 0;
892   if (pRanges) {
893     m_nOutputs = pRanges->GetCount() / 2;
894     m_pRanges = FX_Alloc2D(FX_FLOAT, m_nOutputs, 2);
895     for (int i = 0; i < m_nOutputs * 2; i++) {
896       m_pRanges[i] = pRanges->GetFloat(i);
897     }
898   }
899   FX_DWORD old_outputs = m_nOutputs;
900   if (!v_Init(pObj)) {
901     return FALSE;
902   }
903   if (m_pRanges && m_nOutputs > (int)old_outputs) {
904     m_pRanges = FX_Realloc(FX_FLOAT, m_pRanges, m_nOutputs * 2);
905     if (m_pRanges) {
906       FXSYS_memset(m_pRanges + (old_outputs * 2), 0,
907                    sizeof(FX_FLOAT) * (m_nOutputs - old_outputs) * 2);
908     }
909   }
910   return TRUE;
911 }
912 FX_BOOL CPDF_Function::Call(FX_FLOAT* inputs,
913                             int ninputs,
914                             FX_FLOAT* results,
915                             int& nresults) const {
916   if (m_nInputs != ninputs) {
917     return FALSE;
918   }
919   nresults = m_nOutputs;
920   for (int i = 0; i < m_nInputs; i++) {
921     if (inputs[i] < m_pDomains[i * 2]) {
922       inputs[i] = m_pDomains[i * 2];
923     } else if (inputs[i] > m_pDomains[i * 2 + 1]) {
924       inputs[i] = m_pDomains[i * 2] + 1;
925     }
926   }
927   v_Call(inputs, results);
928   if (m_pRanges) {
929     for (int i = 0; i < m_nOutputs; i++) {
930       if (results[i] < m_pRanges[i * 2]) {
931         results[i] = m_pRanges[i * 2];
932       } else if (results[i] > m_pRanges[i * 2 + 1]) {
933         results[i] = m_pRanges[i * 2 + 1];
934       }
935     }
936   }
937   return TRUE;
938 }