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