1 //========================================================================
5 // Copyright 2001-2003 Glyph & Cog, LLC
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2006, 2008-2010, 2013-2015 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
19 // Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
20 // Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
21 // Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
22 // Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
24 // To see a description of the changes please see the Changelog file that
25 // came with your tarball or type make ChangeLog if you are building from git
27 //========================================================================
31 #ifdef USE_GCC_PRAGMAS
32 #pragma implementation
40 #include "goo/gstrtod.h"
48 #define M_PI 3.14159265358979323846
51 //------------------------------------------------------------------------
53 //------------------------------------------------------------------------
55 Function::Function() {
58 Function::~Function() {
61 Function
*Function::parse(Object
*funcObj
) {
62 std::set
<int> usedParents
;
63 return parse(funcObj
, &usedParents
);
66 Function
*Function::parse(Object
*funcObj
, std::set
<int> *usedParents
) {
72 if (funcObj
->isStream()) {
73 dict
= funcObj
->streamGetDict();
74 } else if (funcObj
->isDict()) {
75 dict
= funcObj
->getDict();
76 } else if (funcObj
->isName("Identity")) {
77 return new IdentityFunction();
79 error(errSyntaxError
, -1, "Expected function dictionary or stream");
83 if (!dict
->lookup("FunctionType", &obj1
)->isInt()) {
84 error(errSyntaxError
, -1, "Function type is missing or wrong type");
88 funcType
= obj1
.getInt();
92 func
= new SampledFunction(funcObj
, dict
);
93 } else if (funcType
== 2) {
94 func
= new ExponentialFunction(funcObj
, dict
);
95 } else if (funcType
== 3) {
96 func
= new StitchingFunction(funcObj
, dict
, usedParents
);
97 } else if (funcType
== 4) {
98 func
= new PostScriptFunction(funcObj
, dict
);
100 error(errSyntaxError
, -1, "Unimplemented function type ({0:d})", funcType
);
111 Function::Function(const Function
*func
) {
115 memcpy(domain
, func
->domain
, funcMaxInputs
* 2 * sizeof(double));
116 memcpy(range
, func
->range
, funcMaxOutputs
* 2 * sizeof(double));
118 hasRange
= func
->hasRange
;
121 GBool
Function::init(Dict
*dict
) {
126 if (!dict
->lookup("Domain", &obj1
)->isArray()) {
127 error(errSyntaxError
, -1, "Function is missing domain");
130 m
= obj1
.arrayGetLength() / 2;
131 if (m
> funcMaxInputs
) {
132 error(errSyntaxError
, -1, "Functions with more than {0:d} inputs are unsupported",
136 for (i
= 0; i
< m
; ++i
) {
137 obj1
.arrayGet(2*i
, &obj2
);
139 error(errSyntaxError
, -1, "Illegal value in function domain array");
142 domain
[i
][0] = obj2
.getNum();
144 obj1
.arrayGet(2*i
+1, &obj2
);
146 error(errSyntaxError
, -1, "Illegal value in function domain array");
149 domain
[i
][1] = obj2
.getNum();
157 if (dict
->lookup("Range", &obj1
)->isArray()) {
159 n
= obj1
.arrayGetLength() / 2;
160 if (n
> funcMaxOutputs
) {
161 error(errSyntaxError
, -1, "Functions with more than {0:d} outputs are unsupported",
165 for (i
= 0; i
< n
; ++i
) {
166 obj1
.arrayGet(2*i
, &obj2
);
168 error(errSyntaxError
, -1, "Illegal value in function range array");
171 range
[i
][0] = obj2
.getNum();
173 obj1
.arrayGet(2*i
+1, &obj2
);
175 error(errSyntaxError
, -1, "Illegal value in function range array");
178 range
[i
][1] = obj2
.getNum();
193 //------------------------------------------------------------------------
195 //------------------------------------------------------------------------
197 IdentityFunction::IdentityFunction() {
200 // fill these in with arbitrary values just in case they get used
204 for (i
= 0; i
< funcMaxInputs
; ++i
) {
211 IdentityFunction::~IdentityFunction() {
214 void IdentityFunction::transform(double *in
, double *out
) {
217 for (i
= 0; i
< funcMaxOutputs
; ++i
) {
222 //------------------------------------------------------------------------
224 //------------------------------------------------------------------------
226 SampledFunction::SampledFunction(Object
*funcObj
, Dict
*dict
) {
234 double in
[funcMaxInputs
];
235 int i
, j
, t
, bit
, idx
;
242 //----- initialize the generic stuff
247 error(errSyntaxError
, -1, "Type 0 function is missing range");
250 if (m
> sampledFuncMaxInputs
) {
251 error(errSyntaxError
, -1, "Sampled functions with more than {0:d} inputs are unsupported",
252 sampledFuncMaxInputs
);
257 sBuf
= (double *)gmallocn(1 << m
, sizeof(double));
259 //----- get the stream
260 if (!funcObj
->isStream()) {
261 error(errSyntaxError
, -1, "Type 0 function isn't a stream");
264 str
= funcObj
->getStream();
267 if (!dict
->lookup("Size", &obj1
)->isArray() ||
268 obj1
.arrayGetLength() != m
) {
269 error(errSyntaxError
, -1, "Function has missing or invalid size array");
272 for (i
= 0; i
< m
; ++i
) {
273 obj1
.arrayGet(i
, &obj2
);
275 error(errSyntaxError
, -1, "Illegal value in function size array");
278 sampleSize
[i
] = obj2
.getInt();
279 if (sampleSize
[i
] <= 0) {
280 error(errSyntaxError
, -1, "Illegal non-positive value in function size array");
286 idxOffset
= (int *)gmallocn(1 << m
, sizeof(int));
287 for (i
= 0; i
< (1<<m
); ++i
) {
289 for (j
= m
- 1, t
= i
; j
>= 1; --j
, t
<<= 1) {
290 if (sampleSize
[j
] == 1) {
293 bit
= (t
>> (m
- 1)) & 1;
295 idx
= (idx
+ bit
) * sampleSize
[j
-1];
297 if (sampleSize
[0] == 1) {
300 bit
= (t
>> (m
- 1)) & 1;
302 idxOffset
[i
] = (idx
+ bit
) * n
;
305 //----- BitsPerSample
306 if (!dict
->lookup("BitsPerSample", &obj1
)->isInt()) {
307 error(errSyntaxError
, -1, "Function has missing or invalid BitsPerSample");
310 sampleBits
= obj1
.getInt();
311 sampleMul
= 1.0 / (pow(2.0, (double)sampleBits
) - 1);
315 if (dict
->lookup("Encode", &obj1
)->isArray() &&
316 obj1
.arrayGetLength() == 2*m
) {
317 for (i
= 0; i
< m
; ++i
) {
318 obj1
.arrayGet(2*i
, &obj2
);
320 error(errSyntaxError
, -1, "Illegal value in function encode array");
323 encode
[i
][0] = obj2
.getNum();
325 obj1
.arrayGet(2*i
+1, &obj2
);
327 error(errSyntaxError
, -1, "Illegal value in function encode array");
330 encode
[i
][1] = obj2
.getNum();
334 for (i
= 0; i
< m
; ++i
) {
336 encode
[i
][1] = sampleSize
[i
] - 1;
340 for (i
= 0; i
< m
; ++i
) {
341 inputMul
[i
] = (encode
[i
][1] - encode
[i
][0]) /
342 (domain
[i
][1] - domain
[i
][0]);
346 if (dict
->lookup("Decode", &obj1
)->isArray() &&
347 obj1
.arrayGetLength() == 2*n
) {
348 for (i
= 0; i
< n
; ++i
) {
349 obj1
.arrayGet(2*i
, &obj2
);
351 error(errSyntaxError
, -1, "Illegal value in function decode array");
354 decode
[i
][0] = obj2
.getNum();
356 obj1
.arrayGet(2*i
+1, &obj2
);
358 error(errSyntaxError
, -1, "Illegal value in function decode array");
361 decode
[i
][1] = obj2
.getNum();
365 for (i
= 0; i
< n
; ++i
) {
366 decode
[i
][0] = range
[i
][0];
367 decode
[i
][1] = range
[i
][1];
374 for (i
= 0; i
< m
; ++i
)
375 nSamples
*= sampleSize
[i
];
376 samples
= (double *)gmallocn(nSamples
, sizeof(double));
379 bitMask
= (1 << sampleBits
) - 1;
381 for (i
= 0; i
< nSamples
; ++i
) {
382 if (sampleBits
== 8) {
384 } else if (sampleBits
== 16) {
386 s
= (s
<< 8) + str
->getChar();
387 } else if (sampleBits
== 32) {
389 s
= (s
<< 8) + str
->getChar();
390 s
= (s
<< 8) + str
->getChar();
391 s
= (s
<< 8) + str
->getChar();
393 while (bits
< sampleBits
) {
394 buf
= (buf
<< 8) | (str
->getChar() & 0xff);
397 s
= (buf
>> (bits
- sampleBits
)) & bitMask
;
400 samples
[i
] = (double)s
* sampleMul
;
405 for (i
= 0; i
< m
; ++i
) {
406 in
[i
] = domain
[i
][0];
407 cacheIn
[i
] = in
[i
] - 1;
409 transform(in
, cacheOut
);
422 SampledFunction::~SampledFunction() {
434 SampledFunction::SampledFunction(const SampledFunction
*func
) : Function(func
) {
435 memcpy(sampleSize
, func
->sampleSize
, funcMaxInputs
* sizeof(int));
437 memcpy(encode
, func
->encode
, funcMaxInputs
* 2 * sizeof(double));
438 memcpy(decode
, func
->decode
, funcMaxOutputs
* 2 * sizeof(double));
440 memcpy(inputMul
, func
->inputMul
, funcMaxInputs
* sizeof(double));
442 nSamples
= func
->nSamples
;
444 idxOffset
= (int *)gmallocn(1 << m
, sizeof(int));
445 memcpy(idxOffset
, func
->idxOffset
, (1 << m
) * (int)sizeof(int));
447 samples
= (double *)gmallocn(nSamples
, sizeof(double));
448 memcpy(samples
, func
->samples
, nSamples
* sizeof(double));
450 sBuf
= (double *)gmallocn(1 << m
, sizeof(double));
452 memcpy(cacheIn
, func
->cacheIn
, funcMaxInputs
* sizeof(double));
453 memcpy(cacheOut
, func
->cacheOut
, funcMaxOutputs
* sizeof(double));
458 void SampledFunction::transform(double *in
, double *out
) {
460 int e
[funcMaxInputs
];
461 double efrac0
[funcMaxInputs
];
462 double efrac1
[funcMaxInputs
];
463 int i
, j
, k
, idx0
, t
;
466 for (i
= 0; i
< m
; ++i
) {
467 if (in
[i
] != cacheIn
[i
]) {
472 for (i
= 0; i
< n
; ++i
) {
473 out
[i
] = cacheOut
[i
];
478 // map input values into sample array
479 for (i
= 0; i
< m
; ++i
) {
480 x
= (in
[i
] - domain
[i
][0]) * inputMul
[i
] + encode
[i
][0];
481 if (x
< 0 || x
!= x
) { // x!=x is a more portable version of isnan(x)
483 } else if (x
> sampleSize
[i
] - 1) {
484 x
= sampleSize
[i
] - 1;
487 if (e
[i
] == sampleSize
[i
] - 1 && sampleSize
[i
] > 1) {
488 // this happens if in[i] = domain[i][1]
489 e
[i
] = sampleSize
[i
] - 2;
491 efrac1
[i
] = x
- e
[i
];
492 efrac0
[i
] = 1 - efrac1
[i
];
495 // compute index for the first sample to be used
497 for (k
= m
- 1; k
>= 1; --k
) {
498 idx0
= (idx0
+ e
[k
]) * sampleSize
[k
-1];
500 idx0
= (idx0
+ e
[0]) * n
;
502 // for each output, do m-linear interpolation
503 for (i
= 0; i
< n
; ++i
) {
505 // pull 2^m values out of the sample array
506 for (j
= 0; j
< (1<<m
); ++j
) {
507 int idx
= idx0
+ idxOffset
[j
] + i
;
508 if (likely(idx
>= 0 && idx
< nSamples
)) {
509 sBuf
[j
] = samples
[idx
];
511 sBuf
[j
] = 0; // TODO Investigate if this is what Adobe does
515 // do m sets of interpolations
516 for (j
= 0, t
= (1<<m
); j
< m
; ++j
, t
>>= 1) {
517 for (k
= 0; k
< t
; k
+= 2) {
518 sBuf
[k
>> 1] = efrac0
[j
] * sBuf
[k
] + efrac1
[j
] * sBuf
[k
+1];
522 // map output value to range
523 out
[i
] = sBuf
[0] * (decode
[i
][1] - decode
[i
][0]) + decode
[i
][0];
524 if (out
[i
] < range
[i
][0]) {
525 out
[i
] = range
[i
][0];
526 } else if (out
[i
] > range
[i
][1]) {
527 out
[i
] = range
[i
][1];
531 // save current result in the cache
532 for (i
= 0; i
< m
; ++i
) {
535 for (i
= 0; i
< n
; ++i
) {
536 cacheOut
[i
] = out
[i
];
540 GBool
SampledFunction::hasDifferentResultSet(Function
*func
) {
541 if (func
->getType() == 0) {
542 SampledFunction
*compTo
= (SampledFunction
*) func
;
543 if (compTo
->getSampleNumber() != nSamples
)
545 double *compSamples
= compTo
->getSamples();
546 for (int i
= 0; i
< nSamples
; i
++) {
547 if (samples
[i
] != compSamples
[i
])
554 //------------------------------------------------------------------------
555 // ExponentialFunction
556 //------------------------------------------------------------------------
558 ExponentialFunction::ExponentialFunction(Object
*funcObj
, Dict
*dict
) {
564 //----- initialize the generic stuff
569 error(errSyntaxError
, -1, "Exponential function with more than one input");
574 if (dict
->lookup("C0", &obj1
)->isArray()) {
575 if (hasRange
&& obj1
.arrayGetLength() != n
) {
576 error(errSyntaxError
, -1, "Function's C0 array is wrong length");
579 n
= obj1
.arrayGetLength();
580 if (unlikely(n
> funcMaxOutputs
)) {
581 error(errSyntaxError
, -1, "Function's C0 array is wrong length");
584 for (i
= 0; i
< n
; ++i
) {
585 obj1
.arrayGet(i
, &obj2
);
587 error(errSyntaxError
, -1, "Illegal value in function C0 array");
590 c0
[i
] = obj2
.getNum();
594 if (hasRange
&& n
!= 1) {
595 error(errSyntaxError
, -1, "Function's C0 array is wrong length");
604 if (dict
->lookup("C1", &obj1
)->isArray()) {
605 if (obj1
.arrayGetLength() != n
) {
606 error(errSyntaxError
, -1, "Function's C1 array is wrong length");
609 for (i
= 0; i
< n
; ++i
) {
610 obj1
.arrayGet(i
, &obj2
);
612 error(errSyntaxError
, -1, "Illegal value in function C1 array");
615 c1
[i
] = obj2
.getNum();
620 error(errSyntaxError
, -1, "Function's C1 array is wrong length");
628 if (!dict
->lookup("N", &obj1
)->isNum()) {
629 error(errSyntaxError
, -1, "Function has missing or invalid N");
635 isLinear
= fabs(e
-1.) < 1e-10;
647 ExponentialFunction::~ExponentialFunction() {
650 ExponentialFunction::ExponentialFunction(const ExponentialFunction
*func
) : Function(func
) {
651 memcpy(c0
, func
->c0
, funcMaxOutputs
* sizeof(double));
652 memcpy(c1
, func
->c1
, funcMaxOutputs
* sizeof(double));
655 isLinear
= func
->isLinear
;
659 void ExponentialFunction::transform(double *in
, double *out
) {
663 if (in
[0] < domain
[0][0]) {
665 } else if (in
[0] > domain
[0][1]) {
670 for (i
= 0; i
< n
; ++i
) {
671 out
[i
] = c0
[i
] + (isLinear
? x
: pow(x
, e
)) * (c1
[i
] - c0
[i
]);
673 if (out
[i
] < range
[i
][0]) {
674 out
[i
] = range
[i
][0];
675 } else if (out
[i
] > range
[i
][1]) {
676 out
[i
] = range
[i
][1];
683 //------------------------------------------------------------------------
685 //------------------------------------------------------------------------
687 StitchingFunction::StitchingFunction(Object
*funcObj
, Dict
*dict
, std::set
<int> *usedParents
) {
697 //----- initialize the generic stuff
702 error(errSyntaxError
, -1, "Stitching function with more than one input");
707 if (!dict
->lookup("Functions", &obj1
)->isArray()) {
708 error(errSyntaxError
, -1, "Missing 'Functions' entry in stitching function");
711 k
= obj1
.arrayGetLength();
712 funcs
= (Function
**)gmallocn(k
, sizeof(Function
*));
713 bounds
= (double *)gmallocn(k
+ 1, sizeof(double));
714 encode
= (double *)gmallocn(2 * k
, sizeof(double));
715 scale
= (double *)gmallocn(k
, sizeof(double));
716 for (i
= 0; i
< k
; ++i
) {
719 for (i
= 0; i
< k
; ++i
) {
720 std::set
<int> usedParentsAux
= *usedParents
;
721 obj1
.arrayGetNF(i
, &obj2
);
723 const Ref ref
= obj2
.getRef();
724 if (usedParentsAux
.find(ref
.num
) == usedParentsAux
.end()) {
725 usedParentsAux
.insert(ref
.num
);
727 obj1
.arrayGet(i
, &obj2
);
732 if (!(funcs
[i
] = Function::parse(&obj2
, &usedParentsAux
))) {
735 if (funcs
[i
]->getInputSize() != 1 ||
736 (i
> 0 && funcs
[i
]->getOutputSize() != funcs
[0]->getOutputSize())) {
737 error(errSyntaxError
, -1,
738 "Incompatible subfunctions in stitching function");
746 if (!dict
->lookup("Bounds", &obj1
)->isArray() ||
747 obj1
.arrayGetLength() != k
- 1) {
748 error(errSyntaxError
, -1, "Missing or invalid 'Bounds' entry in stitching function");
751 bounds
[0] = domain
[0][0];
752 for (i
= 1; i
< k
; ++i
) {
753 if (!obj1
.arrayGet(i
- 1, &obj2
)->isNum()) {
754 error(errSyntaxError
, -1, "Invalid type in 'Bounds' array in stitching function");
757 bounds
[i
] = obj2
.getNum();
760 bounds
[k
] = domain
[0][1];
764 if (!dict
->lookup("Encode", &obj1
)->isArray() ||
765 obj1
.arrayGetLength() != 2 * k
) {
766 error(errSyntaxError
, -1, "Missing or invalid 'Encode' entry in stitching function");
769 for (i
= 0; i
< 2 * k
; ++i
) {
770 if (!obj1
.arrayGet(i
, &obj2
)->isNum()) {
771 error(errSyntaxError
, -1, "Invalid type in 'Encode' array in stitching function");
774 encode
[i
] = obj2
.getNum();
779 //----- pre-compute the scale factors
780 for (i
= 0; i
< k
; ++i
) {
781 if (bounds
[i
] == bounds
[i
+1]) {
782 // avoid a divide-by-zero -- in this situation, function i will
783 // never be used anyway
786 scale
[i
] = (encode
[2*i
+1] - encode
[2*i
]) / (bounds
[i
+1] - bounds
[i
]);
790 n
= funcs
[0]->getOutputSize();
800 StitchingFunction::StitchingFunction(const StitchingFunction
*func
) : Function(func
) {
803 funcs
= (Function
**)gmallocn(k
, sizeof(Function
*));
804 for (int i
= 0; i
< k
; ++i
) {
805 funcs
[i
] = func
->funcs
[i
]->copy();
808 bounds
= (double *)gmallocn(k
+ 1, sizeof(double));
809 memcpy(bounds
, func
->bounds
, (k
+ 1) * sizeof(double));
811 encode
= (double *)gmallocn(2 * k
, sizeof(double));
812 memcpy(encode
, func
->encode
, 2 * k
* sizeof(double));
814 scale
= (double *)gmallocn(k
, sizeof(double));
815 memcpy(scale
, func
->scale
, k
* sizeof(double));
820 StitchingFunction::~StitchingFunction() {
824 for (i
= 0; i
< k
; ++i
) {
836 void StitchingFunction::transform(double *in
, double *out
) {
840 if (in
[0] < domain
[0][0]) {
842 } else if (in
[0] > domain
[0][1]) {
847 for (i
= 0; i
< k
- 1; ++i
) {
848 if (x
< bounds
[i
+1]) {
852 x
= encode
[2*i
] + (x
- bounds
[i
]) * scale
[i
];
853 funcs
[i
]->transform(&x
, out
);
856 //------------------------------------------------------------------------
857 // PostScriptFunction
858 //------------------------------------------------------------------------
906 // Note: 'if' and 'ifelse' are parsed separately.
907 // The rest are listed here in alphabetical order.
908 // The index in this table is equivalent to the entry in PSOp.
909 static const char *psOpNames
[] = {
952 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
962 // In the code array, 'if'/'ifelse' operators take up three slots
963 // plus space for the code in the subclause(s).
965 // +---------------------------------+
966 // | psOperator: psOpIf / psOpIfelse |
967 // +---------------------------------+
968 // | psBlock: ptr=<A> |
969 // +---------------------------------+
970 // | psBlock: ptr=<B> |
971 // +---------------------------------+
974 // | psOperator: psOpReturn |
975 // +---------------------------------+
976 // <A> | else clause |
978 // | psOperator: psOpReturn |
979 // +---------------------------------+
982 // For 'if', pointer <A> is present in the code stream but unused.
987 GBool booln
; // boolean (stack only)
988 int intg
; // integer (stack and code)
989 double real
; // real (stack and code)
990 PSOp op
; // operator (code only)
991 int blk
; // if/ifelse block pointer (code only)
995 #define psStackSize 100
1000 PSStack() {sp
= psStackSize
; }
1001 void clear() { sp
= psStackSize
; }
1002 void pushBool(GBool booln
)
1004 if (checkOverflow()) {
1005 stack
[--sp
].type
= psBool
;
1006 stack
[sp
].booln
= booln
;
1009 void pushInt(int intg
)
1011 if (checkOverflow()) {
1012 stack
[--sp
].type
= psInt
;
1013 stack
[sp
].intg
= intg
;
1016 void pushReal(double real
)
1018 if (checkOverflow()) {
1019 stack
[--sp
].type
= psReal
;
1020 stack
[sp
].real
= real
;
1025 if (checkUnderflow() && checkType(psBool
, psBool
)) {
1026 return stack
[sp
++].booln
;
1032 if (checkUnderflow() && checkType(psInt
, psInt
)) {
1033 return stack
[sp
++].intg
;
1041 if (checkUnderflow() && checkType(psInt
, psReal
)) {
1042 ret
= (stack
[sp
].type
== psInt
) ? (double)stack
[sp
].intg
: stack
[sp
].real
;
1048 GBool
empty() { return sp
== psStackSize
; }
1049 GBool
topIsInt() { return sp
< psStackSize
&& stack
[sp
].type
== psInt
; }
1050 GBool
topTwoAreInts()
1051 { return sp
< psStackSize
- 1 &&
1052 stack
[sp
].type
== psInt
&&
1053 stack
[sp
+1].type
== psInt
; }
1054 GBool
topIsReal() { return sp
< psStackSize
&& stack
[sp
].type
== psReal
; }
1055 GBool
topTwoAreNums()
1056 { return sp
< psStackSize
- 1 &&
1057 (stack
[sp
].type
== psInt
|| stack
[sp
].type
== psReal
) &&
1058 (stack
[sp
+1].type
== psInt
|| stack
[sp
+1].type
== psReal
); }
1060 void roll(int n
, int j
);
1063 if (!checkOverflow()) {
1067 if (unlikely(sp
+ i
+ 1 >= psStackSize
)) {
1068 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1071 if (unlikely(sp
+ i
+ 1 < 0)) {
1072 error(errSyntaxError
, -1, "Stack overflow in PostScript function");
1075 stack
[sp
] = stack
[sp
+ 1 + i
];
1079 if (!checkUnderflow()) {
1087 GBool
checkOverflow(int n
= 1)
1090 error(errSyntaxError
, -1, "Stack overflow in PostScript function");
1095 GBool
checkUnderflow()
1097 if (sp
== psStackSize
) {
1098 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1103 GBool
checkType(PSObjectType t1
, PSObjectType t2
)
1105 if (stack
[sp
].type
!= t1
&& stack
[sp
].type
!= t2
) {
1106 error(errSyntaxError
, -1, "Type mismatch in PostScript function");
1111 PSObject stack
[psStackSize
];
1116 void PSStack::copy(int n
) {
1119 if (sp
+ n
> psStackSize
) {
1120 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1123 if (unlikely(sp
- n
> psStackSize
)) {
1124 error(errSyntaxError
, -1, "Stack underflow in PostScript function");
1127 if (!checkOverflow(n
)) {
1130 for (i
= sp
+ n
- 1; i
>= sp
; --i
) {
1131 stack
[i
- n
] = stack
[i
];
1136 void PSStack::roll(int n
, int j
) {
1140 if (unlikely(n
== 0)) {
1151 if (n
<= 0 || j
== 0 || n
> psStackSize
|| sp
+ n
> psStackSize
) {
1155 for (i
= 0; i
< j
; ++i
) {
1157 for (k
= sp
; k
< sp
+ n
- 1; ++k
) {
1158 stack
[k
] = stack
[k
+1];
1160 stack
[sp
+ n
- 1] = obj
;
1164 for (i
= 0; i
< j
; ++i
) {
1165 obj
= stack
[sp
+ n
- 1];
1166 for (k
= sp
+ n
- 1; k
> sp
; --k
) {
1167 stack
[k
] = stack
[k
-1];
1174 PostScriptFunction::PostScriptFunction(Object
*funcObj
, Dict
*dict
) {
1178 double in
[funcMaxInputs
];
1186 //----- initialize the generic stuff
1191 error(errSyntaxError
, -1, "Type 4 function is missing range");
1195 //----- get the stream
1196 if (!funcObj
->isStream()) {
1197 error(errSyntaxError
, -1, "Type 4 function isn't a stream");
1200 str
= funcObj
->getStream();
1202 //----- parse the function
1203 codeString
= new GooString();
1205 if (!(tok
= getToken(str
)) || tok
->cmp("{")) {
1206 error(errSyntaxError
, -1, "Expected '{{' at start of PostScript function");
1214 if (!parseCode(str
, &codePtr
)) {
1219 //----- set up the cache
1220 for (i
= 0; i
< m
; ++i
) {
1221 in
[i
] = domain
[i
][0];
1222 cacheIn
[i
] = in
[i
] - 1;
1224 transform(in
, cacheOut
);
1234 PostScriptFunction::PostScriptFunction(const PostScriptFunction
*func
) : Function(func
) {
1235 codeSize
= func
->codeSize
;
1237 code
= (PSObject
*)gmallocn(codeSize
, sizeof(PSObject
));
1238 memcpy(code
, func
->code
, codeSize
* sizeof(PSObject
));
1240 codeString
= func
->codeString
->copy();
1242 memcpy(cacheIn
, func
->cacheIn
, funcMaxInputs
* sizeof(double));
1243 memcpy(cacheOut
, func
->cacheOut
, funcMaxOutputs
* sizeof(double));
1248 PostScriptFunction::~PostScriptFunction() {
1253 void PostScriptFunction::transform(double *in
, double *out
) {
1258 for (i
= 0; i
< m
; ++i
) {
1259 if (in
[i
] != cacheIn
[i
]) {
1264 for (i
= 0; i
< n
; ++i
) {
1265 out
[i
] = cacheOut
[i
];
1270 for (i
= 0; i
< m
; ++i
) {
1271 //~ may need to check for integers here
1272 stack
.pushReal(in
[i
]);
1275 for (i
= n
- 1; i
>= 0; --i
) {
1276 out
[i
] = stack
.popNum();
1277 if (out
[i
] < range
[i
][0]) {
1278 out
[i
] = range
[i
][0];
1279 } else if (out
[i
] > range
[i
][1]) {
1280 out
[i
] = range
[i
][1];
1285 // if (!stack->empty()) {
1286 // error(errSyntaxWarning, -1,
1287 // "Extra values on stack at end of PostScript function");
1290 // save current result in the cache
1291 for (i
= 0; i
< m
; ++i
) {
1294 for (i
= 0; i
< n
; ++i
) {
1295 cacheOut
[i
] = out
[i
];
1299 GBool
PostScriptFunction::parseCode(Stream
*str
, int *codePtr
) {
1307 if (!(tok
= getToken(str
))) {
1308 error(errSyntaxError
, -1, "Unexpected end of PostScript function stream");
1311 p
= tok
->getCString();
1312 if (isdigit(*p
) || *p
== '.' || *p
== '-') {
1320 resizeCode(*codePtr
);
1322 code
[*codePtr
].type
= psReal
;
1323 code
[*codePtr
].real
= gatof(tok
->getCString());
1325 code
[*codePtr
].type
= psInt
;
1326 code
[*codePtr
].intg
= atoi(tok
->getCString());
1330 } else if (!tok
->cmp("{")) {
1334 resizeCode(opPtr
+ 2);
1335 if (!parseCode(str
, codePtr
)) {
1338 if (!(tok
= getToken(str
))) {
1339 error(errSyntaxError
, -1, "Unexpected end of PostScript function stream");
1342 if (!tok
->cmp("{")) {
1344 if (!parseCode(str
, codePtr
)) {
1348 if (!(tok
= getToken(str
))) {
1349 error(errSyntaxError
, -1, "Unexpected end of PostScript function stream");
1355 if (!tok
->cmp("if")) {
1357 error(errSyntaxError
, -1,
1358 "Got 'if' operator with two blocks in PostScript function");
1361 code
[opPtr
].type
= psOperator
;
1362 code
[opPtr
].op
= psOpIf
;
1363 code
[opPtr
+2].type
= psBlock
;
1364 code
[opPtr
+2].blk
= *codePtr
;
1365 } else if (!tok
->cmp("ifelse")) {
1367 error(errSyntaxError
, -1,
1368 "Got 'ifelse' operator with one block in PostScript function");
1371 code
[opPtr
].type
= psOperator
;
1372 code
[opPtr
].op
= psOpIfelse
;
1373 code
[opPtr
+1].type
= psBlock
;
1374 code
[opPtr
+1].blk
= elsePtr
;
1375 code
[opPtr
+2].type
= psBlock
;
1376 code
[opPtr
+2].blk
= *codePtr
;
1378 error(errSyntaxError
, -1,
1379 "Expected if/ifelse operator in PostScript function");
1384 } else if (!tok
->cmp("}")) {
1386 resizeCode(*codePtr
);
1387 code
[*codePtr
].type
= psOperator
;
1388 code
[*codePtr
].op
= psOpReturn
;
1394 cmp
= 0; // make gcc happy
1395 // invariant: psOpNames[a] < tok < psOpNames[b]
1398 cmp
= tok
->cmp(psOpNames
[mid
]);
1401 } else if (cmp
< 0) {
1408 error(errSyntaxError
, -1,
1409 "Unknown operator '{0:t}' in PostScript function",
1415 resizeCode(*codePtr
);
1416 code
[*codePtr
].type
= psOperator
;
1417 code
[*codePtr
].op
= (PSOp
)a
;
1424 GooString
*PostScriptFunction::getToken(Stream
*str
) {
1429 s
= new GooString();
1432 if ((c
= str
->getChar()) == EOF
) {
1435 codeString
->append(c
);
1437 if (c
== '\x0a' || c
== '\x0d') {
1440 } else if (c
== '%') {
1442 } else if (!isspace(c
)) {
1446 if (c
== '{' || c
== '}') {
1448 } else if (isdigit(c
) || c
== '.' || c
== '-') {
1451 c
= str
->lookChar();
1452 if (c
== EOF
|| !(isdigit(c
) || c
== '.' || c
== '-')) {
1456 codeString
->append(c
);
1461 c
= str
->lookChar();
1462 if (c
== EOF
|| !isalnum(c
)) {
1466 codeString
->append(c
);
1472 void PostScriptFunction::resizeCode(int newSize
) {
1473 if (newSize
>= codeSize
) {
1475 code
= (PSObject
*)greallocn(code
, codeSize
, sizeof(PSObject
));
1479 void PostScriptFunction::exec(PSStack
*stack
, int codePtr
) {
1481 double r1
, r2
, result
;
1485 switch (code
[codePtr
].type
) {
1487 stack
->pushInt(code
[codePtr
++].intg
);
1490 stack
->pushReal(code
[codePtr
++].real
);
1493 switch (code
[codePtr
++].op
) {
1495 if (stack
->topIsInt()) {
1496 stack
->pushInt(abs(stack
->popInt()));
1498 stack
->pushReal(fabs(stack
->popNum()));
1502 if (stack
->topTwoAreInts()) {
1503 i2
= stack
->popInt();
1504 i1
= stack
->popInt();
1505 stack
->pushInt(i1
+ i2
);
1507 r2
= stack
->popNum();
1508 r1
= stack
->popNum();
1509 stack
->pushReal(r1
+ r2
);
1513 if (stack
->topTwoAreInts()) {
1514 i2
= stack
->popInt();
1515 i1
= stack
->popInt();
1516 stack
->pushInt(i1
& i2
);
1518 b2
= stack
->popBool();
1519 b1
= stack
->popBool();
1520 stack
->pushBool(b1
&& b2
);
1524 r2
= stack
->popNum();
1525 r1
= stack
->popNum();
1526 result
= atan2(r1
, r2
) * 180.0 / M_PI
;
1527 if (result
< 0) result
+= 360.0;
1528 stack
->pushReal(result
);
1531 i2
= stack
->popInt();
1532 i1
= stack
->popInt();
1534 stack
->pushInt(i1
<< i2
);
1535 } else if (i2
< 0) {
1536 stack
->pushInt((int)((Guint
)i1
>> -i2
));
1542 if (!stack
->topIsInt()) {
1543 stack
->pushReal(ceil(stack
->popNum()));
1547 stack
->copy(stack
->popInt());
1550 stack
->pushReal(cos(stack
->popNum() * M_PI
/ 180.0));
1553 if (!stack
->topIsInt()) {
1554 stack
->pushInt((int)stack
->popNum());
1558 if (!stack
->topIsReal()) {
1559 stack
->pushReal(stack
->popNum());
1563 r2
= stack
->popNum();
1564 r1
= stack
->popNum();
1565 stack
->pushReal(r1
/ r2
);
1571 if (stack
->topTwoAreInts()) {
1572 i2
= stack
->popInt();
1573 i1
= stack
->popInt();
1574 stack
->pushBool(i1
== i2
);
1575 } else if (stack
->topTwoAreNums()) {
1576 r2
= stack
->popNum();
1577 r1
= stack
->popNum();
1578 stack
->pushBool(r1
== r2
);
1580 b2
= stack
->popBool();
1581 b1
= stack
->popBool();
1582 stack
->pushBool(b1
== b2
);
1589 r2
= stack
->popNum();
1590 r1
= stack
->popNum();
1591 stack
->pushReal(pow(r1
, r2
));
1594 stack
->pushBool(gFalse
);
1597 if (!stack
->topIsInt()) {
1598 stack
->pushReal(floor(stack
->popNum()));
1602 if (stack
->topTwoAreInts()) {
1603 i2
= stack
->popInt();
1604 i1
= stack
->popInt();
1605 stack
->pushBool(i1
>= i2
);
1607 r2
= stack
->popNum();
1608 r1
= stack
->popNum();
1609 stack
->pushBool(r1
>= r2
);
1613 if (stack
->topTwoAreInts()) {
1614 i2
= stack
->popInt();
1615 i1
= stack
->popInt();
1616 stack
->pushBool(i1
> i2
);
1618 r2
= stack
->popNum();
1619 r1
= stack
->popNum();
1620 stack
->pushBool(r1
> r2
);
1624 i2
= stack
->popInt();
1625 i1
= stack
->popInt();
1626 stack
->pushInt(i1
/ i2
);
1629 stack
->index(stack
->popInt());
1632 if (stack
->topTwoAreInts()) {
1633 i2
= stack
->popInt();
1634 i1
= stack
->popInt();
1635 stack
->pushBool(i1
<= i2
);
1637 r2
= stack
->popNum();
1638 r1
= stack
->popNum();
1639 stack
->pushBool(r1
<= r2
);
1643 stack
->pushReal(log(stack
->popNum()));
1646 stack
->pushReal(log10(stack
->popNum()));
1649 if (stack
->topTwoAreInts()) {
1650 i2
= stack
->popInt();
1651 i1
= stack
->popInt();
1652 stack
->pushBool(i1
< i2
);
1654 r2
= stack
->popNum();
1655 r1
= stack
->popNum();
1656 stack
->pushBool(r1
< r2
);
1660 i2
= stack
->popInt();
1661 i1
= stack
->popInt();
1662 stack
->pushInt(i1
% i2
);
1665 if (stack
->topTwoAreInts()) {
1666 i2
= stack
->popInt();
1667 i1
= stack
->popInt();
1668 //~ should check for out-of-range, and push a real instead
1669 stack
->pushInt(i1
* i2
);
1671 r2
= stack
->popNum();
1672 r1
= stack
->popNum();
1673 stack
->pushReal(r1
* r2
);
1677 if (stack
->topTwoAreInts()) {
1678 i2
= stack
->popInt();
1679 i1
= stack
->popInt();
1680 stack
->pushBool(i1
!= i2
);
1681 } else if (stack
->topTwoAreNums()) {
1682 r2
= stack
->popNum();
1683 r1
= stack
->popNum();
1684 stack
->pushBool(r1
!= r2
);
1686 b2
= stack
->popBool();
1687 b1
= stack
->popBool();
1688 stack
->pushBool(b1
!= b2
);
1692 if (stack
->topIsInt()) {
1693 stack
->pushInt(-stack
->popInt());
1695 stack
->pushReal(-stack
->popNum());
1699 if (stack
->topIsInt()) {
1700 stack
->pushInt(~stack
->popInt());
1702 stack
->pushBool(!stack
->popBool());
1706 if (stack
->topTwoAreInts()) {
1707 i2
= stack
->popInt();
1708 i1
= stack
->popInt();
1709 stack
->pushInt(i1
| i2
);
1711 b2
= stack
->popBool();
1712 b1
= stack
->popBool();
1713 stack
->pushBool(b1
|| b2
);
1720 i2
= stack
->popInt();
1721 i1
= stack
->popInt();
1722 stack
->roll(i1
, i2
);
1725 if (!stack
->topIsInt()) {
1726 r1
= stack
->popNum();
1727 stack
->pushReal((r1
>= 0) ? floor(r1
+ 0.5) : ceil(r1
- 0.5));
1731 stack
->pushReal(sin(stack
->popNum() * M_PI
/ 180.0));
1734 stack
->pushReal(sqrt(stack
->popNum()));
1737 if (stack
->topTwoAreInts()) {
1738 i2
= stack
->popInt();
1739 i1
= stack
->popInt();
1740 stack
->pushInt(i1
- i2
);
1742 r2
= stack
->popNum();
1743 r1
= stack
->popNum();
1744 stack
->pushReal(r1
- r2
);
1748 stack
->pushBool(gTrue
);
1751 if (!stack
->topIsInt()) {
1752 r1
= stack
->popNum();
1753 stack
->pushReal((r1
>= 0) ? floor(r1
) : ceil(r1
));
1757 if (stack
->topTwoAreInts()) {
1758 i2
= stack
->popInt();
1759 i1
= stack
->popInt();
1760 stack
->pushInt(i1
^ i2
);
1762 b2
= stack
->popBool();
1763 b1
= stack
->popBool();
1764 stack
->pushBool(b1
^ b2
);
1768 b1
= stack
->popBool();
1770 exec(stack
, codePtr
+ 2);
1772 codePtr
= code
[codePtr
+ 1].blk
;
1775 b1
= stack
->popBool();
1777 exec(stack
, codePtr
+ 2);
1779 exec(stack
, code
[codePtr
].blk
);
1781 codePtr
= code
[codePtr
+ 1].blk
;
1788 error(errSyntaxError
, -1, "Internal: bad object in PostScript function code");